import { useState, useEffect, useCallback } from "react"; import { Search, Filter, RefreshCw, ChevronLeft, ChevronRight, LogIn, Key, UserPlus, Shield, Settings, AlertTriangle, Terminal, Loader2, CheckCircle2, XCircle, Globe, Lock, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { api, AuditLogEntry, ApiError } from "@/lib/api"; import { formatDateTime } from "@/lib/date"; // ─── category helpers ──────────────────────────────────────────────────────── type Category = "auth" | "ssh" | "org" | "user" | "security" | "token" | "admin" | "other"; const getCategory = (action: string): Category => { const a = action.toLowerCase(); if (a.startsWith("session") || a === "user.login" || a === "user.logout" || a.startsWith("external_auth.login")) return "auth"; if (a.startsWith("ssh")) return "ssh"; if (a.startsWith("admin.")) return "admin"; if (a.startsWith("org") || a.includes("member") || a.includes("department") || a.includes("invite")) return "org"; if (a.startsWith("user")) return "user"; if (a.includes("mfa") || a.includes("totp") || a.includes("webauthn") || a.includes("passkey") || a.includes("password")) return "security"; if (a.includes("token") || a.includes("oidc") || a.includes("client") || a.startsWith("external_auth")) return "token"; return "other"; }; const CATEGORY_META: Record = { auth: { label: "Auth", color: "bg-blue-500/10 text-blue-600 dark:text-blue-400" }, ssh: { label: "SSH", color: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" }, org: { label: "Org", color: "bg-violet-500/10 text-violet-600 dark:text-violet-400" }, user: { label: "User", color: "bg-amber-500/10 text-amber-600 dark:text-amber-400" }, security: { label: "Security", color: "bg-orange-500/10 text-orange-600 dark:text-orange-400" }, token: { label: "Token", color: "bg-cyan-500/10 text-cyan-600 dark:text-cyan-400" }, admin: { label: "Admin", color: "bg-red-500/10 text-red-600 dark:text-red-400" }, other: { label: "Other", color: "bg-muted text-muted-foreground" }, }; const getCategoryIcon = (category: Category) => { const cls = "w-4 h-4"; switch (category) { case "auth": return ; case "ssh": return ; case "org": return ; case "user": return ; case "security": return ; case "token": return ; case "admin": return ; default: return ; } }; const getActionLabel = (action: string) => action .replace(/_/g, " ") .replace(/\./g, " › ") .replace(/\b\w/g, (c) => c.toUpperCase()); // ─── component ─────────────────────────────────────────────────────────────── const ACTION_FILTER_OPTIONS = [ { value: "all", label: "All actions" }, { value: "session.create", label: "Login" }, { value: "session.revoke", label: "Logout" }, { value: "external_auth.login", label: "OAuth Login" }, { value: "external_auth.login.failed", label: "OAuth Failed" }, { value: "external_auth.link.completed", label: "OAuth Account Linked" }, { value: "external_auth.unlink", label: "OAuth Account Unlinked" }, { value: "user.register", label: "Register" }, { value: "ssh.key.added", label: "SSH Key Added" }, { value: "ssh.key.verified", label: "SSH Key Verified" }, { value: "ssh.key.deleted", label: "SSH Key Deleted" }, { value: "ssh.cert.issued", label: "SSH Cert Issued" }, { value: "ssh.cert.revoked", label: "SSH Cert Revoked" }, { value: "ssh.cert.failed", label: "SSH Cert Failed" }, { value: "org.create", label: "Org Created" }, { value: "org.member.add", label: "Member Added" }, { value: "org.member.remove", label: "Member Removed" }, { value: "org.member.role_change", label: "Role Changed" }, { value: "org.security_policy.update", label: "Security Policy Updated" }, { value: "admin.mfa.remove", label: "MFA Removed (Admin)" }, { value: "admin.oauth.unlink", label: "OAuth Unlinked (Admin)" }, { value: "admin.password.set", label: "Password Set (Admin)" }, { value: "totp.enroll.completed", label: "TOTP Enrolled" }, { value: "totp.disabled", label: "TOTP Disabled" }, { value: "webauthn.register.completed", label: "Passkey Registered" }, { value: "webauthn.credential.deleted", label: "Passkey Removed" }, { value: "user.password_change", label: "Password Changed" }, { value: "user.password_reset", label: "Password Reset" }, { value: "user.suspend", label: "User Suspended" }, ]; export default function SystemAuditPage() { const [logs, setLogs] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [accessDenied, setAccessDenied] = useState(false); const [isAdminView, setIsAdminView] = useState(false); // filters const [search, setSearch] = useState(""); const [debouncedSearch, setDebouncedSearch] = useState(""); const [actionFilter, setActionFilter] = useState("all"); const [successFilter, setSuccessFilter] = useState("all"); // pagination const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [totalCount, setTotalCount] = useState(0); const PER_PAGE = 50; // debounce search useEffect(() => { const t = setTimeout(() => setDebouncedSearch(search), 400); return () => clearTimeout(t); }, [search]); const fetchLogs = useCallback(async () => { setIsLoading(true); setError(null); setAccessDenied(false); try { const params: Record = { page: String(page), per_page: String(PER_PAGE), }; if (actionFilter !== "all") params.action = actionFilter; if (successFilter !== "all") params.success = successFilter; if (debouncedSearch) params.q = debouncedSearch; const resp = await api.admin.getAuditLogs(params); setLogs(resp.audit_logs ?? []); setTotalCount(resp.count ?? 0); setTotalPages(resp.pages ?? 1); setIsAdminView(resp.is_admin_view ?? false); } catch (err) { if (err instanceof ApiError && err.code === 403) { setAccessDenied(true); } else { console.error("Failed to fetch system audit logs:", err); setError("Failed to load audit logs. Please try again."); } } finally { setIsLoading(false); } }, [page, actionFilter, successFilter, debouncedSearch]); useEffect(() => { fetchLogs(); }, [fetchLogs]); // reset to page 1 when filters change useEffect(() => { setPage(1); }, [actionFilter, successFilter, debouncedSearch]); const formatDate = (dateString: string) => formatDateTime(dateString); const formatUserAgent = (ua: string | null) => { if (!ua) return null; const m = ua.match(/\(([^)]+)\)/); if (m) return m[1].split(";")[0].trim(); return ua.slice(0, 40); }; return (
{/* Header */}

System Audit Log

{isAdminView ? `All system events — ${totalCount.toLocaleString()} total` : "Your account events"}

{/* Filters */}
setSearch(e.target.value)} className="pl-10" />
{/* Table */} {isLoading ? (
Loading…
) : accessDenied ? (

Access Restricted

You don't have permission to view system-wide audit logs. Contact your administrator to request access.

) : error ? (

{error}

) : logs.length === 0 ? (
No audit events match the current filters.
) : (
{logs.map((log) => { const cat = getCategory(log.action); const meta = CATEGORY_META[cat]; return (
{/* Icon */}
{log.success ? getCategoryIcon(cat) : }
{/* Body */}
{getActionLabel(log.action)} {meta.label} {!log.success && ( Failed )} {log.resource_type && ( {log.resource_type} )}
{/* Description */} {log.description && (

{log.description}

)} {log.error_message && (

{log.error_message}

)} {/* Meta row */}
{log.user?.email ? ( {log.user.email} ) : log.user_id ? ( {log.user_id.slice(0, 8)}… ) : ( System )} {log.ip_address && ( {log.ip_address} )} {log.user_agent && ( {formatUserAgent(log.user_agent)} )} {log.resource_id && ( {log.resource_id.slice(0, 8)}… )}
{/* Timestamp */}

{formatDate(log.created_at)}

{log.success ? ( ) : ( )}
); })}
)}
{/* Pagination */} {totalPages > 1 && (

Page {page} of {totalPages}  ·  {totalCount.toLocaleString()} events

)}
); }