feat(canvas): export canvas dashboards as PDF#9593
Open
nishantmonu51 wants to merge 9 commits into
Open
Conversation
Add a "PDF" tab to the share popover for canvas dashboards that captures the rendered canvas and assembles it into a downloadable PDF. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a client-side “Export as PDF” flow for canvas dashboards, integrating a new PDF export module in web-common and exposing it via a new “PDF” tab in the share popover for canvas dashboards.
Changes:
- Introduces a new
web-common/src/features/exports/pdf/module to settle rendering, capture canvas blocks, paginate, and assemble/download a PDF viajspdf. - Updates the share UI to show a “PDF” tab only when canvas identifiers are present, and wires it to the canvas PDF export orchestrator.
- Adds an off-screen, read-only canvas header render (
CanvasPdfExportHeader) as a capture target and adds thejspdfdependency.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| web-common/src/features/exports/pdf/types.ts | Adds shared PDF export types and capture block schema. |
| web-common/src/features/exports/pdf/settle.ts | Adds “settle before capture” utilities for stores, queries, and fonts. |
| web-common/src/features/exports/pdf/layout.ts | Implements pagination/layout logic for captured blocks across PDF pages. |
| web-common/src/features/exports/pdf/layout.spec.ts | Adds vitest coverage for pagination/orientation behavior. |
| web-common/src/features/exports/pdf/filename.ts | Adds filename slug + timestamp helper for PDF downloads. |
| web-common/src/features/exports/pdf/ExportPdfOptions.svelte | Adds share-popover UI for running the PDF export with options/progress. |
| web-common/src/features/exports/pdf/export-canvas-pdf.ts | Orchestrates canvas-to-PDF export (settle → capture → paginate → assemble). |
| web-common/src/features/exports/pdf/capture.ts | Captures filter header + component cards into raster blocks for PDF assembly. |
| web-common/src/features/exports/pdf/CanvasPdfExportHeader.svelte | Off-screen read-only header (time range + filters) for capture. |
| web-common/src/features/exports/pdf/assemble.ts | Renders paginated placements into a jsPDF document and triggers download. |
| web-common/src/features/exports/pdf/assemble.spec.ts | Adds tests for background color parsing used in PDF rendering. |
| web-common/src/features/canvas/CanvasDashboardWrapper.svelte | Mounts the off-screen PDF header capture target for canvases. |
| web-common/package.json | Adds jspdf dependency. |
| web-admin/src/features/projects/ProjectHeader.svelte | Passes canvasName/instanceId to enable the PDF tab for canvas dashboards. |
| web-admin/src/features/dashboards/share/ShareDashboardPopover.svelte | Adds “PDF” tab + hooks it up to exportCanvasPdf. |
| package-lock.json | Updates lockfile for the new dependency and transitive packages. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
capture.spec.ts uses the DOM (document) but is batched with pure-logic specs in the same directory. Under vitest's parallel forks pool the jsdom global was intermittently unavailable, causing 'document is not defined'. Pin the spec to the jsdom environment to make it deterministic.
The off-screen canvas PDF export header was always mounted, so its read-only filter chips duplicated the live filter bar's text and the 'Readonly Filter Chips' aria-label. Off-screen positioning still counts as visible/queryable to Playwright, so this caused strict-mode violations in unrelated canvas e2e tests (web-local default-filters, web-admin bookmarks). Keep it display:none in normal use (excluded from the a11y tree and text/label locators) and have capture.ts reveal it only while measuring and rasterizing.
The previous display:none approach did not work: Playwright locators (getByText/getByLabel) and the accessibility tree match elements regardless of CSS visibility, so the always-mounted off-screen header still duplicated the live filter bar's text and 'Readonly Filter Chips' label, failing web-local default-filters and web-admin bookmarks e2e tests with strict-mode violations. Gate the header behind a canvasPdfExportActive store so it only exists in the DOM during an active export (mirroring the ScreenshotContainer dialog pattern). prepareCanvasForCapture's tick() flushes it into the DOM before capture reads it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a PDF tab to the share popover for canvas dashboards, allowing users to export the rendered canvas as a downloadable PDF.
web-common/src/features/exports/pdf/module: captures the canvas, expands tables, settles async rendering, lays out pages, and assembles the PDF viajspdf.ShareDashboardPopovergains a "PDF" tab, shown only for canvas dashboards (whencanvasNameandinstanceIdare provided).CanvasDashboardWrapperrenders an off-screenCanvasPdfExportHeaderused solely as the PDF capture target.jspdfdependency.Checklist:
Developed in collaboration with Claude Code