Files
image-studio/view/GenerationJobStatus.tsx
syntaxbullet 5e4b548ad4 feat: add ComfyUI integration for image generation and management
- Implemented ComfyGenerateRequest type and associated functions for generating images using various architectures and modes.
- Added functions for listing generation options and handling image uploads.
- Created workflows for different generation modes including SDXL, Z-Image, Z-Image Turbo, and Anima.
- Introduced GenerationJobStatus component to display the status of ongoing generation jobs.
- Developed MaskControls for managing mask operations and displaying mask analysis.
- Created palette items for tool selection, layer management, and generation settings.
2026-07-10 23:15:02 +02:00

30 lines
1.5 KiB
TypeScript

import { useEffect, useState } from "react";
import type { GenerationJob, GenerationState } from "@editor/state";
export function currentGenerationJob(generation: GenerationState): GenerationJob | undefined {
return generation.jobs.find((job) => job.status === "running") ?? generation.jobs[0];
}
export function GenerationJobStatus({ generation, compact = false }: { generation: GenerationState; compact?: boolean }) {
const job = currentGenerationJob(generation);
const [, setTick] = useState(0);
useEffect(() => {
if (job?.status !== "running") return;
const interval = window.setInterval(() => setTick((tick) => tick + 1), 1000);
return () => window.clearInterval(interval);
}, [job?.id, job?.status]);
if (!job) return null;
const elapsed = Math.max(0, Math.floor(((job.finishedAt ?? Date.now()) - job.startedAt) / 1000));
const label = job.status === "running" ? `${job.label} ${formatElapsed(elapsed)}` : job.status === "failed" ? job.error ?? `${job.label} failed` : `${job.label} complete`;
const tone = job.status === "failed" ? "bg-red-500/15 text-red-100" : job.status === "running" ? "bg-white/10 text-white/70" : "bg-emerald-500/15 text-emerald-100";
return <span className={`${compact ? "max-w-56" : "max-w-80"} truncate rounded-full px-3 py-2 text-xs font-medium ${tone}`} title={label} aria-live="polite">{label}</span>;
}
function formatElapsed(seconds: number) {
const minutes = Math.floor(seconds / 60);
return `${minutes}:${(seconds % 60).toString().padStart(2, "0")}`;
}