chunker and ui

This commit is contained in:
2026-03-13 14:29:38 -03:00
parent 3eeedebb15
commit ccc478fbaa
69 changed files with 6481 additions and 282 deletions

View File

@@ -0,0 +1,81 @@
import { useCallback, useEffect, useRef, useState } from "react";
import type { PipelineEvent } from "../types";
/**
* SSE hook — connects to /api/chunker/stream/{jobId} via native EventSource.
*
* Demonstrates: real-time event streaming from backend to UI.
*/
export function useEventStream(jobId: string | null) {
const [events, setEvents] = useState<PipelineEvent[]>([]);
const [connected, setConnected] = useState(false);
const [done, setDone] = useState(false);
const esRef = useRef<EventSource | null>(null);
const close = useCallback(() => {
if (esRef.current) {
esRef.current.close();
esRef.current = null;
setConnected(false);
}
}, []);
useEffect(() => {
if (!jobId) return;
setEvents([]);
setDone(false);
const es = new EventSource(`/api/chunker/stream/${jobId}`);
esRef.current = es;
es.onopen = () => setConnected(true);
es.onerror = () => setConnected(false);
const handleEvent = (eventType: string) => (e: MessageEvent) => {
try {
const data = JSON.parse(e.data) as PipelineEvent;
setEvents((prev) => [...prev, { ...data, status: eventType }]);
} catch {
// ignore parse errors
}
};
// Listen to all chunker event types
const eventTypes = [
"waiting",
"pending",
"chunking",
"processing",
"collecting",
"completed",
"failed",
"cancelled",
"done",
"timeout",
];
for (const type of eventTypes) {
es.addEventListener(type, handleEvent(type));
}
es.addEventListener("done", () => {
setDone(true);
es.close();
setConnected(false);
});
es.addEventListener("timeout", () => {
setDone(true);
es.close();
setConnected(false);
});
return () => {
es.close();
esRef.current = null;
};
}, [jobId]);
return { events, connected, done, close };
}