import { useState, useEffect, useRef } from 'react'; import { Terminal, Activity, RefreshCw, CheckCircle2, Circle, XCircle, Clock, Loader2 } from 'lucide-react'; import apiClient from '../../api/client'; import type { WorkflowDetail, WorkflowStep } from '../../types'; interface RightPanelProps { selectedWorkflow: string | null; } function stepStatusIcon(status: string) { switch (status) { case 'completed': return ; case 'running': return ; case 'failed': return ; default: return ; } } export function RightPanel({ selectedWorkflow }: RightPanelProps) { const [detail, setDetail] = useState(null); const [loading, setLoading] = useState(false); const [logs, setLogs] = useState([]); const [sseConnected, setSseConnected] = useState(false); const eventSourceRef = useRef(null); const fetchDetail = async (traceId: string) => { setLoading(true); setLogs([]); try { const response = await apiClient.get(`/api/v1/workflow/${traceId}`); setDetail(response.data); } catch { setDetail(null); } finally { setLoading(false); } }; useEffect(() => { if (!selectedWorkflow) { setDetail(null); setLogs([]); return; } fetchDetail(selectedWorkflow); const protocol = window.location.protocol; const host = window.location.host; const apiBase = import.meta.env.VITE_API_BASE_URL || `${protocol}//${host}`; const es = new EventSource(`${apiBase}/api/v1/workflow/sse/${selectedWorkflow}`); eventSourceRef.current = es; es.onopen = () => { setSseConnected(true); }; es.onmessage = (event) => { setLogs(prev => [...prev, event.data]); }; es.onerror = () => { setSseConnected(false); }; const interval = setInterval(() => { fetchDetail(selectedWorkflow); }, 3000); return () => { es.close(); eventSourceRef.current = null; clearInterval(interval); }; }, [selectedWorkflow]); const isActive = detail?.status === 'llm_working' || detail?.status === 'tool_working'; if (!selectedWorkflow) { return (

No Workflow Selected

Select a workflow from the left panel to view its details.

); } return (

Workflow Detail

{sseConnected ? 'Live' : '--'}
{loading && !detail ? (
Loading...
) : !detail ? (
Failed to load workflow details
) : ( <> {/* Header */}

{detail.workflow_title || 'Workflow'}

ID: {detail.event_id}

{detail.command && (

Command: {detail.command}

)}
{detail.status} Step {detail.current_step}/{detail.steps.length}
{/* Steps */} {detail.steps.length > 0 && (

Steps

{detail.steps.map((step: WorkflowStep) => (
{stepStatusIcon(step.status)} {step.step} {step.name} {step.node}
))}
)} {detail.steps.length === 0 && (

Workflow is being generated...

)} {/* SSE Logs */} {logs.length > 0 && (

Live Logs

{logs.map((msg, idx) => (

{msg}

))}
)} {logs.length === 0 && sseConnected && isActive && (
Waiting for live events...
)} )}
); }