/** * Evaluation Command Center — the aggregate-first landing page. * * Mental model surfaced in the UI: * Dataset (population) → Evaluation Run → Population → Cohort → Container → Annotation * Aggregates come first; individual annotations are the deepest drill-down. * * Runs are async: launched runs are queued, progress streams over SSE * (stream.megaeval.active_runs) with a 1.5s polling fallback on GET /runs/{id}, * and the page auto-refreshes when the run publishes. */ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import Alert from '@mui/material/Alert'; import Box from '@mui/material/Box'; import Tab from '@mui/material/Tab'; import Tabs from '@mui/material/Tabs'; import Typography from '@mui/material/Typography'; import type { EvaluationRunInfo, ReviewState, RunStatus } from '../types/megaeval'; import { getCacheStats, getPopulations, getRun, getRunReview, getRuns, } from '../services/megaeval'; import { usePoll } from '../services/labeleval'; import { useLabelEval } from '../context/LabelEvalContext'; import { EmptyState, ErrorNote, LoadingBox, SectionCard } from '../components/labeleval/shared'; import HeaderBar, { GeneratePopulationButton, NewRunButton, } from '../components/megaeval/HeaderBar'; import RunProgressCard from '../components/megaeval/RunProgressCard'; import HeroRow from '../components/megaeval/HeroRow'; import QualityTab from '../components/megaeval/QualityTab'; import CohortTab from '../components/megaeval/CohortTab'; import ContainersTab from '../components/megaeval/ContainersTab'; import InvestigationTab from '../components/megaeval/InvestigationTab'; import CompareTab from '../components/megaeval/CompareTab'; import ReviewTab from '../components/megaeval/ReviewTab'; import ShiftTab from '../components/megaeval/ShiftTab'; import LineageCard from '../components/megaeval/LineageCard'; import VisualQueryTab from '../components/megaeval/VisualQueryTab'; const ACTIVE_STATUSES: RunStatus[] = ['created', 'queued', 'running', 'reducing', 'materializing']; type TabId = | 'quality' | 'visual-query' | 'cohorts' | 'containers' | 'investigation' | 'compare' | 'review' | 'shift' | 'lineage'; export default function CommandCenterPage() { const { stream, entityId, navigate } = useLabelEval(); const populationsPoll = usePoll(getPopulations, 15000); const runsPoll = usePoll(getRuns, 8000); const cachePoll = usePoll(getCacheStats, 10000); const populations = useMemo(() => { const list = populationsPoll.data?.populations ?? []; return [...list].sort((a, b) => (b.created_at ?? '').localeCompare(a.created_at ?? '')); }, [populationsPoll.data]); const runs = useMemo(() => runsPoll.data?.runs ?? [], [runsPoll.data]); const [populationId, setPopulationId] = useState(null); const [runId, setRunId] = useState(entityId); const [baselineRunId, setBaselineRunId] = useState(null); const [tab, setTab] = useState('quality'); const [drillContainerId, setDrillContainerId] = useState(null); const [publishTick, setPublishTick] = useState(0); const [review, setReview] = useState(null); const [selectedRun, setSelectedRun] = useState(null); const [runError, setRunError] = useState(null); // Explicit selection persists the run in the URL hash (#/command/). const selectRun = useCallback( (id: string) => { setRunId(id); setDrillContainerId(null); navigate('command', id); }, [navigate] ); // Follow hash changes (back/forward navigation, deep links). useEffect(() => { if (entityId && entityId !== runId) { setRunId(entityId); setDrillContainerId(null); } }, [entityId]); // eslint-disable-line react-hooks/exhaustive-deps // Default selections once data arrives. useEffect(() => { if (!populationId && populations.length) setPopulationId(populations[0].population_id); }, [populations, populationId]); useEffect(() => { if (!runId && runs.length) { const byCreated = [...runs].sort((a, b) => (b.created_at ?? '').localeCompare(a.created_at ?? '')); const pick = byCreated.find((r) => r.status === 'published') ?? byCreated[0]; if (pick) setRunId(pick.run_id); } }, [runs, runId]); // Selected run detail: 1.5s polling while the run is in flight (SSE-independent fallback). useEffect(() => { setSelectedRun(null); setRunError(null); if (!runId) return; let cancelled = false; let timer: ReturnType | null = null; const load = async () => { try { const info = await getRun(runId); if (cancelled) return; setSelectedRun(info); setRunError(null); if (info.status !== 'published' && info.status !== 'failed') timer = setTimeout(() => void load(), 1500); } catch (err) { if (cancelled) return; setRunError(err instanceof Error ? err.message : String(err)); timer = setTimeout(() => void load(), 3000); } }; void load(); return () => { cancelled = true; if (timer) clearTimeout(timer); }; }, [runId]); // Auto-refresh all panels when the selected run publishes. const prevStatusRef = useRef(null); const runsRefresh = runsPoll.refresh; useEffect(() => { const status = selectedRun?.status ?? null; if (status === 'published' && prevStatusRef.current && prevStatusRef.current !== 'published') { setPublishTick((t) => t + 1); runsRefresh(); } prevStatusRef.current = status; }, [selectedRun?.status, runsRefresh]); const published = selectedRun?.status === 'published'; // Review state (shared by the hero CI annotations and the Review tab). useEffect(() => { setReview(null); if (!runId || !published) return; let cancelled = false; getRunReview(runId) .then((r) => { if (!cancelled) setReview(r); }) .catch(() => undefined); return () => { cancelled = true; }; }, [runId, published, publishTick]); const megaStatus = stream?.megaeval ?? null; const cache = megaStatus?.cache ?? cachePoll.data ?? null; // Prefer SSE progress for the selected run when it is fresher than the poll. const streamProgress = megaStatus?.active_runs.find((r) => r.run_id === runId) ?? null; const selectedInFlight = selectedRun && ACTIVE_STATUSES.includes(selectedRun.status) ? streamProgress ?? selectedRun : null; const otherActiveRuns = (megaStatus?.active_runs ?? []).filter((r) => r.run_id !== runId); const openContainer = useCallback((cid: number) => { setDrillContainerId(cid); setTab('containers'); }, []); const initialLoading = populationsPoll.loading && !populationsPoll.data && runsPoll.loading && !runsPoll.data; const noPopulation = populationsPoll.data !== null && populations.length === 0; const noRuns = !noPopulation && runsPoll.data !== null && runs.length === 0; const onPopulationGenerated = useCallback( (pop: { population_id: string }) => { populationsPoll.refresh(); setPopulationId(pop.population_id); }, [populationsPoll] ); const onRunCreated = useCallback( (run: EvaluationRunInfo) => { runsRefresh(); selectRun(run.run_id); }, [runsRefresh, selectRun] ); if (initialLoading) return ; return ( {populationsPoll.error && !populationsPoll.data ? : null} Dataset (population) → Evaluation run → Population → Cohort → Container → Annotation — aggregates first, individual annotations only at the deepest drill-down. {/* Empty states: nothing generated / no runs yet */} {noPopulation ? ( } /> ) : null} {noRuns ? ( } /> ) : null} {runError && !selectedRun ? : null} {/* Live progress for the selected run + any other active runs */} {selectedInFlight ? : null} {otherActiveRuns.map((r) => ( ))} {selectedRun?.status === 'failed' ? ( Run {selectedRun.run_id.slice(0, 8)} failed{selectedRun.error ? `: ${selectedRun.error}` : '.'} Launch a new evaluation run from the header. ) : null} {/* Hero aggregates + tab sections (published runs only) */} {published && selectedRun ? ( <> setTab(v)} variant="scrollable" scrollButtons="auto" sx={{ minHeight: 36, borderBottom: '1px solid #232a31', '& .MuiTab-root': { minHeight: 36, py: 0.5 }, }} > {tab === 'quality' ? ( ) : null} {tab === 'visual-query' ? : null} {tab === 'cohorts' ? : null} {tab === 'containers' ? ( ) : null} {tab === 'investigation' ? ( ) : null} {tab === 'compare' ? ( ) : null} {tab === 'review' ? ( ) : null} {tab === 'shift' ? : null} {tab === 'lineage' ? : null} ) : null} ); }