import { Link } from 'react-router'; import { History } from 'lucide-react'; import { DataTable, EmptyState, useGlobalFilters, } from '@cameleer/design-system'; import type { Column } from '@cameleer/design-system'; import { PageLoader } from '../../components/PageLoader'; import { SeverityBadge } from '../../components/SeverityBadge'; import { useAlerts, type AlertDto, } from '../../api/queries/alerts'; import { severityToAccent } from './severity-utils'; import { formatRelativeTime } from './time-utils'; import { renderAlertExpanded } from './alert-expanded'; import css from './alerts-page.module.css'; import tableStyles from '../../styles/table-section.module.css'; /** Duration in s/m/h/d. Pure, best-effort. */ function formatDuration(from?: string | null, to?: string | null): string { if (!from || !to) return '—'; const ms = new Date(to).getTime() - new Date(from).getTime(); if (ms < 0 || Number.isNaN(ms)) return '—'; const sec = Math.floor(ms / 1000); if (sec < 60) return `${sec}s`; if (sec < 3600) return `${Math.floor(sec / 60)}m`; if (sec < 86_400) return `${Math.floor(sec / 3600)}h`; return `${Math.floor(sec / 86_400)}d`; } export default function HistoryPage() { const { timeRange } = useGlobalFilters(); // useAlerts doesn't accept a time range today; filter client-side // against the global TimeRangeDropdown in the top bar. const { data, isLoading, error } = useAlerts({ state: 'RESOLVED', limit: 200 }); const filtered = (data ?? []).filter((a) => { if (!a.firedAt) return false; const t = new Date(a.firedAt).getTime(); return t >= timeRange.start.getTime() && t <= timeRange.end.getTime(); }); const columns: Column[] = [ { key: 'severity', header: 'Severity', width: '110px', render: (_, row) => row.severity ? : null, }, { key: 'title', header: 'Title', render: (_, row) => (
{row.title ?? '(untitled)'} {row.message && {row.message}}
), }, { key: 'firedAt', header: 'Fired at', width: '140px', sortable: true, render: (_, row) => row.firedAt ? ( {formatRelativeTime(row.firedAt)} ) : '—', }, { key: 'resolvedAt', header: 'Resolved at', width: '140px', sortable: true, render: (_, row) => row.resolvedAt ? ( {formatRelativeTime(row.resolvedAt)} ) : '—', }, { key: 'duration', header: 'Duration', width: '90px', render: (_, row) => formatDuration(row.firedAt, row.resolvedAt), }, ]; if (isLoading) return ; if (error) return
Failed to load history: {String(error)}
; return (

Alert history

{filtered.length === 0 ? 'No resolved alerts in range' : `${filtered.length} resolved alert${filtered.length === 1 ? '' : 's'} in range`}
{filtered.length === 0 ? ( } title="No resolved alerts" description="Nothing in the selected date range. Try widening it." /> ) : (
columns={columns as Column[]} data={filtered as Array} sortable flush fillHeight pageSize={200} rowAccent={(row) => row.severity ? severityToAccent(row.severity) : undefined} expandedContent={renderAlertExpanded} />
)}
); }