import { useState, useEffect, useCallback, useRef } from "react"; import { useTranslation } from "react-i18next"; import { Button } from "@/components/button"; import { Input } from "@/components/input"; import { ChevronLeft, ChevronRight, ClipboardList, RefreshCw, X, } from "lucide-react"; import { AccordionSection } from "./AdminSettingsShared"; import { getAuditLogs, getAuditLogActions, getAuditForwarding, updateAuditForwarding, type AuditLog, type AuditLogFilters, } from "@/api/audit-log-api"; import { toast } from "sonner"; import type { AdminUser } from "./AdminManagementSections"; import { Select2 } from "@/components/select2"; const RESOURCE_TYPES = [ "user", "host", "credential", "plugin", "session", "api_key", "setting", ]; type AdminAuditLogSectionProps = { open: boolean; onToggle: () => void; users: AdminUser[]; }; export function AdminAuditLogSection({ open, onToggle, users, }: AdminAuditLogSectionProps) { const { t } = useTranslation(); const [logs, setLogs] = useState([]); const [forwardUrl, setForwardUrl] = useState(""); const [forwardToken, setForwardToken] = useState(""); const [forwardHasToken, setForwardHasToken] = useState(false); const [forwardEnvConfigured, setForwardEnvConfigured] = useState(false); const [forwardSaving, setForwardSaving] = useState(false); useEffect(() => { if (!open) return; getAuditForwarding() .then((settings) => { setForwardUrl(settings.url); setForwardHasToken(settings.hasToken); setForwardEnvConfigured(settings.envConfigured); }) .catch(() => {}); }, [open]); async function handleSaveForwarding() { setForwardSaving(true); try { const result = await updateAuditForwarding( forwardUrl, forwardToken || undefined, ); setForwardHasToken(result.hasToken || (!!result.url && forwardHasToken)); setForwardToken(""); toast.success(t("admin.auditForwardingSaved")); } catch { toast.error(t("admin.auditForwardingSaveError")); } finally { setForwardSaving(false); } } const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [loading, setLoading] = useState(false); const [expandedId, setExpandedId] = useState(null); const [actions, setActions] = useState([]); const [filterUserId, setFilterUserId] = useState(""); const [filterAction, setFilterAction] = useState(""); const [filterResourceType, setFilterResourceType] = useState(""); const [filterSuccess, setFilterSuccess] = useState<"" | "true" | "false">(""); const [filterStartDate, setFilterStartDate] = useState(""); const [filterEndDate, setFilterEndDate] = useState(""); const debounceRef = useRef | null>(null); const fetchLogs = useCallback( async (filters: AuditLogFilters, pg: number) => { setLoading(true); try { const result = await getAuditLogs({ ...filters, page: pg, limit: 50 }); setLogs(result.logs); setTotal(result.total); setTotalPages(result.totalPages); } catch { // non-fatal } finally { setLoading(false); } }, [], ); const buildFilters = useCallback((): AuditLogFilters => { const f: AuditLogFilters = {}; if (filterUserId) f.userId = filterUserId; if (filterAction) f.action = filterAction; if (filterResourceType) f.resourceType = filterResourceType; if (filterSuccess !== "") f.success = filterSuccess === "true"; if (filterStartDate) f.startDate = filterStartDate; if (filterEndDate) f.endDate = filterEndDate; return f; }, [ filterUserId, filterAction, filterResourceType, filterSuccess, filterStartDate, filterEndDate, ]); useEffect(() => { if (!open) return; getAuditLogActions() .then((r) => setActions(r.actions)) .catch(() => {}); fetchLogs(buildFilters(), 1); setPage(1); }, [open, buildFilters, fetchLogs]); useEffect(() => { if (!open) return; if (debounceRef.current) clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => { setPage(1); fetchLogs(buildFilters(), 1); }, 300); return () => { if (debounceRef.current) clearTimeout(debounceRef.current); }; }, [ open, buildFilters, fetchLogs, filterUserId, filterAction, filterResourceType, filterSuccess, filterStartDate, filterEndDate, ]); function clearFilters() { setFilterUserId(""); setFilterAction(""); setFilterResourceType(""); setFilterSuccess(""); setFilterStartDate(""); setFilterEndDate(""); } function handlePageChange(newPage: number) { setPage(newPage); fetchLogs(buildFilters(), newPage); } function formatTimestamp(ts: string) { try { return new Date(ts).toLocaleString(undefined, { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", }); } catch { return ts; } } const hasFilters = filterUserId || filterAction || filterResourceType || filterSuccess !== "" || filterStartDate || filterEndDate; return ( } open={open} onToggle={onToggle} >
{/* SIEM forwarding */}
{t("admin.auditForwardingTitle")}

{t("admin.auditForwardingDesc")} {forwardEnvConfigured && ( <> {t("admin.auditForwardingEnvNotice")} )}

setForwardUrl(e.target.value)} className="text-[10px] h-7" /> setForwardToken(e.target.value)} className="text-[10px] h-7" />
{/* Filters */}
setFilterUserId(e.target.value)} > {(Array.isArray(users) ? users : []).map((u) => ( ))}
setFilterAction(e.target.value)} > {actions.map((a) => ( ))}
setFilterResourceType(e.target.value)} > {RESOURCE_TYPES.map((r) => ( ))}
setFilterSuccess(e.target.value as "" | "true" | "false") } >
setFilterStartDate(e.target.value)} className="text-[10px] h-7" />
setFilterEndDate(e.target.value)} className="text-[10px] h-7" />
{/* Toolbar */}
{t("admin.auditLogTotal", { total })}
{hasFilters && ( )}
{/* Log table */} {logs.length === 0 && !loading ? (
{t("admin.auditLogEmpty")}
) : (
{logs.map((log) => (
setExpandedId(expandedId === log.id ? null : log.id) } >
{(log.action || "unknown").replace(/_/g, " ")} {log.resourceType} {log.resourceName && ( {log.resourceName} )}
{log.username} {formatTimestamp(log.timestamp)}
{log.success ? t("admin.auditLogSuccess") : t("admin.auditLogFailed")}
{expandedId === log.id && (
{log.ipAddress && ( {t("admin.auditLogIp")}: {log.ipAddress} )} {log.resourceId && ( {t("admin.auditLogResourceId")}: {log.resourceId} )} {log.details && ( {log.details} )} {log.errorMessage && ( {log.errorMessage} )}
)}
))}
)} {/* Pagination */} {totalPages > 1 && (
{t("admin.auditLogPage", { page, totalPages, total })}
)}
); }