Spaces:
Runtime error
Runtime error
Download frontend/src/hooks/useJob.ts from firebird-technologies/NoteStack-Test: direct link, hf CLI and curl.
- Browser
- Download file 2.18 kB
-
https://huggingface.co/spaces/firebird-technologies/NoteStack-Test/resolve/main/frontend/src/hooks/useJob.ts
- Command line
-
hf download hf://spaces/firebird-technologies/NoteStack-Test/frontend/src/hooks/useJob.ts
-
curl -L -o useJob.ts https://huggingface.co/spaces/firebird-technologies/NoteStack-Test/resolve/main/frontend/src/hooks/useJob.ts
2.18 kB
| import { useEffect, useRef, useState } from "react"; | |
| import { streamSSE } from "../api/stream"; | |
| import type { Job } from "../api/types"; | |
| const TERMINAL = new Set(["done", "failed"]); | |
| /** Follows a job over SSE until it finishes. `onFinish` fires once with the final state. */ | |
| export function useJob(initial: Job | null | undefined, onFinish?: (job: Job) => void): Job | null { | |
| const [job, setJob] = useState<Job | null>(initial ?? null); | |
| const finish = useRef(onFinish); | |
| finish.current = onFinish; | |
| const id = initial?.id; | |
| useEffect(() => { | |
| setJob(initial ?? null); | |
| if (!initial || TERMINAL.has(initial.status)) return; | |
| const ctrl = new AbortController(); | |
| let done = false; | |
| streamSSE( | |
| `/api/jobs/${initial.id}/events`, | |
| (_event, data) => { | |
| const next = data as Job; | |
| setJob(next); | |
| if (TERMINAL.has(next.status) && !done) { | |
| done = true; | |
| finish.current?.(next); | |
| } | |
| }, | |
| {}, | |
| ctrl.signal, | |
| ).catch(() => { | |
| /* aborted or dropped: the row keeps the final state */ | |
| }); | |
| return () => ctrl.abort(); | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, [id]); | |
| return job; | |
| } | |
| /** Tracks many jobs by key (e.g. per source), each streamed until done. */ | |
| export function useJobMap(onFinish?: (key: string, job: Job) => void) { | |
| const [jobs, setJobs] = useState<Record<string, Job>>({}); | |
| const ctrls = useRef<Record<string, AbortController>>({}); | |
| const finish = useRef(onFinish); | |
| finish.current = onFinish; | |
| useEffect(() => () => Object.values(ctrls.current).forEach((c) => c.abort()), []); | |
| const watch = (key: string, job: Job) => { | |
| ctrls.current[key]?.abort(); | |
| setJobs((j) => ({ ...j, [key]: job })); | |
| if (TERMINAL.has(job.status)) return; | |
| const ctrl = new AbortController(); | |
| ctrls.current[key] = ctrl; | |
| streamSSE( | |
| `/api/jobs/${job.id}/events`, | |
| (_e, data) => { | |
| const next = data as Job; | |
| setJobs((j) => ({ ...j, [key]: next })); | |
| if (TERMINAL.has(next.status)) finish.current?.(key, next); | |
| }, | |
| {}, | |
| ctrl.signal, | |
| ).catch(() => {}); | |
| }; | |
| return { jobs, watch }; | |
| } | |