import { useCallback, useEffect, useMemo, useState } from "react"; import { Activity, DatabaseZap, Loader2, Wifi, WifiOff } from "lucide-react"; import type { WidgetProps } from "@mosaic/shared"; interface OrchestratorEvent { type: string; timestamp: string; agentId?: string; taskId?: string; data?: Record; } interface RecentEventsResponse { events: OrchestratorEvent[]; } function isMatrixSignal(event: OrchestratorEvent): boolean { const text = JSON.stringify(event).toLowerCase(); return ( text.includes("matrix") || text.includes("room") || text.includes("channel") || text.includes("thread") ); } export function OrchestratorEventsWidget({ id: _id, config: _config, }: WidgetProps): React.JSX.Element { const [events, setEvents] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [streamConnected, setStreamConnected] = useState(false); const [backendReady, setBackendReady] = useState(null); const loadRecentEvents = useCallback(async (): Promise => { try { const response = await fetch("/api/orchestrator/events/recent?limit=25"); if (!response.ok) { throw new Error(`Unable to load events: HTTP ${String(response.status)}`); } const payload = (await response.json()) as unknown; const events = payload && typeof payload === "object" && "events" in payload && Array.isArray(payload.events) ? (payload.events as RecentEventsResponse["events"]) : []; setEvents(events); setError(null); } catch (err) { setError(err instanceof Error ? err.message : "Unable to load events."); } finally { setIsLoading(false); } }, []); const loadHealth = useCallback(async (): Promise => { try { const response = await fetch("/api/orchestrator/health"); setBackendReady(response.ok); } catch { setBackendReady(false); } }, []); useEffect(() => { void loadRecentEvents(); void loadHealth(); const eventSource = typeof EventSource !== "undefined" ? new EventSource("/api/orchestrator/events") : null; if (eventSource) { eventSource.onopen = (): void => { setStreamConnected(true); }; eventSource.onmessage = (): void => { void loadRecentEvents(); void loadHealth(); }; eventSource.onerror = (): void => { setStreamConnected(false); }; } const interval = setInterval(() => { void loadRecentEvents(); void loadHealth(); }, 15000); return (): void => { clearInterval(interval); eventSource?.close(); }; }, [loadHealth, loadRecentEvents]); const matrixSignals = useMemo( () => events.filter((event) => isMatrixSignal(event)).length, [events] ); if (isLoading) { return (
Loading orchestrator events...
); } if (error) { return (
{error}
); } return (
{streamConnected ? ( ) : ( )} {streamConnected ? "Live stream connected" : "Polling mode"} {backendReady === true ? "ready" : backendReady === false ? "degraded" : "unknown"}
Matrix signals: {matrixSignals}
{events.length === 0 ? (
No recent orchestration events.
) : ( events .slice() .reverse() .map((event, index) => (
{event.type} {isMatrixSignal(event) && ( matrix )}
{new Date(event.timestamp).toLocaleTimeString()}
{event.taskId ? `Task ${event.taskId}` : "Task n/a"} {event.agentId ? ` ยท Agent ${event.agentId.slice(0, 8)}` : ""}
)) )}
); }