import { useNavigate } from '@tanstack/react-router' import { useMemo } from 'react' import { Button } from '@evobgp/ui/components/button' import { AnalyticsActivityList } from '@/components/analytics/analytics-activity-list' import { AnalyticsCardShell } from '@/components/analytics/analytics-card-shell' import { AnalyticsKpiRow } from '@/components/analytics/analytics-kpi-row' import { AnalyticsProgress } from '@/components/analytics/analytics-progress' import { deploymentProgress, deploymentProgressMeta, recentPlatformActivity, } from '@/lib/metrics' import { runningJobCount } from '@/queries/overview' import type { JobRow, ModuleRow, PeerRow, RevisionRow, SpeakerRow } from '@/types/api' export function DashboardPlatformCard({ modules, peers, speakers, jobs, revisions, loading, }: { modules: ModuleRow[] peers: PeerRow[] speakers: SpeakerRow[] jobs: JobRow[] revisions: RevisionRow[] loading?: boolean }) { const navigate = useNavigate() const enabledModules = modules.filter((m) => m.enabled !== false).length const peersEnabled = peers.filter((p) => p.enabled !== false).length const peersEstablished = peers.filter( (p) => p.enabled !== false && p.session_state === 'Established', ).length const peersMismatch = peers.filter((p) => p.session_mismatch).length const speakersOnline = speakers.filter((s) => s.live?.agent_ok).length const failedJobs = jobs.filter((j) => ['failed', 'error', 'cancelled'].includes(j.status.toLowerCase()), ).length const running = runningJobCount(jobs) const riskCount = peersMismatch + failedJobs + Math.max(0, speakers.length - speakersOnline) const bgpPct = peersEnabled > 0 ? Math.round((peersEstablished / peersEnabled) * 100) : null const deploy = useMemo(() => deploymentProgress(speakers), [speakers]) const deployMeta = useMemo(() => deploymentProgressMeta(deploy), [deploy]) const activity = useMemo( () => recentPlatformActivity(jobs, revisions, peers, speakers), [jobs, revisions, peers, speakers], ) const kpis = [ { label: 'Модули активны', value: loading ? '—' : `${enabledModules}/${modules.length || 0}`, delta: { direction: 'neutral' as const, label: `${modules.length} всего`, tone: 'muted' as const, }, }, { label: 'BGP готовность', value: loading || bgpPct === null ? '—' : `${bgpPct}%`, delta: { direction: (bgpPct !== null && bgpPct >= 90 ? 'up' : bgpPct !== null && bgpPct < 70 ? 'down' : 'neutral') as | 'up' | 'down' | 'neutral', label: bgpPct === null ? 'нет включённых пиров' : `${peersEstablished} установлено`, tone: (bgpPct !== null && bgpPct >= 90 ? 'success' : bgpPct !== null && bgpPct < 70 ? 'warning' : 'muted') as 'success' | 'warning' | 'muted', }, }, { label: 'Риски', value: loading ? '—' : String(riskCount), delta: { direction: (riskCount > 0 ? 'down' : 'up') as 'up' | 'down', label: riskCount > 0 ? `${failedJobs} задач, ${peersMismatch} расхождений` : 'в норме', tone: (riskCount > 0 ? 'destructive' : 'success') as 'destructive' | 'success', }, }, ] const progressLabel = deployMeta.label const progressHint = deployMeta.hint return ( } >
Недавняя активность {!loading ? ( {running} активных задач ) : null}
{loading ? (

Загрузка…

) : ( )}
) }