Upload updates

This commit is contained in:
2026-09-21 09:01:01 -05:00
parent 98025e9e6d
commit 474403ffe2
18 changed files with 2539 additions and 796 deletions
+2
View File
@@ -15,6 +15,7 @@ import { ConfirmDialog } from "@/components/ConfirmDialog";
import { StatusFooter } from "@/components/StatusFooter";
import { StatusPill } from "@/components/StatusPill";
import { Toasts } from "@/components/Toasts";
import { UploadIndicator } from "@/components/UploadIndicator";
import { api } from "@/lib/api";
import { hasBackend } from "@/lib/backend";
import { cn } from "@/lib/cn";
@@ -153,6 +154,7 @@ export function AppShell() {
<div className="ml-auto flex items-center gap-3">
{backend ? (
<>
<UploadIndicator />
<StatusPill status={status} />
{user ? (
<>
@@ -0,0 +1,56 @@
import { Link } from "react-router-dom";
import { cn } from "@/lib/cn";
import { useUploadStatus } from "@/lib/uploadStatus";
const PHASE_LABELS: Record<string, string> = {
md5: "e621 MD5",
visual: "Visual similarity",
iqdb: "IQDB",
};
/**
* Shell-wide progress for the server-side upload pipeline.
*
* Staged uploads keep processing after the Upload page is closed, so this
* pill is the "leave and keep an eye on it" view: it lives in the header on
* every page and links back to the board.
*/
export function UploadIndicator() {
const { data: status } = useUploadStatus();
if (!status || !status.active) return null;
const total = Math.max(status.total, status.processed + status.failed);
const done = status.processed + status.failed;
const percent = total > 0 ? Math.min(100, Math.round((done / total) * 100)) : 0;
const broken = status.status === "paused" || status.status === "error";
const label =
status.status === "paused"
? "uploads paused"
: status.status === "error"
? "uploads failed"
: (PHASE_LABELS[status.phase] ?? "processing uploads");
const count = total > 0 ? `${done}/${total}` : `${status.outstanding} left`;
return (
<Link
to="/upload"
title={status.error || "Staged uploads are being processed in the background"}
className={cn(
"flex items-center gap-2 rounded-md border px-2 py-1 font-mono text-[10px] transition",
broken
? "border-ctp-red/40 text-ctp-red hover:bg-ctp-red/10"
: "border-ctp-surface1 text-ctp-subtext0 hover:bg-ctp-surface0 hover:text-ctp-text",
)}
>
<span className="hidden sm:inline">{label}</span>
<span>{count}</span>
<span className="h-1 w-12 overflow-hidden rounded-full bg-ctp-surface0">
<span
className={cn("block h-full", broken ? "bg-ctp-red" : "bg-ctp-teal")}
style={{ width: `${percent}%` }}
/>
</span>
</Link>
);
}