import React, { useEffect, useMemo, useState } from 'react'; import { AlertTriangle, RefreshCw, Route, ServerCrash, Workflow } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useAppContext } from '../context/AppContext'; import { FixedButton } from '../components/Button'; import EKGDistributionCard from '../components/ekg/EKGDistributionCard'; import EKGRankingCard from '../components/ekg/EKGRankingCard'; import { SelectField } from '../components/FormControls'; import MetricPanel from '../components/MetricPanel'; type EKGKV = { key?: string; score?: number; count?: number }; const EKG: React.FC = () => { const { t } = useTranslation(); const { q } = useAppContext(); const [loading, setLoading] = useState(false); const [ekgWindow, setEkgWindow] = useState<'6h' | '24h' | '7d'>(() => { const saved = typeof window !== 'undefined' ? window.localStorage.getItem('taskAudit.ekgWindow') : null; return saved === '6h' || saved === '24h' || saved === '7d' ? saved : '24h'; }); const [providerTop, setProviderTop] = useState([]); const [providerTopWorkload, setProviderTopWorkload] = useState([]); const [errsigTop, setErrsigTop] = useState([]); const [errsigTopWorkload, setErrsigTopWorkload] = useState([]); const [sourceStats, setSourceStats] = useState>({}); const [channelStats, setChannelStats] = useState>({}); const [escalationCount, setEscalationCount] = useState(0); const fetchData = async () => { setLoading(true); try { const ekgJoin = q ? `${q}&window=${encodeURIComponent(ekgWindow)}` : `?window=${encodeURIComponent(ekgWindow)}`; const er = await fetch(`/webui/api/ekg_stats${ekgJoin}`); if (!er.ok) throw new Error(await er.text()); const ej = await er.json(); setProviderTop(Array.isArray(ej.provider_top) ? ej.provider_top : []); setProviderTopWorkload(Array.isArray(ej.provider_top_workload) ? ej.provider_top_workload : []); setErrsigTop(Array.isArray(ej.errsig_top) ? ej.errsig_top : []); setErrsigTopWorkload(Array.isArray(ej.errsig_top_workload) ? ej.errsig_top_workload : []); setSourceStats(ej.source_stats && typeof ej.source_stats === 'object' ? ej.source_stats : {}); setChannelStats(ej.channel_stats && typeof ej.channel_stats === 'object' ? ej.channel_stats : {}); setEscalationCount(Number(ej.escalation_count || 0)); } catch (e) { console.error(e); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }, [q, ekgWindow]); useEffect(() => { if (typeof window !== 'undefined') window.localStorage.setItem('taskAudit.ekgWindow', ekgWindow); }, [ekgWindow]); const sourceCount = Object.keys(sourceStats).length; const channelCount = Object.keys(channelStats).length; const totalErrorHits = errsigTop.reduce((sum, item) => sum + Number(item.count || 0), 0); const topWorkloadProvider = providerTopWorkload[0]?.key || '-'; return (

{t('ekg')}

{t('ekgOverviewHint')}
setEkgWindow(e.target.value as '6h' | '24h' | '7d')} className="h-12 min-w-[96px]">
} iconContainerClassName="flex h-10 w-10 items-center justify-center rounded-xl ui-pill ui-pill-warning border" layout="split" /> } iconContainerClassName="flex h-10 w-10 items-center justify-center rounded-xl ui-pill ui-pill-info border" layout="split" /> } iconContainerClassName="flex h-10 w-10 items-center justify-center rounded-xl ui-pill ui-pill-accent border" layout="split" /> } iconContainerClassName="flex h-10 w-10 items-center justify-center rounded-xl ui-pill ui-pill-danger border" layout="split" />
); }; export default EKG;