From 0da56d780f0265581a46a35e3428f8145a9d320b Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 1 Jun 2026 22:00:50 +0000 Subject: [PATCH] Align attachment video detection with server Co-Authored-By: Paperclip --- .../IssueAttachmentsSection.test.tsx | 29 +++++++++++++++++++ ui/src/lib/issue-attachments.ts | 10 ++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/ui/src/components/IssueAttachmentsSection.test.tsx b/ui/src/components/IssueAttachmentsSection.test.tsx index 23be53b0..6fca448a 100644 --- a/ui/src/components/IssueAttachmentsSection.test.tsx +++ b/ui/src/components/IssueAttachmentsSection.test.tsx @@ -207,6 +207,35 @@ describe("IssueAttachmentsSection", () => { expect(fetchSpy).not.toHaveBeenCalled(); }); + it("does not promote specific non-video content types by filename alone", async () => { + const attachment = makeAttachment({ + id: "zip-mp4", + originalFilename: "bundle.mp4", + contentType: "application/zip", + contentPath: "/api/attachments/zip-mp4/content", + openPath: "/api/attachments/zip-mp4/content", + downloadPath: "/api/attachments/zip-mp4/content?download=1", + }); + + await act(async () => { + root.render( + + + , + ); + }); + await flushReact(); + + expect(container.querySelector("video")).toBeNull(); + expect(container.textContent).toContain("bundle.mp4"); + expect(container.textContent).toContain("application/zip"); + expect(fetchSpy).not.toHaveBeenCalled(); + }); + it("keeps generic attachments as compact file rows with open and download actions", async () => { const attachment = makeAttachment({ id: "pdf-attachment", diff --git a/ui/src/lib/issue-attachments.ts b/ui/src/lib/issue-attachments.ts index 29219c46..39534d48 100644 --- a/ui/src/lib/issue-attachments.ts +++ b/ui/src/lib/issue-attachments.ts @@ -1,6 +1,12 @@ import type { IssueAttachment } from "@paperclipai/shared"; import { isVideoContentType } from "./issue-output"; +const GENERIC_ATTACHMENT_CONTENT_TYPES = new Set([ + "application/octet-stream", + "binary/octet-stream", + "application/x-binary", +]); + function normalizedContentType(attachment: Pick) { return attachment.contentType.toLowerCase().split(";")[0]?.trim() ?? ""; } @@ -28,7 +34,9 @@ export function isImageAttachment(attachment: Pick, ) { - if (isVideoContentType(normalizedContentType(attachment))) return true; + const contentType = normalizedContentType(attachment); + if (isVideoContentType(contentType)) return true; + if (!GENERIC_ATTACHMENT_CONTENT_TYPES.has(contentType)) return false; const filename = (attachment.originalFilename ?? "").toLowerCase(); return (