import { useInfiniteQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { Download, NotebookTabs, RefreshCw, Search } from "lucide-react"; import * as React from "react"; import { PageHeader } from "../../../../common/core/components/page"; import { SearchFilterBar } from "../../../../common/ui/search-filter-bar"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "../../components/ui/card"; import { Input } from "../../components/ui/input"; import type { AuditLog } from "../../lib/adminApi"; import { fetchAuditLogs } from "../../lib/adminApi"; import { t } from "../../lib/i18n"; import { VirtualizedAuditLogTable } from "./VirtualizedAuditLogTable"; function AuditLogsPage() { const [searchActorId, setSearchActorId] = React.useState(""); const [searchAction, setSearchAction] = React.useState(""); const [statusFilter, setStatusFilter] = React.useState("all"); const deferredSearchActorId = React.useDeferredValue(searchActorId.trim()); const deferredSearchAction = React.useDeferredValue(searchAction.trim()); const { data, isLoading, error, fetchNextPage, hasNextPage, isFetchingNextPage, isFetching, refetch, } = useInfiniteQuery({ queryKey: [ "audit-logs", deferredSearchActorId, deferredSearchAction, statusFilter, ], queryFn: ({ pageParam }) => { const search = [deferredSearchActorId, deferredSearchAction] .filter(Boolean) .join(" "); return fetchAuditLogs( 50, pageParam, search || undefined, statusFilter === "all" ? undefined : statusFilter, ); }, initialPageParam: undefined as string | undefined, getNextPageParam: (lastPage) => lastPage.next_cursor || undefined, }); const logs = data?.pages?.flatMap( (page) => page?.items?.filter((item): item is AuditLog => Boolean(item)) ?? [], ) ?? []; return (
} actions={ <> {t("msg.common.audit.registry.count", "총 {{count}}개 로그", { count: logs.length, })} } />
{t("ui.common.audit.registry.title", "Audit registry")} {t( "msg.admin.audit.registry.description", "최근 감사 로그를 검색 조건에 맞춰 필터링하고, 작업 이력을 빠르게 확인합니다.", )}
{isLoading ? (
{t("msg.common.audit.loading", "Loading audit logs...")}
) : error ? (
{t("msg.common.audit.load_error", "Error loading logs: {{error}}", { error: (error as AxiosError<{ error?: string }>).response?.data ?.error ?? (error as Error).message, })}
) : ( { e.preventDefault(); refetch(); }} className="grid flex-1 gap-2 md:grid-cols-[1fr,1fr,180px]" >
setSearchActorId(event.target.value)} placeholder={t( "ui.common.audit.filters.user_id", "Filter by User ID", )} />
setSearchAction(event.target.value.toUpperCase()) } placeholder={t( "ui.common.audit.filters.action", "Filter by Action (e.g. ROTATE_SECRET)", )} /> } /> fetchNextPage()} />
)}
); } export default AuditLogsPage;