import React, { useState, useEffect } from 'react'; import { Table, Card, Typography, Space, Tag, DatePicker, Select, Input, Button, Row, Col, Alert, Timeline, } from 'antd'; import { AuditOutlined, SearchOutlined, FilterOutlined, UserOutlined, AppstoreOutlined, KeyOutlined, ClockCircleOutlined, CheckCircleOutlined, ExclamationCircleOutlined, DeleteOutlined, } from '@ant-design/icons'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import { apiService, AuditEvent, AuditQueryParams } from '../services/apiService'; dayjs.extend(relativeTime); const { Title, Text } = Typography; const { RangePicker } = DatePicker; const { Option } = Select; const Audit: React.FC = () => { const [auditData, setAuditData] = useState([]); const [filteredData, setFilteredData] = useState([]); const [loading, setLoading] = useState(true); const [filters, setFilters] = useState({ dateRange: null as any, action: '', status: '', user: '', resourceType: '', }); // Load audit data on component mount useEffect(() => { loadAuditData(); }, []); const loadAuditData = async () => { try { setLoading(true); const response = await apiService.getAuditEvents({ limit: 100, order_by: 'timestamp', order_desc: true, }); setAuditData(response.events); setFilteredData(response.events); } catch (error) { console.error('Failed to load audit data:', error); // Keep empty arrays on error setAuditData([]); setFilteredData([]); } finally { setLoading(false); } }; const applyFilters = async () => { // For real-time filtering, we'll use the API with filters try { setLoading(true); const params: AuditQueryParams = { limit: 100, order_by: 'timestamp', order_desc: true, }; if (filters.dateRange && filters.dateRange.length === 2) { const [start, end] = filters.dateRange; params.start_time = start.toISOString(); params.end_time = end.toISOString(); } if (filters.action) { params.event_types = [filters.action]; } if (filters.status) { params.statuses = [filters.status]; } if (filters.user) { params.actor_id = filters.user; } if (filters.resourceType) { params.resource_type = filters.resourceType; } const response = await apiService.getAuditEvents(params); setFilteredData(response.events); } catch (error) { console.error('Failed to apply filters:', error); } finally { setLoading(false); } }; const clearFilters = () => { setFilters({ dateRange: null, action: '', status: '', user: '', resourceType: '', }); loadAuditData(); // Reload original data }; const getStatusIcon = (status: string) => { switch (status) { case 'success': return ; case 'failure': return ; case 'warning': return ; default: return ; } }; const getActionIcon = (action: string) => { if (action.includes('APPLICATION')) return ; if (action.includes('TOKEN')) return ; if (action.includes('USER')) return ; return ; }; const columns = [ { title: 'Timestamp', dataIndex: 'timestamp', key: 'timestamp', render: (timestamp: string) => (
{dayjs(timestamp).format('MMM DD, YYYY')}
{dayjs(timestamp).format('HH:mm:ss')}
), sorter: (a: AuditEvent, b: AuditEvent) => dayjs(a.timestamp).unix() - dayjs(b.timestamp).unix(), defaultSortOrder: 'descend' as const, }, { title: 'User', dataIndex: 'actor_id', key: 'actor_id', render: (actorId: string) => (
{actorId || 'System'}
), }, { title: 'Action', dataIndex: 'type', key: 'type', render: (type: string) => (
{getActionIcon(type)} {type.replace(/_/g, ' ').replace(/\./g, ' ')}
), }, { title: 'Resource', key: 'resource', render: (_: any, record: AuditEvent) => (
{record.resource_type?.toUpperCase() || 'N/A'}
{record.resource_id || 'N/A'}
), }, { title: 'Status', dataIndex: 'status', key: 'status', render: (status: string) => ( {status.toUpperCase()} ), }, { title: 'IP Address', dataIndex: 'actor_ip', key: 'actor_ip', render: (ip: string) => {ip || 'N/A'}, }, ]; const expandedRowRender = (record: AuditEvent) => (
User Agent:
{record.user_agent}
Event ID:
{record.id}
Additional Details:
              {JSON.stringify(record.details, null, 2)}
            
); return (
Audit Log Monitor and track all system activities and security events
{/* Statistics Cards */}
{filteredData.length}
Total Events
{filteredData.filter(e => e.status === 'success').length}
Successful
{filteredData.filter(e => e.status === 'failure').length}
Failed
{new Set(filteredData.map(e => e.actor_id).filter(id => id)).size}
Unique Users
{/* Filters */}
}>
Date Range:
setFilters({ ...filters, dateRange: dates })} />
Action:
Status:
User:
setFilters({ ...filters, user: e.target.value })} allowClear />
Resource Type:
{/* Recent Activity Timeline */} {filteredData.slice(0, 5).map((entry) => (
{entry.type.replace(/_/g, ' ').replace(/\./g, ' ')}
{entry.actor_id || 'System'} • {dayjs(entry.timestamp).fromNow()}
{entry.resource_type || 'N/A'} {entry.resource_id || 'N/A'}
))}
{/* Audit Log Table */} {filteredData.length === 0 && !loading && ( )} `${range[0]}-${range[1]} of ${total} audit entries`, }} /> ); }; export default Audit;