import { useEffect, useMemo, useState } from "react"; import { ExternalLink, RefreshCw, Settings } from "lucide-react"; import { fetchSettings } from "../api"; import { useEvals } from "../hooks/useEvals"; import type { SectionId } from "./SettingsModal"; import "./EvalsView.css"; interface EvalsViewProps { projectId?: string; onOpenSettings?: (section?: SectionId) => void; onOpenTaskDetail?: (taskId: string) => void; } export function EvalsView({ projectId, onOpenSettings, onOpenTaskDetail }: EvalsViewProps) { const { loading, error, results, runs, filters, setFilters, selectedEvalId, setSelectedEvalId, selectedEval, refresh } = useEvals({ projectId }); const [scheduledEnabled, setScheduledEnabled] = useState(true); useEffect(() => { let cancelled = false; fetchSettings(projectId) .then((settings) => { if (cancelled) return; const enabled = (settings as { evalSettings?: { enabled?: boolean } }).evalSettings?.enabled; setScheduledEnabled(enabled ?? false); }) .catch(() => { if (!cancelled) setScheduledEnabled(false); }); return () => { cancelled = true; }; }, [projectId]); const hasResults = results.length > 0; const selectedSummary = useMemo(() => results.find((result) => result.id === selectedEvalId) ?? null, [results, selectedEvalId]); if (!scheduledEnabled) { return (

Scheduled evals are disabled

Enable Scheduled Evals to review scored tasks, evidence, and follow-up recommendations.

); } return (
setFilters((prev) => ({ ...prev, q: event.target.value }))} /> setFilters((prev) => ({ ...prev, scoreMin: event.target.value }))} /> setFilters((prev) => ({ ...prev, scoreMax: event.target.value }))} />
{loading &&

Loading evals…

} {error &&

{error}

} {!loading && !error && !hasResults && (

No evals yet. Scheduled evals review tasks completed since the last run.

)}
{!selectedEval &&

Select an evaluation to inspect scores, rationale, and evidence.

} {selectedEval && ( <>

{selectedSummary?.taskTitle ?? selectedEval.taskTitle}

{selectedEval.taskId} · {selectedEval.runId}

Overall score: {selectedEval.overallScore ?? "n/a"}

{selectedEval.rationale || "No rationale recorded."}

Evidence

    {selectedEval.evidence.map((item, index) => { const taskId = typeof item.metadata?.taskId === "string" ? item.metadata.taskId : undefined; const url = typeof item.metadata?.url === "string" ? item.metadata.url : undefined; return (
  • {taskId ? ( ) : url ? ( {item.ref} ) : ( {item.ref} )}
  • ); })}

Suggested follow-up tasks

    {selectedEval.followUps.length === 0 &&
  • None
  • } {selectedEval.followUps.map((followUp) => (
  • {followUp.title}

    {followUp.rationale}

  • ))}
)}
); }