From 2f613b70271d0538e164a99a1ee9898d2ae3798e Mon Sep 17 00:00:00 2001 From: JakeBreath Date: Sat, 19 Sep 2026 00:06:05 -0500 Subject: [PATCH] Stop Firefox from squashing upload tiles and show IQDB queue progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upload grid was its own scroll container (max-height + overflow on the same element). Firefox sizes auto grid rows to min-content in that setup, so every tile collapsed to its footer height and the image was clipped to a wide strip; Chromium sizes them to max-content, which is why this only showed up in the user's browser. auto-rows-max pins rows to max-content in both; verified with headless Firefox screenshots and Chromium measurements (60 tiles render 152x194 each, 1845px of content in a 639px scroller). The box is now 70vh so it behaves as a proper fixed gallery area with its own scrollbar instead of shrinking with the item count. IQDB progress: the page header now shows a live 'Checking IQDB — x/y' counter with a bar while background checks run, so the queue is visible without opening the per-file modal (which keeps its spinner, candidates and per-file errors). --- frontend/src/features/upload/UploadPage.tsx | 51 +++++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/frontend/src/features/upload/UploadPage.tsx b/frontend/src/features/upload/UploadPage.tsx index 61ec58c..c4fc73c 100644 --- a/frontend/src/features/upload/UploadPage.tsx +++ b/frontend/src/features/upload/UploadPage.tsx @@ -679,6 +679,10 @@ export default function UploadPage() { const [processing, setProcessing] = useState(false); const [checkingIds, setCheckingIds] = useState([]); const [checkErrors, setCheckErrors] = useState>({}); + const [iqdbProgress, setIqdbProgress] = useState<{ + done: number; + total: number; + } | null>(null); const [modalId, setModalId] = useState(null); const [bulkOpen, setBulkOpen] = useState(false); @@ -796,6 +800,10 @@ export default function UploadPage() { for (const temp of targets) { if (!temp.file_url) continue; if (/\.(mp4|webm)$/i.test(temp.original_filename)) continue; + setIqdbProgress((current) => ({ + done: current?.done ?? 0, + total: (current?.total ?? 0) + 1, + })); try { const blob = await fetchTempBlob(temp.file_url); const results = await iqdbSearch( @@ -822,6 +830,9 @@ export default function UploadPage() { [temp.temp_id]: describeError(error), })); } finally { + setIqdbProgress((current) => + current ? { ...current, done: current.done + 1 } : current, + ); setCheckingIds((current) => current.filter((value) => value !== temp.temp_id), ); @@ -830,6 +841,9 @@ export default function UploadPage() { } finally { setProcessing(false); setCheckingIds([]); + setIqdbProgress((current) => + current === null || current.done >= current.total ? null : current, + ); invalidateUploads(); } } @@ -1010,14 +1024,30 @@ export default function UploadPage() {

{busy || processing ? ( -

- - {busy - ? `Uploading ${Math.min(uploadedCount + 1, entries.length)}/${entries.length}…` - : checkingIds.length > 0 - ? `Checking ${checkingIds.length} file(s) against IQDB…` - : "Processing uploads…"} -

+
+

+ + + {busy + ? `Uploading ${Math.min(uploadedCount + 1, entries.length)}/${entries.length}…` + : iqdbProgress + ? `Checking IQDB — ${iqdbProgress.done}/${iqdbProgress.total}` + : "Processing uploads…"} + +

+ {!busy && iqdbProgress ? ( +
+
+
+ ) : null} +
) : null} @@ -1120,7 +1150,10 @@ export default function UploadPage() { ))}
) : null} -
+ {/* auto-rows-max: when the grid is its own scroll container Firefox + sizes auto rows to min-content and squashes the tiles; max-content + keeps every tile at its aspect-ratio size and scrolls instead. */} +
{entries.map((entry) => (