"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { Eye, Filter, RotateCcw } from "lucide-react"; import DataTable, { type DataTableColumn } from "@/components/common/DataTable"; import SearchInput from "@/components/common/SearchInput"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/lib/api"; import type { ApiSuccess, AuditLog, AuditLogListResponse } from "@/types/audit"; const pageSize = 20; function getErrorMessage(error: unknown) { if (typeof error === "object" && error !== null && "response" in error) { const response = (error as { response?: { data?: { detail?: string; message?: string } } }).response; return response?.data?.message ?? response?.data?.detail ?? "Audit Logs konnten nicht geladen werden"; } return "Audit Logs konnten nicht geladen werden"; } function formatDate(value: string) { return new Intl.DateTimeFormat("de-DE", { dateStyle: "short", timeStyle: "medium", }).format(new Date(value)); } function formatJson(value: unknown) { if (value === null || value === undefined) { return "-"; } return JSON.stringify(value, null, 2); } export default function AuditLogsPage() { const [items, setItems] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [search, setSearch] = useState(""); const [entityType, setEntityType] = useState(""); const [action, setAction] = useState(""); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [selectedLog, setSelectedLog] = useState(null); const loadAuditLogs = useCallback(async () => { setLoading(true); setError(""); try { const params = new URLSearchParams({ page: String(page), page_size: String(pageSize), }); if (entityType.trim()) { params.set("entity_type", entityType.trim()); } if (action.trim()) { params.set("action", action.trim()); } const response = await api.get>(`/audit-logs?${params.toString()}`); setItems(response.data.data.items); setTotal(response.data.data.total); } catch (err) { setError(getErrorMessage(err)); } finally { setLoading(false); } }, [action, entityType, page]); useEffect(() => { queueMicrotask(() => { void loadAuditLogs(); }); }, [loadAuditLogs]); const filteredItems = useMemo(() => { const normalized = search.trim().toLowerCase(); if (!normalized) { return items; } return items.filter((item) => ( item.actor_username.toLowerCase().includes(normalized) || item.action.toLowerCase().includes(normalized) || item.entity_type.toLowerCase().includes(normalized) || item.entity_label.toLowerCase().includes(normalized) )); }, [items, search]); const totalPages = Math.max(1, Math.ceil(total / pageSize)); const columns: DataTableColumn[] = [ { key: "created_at", label: "Zeitpunkt", render: (log) => {formatDate(log.created_at)}, }, { key: "actor_username", label: "Benutzer", render: (log) => log.actor_username || "System", }, { key: "action", label: "Aktion", render: (log) => {log.action}, }, { key: "entity", label: "Objekt", render: (log) => (

{log.entity_label || "-"}

{log.entity_type}{log.entity_id ? ` #${log.entity_id}` : ""}

), }, { key: "ip_address", label: "IP", render: (log) => log.ip_address || "-", }, { key: "details", label: "", className: "px-4 py-3 text-right", render: (log) => ( ), }, ]; return (

Audit Logs

Nachvollziehbare Systemereignisse und Änderungen

{ setEntityType(event.target.value); setPage(1); }} placeholder="customers" />
{ setAction(event.target.value); setPage(1); }} placeholder="users.update" />
row.id} sortKey="created_at" sortDirection="desc" loading={loading} error={error} emptyTitle="Keine Audit Logs gefunden" emptyDescription="Für die aktuellen Filter sind keine Einträge vorhanden." onSort={() => undefined} />
{total} Einträge
Seite {page} von {totalPages}
!open && setSelectedLog(null)}> Audit Log Details {selectedLog && (
)}
); } function Detail({ label, value }: { label: string; value: string }) { return (

{label}

{value}

); } function JsonPanel({ title, value }: { title: string; value: unknown }) { return (

{title}

        {formatJson(value)}
      
); }