fix: correct page directory casing for case-sensitive filesystems
Rename admin/ → Admin/ and swagger/ → Swagger/ to match router imports. Windows is case-insensitive so the mismatch was invisible locally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
59
ui/src/pages/Admin/AuditLogPage.tsx
Normal file
59
ui/src/pages/Admin/AuditLogPage.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { DataTable, Badge, Input, Select, MonoText, CodeBlock } from '@cameleer/design-system';
|
||||
import type { Column } from '@cameleer/design-system';
|
||||
import { useAuditLog } from '../../api/queries/admin/audit';
|
||||
|
||||
export default function AuditLogPage() {
|
||||
const [search, setSearch] = useState('');
|
||||
const [category, setCategory] = useState('');
|
||||
const [page, setPage] = useState(0);
|
||||
|
||||
const { data, isLoading } = useAuditLog({ search, category: category || undefined, page, size: 25 });
|
||||
|
||||
const columns: Column<any>[] = [
|
||||
{ key: 'timestamp', header: 'Time', sortable: true, render: (v) => new Date(v as string).toLocaleString() },
|
||||
{ key: 'username', header: 'User', render: (v) => <MonoText size="sm">{String(v)}</MonoText> },
|
||||
{ key: 'action', header: 'Action' },
|
||||
{ key: 'category', header: 'Category', render: (v) => <Badge label={String(v)} color="auto" /> },
|
||||
{ key: 'target', header: 'Target', render: (v) => v ? <MonoText size="sm">{String(v)}</MonoText> : null },
|
||||
{ key: 'result', header: 'Result', render: (v) => <Badge label={String(v)} color={v === 'SUCCESS' ? 'success' : 'error'} /> },
|
||||
];
|
||||
|
||||
const rows = useMemo(() =>
|
||||
(data?.items || []).map((item: any) => ({ ...item, id: String(item.id) })),
|
||||
[data],
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 style={{ marginBottom: '1rem' }}>Audit Log</h2>
|
||||
|
||||
<div style={{ display: 'flex', gap: '0.75rem', marginBottom: '1rem' }}>
|
||||
<Input placeholder="Search..." value={search} onChange={(e) => setSearch(e.target.value)} />
|
||||
<Select
|
||||
options={[
|
||||
{ value: '', label: 'All Categories' },
|
||||
{ value: 'AUTH', label: 'Auth' },
|
||||
{ value: 'CONFIG', label: 'Config' },
|
||||
{ value: 'RBAC', label: 'RBAC' },
|
||||
{ value: 'INFRA', label: 'Infra' },
|
||||
]}
|
||||
value={category}
|
||||
onChange={(e) => setCategory(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={rows}
|
||||
sortable
|
||||
pageSize={25}
|
||||
expandedContent={(row) => (
|
||||
<div style={{ padding: '0.75rem' }}>
|
||||
<CodeBlock content={JSON.stringify(row.detail, null, 2)} />
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user