import { useCallback, useEffect, useMemo, useState } from "react"; import type { ResearchRun, ResearchRunStatus } from "@fusion/core"; import { getResearchStats, listResearchRuns } from "../api"; import "./ResearchView.css"; interface ResearchViewProps { projectId?: string; addToast?: (message: string, type?: "success" | "error" | "info") => void; } interface ResearchStats { total: number; byStatus: Record; } const STATUS_LABELS: Record = { pending: "Pending", running: "Running", completed: "Completed", failed: "Failed", cancelled: "Cancelled", }; export function ResearchView({ projectId, addToast }: ResearchViewProps) { const [runs, setRuns] = useState([]); const [stats, setStats] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(async () => { setIsLoading(true); setError(null); try { const [runsResponse, statsResponse] = await Promise.all([ listResearchRuns({ limit: 50 }, projectId), getResearchStats(projectId), ]); setRuns(runsResponse.runs); setStats(statsResponse); } catch (err) { const message = err instanceof Error ? err.message : "Failed to load research runs"; setError(message); addToast?.(message, "error"); } finally { setIsLoading(false); } }, [projectId, addToast]); useEffect(() => { void load(); }, [load]); const hasResults = useMemo( () => runs.some((run) => run.status === "completed" && run.results?.summary), [runs], ); return (

Research

Track synthesis runs, source collection, and export artifacts.

{isLoading && (
Loading research runs…
)} {!isLoading && error && (

{error}

)} {!isLoading && !error && runs.length === 0 && (
No research runs yet. Start a run from the API or upcoming orchestration workflow.
)} {!isLoading && !error && runs.length > 0 && ( <>
Total Runs
{stats?.total ?? runs.length}
Running
{stats?.byStatus.running ?? 0}
Completed
{stats?.byStatus.completed ?? 0}
{runs.map((run) => (
{STATUS_LABELS[run.status]} {run.id}

{run.topic || run.query}

{run.query}

{run.results?.summary &&

{run.results.summary}

}
))}
{!hasResults && (

Runs are active, but no summarized results are available yet.

)} )}
); }