Audit Activity Stream

Data & Tables

Real-time enterprise agent activity audit trail with JSON payload diff inspector.

Interactive Live Preview
components/ui/audit-log-table.tsxTypeScript · React 19
1"use client";
2
3import * as React from "react";
4
5interface AuditLogTableProps {
6 variant?: string;
7}
8
9export default function AuditLogTable({ variant = "Stream" }: AuditLogTableProps) {
10 const [filter, setFilter] = React.useState<"ALL" | "CRITICAL" | "WARN" | "INFO">("ALL");
11 const [expandedId, setExpandedId] = React.useState<string | null>("log-1");
12
13 const logs = [
14 {
15 id: "log-1",
16 timestamp: "14:22:08.412",
17 event: "agent.schema.migrate_table",
18 actor: "SchemaAuditor (Agent-4)",
19 level: "CRITICAL",
20 status: "APPROVED",
21 duration: "340ms",
22 details: {
23 table: "public.organizations",
24 statement: "CREATE INDEX CONCURRENTLY idx_org_slug ON organizations (slug);",
25 lockHeld: "ShareUpdateExclusiveLock (Non-blocking)",
26 },
27 },
28 {
29 id: "log-2",
30 timestamp: "14:21:45.190",
31 event: "tool.vector.similarity_search",
32 actor: "LeadPlanner (Agent-1)",
33 level: "INFO",
34 status: "SUCCESS",
35 duration: "48ms",
36 details: {
37 index: "pinecone-prod-knowledge-1536",
38 topK: 8,
39 latency: "48ms",
40 },
41 },
42 {
43 id: "log-3",
44 timestamp: "14:20:12.871",
45 event: "llm.guardrail.pii_redacted",
46 actor: "SecurityCritic (Agent-3)",
47 level: "WARN",
48 status: "REDACTED",
49 duration: "12ms",
50 details: {
51 pattern: "CREDIT_CARD_NUM",
52 maskedTokens: 16,
53 confidence: 0.994,
54 },
55 },
56 {
57 id: "log-4",
58 timestamp: "14:18:59.034",
59 event: "api.webhook.dispatch",
60 actor: "WorkflowEngine (System)",
61 level: "INFO",
62 status: "200 OK",
63 duration: "120ms",
64 details: {
65 endpoint: "https://api.acme.corp/v1/agent-events",
66 payloadBytes: 1042,
67 },
68 },
69 ];
70
71 const filtered = logs.filter((l) => (filter === "ALL" ? true : l.level === filter));
72
73 return (
74 <div className="w-full max-w-120 overflow-hidden rounded-card bg-surface shadow-card border border-line">
75 {/* Table Header & Filters */}
76 <div className="primitive-card-bar flex flex-wrap items-center justify-between gap-2 border-b border-line bg-surface/90 px-4 py-3">
77 <div className="flex items-center gap-2">
78 <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
79 <polyline points="22 12 18 12 15 21 9 3 6 12 2 12" />
80 </svg>
81 <span className="font-display font-semibold text-[14px] text-ink">
82 Audit Activity Stream
83 </span>
84 </div>
85
86 {/* Level Filters */}
87 <div className="flex items-center gap-1 font-mono text-[10.5px]">
88 {(["ALL", "CRITICAL", "WARN", "INFO"] as const).map((lvl) => (
89 <button
90 key={lvl}
91 onClick={() => setFilter(lvl)}
92 className={`rounded-chip px-2 py-0.5 transition-colors border ${
93 filter === lvl
94 ? "bg-accent text-accent-ink font-bold border-accent"
95 : "bg-field text-ink-3 hover:text-ink border-line"
96 }`}
97 >
98 {lvl}
99 </button>
100 ))}
101 </div>
102 </div>
103
104 {/* Rows Table */}
105 <div className="divide-y divide-line/60">
106 {filtered.map((log) => {
107 const isExpanded = expandedId === log.id;
108 return (
109 <div key={log.id} className="transition-colors hover:bg-hover/30">
110 <div
111 onClick={() => setExpandedId(isExpanded ? null : log.id)}
112 className="flex items-center justify-between p-3 cursor-pointer text-[12px] font-mono"
113 >
114 <div className="flex items-center gap-2 min-w-0">
115 <span
116 className={`size-2 rounded-full shrink-0 ${
117 log.level === "CRITICAL"
118 ? "bg-red animate-pulse"
119 : log.level === "WARN"
120 ? "bg-orange"
121 : "bg-green"
122 }`}
123 />
124 <span className="text-ink-3 truncate">{log.timestamp}</span>
125 <span className="text-ink font-semibold truncate">{log.event}</span>
126 </div>
127
128 <div className="flex items-center gap-2 shrink-0">
129 <span className="rounded-[4px] bg-field px-1.5 py-0.2 text-[10px] text-ink-3">
130 {log.duration}
131 </span>
132 <span className="text-accent text-[11px]">{isExpanded ? "▲" : "▼"}</span>
133 </div>
134 </div>
135
136 {/* Expandable JSON Detail Payload */}
137 {isExpanded && (
138 <div className="px-3.5 pb-3 pt-0">
139 <div className="rounded-control bg-inset/80 p-3 font-mono text-[11px] leading-relaxed text-ink border border-line/60">
140 <div className="flex items-center justify-between text-ink-3 pb-1 mb-1 border-b border-line/40">
141 <span>Actor: {log.actor}</span>
142 <span className="text-accent">Status: {log.status}</span>
143 </div>
144 <pre className="whitespace-pre-wrap text-emerald-400">
145 {JSON.stringify(log.details, null, 2)}
146 </pre>
147 </div>
148 </div>
149 )}
150 </div>
151 );
152 })}
153 </div>
154
155 {/* Footer */}
156 <div className="flex items-center justify-between border-t border-line bg-inset/40 px-4 py-2 font-mono text-[10.5px] text-ink-3">
157 <span>Immutable Hash Ring: #b82a...91f4</span>
158 <span className="text-accent">Export Audit Log (JSONL) →</span>
159 </div>
160 </div>
161 );
162}
163

Props & Specification

PropTypeDefaultDescription
variantStream | CriticalStreamVisual state and layout presentation mode.
classNamestring""Optional Tailwind CSS wrapper class overrides.

Related Components in Data & Tables