From ef6dc95201c01094a2b8fbb757571dbde3877c22 Mon Sep 17 00:00:00 2001 From: Aditya Garud <153842990+yashranaway@users.noreply.github.com> Date: Sun, 1 Nov 2026 07:22:23 +0000 Subject: [PATCH 1/2] fix(web): stop showing screenshot Caps as uploading in the mobile app --- .../__tests__/unit/mobile-caps-list.test.ts | 21 ++++++++++++------- apps/web/app/api/mobile/[...route]/route.ts | 15 +++++++++---- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/web/__tests__/unit/mobile-caps-list.test.ts b/apps/web/__tests__/unit/mobile-caps-list.test.ts index 55823a413c9..6083f67fca6 100644 --- a/apps/web/__tests__/unit/mobile-caps-list.test.ts +++ b/apps/web/__tests__/unit/mobile-caps-list.test.ts @@ -57,6 +57,7 @@ let empty = false; let denied = false; let failDatabase = false; let failAnalytics = false; +let leftoverScreenshotUpload = false; let latency = 0; let activeQueries = 0; let peakQueries = 0; @@ -111,13 +112,11 @@ const client = drizzle(async (sql, params) => { index === 7, 2, 1, - null, - null, - null, - null, - null, - null, - null, + ...(leftoverScreenshotUpload && + index === 5 && + !sql.includes("`videos`.`isScreenshot` = ?") + ? [`video-${index}`, 2048, 2048, "uploading", 0, null, null] + : [null, null, null, null, null, null, null]), null, null, ]; @@ -257,6 +256,7 @@ beforeEach(() => { denied = false; failDatabase = false; failAnalytics = false; + leftoverScreenshotUpload = false; latency = 0; activeQueries = 0; peakQueries = 0; @@ -334,6 +334,13 @@ describe("mobile Caps list", () => { expect((await response.json()).caps).toEqual(expectedCaps()); }); + it("keeps screenshots with a leftover progress row out of the upload state", async () => { + leftoverScreenshotUpload = true; + const response = await list(); + expect(response.status).toBe(200); + expect((await response.json()).caps).toEqual(expectedCaps()); + }); + it("rejects inaccessible spaces before loading caps", async () => { denied = true; expect((await list("&spaceId=team")).status).toBe(403); diff --git a/apps/web/app/api/mobile/[...route]/route.ts b/apps/web/app/api/mobile/[...route]/route.ts index 6cdbe00c1ad..591cc95c2ba 100644 --- a/apps/web/app/api/mobile/[...route]/route.ts +++ b/apps/web/app/api/mobile/[...route]/route.ts @@ -356,6 +356,13 @@ const getUploadTitle = (fileName: string) => { return title.length > 0 ? title : "Mobile Upload"; }; +// Web image imports leave a progress row behind, and the web never treats a +// screenshot as uploading, so the app shouldn't either. +const activeUploadJoin = and( + eq(Db.videos.id, Db.videoUploads.videoId), + eq(Db.videos.isScreenshot, false), +); + const toMobileCapSummary = ( row: CapRow, viewCount: number, @@ -1633,7 +1640,7 @@ const getCapRows = Effect.fn("Mobile.getCapRows")(function* ( .from(Db.videos) .leftJoin(Db.comments, eq(Db.videos.id, Db.comments.videoId)) .leftJoin(Db.users, eq(Db.videos.ownerId, Db.users.id)) - .leftJoin(Db.videoUploads, eq(Db.videos.id, Db.videoUploads.videoId)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where( inArray( Db.videos.id, @@ -1765,7 +1772,7 @@ const getCapStatuses = Effect.fn("Mobile.getCapStatuses")(function* ( processingError: Db.videoUploads.processingError, }) .from(Db.videos) - .leftJoin(Db.videoUploads, eq(Db.videos.id, Db.videoUploads.videoId)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where(and(eq(Db.videos.ownerId, user.id), inArray(Db.videos.id, ids))), ); @@ -2141,7 +2148,7 @@ const getCapById = Effect.fn("Mobile.getCapById")(function* ( .from(Db.videos) .leftJoin(Db.comments, eq(Db.videos.id, Db.comments.videoId)) .leftJoin(Db.users, eq(Db.videos.ownerId, Db.users.id)) - .leftJoin(Db.videoUploads, eq(Db.videos.id, Db.videoUploads.videoId)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where(eq(Db.videos.id, videoId)) .groupBy( Db.videos.id, @@ -2597,7 +2604,7 @@ const trackMobileCapView = Effect.fn("Mobile.trackCapView")(function* ( activeUploadVideoId: Db.videoUploads.videoId, }) .from(Db.videos) - .leftJoin(Db.videoUploads, eq(Db.videoUploads.videoId, Db.videos.id)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where(eq(Db.videos.id, videoId)) .limit(1), ); From f4b4ec9e8b11d147390d06f527b504b4bdd30002 Mon Sep 17 00:00:00 2001 From: Aditya Garud <153842990+yashranaway@users.noreply.github.com> Date: Sun, 1 Nov 2026 08:19:39 +0000 Subject: [PATCH 2/2] test(web): check the screenshot upload filter's bound value --- .../__tests__/unit/mobile-caps-list.test.ts | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/web/__tests__/unit/mobile-caps-list.test.ts b/apps/web/__tests__/unit/mobile-caps-list.test.ts index 6083f67fca6..42a5a8cb056 100644 --- a/apps/web/__tests__/unit/mobile-caps-list.test.ts +++ b/apps/web/__tests__/unit/mobile-caps-list.test.ts @@ -57,7 +57,7 @@ let empty = false; let denied = false; let failDatabase = false; let failAnalytics = false; -let leftoverScreenshotUpload = false; +let uploadRows = false; let latency = 0; let activeQueries = 0; let peakQueries = 0; @@ -68,6 +68,14 @@ function owner(index: number) { return !sharedList || index % 4 === 0 ? "viewer" : `owner-${index % 4}`; } +function joinsUpload(index: number, sql: string, params: unknown[]) { + if (!uploadRows || (index !== 5 && index !== 6)) return false; + const filter = sql.indexOf("`videos`.`isScreenshot` = ?"); + if (filter === -1) return true; + const isScreenshot = params[sql.slice(0, filter).split("?").length - 1]; + return isScreenshot === (index === 5); +} + function preferences(id: string) { return { blockedUserIds: @@ -112,10 +120,8 @@ const client = drizzle(async (sql, params) => { index === 7, 2, 1, - ...(leftoverScreenshotUpload && - index === 5 && - !sql.includes("`videos`.`isScreenshot` = ?") - ? [`video-${index}`, 2048, 2048, "uploading", 0, null, null] + ...(joinsUpload(index, sql, params) + ? [`video-${index}`, 1024, 2048, "uploading", 0, null, null] : [null, null, null, null, null, null, null]), null, null, @@ -256,7 +262,7 @@ beforeEach(() => { denied = false; failDatabase = false; failAnalytics = false; - leftoverScreenshotUpload = false; + uploadRows = false; latency = 0; activeQueries = 0; peakQueries = 0; @@ -334,11 +340,29 @@ describe("mobile Caps list", () => { expect((await response.json()).caps).toEqual(expectedCaps()); }); - it("keeps screenshots with a leftover progress row out of the upload state", async () => { - leftoverScreenshotUpload = true; + it("shows video uploads but not leftover screenshot progress rows", async () => { + uploadRows = true; const response = await list(); expect(response.status).toBe(200); - expect((await response.json()).caps).toEqual(expectedCaps()); + expect((await response.json()).caps).toEqual( + expectedCaps().map((cap) => + cap.id === "video-6" + ? { + ...cap, + thumbnailUrl: null, + thumbnailCacheKey: null, + upload: { + uploaded: 1024, + total: 2048, + phase: "uploading", + processingProgress: 0, + processingMessage: null, + processingError: null, + }, + } + : cap, + ), + ); }); it("rejects inaccessible spaces before loading caps", async () => {