import { useCoverageGaps, useSymbolCoverage } from '../api/hooks'; import { LoadingSpinner, StatusBadge, Card } from '../components/ui'; export function OpsCoveragePage() { const { data: gaps, isLoading: gapsLoading } = useCoverageGaps(); const { data: coverage, isLoading: covLoading } = useSymbolCoverage(); if (gapsLoading || covLoading) return ; const missing = (gaps?.missing_source_types ?? []) as Array>; const stale = (gaps?.stale_sources ?? []) as Array>; const matrix = (coverage ?? []) as Array>; return (

Source Coverage

{/* Coverage Matrix */}

Company × Source Type Matrix

{matrix.map((row, i) => ( ))}
Ticker Name Market News Filings Web Broker Total
{String(row.ticker)} {String(row.legal_name)} {String(row.active_sources)}
{/* Missing Source Types */} {missing.length > 0 && (

Missing Source Types ({missing.length})

{missing.map((m, i) => { const activeTypes = (m.active_types as string[]) ?? []; const expected = (m.expected_types as string[]) ?? []; const missingTypes = expected.filter((t) => !activeTypes.includes(t)); return (
{String(m.ticker)} missing: {missingTypes.map((t) => ( ))}
); })}
)} {/* Stale Sources */} {stale.length > 0 && (

Stale Sources ({stale.length})

{stale.map((s, i) => (
{String(s.ticker)} {String(s.source_name)}
Last success: {s.last_success ? new Date(String(s.last_success)).toLocaleString() : 'never'} {s.recent_failures ? ` | ${s.recent_failures} failures (24h)` : ''}
))}
)}
); } function CoverageCell({ count }: { count: number }) { const color = count > 0 ? 'text-green-400' : 'text-red-400'; return {count}; }