import { useEffect, useRef } from "react"; import { TrashIcon } from "@phosphor-icons/react"; import { Button, Surface } from "@cloudflare/kumo"; export interface LogEntry { id: string; timestamp: Date; direction: "in" | "out" | "error" | "info"; type: string; data: unknown; } interface LogPanelProps { logs: LogEntry[]; onClear: () => void; maxHeight?: string; } export function LogPanel({ logs, onClear, maxHeight = "300px" }: LogPanelProps) { const scrollRef = useRef(null); useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [logs]); const getLogClass = (direction: LogEntry["direction"]) => { switch (direction) { case "in": return "log-entry log-entry-in"; case "out": return "log-entry log-entry-out"; case "error": return "log-entry log-entry-error"; case "info": return "log-entry log-entry-info"; default: return "log-entry"; } }; const getDirectionLabel = (direction: LogEntry["direction"]) => { switch (direction) { case "in": return "←"; case "out": return "→"; case "error": return "✕"; default: return "•"; } }; const getDirectionColor = (direction: LogEntry["direction"]) => { switch (direction) { case "in": return "text-kumo-success"; case "out": return "text-kumo-info"; case "error": return "text-kumo-danger"; default: return "text-kumo-subtle"; } }; return (
Event Log
{logs.length === 0 ? (
Waiting for events…
) : ( logs.map((log) => (
{log.timestamp.toLocaleTimeString()} {getDirectionLabel(log.direction)} {log.type} {log.data !== undefined && ( {typeof log.data === "string" ? log.data : JSON.stringify(log.data)} )}
)) )}
); }