import * as React from 'react'; import type { AuditEvent, AuditAction, AuditOutcome } from '@sentryagent/idp-sdk'; import { Badge } from '@/components/ui/badge'; import { getClient } from '@/lib/client'; const PAGE_LIMIT = 20; /** All AuditAction values for the filter dropdown. */ const AUDIT_ACTIONS: AuditAction[] = [ 'agent.created', 'agent.updated', 'agent.decommissioned', 'agent.suspended', 'agent.reactivated', 'token.issued', 'token.revoked', 'token.introspected', 'credential.generated', 'credential.rotated', 'credential.revoked', 'auth.failed', ]; /** Formats an ISO timestamp to a readable local date-time string. */ function formatDateTime(iso: string): string { return new Date(iso).toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', }); } /** Truncates a string to a maximum length with ellipsis. */ function truncate(value: string, maxLen = 24): string { return value.length > maxLen ? `${value.slice(0, maxLen)}…` : value; } /** * Audit Log page — displays audit events with filters for agent, action, outcome, and date range. * Route: /dashboard/audit */ export default function AuditLog(): React.JSX.Element { const [events, setEvents] = React.useState([]); const [total, setTotal] = React.useState(0); const [page, setPage] = React.useState(1); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); // Filters const [agentIdFilter, setAgentIdFilter] = React.useState(''); const [actionFilter, setActionFilter] = React.useState(''); const [outcomeFilter, setOutcomeFilter] = React.useState(''); const [fromDate, setFromDate] = React.useState(''); const [toDate, setToDate] = React.useState(''); // Reset to page 1 on filter change React.useEffect(() => { setPage(1); }, [agentIdFilter, actionFilter, outcomeFilter, fromDate, toDate]); React.useEffect(() => { let cancelled = false; setLoading(true); setError(null); const fetchEvents = async (): Promise => { try { const result = await getClient().audit.queryAuditLog({ page, limit: PAGE_LIMIT, agentId: agentIdFilter.trim() || undefined, action: actionFilter !== '' ? actionFilter : undefined, outcome: outcomeFilter !== '' ? outcomeFilter : undefined, fromDate: fromDate || undefined, toDate: toDate || undefined, }); if (!cancelled) { setEvents(result.data); setTotal(result.total); } } catch (err) { if (!cancelled) { setError(err instanceof Error ? err.message : 'Failed to load audit log.'); } } finally { if (!cancelled) setLoading(false); } }; void fetchEvents(); return () => { cancelled = true; }; }, [page, agentIdFilter, actionFilter, outcomeFilter, fromDate, toDate]); const totalPages = Math.max(1, Math.ceil(total / PAGE_LIMIT)); return (

Audit Log

{/* Filters */}
{ setAgentIdFilter(e.target.value); }} placeholder="Agent ID…" className="rounded-md border border-slate-300 px-3 py-2 text-sm focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500" /> { setFromDate(e.target.value); }} className="rounded-md border border-slate-300 px-3 py-2 text-sm focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500" title="From date" /> { setToDate(e.target.value); }} className="rounded-md border border-slate-300 px-3 py-2 text-sm focus:border-brand-500 focus:outline-none focus:ring-1 focus:ring-brand-500" title="To date" />
{error && (
{error}
)}
{['Timestamp', 'Agent ID', 'Action', 'Outcome', 'IP Address'].map((col) => ( ))} {loading ? Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: 5 }).map((__, j) => ( ))} )) : events.length === 0 ? ( ) : events.map((event) => ( )) }
{col}
No audit events found.
{formatDateTime(event.timestamp)} {truncate(event.agentId)} {event.action} {event.outcome} {event.ipAddress}
{/* Pagination */} {!loading && total > 0 && (
Page {page} of {totalPages} ({total} total)
)}
); }