Skip to content

feat(desktop): Slack-style in-app preview for generic file attachments - #23

Merged
jmfcamp merged 2 commits into
mainfrom
cursor/file-attachment-preview-3867
Aug 20, 2026
Merged

jmfcamp merged 2 commits into
mainfrom
cursor/file-attachment-preview-3867

Conversation

@jmfcamp

@jmfcamp jmfcamp commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary

Generic file attachments (.md, .html, PDF, zip, …) used to open the native save dialog on FileCard click. This change matches Slack-style behavior: click opens an in-app preview window; Download stays available from that window.

Images and video are unchanged (lightbox / player). Relay serve_inline and MIME deny lists are unchanged — HTML stays an inert download on the wire (block/buzz#5569).

Preview routing:

  • Markdown (.md / text/markdown) — existing sanitized chat markdown pipeline (interactive={false})
  • HTML (.html / .htm / text/html) — inert syntax-highlighted source only. No <iframe>, no srcdoc, no webview navigation to /media/ (stored-XSS)
  • Text-ish (text/plain, CSV, JSON, sniffed UTF-8 octet-stream) — scrollable preview
  • Binary / oversized (2 MiB cap) — chrome + “no preview — download”
  • Bytes come from fetch_media_bytes / download_file, never <a href>

FileCard clicks stopPropagation() so a preview opened from a forum post card (or any other clickable row) is not immediately unmounted by the row’s own click handler.

Hula Buzz branding (productName, com.huladesk.buzz, hulabuzz://) is untouched.

Related issue

None found in this fork. Closest official context: block/buzz#5569 (HTML accepted as inert download).

Testing

  • Unit tests: desktop/src/shared/ui/filePreview.test.mjs — md/html/text/binary routing, size cap, UTF-8 sniff, and “HTML is never a webview navigation / unsandboxed iframe”
  • resolveFileCard now forwards imeta MIME for preview routing
  • Desktop tsc --noEmit passed
  • Focused unit tests passed (51)
  • Local Playwright smoke on file-attachment.spec.ts:
    • FileCard click opens preview; Download invokes download_file; Escape dismisses
    • Forum FileCard preview (after stopPropagation fix)
    • Markdown renders via the chat pipeline; HTML is source-only, no iframe, <script> does not run in the app webview
cd desktop
pnpm typecheck
node --import ./test-loader.mjs --experimental-strip-types --test \
  src/shared/ui/filePreview.test.mjs \
  src/shared/ui/markdownFileCard.test.mjs
pnpm exec playwright test tests/e2e/file-attachment.spec.ts --project=smoke
Open in Web Open in Cursor 

cursoragent and others added 2 commits August 20, 2026 23:19
Clicking a FileCard now opens an in-app preview dialog (name, type, size,
Close, Download) instead of immediately invoking the native save dialog.

Markdown uses the existing sanitized chat renderer; HTML is inert source
only and is never given to webview navigation or an iframe. Other text
types get a scrollable preview; binaries keep chrome plus a no-preview
state. Bytes still load through fetch_media_bytes / download_file.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: jmfcamp <jmfcamp@users.noreply.github.com>
…e row

Forum post cards wrap Markdown in a row button. The FileCard click was
bubbling, navigating away, and unmounting the preview before it opened.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: jmfcamp <jmfcamp@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants