"use client"; import { useState, useCallback, useEffect } from "react"; import { StemeDBClient, type AuditResponse, ApiError } from "@/lib/api"; import type { PanelState } from "@/lib/types"; import { AUDIT_FETCH_LIMIT, TIME_RANGES_MS, type TimeRangeKey } from "@/lib/constants"; import { ErrorState } from "@/components/shared/error-state"; import { AuditList } from "./audit-list"; import { AuditLoadingSkeleton } from "./audit-loading-skeleton"; import { AuditEmptyState } from "./audit-empty-state"; import type { AuditFilterValues } from "./audit-filters"; interface AuditPanelProps { initialFilters?: Partial; } export function AuditPanel({ initialFilters }: AuditPanelProps) { const [state, setState] = useState>({ status: "idle" }); const [filters, setFilters] = useState({ subject: initialFilters?.subject ?? "", predicate: initialFilters?.predicate ?? "", agentId: initialFilters?.agentId ?? "", action: initialFilters?.action ?? "", timeRange: initialFilters?.timeRange ?? "24h", }); const fetchData = useCallback(async (currentFilters: AuditFilterValues) => { setState({ status: "loading" }); try { const client = new StemeDBClient(); // Convert time range to from/to timestamps let fromTs: number | undefined; let toTs: number | undefined; if (currentFilters.timeRange !== "all") { const now = Date.now(); const rangeMs = TIME_RANGES_MS[currentFilters.timeRange as TimeRangeKey] ?? TIME_RANGES_MS["24h"]; fromTs = now - rangeMs; toTs = now; } const data = await client.auditQueries({ limit: AUDIT_FETCH_LIMIT, agentId: currentFilters.agentId || undefined, subject: currentFilters.subject || undefined, predicate: currentFilters.predicate || undefined, from: fromTs, to: toTs, }); setState({ status: "success", data }); } catch (err) { // 404 means no audit entries - treat as empty success if (err instanceof ApiError && err.status === 404) { setState({ status: "success", data: { audits: [], total_count: 0 }, }); return; } const message = err instanceof ApiError ? err.userMessage : err instanceof Error ? err.message : "Unknown error"; setState({ status: "error", error: message }); } }, []); // Load data on mount useEffect(() => { fetchData(filters); }, [fetchData, filters]); const handleFilterChange = useCallback((newFilters: AuditFilterValues) => { setFilters(newFilters); // fetchData will be called by the useEffect above }, []); const handleRetry = useCallback(() => { fetchData(filters); }, [fetchData, filters]); const hasFilters = filters.subject !== "" || filters.predicate !== "" || filters.agentId !== "" || filters.action !== "" || filters.timeRange !== "24h"; return (
{/* Header */}

Query & Action History

Browse the complete audit trail of queries and administrative actions. Filter by subject, predicate, agent, or time range. Export data as JSON or CSV.

{/* Content */}
{state.status === "idle" && } {state.status === "loading" && } {state.status === "error" && ( )} {state.status === "success" && ( <> {state.data.audits.length === 0 && !hasFilters ? ( ) : ( )} )}
); }