feat(import): imports store tracking per-meeting import phase progress
This commit is contained in:
1 parent
c63cabaf88
commit
683838bef1
1 file changed
+63
@@ -0,0 +1,63 @@
|
||||
// Live per-meeting progress of background media imports (feeds ImportTracker).
|
||||
// Fed entirely by `import://progress` events emitted by `import_media`; kept in
|
||||
// memory only (the meeting's `status` badge is the persistent story after a
|
||||
// restart). See commands.rs `run_import_pipeline`.
|
||||
|
||||
import { events, type ImportPhase, type ImportProgress, type MeetingId } from "../api";
|
||||
|
||||
export type PhaseState = "pending" | "active" | "done" | "error";
|
||||
|
||||
// The four phases in the order the backend runs (and the tracker renders) them.
|
||||
export const IMPORT_PHASES: ImportPhase[] = ["prepare", "transcribe", "diarize", "finalize"];
|
||||
|
||||
export interface PhaseInfo {
|
||||
phase: ImportPhase;
|
||||
state: PhaseState;
|
||||
elapsedMs: number | null;
|
||||
}
|
||||
|
||||
export interface ImportRun {
|
||||
meetingId: MeetingId;
|
||||
phases: PhaseInfo[];
|
||||
error: string | null;
|
||||
done: boolean;
|
||||
}
|
||||
|
||||
function freshRun(meetingId: MeetingId): ImportRun {
|
||||
return {
|
||||
meetingId,
|
||||
phases: IMPORT_PHASES.map((phase) => ({ phase, state: "pending", elapsedMs: null })),
|
||||
error: null,
|
||||
done: false,
|
||||
};
|
||||
}
|
||||
|
||||
class ImportsStore {
|
||||
runs = $state<Record<MeetingId, ImportRun>>({});
|
||||
|
||||
get(meetingId: MeetingId): ImportRun | undefined {
|
||||
return this.runs[meetingId];
|
||||
}
|
||||
|
||||
async init() {
|
||||
await events.onImportProgress((p) => this.apply(p));
|
||||
}
|
||||
|
||||
private apply(p: ImportProgress) {
|
||||
// Re-read through the record after inserting so we mutate the $state proxy,
|
||||
// not the raw object (Svelte 5 deep reactivity only tracks the proxy).
|
||||
if (!this.runs[p.meetingId]) this.runs[p.meetingId] = freshRun(p.meetingId);
|
||||
const run = this.runs[p.meetingId];
|
||||
const info = run.phases.find((x) => x.phase === p.phase);
|
||||
if (!info) return;
|
||||
info.state = p.state;
|
||||
if (p.state === "done") info.elapsedMs = p.elapsedMs;
|
||||
if (p.state === "error") {
|
||||
run.error = p.error;
|
||||
run.done = true;
|
||||
}
|
||||
if (p.phase === "finalize" && p.state === "done") run.done = true;
|
||||
}
|
||||
}
|
||||
|
||||
export const imports = new ImportsStore();
|
||||
Reference in new issue
Block a user