/** * Usage Logs Table Component * Displays API usage logs in a table with pagination and filtering. * Terminal-themed UI matching scheduler dashboard style. */ import React, { useState, useEffect } from 'react'; import { Box, Table, TableBody, TableContainer, TableHead, TableRow, TablePagination, IconButton, Tooltip, Select, MenuItem, FormControl, InputLabel, CircularProgress } from '@mui/material'; import { CheckCircle as CheckCircleIcon, Error as ErrorIcon, Refresh as RefreshIcon, Receipt as ReceiptIcon } from '@mui/icons-material'; import { billingService } from '../../services/billingService'; import { UsageLog, UsageLogsResponse } from '../../types/billing'; import { TerminalPaper, TerminalTypography, TerminalChipSuccess, TerminalChipError, TerminalTableCell, TerminalTableRow, TerminalAlert, terminalColors } from '../SchedulerDashboard/terminalTheme'; import { formatCurrency } from '../../services/billingService'; interface UsageLogsTableProps { initialLimit?: number; } const UsageLogsTable: React.FC = ({ initialLimit = 50 }) => { const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(initialLimit); const [totalCount, setTotalCount] = useState(0); const [statusFilter, setStatusFilter] = useState<'success' | 'failed' | 'all'>('all'); const [providerFilter, setProviderFilter] = useState('all'); const fetchLogs = async () => { try { setLoading(true); setError(null); const statusCode = statusFilter === 'all' ? undefined : (statusFilter === 'success' ? 200 : 400); const provider = providerFilter === 'all' ? undefined : providerFilter; const response: UsageLogsResponse = await billingService.getUsageLogs( rowsPerPage, page * rowsPerPage, provider, statusCode ); setLogs(response.logs || []); setTotalCount(response.total_count || 0); } catch (err: any) { setError(err.message || 'Failed to fetch usage logs'); console.error('Error fetching usage logs:', err); } finally { setLoading(false); } }; useEffect(() => { fetchLogs(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [page, rowsPerPage, statusFilter, providerFilter]); const handleChangePage = (_event: unknown, newPage: number) => { setPage(newPage); }; const handleChangeRowsPerPage = (event: React.ChangeEvent) => { setRowsPerPage(parseInt(event.target.value, 10)); setPage(0); }; const getStatusIcon = (status: string): React.ReactElement | undefined => { switch (status) { case 'success': return ; case 'failed': return ; default: return undefined; } }; const formatDate = (dateString: string) => { try { const date = new Date(dateString); return date.toLocaleString(); } catch { return dateString; } }; const formatResponseTime = (seconds: number) => { if (!seconds) return 'N/A'; const ms = seconds * 1000; if (ms < 1000) return `${ms.toFixed(0)}ms`; return `${seconds.toFixed(2)}s`; }; const formatTokens = (tokens: number) => { return new Intl.NumberFormat('en-US').format(tokens); }; return ( API Usage Logs Provider Status {error && ( {error} )} {loading ? ( ) : ( <> Timestamp Provider Model Tokens Cost Status Response Time Endpoint {logs.length === 0 ? ( No Usage Logs Yet API usage logs will appear here once you start making API calls. ) : ( logs.map((log) => ( {formatDate(log.timestamp)} {log.provider} {log.model_used || 'N/A'} {formatTokens(log.tokens_total)} {formatCurrency(log.cost_total)} {log.status === 'success' ? ( ) : ( )} {formatResponseTime(log.response_time)} {log.is_aggregated ? ( [AGGREGATED] {log.error_message || 'Historical data'} ) : ( `${log.method} ${log.endpoint?.substring(0, 30)}...` )} )) )}
)}
); }; export default UsageLogsTable;