import React, { useState, useEffect, useCallback } from 'react'; import { X, Loader, AlertCircle, ChevronLeft, ChevronRight, Search } from 'lucide-react'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; const ACTION_BADGES = { login: { bg: 'bg-green-100', text: 'text-green-800' }, logout: { bg: 'bg-gray-100', text: 'text-gray-800' }, login_failed: { bg: 'bg-red-100', text: 'text-red-800' }, cve_create: { bg: 'bg-blue-100', text: 'text-blue-800' }, cve_update_status: { bg: 'bg-yellow-100', text: 'text-yellow-800' }, document_upload: { bg: 'bg-purple-100', text: 'text-purple-800' }, document_delete: { bg: 'bg-red-100', text: 'text-red-800' }, user_create: { bg: 'bg-blue-100', text: 'text-blue-800' }, user_update: { bg: 'bg-yellow-100', text: 'text-yellow-800' }, user_delete: { bg: 'bg-red-100', text: 'text-red-800' }, cve_edit: { bg: 'bg-orange-100', text: 'text-orange-800' }, cve_delete: { bg: 'bg-red-100', text: 'text-red-800' }, cve_nvd_sync: { bg: 'bg-green-100', text: 'text-green-800' }, }; const ENTITY_TYPES = ['auth', 'cve', 'document', 'user']; export default function AuditLog({ onClose }) { const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [actions, setActions] = useState([]); const [pagination, setPagination] = useState({ page: 1, limit: 25, total: 0, totalPages: 0 }); // Filters const [userFilter, setUserFilter] = useState(''); const [actionFilter, setActionFilter] = useState(''); const [entityTypeFilter, setEntityTypeFilter] = useState(''); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); const fetchLogs = useCallback(async (page = 1) => { setLoading(true); setError(null); try { const params = new URLSearchParams({ page, limit: 25 }); if (userFilter) params.append('user', userFilter); if (actionFilter) params.append('action', actionFilter); if (entityTypeFilter) params.append('entityType', entityTypeFilter); if (startDate) params.append('startDate', startDate); if (endDate) params.append('endDate', endDate); const response = await fetch(`${API_BASE}/audit-logs?${params}`, { credentials: 'include' }); if (!response.ok) throw new Error('Failed to fetch audit logs'); const data = await response.json(); setLogs(data.logs); setPagination(data.pagination); } catch (err) { setError(err.message); } finally { setLoading(false); } }, [userFilter, actionFilter, entityTypeFilter, startDate, endDate]); const fetchActions = async () => { try { const response = await fetch(`${API_BASE}/audit-logs/actions`, { credentials: 'include' }); if (response.ok) { const data = await response.json(); setActions(data); } } catch (err) { // Non-critical, ignore } }; useEffect(() => { fetchLogs(1); fetchActions(); }, [fetchLogs]); const formatDate = (dateStr) => { if (!dateStr) return '-'; return new Date(dateStr).toLocaleString(); }; const formatDetails = (details) => { if (!details) return '-'; try { const parsed = typeof details === 'string' ? JSON.parse(details) : details; return Object.entries(parsed) .map(([k, v]) => `${k}: ${v}`) .join(', '); } catch { return details; } }; const getActionBadge = (action) => { const style = ACTION_BADGES[action] || { bg: 'bg-gray-100', text: 'text-gray-800' }; return ( {action} ); }; const handleFilter = (e) => { e.preventDefault(); fetchLogs(1); }; const handleReset = () => { setUserFilter(''); setActionFilter(''); setEntityTypeFilter(''); setStartDate(''); setEndDate(''); }; return (
{/* Header */}

Audit Log

Track all user actions across the system

{/* Filter Bar */}
setUserFilter(e.target.value)} className="w-full pl-8 pr-3 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-[#0476D9] focus:border-transparent" />
setStartDate(e.target.value)} className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-[#0476D9] focus:border-transparent" />
setEndDate(e.target.value)} className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-[#0476D9] focus:border-transparent" />
{/* Content */}
{loading ? (

Loading audit logs...

) : error ? (

{error}

) : logs.length === 0 ? (

No audit log entries found.

) : (
{logs.map((log) => ( ))}
Time User Action Entity Details IP Address
{formatDate(log.created_at)} {log.username} {getActionBadge(log.action)} {log.entity_type} {log.entity_id && ( {log.entity_id} )} {formatDetails(log.details)} {log.ip_address || '-'}
)}
{/* Pagination */} {pagination.totalPages > 1 && (

Showing {((pagination.page - 1) * pagination.limit) + 1} - {Math.min(pagination.page * pagination.limit, pagination.total)} of {pagination.total} entries

Page {pagination.page} of {pagination.totalPages}
)}
); }