import { useEffect } from 'react'; import { useParams, useSearchParams } from 'react-router-dom'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { ScrollArea } from "@/components/ui/scroll-area" import { WorkflowVisualizer } from '@/components/workflow/WorkflowVisualizer'; import { useWorkflowStore } from '@/stores/useWorkflowStore'; import { TaskStatus, schemas } from '@/api/schema.gen'; import { Terminal, Loader2, Sparkles, CheckCircle2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { FinancialTable } from '@/components/report/FinancialTable'; import { useAnalysisTemplates } from "@/hooks/useConfig" export function ReportPage() { const { id } = useParams(); const [searchParams] = useSearchParams(); const symbol = searchParams.get('symbol'); const market = searchParams.get('market'); const templateId = searchParams.get('templateId'); const { initialize, handleEvent, status, tasks, dag, activeTab, setActiveTab } = useWorkflowStore(); const { data: templates } = useAnalysisTemplates(); const templateName = templates && templateId ? templates[templateId]?.name : templateId; // SSE Connection Logic useEffect(() => { if (!id) return; initialize(id); // Connect to real backend SSE const eventSource = new EventSource(`/api/v1/workflow/events/${id}`); eventSource.onmessage = (event) => { try { const parsedEvent = JSON.parse(event.data); handleEvent(parsedEvent); } catch (e) { console.error("Failed to parse SSE event:", e); } }; eventSource.onerror = (err) => { console.error("SSE Connection Error:", err); // Optional: Retry logic or error state update // eventSource.close(); }; return () => { eventSource.close(); }; }, [id, initialize, handleEvent]); // Combine logs from all tasks for the "Global Log" view const allLogs = Object.entries(tasks).flatMap(([taskId, state]) => state.logs.map(log => ({ taskId, log })) ); const tabNodes = dag?.nodes.filter(n => n.type === schemas.TaskType.enum.Analysis) || []; return (
Select a task tab above or click a node in the graph to view details.
Waiting to start...
} {tasks[node.id]?.status === schemas.TaskStatus.enum.Running && !tasks[node.id]?.content &&