"use client"; import { Ban, Check, Loader2, ShieldCheck, X } from "lucide-react"; import { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import type { BatchItemStatus, VerificationSummary } from "./studio-types"; function SummaryRow({ label, value, tone, }: { label: string; value: string | number; tone?: "ok" | "warn"; }) { return (
{label} {value}
); } function formatEta(ms: number): string { if (ms < 60_000) return `${Math.ceil(ms / 1000)}s`; const min = Math.floor(ms / 60_000); const sec = Math.ceil((ms % 60_000) / 1000); return `${min}m ${sec}s`; } export function BatchProgress({ progress, done, succeeded, failed, cancelling, verification, startTime, failedClassnames, onCancel, onDismiss, onRetry, }: { progress: Map; done: boolean; succeeded: number; failed: number; cancelling?: boolean; verification?: VerificationSummary | null; startTime?: number; failedClassnames?: string[]; onCancel?: () => void; onDismiss?: () => void; onRetry?: (classnames: string[]) => void; }) { const entries = [...progress.entries()]; const total = entries.length; const completed = entries.filter( ([, s]) => s.status === "done" || s.status === "failed", ).length; const percent = total > 0 ? Math.round((completed / total) * 100) : 0; // Live ETA calculation const [eta, setEta] = useState(null); useEffect(() => { if (done || !startTime || completed === 0) { setEta(null); return; } const elapsed = Date.now() - startTime; const avgPerItem = elapsed / completed; const remaining = (total - completed) * avgPerItem; setEta(formatEta(remaining)); const interval = setInterval(() => { const elapsed = Date.now() - startTime; const avgPerItem = elapsed / completed; const remaining = (total - completed) * avgPerItem; setEta(formatEta(remaining)); }, 2000); return () => clearInterval(interval); }, [done, startTime, completed, total]); return (
{done ? "Import finished" : "Importing…"} {done ? ( 0 ? "text-[var(--admin-warning)]" : "text-[var(--admin-success)]", )} > {completed}/{total} · {succeeded} ok {failed > 0 ? ` · ${failed} failed` : ""} ) : ( {completed}/{total} {eta && ( ~{eta} )} )}
{!done && (
{percent}%
)}
{entries.map(([classname, s]) => (
{s.status === "done" ? ( ) : s.status === "failed" ? ( ) : ( )} {classname} {s.status.replace(/_/g, " ")}
))}
{done && verification && (
Post-import verification
0 ? "warn" : "ok"} /> 0 ? "warn" : "ok"} />
)}
{done ? ( <> {failedClassnames && failedClassnames.length > 0 && onRetry && ( )} ) : ( )}
); }