diff options
| author | soryu <soryu@soryu.co> | 2026-02-06 20:06:30 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-06 20:15:27 +0000 |
| commit | 1b692b8cde4a888c8a35af69231f181b57bf5619 (patch) | |
| tree | 74ce25ce6ee5fb4536b53404e1a0ae923e85c30d /makima/frontend/src/components/directives/EventsTab.tsx | |
| parent | 139be135c2086d725e4f040e744bb25acd436549 (diff) | |
| download | soryu-1b692b8cde4a888c8a35af69231f181b57bf5619.tar.gz soryu-1b692b8cde4a888c8a35af69231f181b57bf5619.zip | |
Fix: Cleanup old chain code
Diffstat (limited to 'makima/frontend/src/components/directives/EventsTab.tsx')
| -rw-r--r-- | makima/frontend/src/components/directives/EventsTab.tsx | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/makima/frontend/src/components/directives/EventsTab.tsx b/makima/frontend/src/components/directives/EventsTab.tsx new file mode 100644 index 0000000..4dd739a --- /dev/null +++ b/makima/frontend/src/components/directives/EventsTab.tsx @@ -0,0 +1,77 @@ +import { useMemo } from "react"; +import type { DirectiveWithProgress } from "../../lib/api"; +import { useDirectiveEventSubscription } from "../../hooks/useDirectives"; + +export function EventsTab({ directive }: { directive: DirectiveWithProgress }) { + // Subscribe to real-time events via SSE + const { events: streamEvents, isConnected, error: sseError } = useDirectiveEventSubscription(directive.id); + + // Combine initial events with streamed events (avoiding duplicates) + const allEvents = useMemo(() => { + const eventMap = new Map(); + // Add initial events first + directive.recentEvents.forEach((e) => eventMap.set(e.id, e)); + // Add streamed events (will override any duplicates) + streamEvents.forEach((e) => eventMap.set(e.id, e)); + // Sort by created_at descending (most recent first) + return Array.from(eventMap.values()).sort( + (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + ); + }, [directive.recentEvents, streamEvents]); + + return ( + <div className="space-y-4"> + {/* Connection status */} + <div className="flex items-center justify-between text-[10px] font-mono"> + <div className="flex items-center gap-2"> + <span className={isConnected ? "text-green-400" : "text-[#556677]"}> + {isConnected ? "\u25CF Live" : "\u25CB Connecting..."} + </span> + {sseError && <span className="text-red-400">{sseError}</span>} + </div> + <span className="text-[#556677]">{allEvents.length} events</span> + </div> + + {/* Event list */} + {allEvents.length === 0 ? ( + <div className="text-center py-8"> + <p className="font-mono text-sm text-[#556677]">No events yet</p> + </div> + ) : ( + <div className="space-y-2"> + {allEvents.map((event) => { + const severityColors: Record<string, string> = { + info: "text-[#75aafc]", + warning: "text-yellow-400", + error: "text-red-400", + critical: "text-red-600", + }; + const severityColor = severityColors[event.severity] || "text-[#556677]"; + + return ( + <div + key={event.id} + className="p-3 bg-[rgba(117,170,252,0.02)] border border-[rgba(117,170,252,0.1)]" + > + <div className="flex items-center justify-between"> + <div className="flex items-center gap-2"> + <span className={`font-mono text-xs ${severityColor}`}>{event.eventType}</span> + <span className="font-mono text-[10px] text-[#556677]">{event.actorType}</span> + </div> + <span className="font-mono text-[10px] text-[#556677]"> + {new Date(event.createdAt).toLocaleString()} + </span> + </div> + {event.eventData != null && ( + <pre className="font-mono text-[10px] text-[#556677] mt-1 overflow-x-auto"> + {JSON.stringify(event.eventData, null, 2)} + </pre> + )} + </div> + ); + })} + </div> + )} + </div> + ); +} |
