import React, { useState, useEffect } from 'react'; import { ShieldCheck, Search, Filter, Download, Calendar, User, Bot, FileText, ChevronDown, ChevronUp, RefreshCw, ExternalLink } from 'lucide-react'; import { supabase } from '../services/supabase'; interface AuditLog { id: string; created_at: string; user_id: string | null; action: string; agent_id: string | null; task_id: string | null; metadata: any; profiles?: { full_name: string | null; email: string | null; }; agents?: { name: string | null; }; tasks?: { title: string | null; }; } const AuditView: React.FC = () => { const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [, setError] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [expandedLog, setExpandedLog] = useState(null); const [page, setPage] = useState(0); const pageSize = 50; useEffect(() => { fetchLogs(); }, [page]); const fetchLogs = async () => { setLoading(true); try { const { data, error: fetchError } = await supabase .from('audit_logs_with_details') .select('*') .order('created_at', { ascending: false }) .range(page * pageSize, (page + 1) * pageSize - 1); if (fetchError) throw fetchError; setLogs(data || []); } catch (err: any) { setError(err.message); } finally { setLoading(false); } }; const exportCSV = () => { const headers = ['Timestamp', 'Action', 'User', 'Agent', 'Task', 'Metadata']; const rows = logs.map(log => [ log.created_at, log.action, (log as any).actor_email || 'System', (log as any).agent_name || 'N/A', (log as any).task_title || 'N/A', JSON.stringify(log.metadata) ]); const csvContent = [headers, ...rows].map(e => e.join(',')).join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', `aubm_audit_logs_${new Date().toISOString()}.csv`); link.click(); }; const filteredLogs = logs.filter(log => log.action.toLowerCase().includes(searchTerm.toLowerCase()) || ((log as any).actor_email || '').toLowerCase().includes(searchTerm.toLowerCase()) || ((log as any).agent_name || '').toLowerCase().includes(searchTerm.toLowerCase()) ); const formatTimestamp = (ts: string) => { return new Date(ts).toLocaleString(); }; const getActionBadgeColor = (action: string) => { if (action.includes('error') || action.includes('failed')) return 'var(--danger)'; if (action.includes('created') || action.includes('added')) return 'var(--success)'; if (action.includes('approved')) return 'var(--accent)'; return 'var(--text-dim)'; }; return (

Audit Explorer

Track system actions and governance events

setSearchTerm(e.target.value)} style={{ width: '100%', paddingLeft: '40px' }} />
{filteredLogs.map(log => ( setExpandedLog(expandedLog === log.id ? null : log.id)} > {expandedLog === log.id && ( )} ))}
Timestamp Action Actor Context
{formatTimestamp(log.created_at)} {log.action.replace(/_/g, ' ')}
{(log as any).actor_email || System}
{log.agent_id && (
{(log as any).agent_name}
)} {log.task_id && (
{(log as any).task_title}
)} {!log.agent_id && !log.task_id && -}
{expandedLog === log.id ? : }
Metadata
                              {JSON.stringify(log.metadata, null, 2)}
                            
Quick Links
{log.task_id && ( )} {log.metadata?.project_id && ( )}
Showing {filteredLogs.length} logs on this page
{page + 1}
); }; export default AuditView;