Skip to content

fix(pdf): a pdf now dont forget its name when it gets downloadet #10048

Open
Excubitorum wants to merge 6 commits into
TriliumNext:mainfrom
Excubitorum:fix/pdf-download-filename
Open

fix(pdf): a pdf now dont forget its name when it gets downloadet #10048
Excubitorum wants to merge 6 commits into
TriliumNext:mainfrom
Excubitorum:fix/pdf-download-filename

Conversation

@Excubitorum

@Excubitorum Excubitorum commented Jun 4, 2026

Copy link
Copy Markdown

Thanks for your work this Project looks really promissing and nice

  • Replaces trilium-request-download postMessage with a direct call to /api/notes/:id/download
  • The server endpoint sets Content-Disposition: attachment; filename="<note title>.pdf" via BNote.getFileName(), so the browser uses the Trilium note title as the default download filename
  • Adds Electron support via electronApi.shell.downloadURL()
  • Fixes read-only PDFs where the iframe handler (manageDownload) was never registered (it only runs when editable=1)

Test plan

  • Open a PDF note, click download → filename should match the note title
  • Works for read-only PDFs (no #readOnly label required)
  • Works in browser (server mode)
grafik grafik

Replace the postMessage-based download (trilium-request-download) with a
direct call to /api/notes/:id/download, which sets Content-Disposition with
the note title. Adds Electron support and fixes read-only notes where the
iframe handler was never registered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Jun 4, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the PDF preview widget to handle custom downloads directly. Instead of posting a message to an iframe, it now triggers a download using window.electronApi.shell.downloadURL in Electron environments, or by updating window.location.href in web environments. A review comment correctly identifies that the constructed URL may be relative, which will cause the Electron download API to fail, and suggests resolving this by converting the URL to an absolute path using the new URL constructor.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread apps/client/src/widgets/type_widgets/file/Pdf.tsx Outdated
@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes PDF downloads so the browser uses the Trilium note title as the filename, by routing the download through /api/notes/:id/download instead of pdf.js's built-in save. It also repairs downloads for read-only PDFs, which previously could not receive the trilium-request-download postMessage because manageDownload() was only registered when editable=1.

  • Pdf.tsx: Replaces the iframe postMessage approach with open.getUrlForDownload() + open.download(), correctly handling both Electron (absolute URL) and web (relative URL). A spacedUpdate.updateNowIfNecessary() flush is added before downloading to ensure any pending annotation edits are persisted first.
  • custom.ts: Removes the now-unneeded manageDownload() function and its registration inside the isEditable block entirely.

Confidence Score: 5/5

Safe to merge — the change is a self-contained swap of the download mechanism that follows existing patterns already used elsewhere in the codebase.

Both changed files are small and focused. The new download path reuses open.getUrlForDownload() and open.download(), the same helpers used for every other note download in the app, so Electron and web browser compatibility is handled identically to the rest of the codebase. The manageDownload() removal is clean with no remaining callers.

No files require special attention.

Important Files Changed

Filename Overview
apps/client/src/widgets/type_widgets/file/Pdf.tsx Replaces postMessage-based download with direct API call; correctly uses open.getUrlForDownload() for Electron/browser compatibility and flushes pending saves before downloading.
packages/pdfjs-viewer/src/custom.ts Removes the manageDownload() function and its registration cleanly; no remaining callers exist.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant PdfPreview as PdfPreview (Pdf.tsx)
    participant SpacedUpdate
    participant OpenService as open.ts
    participant Server

    User->>PdfPreview: clicks Download
    PdfPreview->>PdfPreview: useTriliumEvent customDownload fires
    PdfPreview->>SpacedUpdate: updateNowIfNecessary()
    SpacedUpdate->>Server: POST blob (if pending edits)
    Server-->>SpacedUpdate: 200 OK
    SpacedUpdate-->>PdfPreview: resolved
    PdfPreview->>OpenService: getUrlForDownload api/notes/:id/download
    OpenService-->>PdfPreview: absolute URL (Electron) or relative URL (web)
    PdfPreview->>OpenService: download(url)
    alt Electron
        OpenService->>OpenService: electronApi.shell.downloadURL(url)
    else Web browser
        OpenService->>Server: GET /api/notes/:id/download
        Server-->>User: attachment with note title as filename
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant PdfPreview as PdfPreview (Pdf.tsx)
    participant SpacedUpdate
    participant OpenService as open.ts
    participant Server

    User->>PdfPreview: clicks Download
    PdfPreview->>PdfPreview: useTriliumEvent customDownload fires
    PdfPreview->>SpacedUpdate: updateNowIfNecessary()
    SpacedUpdate->>Server: POST blob (if pending edits)
    Server-->>SpacedUpdate: 200 OK
    SpacedUpdate-->>PdfPreview: resolved
    PdfPreview->>OpenService: getUrlForDownload api/notes/:id/download
    OpenService-->>PdfPreview: absolute URL (Electron) or relative URL (web)
    PdfPreview->>OpenService: download(url)
    alt Electron
        OpenService->>OpenService: electronApi.shell.downloadURL(url)
    else Web browser
        OpenService->>Server: GET /api/notes/:id/download
        Server-->>User: attachment with note title as filename
    end
Loading

Reviews (4): Last reviewed commit: "fix(pdf): flush pending edits before dow..." | Re-trigger Greptile

Comment thread apps/client/src/widgets/type_widgets/file/Pdf.tsx Outdated
excubitor and others added 2 commits June 4, 2026 09:25
Use getUrlForDownload() and download() from open.ts instead of inline
logic to ensure the correct absolute URL is passed to the Electron
downloader.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dosubot dosubot Bot added size:XS This PR changes 0-9 lines, ignoring generated files. and removed size:S This PR changes 10-29 lines, ignoring generated files. labels Jun 4, 2026
Excubitorum and others added 2 commits June 18, 2026 10:55
Flush any pending in-viewer annotation edits via spacedUpdate before the
server download, so the file reflects the latest state and not just the
last debounced auto-save.

Also remove the now-unused manageDownload() iframe handler and its
registration: nothing posts trilium-request-download anymore since the
download is triggered at the component level.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Jun 22, 2026
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/client/src/widgets/type_widgets/file/Pdf.tsx 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 2.55MB (2.63%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
client-esm 49.08MB 2.55MB (5.47%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: client-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
src/Spreadsheet-*.js -444.41kB 5.4MB -7.6%
src/chunk-*.js 326 bytes 226.95kB 0.14%
src/leaflet-*.js 8 bytes 148.82kB 0.01%
src/leaflet-*.js 125 bytes 1.03MB 0.01%
src/render_to_xlsx-*.js 1.25kB 934.92kB 0.13%
src/dist-*.js 7 bytes 63 bytes 12.5% ⚠️
src/dist-*.js 25 bytes 30.83kB 0.08%
src/dist-*.js 163 bytes 230.05kB 0.07%
src/dist-*.js 19 bytes 82 bytes 30.16% ⚠️
src/dist-*.js -26 bytes 56 bytes -31.71%
src/dist-*.js -24 bytes 14.38kB -0.17%
src/src-*.js 470 bytes 537.17kB 0.09%
src/src-*.js 2 bytes 25.04kB 0.01%
src/mathlive.min-*.js 93 bytes 808.01kB 0.01%
src/ru-*.js 461.27kB 546.23kB 542.99% ⚠️
src/ru-*.js 7.68kB 8.05kB 2030.95% ⚠️
src/ru-*.js -52.97kB 2.09kB -96.2%
src/ru-*.js -3.88kB 55.06kB -6.58%
src/ru-*.js (New) 1.97kB 1.97kB 100.0% 🚀
src/ru-*.js (New) 3.11kB 3.11kB 100.0% 🚀
src/ru-*.js (New) 378 bytes 378 bytes 100.0% 🚀
src/ru-*.js (New) 84.95kB 84.95kB 100.0% 🚀
src/ru-*.js (New) 302 bytes 302 bytes 100.0% 🚀
src/ru-*.js (New) 1.12kB 1.12kB 100.0% 🚀
src/ru-*.js (New) 4.27kB 4.27kB 100.0% 🚀
src/ru-*.js (New) 5.44kB 5.44kB 100.0% 🚀
src/ru-*.js (New) 58.94kB 58.94kB 100.0% 🚀
src/Canvas-*.js 1.23kB 536.67kB 0.23%
src/ja-*.js 1.04kB 2.36kB 78.74% ⚠️
src/ja-*.js -22.09kB 1.32kB -94.35%
src/ja-*.js -45.65kB 935 bytes -97.99%
src/ja-*.js (New) 368.17kB 368.17kB 100.0% 🚀
src/ja-*.js (New) 46.58kB 46.58kB 100.0% 🚀
src/ja-*.js (New) 2.86kB 2.86kB 100.0% 🚀
src/ja-*.js (New) 23.41kB 23.41kB 100.0% 🚀
src/ja-*.js (New) 1.56kB 1.56kB 100.0% 🚀
src/ja-*.js (New) 6.69kB 6.69kB 100.0% 🚀
src/ja-*.js (New) 1.39kB 1.39kB 100.0% 🚀
src/ja-*.js (New) 232 bytes 232 bytes 100.0% 🚀
src/ja-*.js (New) 3.88kB 3.88kB 100.0% 🚀
src/es-*.js 299.39kB 343.52kB 678.48% ⚠️
src/es-*.js 277 bytes 1.5kB 22.56% ⚠️
src/es-*.js 5.08kB 5.73kB 786.53% ⚠️
src/es-*.js -38.81kB 3.87kB -90.93%
src/es-*.js (New) 1.23kB 1.23kB 100.0% 🚀
src/es-*.js (New) 798 bytes 798 bytes 100.0% 🚀
src/es-*.js (New) 1.33kB 1.33kB 100.0% 🚀
src/es-*.js (New) 646 bytes 646 bytes 100.0% 🚀
src/es-*.js (New) 2.67kB 2.67kB 100.0% 🚀
src/es-*.js (New) 2.26kB 2.26kB 100.0% 🚀
src/es-*.js (New) 42.69kB 42.69kB 100.0% 🚀
src/es-*.js (New) 322.06kB 322.06kB 100.0% 🚀
src/es-*.js (New) 44.13kB 44.13kB 100.0% 🚀
src/es-*.js (New) 202 bytes 202 bytes 100.0% 🚀
src/tabulator-*.js 2.09kB 337.77kB 0.62%
src/fr-*.js 126 bytes 1.37kB 10.13% ⚠️
src/fr-*.js -19.34kB 4.11kB -82.47%
src/fr-*.js -12.78kB 23.45kB -35.28%
src/fr-*.js -43.6kB 773 bytes -98.26%
src/fr-*.js (New) 1.24kB 1.24kB 100.0% 🚀
src/fr-*.js (New) 213 bytes 213 bytes 100.0% 🚀
src/fr-*.js (New) 1.65kB 1.65kB 100.0% 🚀
src/fr-*.js (New) 2.8kB 2.8kB 100.0% 🚀
src/fr-*.js (New) 326.0kB 326.0kB 100.0% 🚀
src/fr-*.js (New) 6.04kB 6.04kB 100.0% 🚀
src/fr-*.js (New) 36.23kB 36.23kB 100.0% 🚀
src/fr-*.js (New) 44.37kB 44.37kB 100.0% 🚀
src/fr-*.js (New) 2.35kB 2.35kB 100.0% 🚀
src/en-*.js 1.34kB 2.25kB 147.96% ⚠️
src/en-*.js 1.5kB 2.08kB 262.02% ⚠️
src/en-*.js 210.12kB 321.48kB 188.67% ⚠️
src/en-*.js 4.92kB 5.14kB 2156.14% ⚠️
src/en-*.js 617 bytes 681 bytes 964.06% ⚠️
src/en-*.js -28.68kB 1.29kB -95.7%
src/en-*.js -65.76kB 64 bytes -99.9%
src/en-*.js -64.74kB 1.18kB -98.21%
src/en-*.js (New) 186 bytes 186 bytes 100.0% 🚀
src/en-*.js (New) 29.97kB 29.97kB 100.0% 🚀
src/en-*.js (New) 65.83kB 65.83kB 100.0% 🚀
src/en-*.js (New) 3.67kB 3.67kB 100.0% 🚀
src/en-*.js (New) 65.92kB 65.92kB 100.0% 🚀
src/en-*.js (New) 907 bytes 907 bytes 100.0% 🚀
src/en-*.js (New) 228 bytes 228 bytes 100.0% 🚀
src/en-*.js (New) 574 bytes 574 bytes 100.0% 🚀
src/en-*.js (New) 111.36kB 111.36kB 100.0% 🚀
src/zh-*.js 15 bytes 1.29kB 1.18%
src/zh-*.js 383 bytes 669 bytes 133.92% ⚠️
src/zh-*.js 3.54kB 5.06kB 233.14% ⚠️
src/zh-*.js 3.45kB 4.93kB 232.03% ⚠️
src/zh-*.js 2.01kB 2.27kB 775.29% ⚠️
src/zh-*.js -17.7kB 1.29kB -93.21%
src/zh-*.js -17.54kB 1.52kB -92.03%
src/zh-*.js -36.01kB 666 bytes -98.18%
src/zh-*.js -33.38kB 3.34kB -90.9%
src/zh-*.js (New) 286 bytes 286 bytes 100.0% 🚀
src/zh-*.js (New) 36.68kB 36.68kB 100.0% 🚀
src/zh-*.js (New) 1.17kB 1.17kB 100.0% 🚀
src/zh-*.js (New) 199 bytes 199 bytes 100.0% 🚀
src/zh-*.js (New) 18.99kB 18.99kB 100.0% 🚀
src/zh-*.js (New) 292.94kB 292.94kB 100.0% 🚀
src/zh-*.js (New) 290.96kB 290.96kB 100.0% 🚀
src/zh-*.js (New) 1.12kB 1.12kB 100.0% 🚀
src/zh-*.js (New) 2.27kB 2.27kB 100.0% 🚀
src/zh-*.js (New) 1.49kB 1.49kB 100.0% 🚀
src/zh-*.js (New) 199 bytes 199 bytes 100.0% 🚀
src/zh-*.js (New) 1.89kB 1.89kB 100.0% 🚀
src/zh-*.js (New) 1.88kB 1.88kB 100.0% 🚀
src/zh-*.js (New) 1.28kB 1.28kB 100.0% 🚀
src/zh-*.js (New) 19.06kB 19.06kB 100.0% 🚀
src/zh-*.js (New) 259 bytes 259 bytes 100.0% 🚀
src/zh-*.js (New) 36.73kB 36.73kB 100.0% 🚀
src/zh-*.js (New) 3.35kB 3.35kB 100.0% 🚀
src/content_renderer-*.js 2.34kB 226.54kB 1.04%
src/presentation-*.js 1 bytes 175.78kB 0.0%
src/note_tree-*.js 1.29kB 132.52kB 0.98%
src/snapdom-*.js 188 bytes 123.33kB 0.15%
src/MindMap-*.js 1 bytes 104.23kB 0.0%
src/ContentWidget-*.js 3.0kB 101.06kB 3.06%
src/layout_commons-*.js -2.44kB 84.08kB -2.82%
src/Spreadsheet-*.css 119 bytes 83.87kB 0.14%
src/desktop_layout-*.js 2 bytes 76.32kB 0.0%
src/script_api-*.js 1.19kB 55.86kB 2.18%
src/NoteActions-*.js 2.97kB 47.4kB 6.69% ⚠️
src/tabulator-*.css 121 bytes 34.41kB 0.35%
src/image_upload-*.js (New) 34.25kB 34.25kB 100.0% 🚀
src/dagre-*.js 34 bytes 33.25kB 0.1%
src/PopupEditor-*.js 11 bytes 29.95kB 0.04%
src/File-*.js 11.94kB 28.56kB 71.79% ⚠️
src/geomap-*.js 40 bytes 25.57kB 0.16%
src/hooks-*.js -248 bytes 24.67kB -1.0%
src/revisions-*.js -4 bytes 22.34kB -0.02%
src/ribbon-*.js 22 bytes 18.47kB 0.12%
src/EditableText-*.js 143 bytes 17.79kB 0.81%
src/mobile_layout-*.js -4 bytes 17.11kB -0.02%
src/setup-*.js 320 bytes 16.85kB 1.94%
src/ContentWidget-*.css 223 bytes 15.16kB 1.49%
src/import_provider-*.js (New) 12.73kB 12.73kB 100.0% 🚀
src/NoteDetail-*.js 71 bytes 11.06kB 0.65%
src/setup-*.css 150 bytes 9.08kB 1.68%
src/Attachment-*.js -15 bytes 8.29kB -0.18%
src/frontend_script_api-*.js 450 bytes 7.85kB 6.08% ⚠️
src/ListOrGridView-*.js 1 bytes 7.51kB 0.01%
src/render_to_html-*.js 2.44kB 6.71kB 57.06% ⚠️
src/SiblingNavigator-*.js -41 bytes 4.49kB -0.91%
src/theme-*.js 376 bytes 4.36kB 9.45% ⚠️
src/File-*.css 1.03kB 3.92kB 35.58% ⚠️
src/index-*.js 16 bytes 3.81kB 0.42%
src/merge-*.js (New) 3.21kB 3.21kB 100.0% 🚀
src/Modal-*.js 79 bytes 3.16kB 2.57%
src/export-*.js -32 bytes 2.78kB -1.14%
src/import-*.js 178 bytes 2.03kB 9.6% ⚠️
src/Dropdown-*.js 187 bytes 2.4kB 8.44% ⚠️
src/note_type_chooser-*.js -5 bytes 1.86kB -0.27%
src/ListPrintView-*.js 1 bytes 1.86kB 0.05%
src/import_provider-*.css (New) 1.84kB 1.84kB 100.0% 🚀
src/render_to_csv-*.js 5 bytes 1.83kB 0.27%
src/workbook_model-*.js 277 bytes 1.7kB 19.48% ⚠️
src/Admonition-*.css 40 bytes 1.28kB 3.23%
src/prompt-*.js 5 bytes 1.23kB 0.41%
src/Doc-*.js -5 bytes 721 bytes -0.69%
src/react_utils-*.js 15 bytes 566 bytes 2.72%
src/react_utils-*.js 44 bytes 302 bytes 17.05% ⚠️
src/_baseSet-*.js -3.07kB 448 bytes -87.27%
src/OptionsSection-*.css (New) 230 bytes 230 bytes 100.0% 🚀
src/extends-*.js (Deleted) -33.52kB 0 bytes -100.0% 🗑️

Files in src/File-*.js:

  • ./src/widgets/type_widgets/file/Pdf.tsx → Total Size: 6.63kB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants