Add database history to each admin member page

This commit is contained in:
Tanner Collin 2023-10-12 21:26:13 +09:00
parent 46d0e78d3c
commit 20db25afdd
3 changed files with 32 additions and 21 deletions

View File

@ -1128,9 +1128,15 @@ class HistoryViewSet(Base, List, Retrieve):
def get_queryset(self): def get_queryset(self):
queryset = models.HistoryIndex.objects queryset = models.HistoryIndex.objects
if 'exclude_system' in self.request.query_params: exclude_system = self.request.query_params.get('exclude_system', '') == 'true'
member_id = self.request.query_params.get('member_id', '')
if exclude_system:
queryset = queryset.filter(is_system=False) queryset = queryset.filter(is_system=False)
if member_id:
queryset = queryset.filter(owner_id=member_id)
return queryset.order_by('-history_date')[:50] return queryset.order_by('-history_date')[:50]

View File

@ -118,7 +118,7 @@ export function AdminVetting(props) {
} }
export function AdminHistory(props) { export function AdminHistory(props) {
const { token } = props; const { token, filterMember } = props;
const [history, setHistory] = useState(historyCache); const [history, setHistory] = useState(historyCache);
const [excludeSystem, setExcludeSystem] = useState(excludeSystemCache); const [excludeSystem, setExcludeSystem] = useState(excludeSystemCache);
const [focus, setFocus] = useState(focusCache); const [focus, setFocus] = useState(focusCache);
@ -131,7 +131,11 @@ export function AdminHistory(props) {
}; };
useEffect(() => { useEffect(() => {
const extra = excludeSystem ? '?exclude_system' : ''; let extra = '?exclude_system=' + excludeSystem;
if (filterMember) {
extra += '&member_id=' + filterMember;
}
requester('/history/'+extra, 'GET', token) requester('/history/'+extra, 'GET', token)
.then(res => { .then(res => {
setHistory(res.results); setHistory(res.results);
@ -148,6 +152,9 @@ export function AdminHistory(props) {
{!error ? {!error ?
history ? history ?
<> <>
<Header size='medium'>History</Header>
<p>Last 50 database changes:</p>
<Checkbox <Checkbox
label='Exclude System' label='Exclude System'
onChange={handleExcludeSystem} onChange={handleExcludeSystem}
@ -160,13 +167,15 @@ export function AdminHistory(props) {
<Table.HeaderCell>Date</Table.HeaderCell> <Table.HeaderCell>Date</Table.HeaderCell>
<Table.HeaderCell>Username</Table.HeaderCell> <Table.HeaderCell>Username</Table.HeaderCell>
<Table.HeaderCell>Type</Table.HeaderCell> <Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell>Owner</Table.HeaderCell> {!filterMember && <Table.HeaderCell>Owner</Table.HeaderCell>}
<Table.HeaderCell>Object</Table.HeaderCell> <Table.HeaderCell>Object</Table.HeaderCell>
<Table.HeaderCell>Changed Fields</Table.HeaderCell> <Table.HeaderCell>Changed Fields</Table.HeaderCell>
</Table.Row> </Table.Row>
</Table.Header>} </Table.Header>}
<Table.Body> <Table.Body>
{!history.length && <p>None</p>}
{history.map(x => {history.map(x =>
<React.Fragment key={x.id}> <React.Fragment key={x.id}>
<Table.Row> <Table.Row>
@ -177,7 +186,7 @@ export function AdminHistory(props) {
</Table.Cell> </Table.Cell>
<Table.Cell>{isMobile && 'User: '}{x.is_system ? 'System' : (x.history_user || 'Deleted User')}</Table.Cell> <Table.Cell>{isMobile && 'User: '}{x.is_system ? 'System' : (x.history_user || 'Deleted User')}</Table.Cell>
<Table.Cell>{isMobile && 'Type: '}{x.history_type}</Table.Cell> <Table.Cell>{isMobile && 'Type: '}{x.history_type}</Table.Cell>
<Table.Cell>{isMobile && 'Owner: '}{x.owner_name}</Table.Cell> {!filterMember && <Table.Cell>{isMobile && 'Owner: '}{x.owner_name}</Table.Cell>}
<Table.Cell>{isMobile && 'Object: '}{x.object_name}</Table.Cell> <Table.Cell>{isMobile && 'Object: '}{x.object_name}</Table.Cell>
<Table.Cell>{isMobile && 'Changed: '}{x.changes.map(x => x.field).join(', ')}</Table.Cell> <Table.Cell>{isMobile && 'Changed: '}{x.changes.map(x => x.field).join(', ')}</Table.Cell>
</Table.Row> </Table.Row>
@ -357,9 +366,7 @@ export function Admin(props) {
<p>All times are in Mountain time.</p> <p>All times are in Mountain time.</p>
<AdminUsage {...props} /> <AdminUsage {...props} />
<p/>
<Header size='medium'>History</Header>
<p>Last 50 database changes:</p>
<AdminHistory {...props} /> <AdminHistory {...props} />

View File

@ -6,6 +6,7 @@ import { statusColor, isAdmin, isInstructor, BasicTable, staticUrl, requester }
import { NotFound } from './Misc.js'; import { NotFound } from './Misc.js';
import { AdminMemberInfo, AdminMemberPause, AdminMemberForm, AdminMemberCards, AdminMemberTraining, AdminMemberCertifications } from './AdminMembers.js'; import { AdminMemberInfo, AdminMemberPause, AdminMemberForm, AdminMemberCards, AdminMemberTraining, AdminMemberCertifications } from './AdminMembers.js';
import { AdminMemberTransactions } from './AdminTransactions.js'; import { AdminMemberTransactions } from './AdminTransactions.js';
import { AdminHistory } from './Admin.js';
import { StorageButton } from './Storage.js'; import { StorageButton } from './Storage.js';
import AbortController from 'abort-controller'; import AbortController from 'abort-controller';
@ -341,7 +342,8 @@ export function MemberDetail(props) {
<Link to={'/members/'+member.id+'/cards'}>Cards</Link>{' - '} <Link to={'/members/'+member.id+'/cards'}>Cards</Link>{' - '}
<Link to={'/members/'+member.id+'/lockouts'}>Lockouts</Link>{' - '} <Link to={'/members/'+member.id+'/lockouts'}>Lockouts</Link>{' - '}
<Link to={'/members/'+member.id+'/training'}>Training</Link>{' - '} <Link to={'/members/'+member.id+'/training'}>Training</Link>{' - '}
<Link to={'/members/'+member.id+'/transactions'}>Transactions</Link> <Link to={'/members/'+member.id+'/transactions'}>Transactions</Link>{' - '}
<Link to={'/members/'+member.id+'/history'}>History</Link>
</p> </p>
} }
@ -365,27 +367,23 @@ export function MemberDetail(props) {
</Route>} </Route>}
{isAdmin(user) && <Route path='/members/:id/cards'> {isAdmin(user) && <Route path='/members/:id/cards'>
<Segment padded>
<AdminMemberCards result={result} refreshResult={refreshResult} {...props} /> <AdminMemberCards result={result} refreshResult={refreshResult} {...props} />
</Segment>
</Route>} </Route>}
{isAdmin(user) && <Route path='/members/:id/lockouts'> {isAdmin(user) && <Route path='/members/:id/lockouts'>
<Segment padded>
<AdminMemberCertifications result={result} refreshResult={refreshResult} {...props} /> <AdminMemberCertifications result={result} refreshResult={refreshResult} {...props} />
</Segment>
</Route>} </Route>}
{isAdmin(user) && <Route path='/members/:id/training'> {isAdmin(user) && <Route path='/members/:id/training'>
<Segment padded>
<AdminMemberTraining result={result} refreshResult={refreshResult} {...props} /> <AdminMemberTraining result={result} refreshResult={refreshResult} {...props} />
</Segment>
</Route>} </Route>}
{isAdmin(user) && <Route path='/members/:id/transactions'> {isAdmin(user) && <Route path='/members/:id/transactions'>
<Segment padded>
<AdminMemberTransactions result={result} refreshResult={refreshResult} {...props} /> <AdminMemberTransactions result={result} refreshResult={refreshResult} {...props} />
</Segment> </Route>}
{isAdmin(user) && <Route path='/members/:id/history'>
<AdminHistory filterMember={member.id} {...props} />
</Route>} </Route>}
<Route path='/members/:id'> <Route path='/members/:id'>