import "./WorkflowTimeline.css"; /** * Renders a timeline of workflow events. * Constructed from workflow metadata (started_at, completed_at, status) * and proposal data (created_at, reviewed_at, status). */ export function WorkflowTimeline({ workflow, proposals = [] }) { const events = []; // Workflow start if (workflow.started_at) { events.push({ time: new Date(workflow.started_at), icon: "▶", label: "Workflow started", tone: "default", }); } // Infer extraction/processing from the delta if (workflow.status !== "PENDING") { events.push({ time: new Date(new Date(workflow.started_at).getTime() + 1000), icon: "📄", label: "Document extracted and processed", tone: "default", }); } // If waiting for review or completed with proposals if (proposals.length > 0) { const earliest = proposals.reduce( (min, p) => (p.created_at && new Date(p.created_at) < min ? new Date(p.created_at) : min), new Date() ); events.push({ time: earliest, icon: "📝", label: `${proposals.length} proposal(s) generated`, tone: "default", }); } // Validation failed → review requested if (workflow.status === "WAITING_FOR_REVIEW" || workflow.validation_results?.some((r) => r.status === "FAIL" || r.status === "WARNING")) { events.push({ time: new Date(new Date(workflow.started_at).getTime() + 3000), icon: "⚠️", label: "Validation triggered human review", tone: "warning", }); } // Proposal decisions for (const p of proposals) { if (p.status === "APPROVED" && p.reviewed_at) { events.push({ time: new Date(p.reviewed_at), icon: "✓", label: `Approved: ${p.summary?.slice(0, 50) || "proposal"}`, tone: "success", }); } if (p.status === "REJECTED" && p.reviewed_at) { events.push({ time: new Date(p.reviewed_at), icon: "✗", label: `Rejected: ${p.summary?.slice(0, 50) || "proposal"}`, tone: "danger", }); } } // Workflow completed if (workflow.completed_at) { events.push({ time: new Date(workflow.completed_at), icon: "✅", label: "Workflow completed", tone: "success", }); } // Sort by time events.sort((a, b) => a.time - b.time); if (events.length === 0) return null; return (