Audit Activity Stream
Data & TablesReal-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";23import * as React from "react";45interface AuditLogTableProps {6 variant?: string;7}89export 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");1213 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 ];7071 const filtered = logs.filter((l) => (filter === "ALL" ? true : l.level === filter));7273 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 Stream83 </span>84 </div>8586 {/* 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 <button90 key={lvl}91 onClick={() => setFilter(lvl)}92 className={`rounded-chip px-2 py-0.5 transition-colors border ${93 filter === lvl94 ? "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>103104 {/* 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 <div111 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 <span116 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>127128 <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>135136 {/* 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>154155 {/* 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
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | Stream | Critical | Stream | Visual state and layout presentation mode. |
| className | string | "" | Optional Tailwind CSS wrapper class overrides. |