From 27e427abf6111ee8456e1275bbd81e6c86d6fc29 Mon Sep 17 00:00:00 2001 From: Nishant Bangarwa Date: Wed, 22 Jul 2026 09:08:08 +0530 Subject: [PATCH 1/2] feat: export canvas tab groups to PDF --- .../share/ShareDashboardPopover.svelte | 16 +++++ .../features/canvas/stores/canvas-entity.ts | 4 ++ .../exports/pdf/CanvasPdfExportTab.svelte | 56 +++++++++++++++++ .../pdf/CanvasPdfExportTabGroup.svelte | 32 ++++++++++ .../exports/pdf/CanvasPdfExportView.svelte | 38 ++++++++---- .../exports/pdf/ExportDashboardForm.svelte | 18 ++++++ .../src/features/exports/pdf/capture.spec.ts | 62 ++++++++++++++++++- .../src/features/exports/pdf/capture.ts | 48 +++++++++----- .../features/exports/pdf/export-canvas-pdf.ts | 1 + web-common/src/features/exports/pdf/types.ts | 4 ++ web-common/src/lib/i18n/messages/en.json | 2 + web-common/src/lib/i18n/messages/es.json | 2 + 12 files changed, 254 insertions(+), 29 deletions(-) create mode 100644 web-common/src/features/exports/pdf/CanvasPdfExportTab.svelte create mode 100644 web-common/src/features/exports/pdf/CanvasPdfExportTabGroup.svelte diff --git a/web-admin/src/features/dashboards/share/ShareDashboardPopover.svelte b/web-admin/src/features/dashboards/share/ShareDashboardPopover.svelte index c0fc661ff5e5..793b877fa316 100644 --- a/web-admin/src/features/dashboards/share/ShareDashboardPopover.svelte +++ b/web-admin/src/features/dashboards/share/ShareDashboardPopover.svelte @@ -17,10 +17,13 @@ import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte"; import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte"; import { featureFlags } from "@rilldata/web-common/features/feature-flags"; + import { getCanvasStoreUnguarded } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import type { LayoutBlock } from "@rilldata/web-common/features/canvas/stores/tab-group"; import ExportDashboardForm from "@rilldata/web-common/features/exports/pdf/ExportDashboardForm.svelte"; import { exportCanvasPdf } from "@rilldata/web-common/features/exports/pdf/export-canvas-pdf"; import type { PdfExportRunOptions } from "@rilldata/web-common/features/exports/pdf/types"; import { m } from "@rilldata/web-common/lib/i18n/gen/messages"; + import { readable } from "svelte/store"; export let createMagicAuthTokens: boolean; // Provide canvas identifiers to enable the "PDF" tab (canvas dashboards only). @@ -42,6 +45,18 @@ exportCanvasPdf({ canvasName: name, instanceId: id, ...o }); } + const emptyLayout = readable([]); + // Resolved when the popover opens (the canvas store may not yet be + // initialized when this header button first mounts). + $: layoutStore = + (isOpen && + canvasName && + instanceId && + getCanvasStoreUnguarded(canvasName, instanceId)?.canvasEntity.layout) || + emptyLayout; + // Gates the all-tabs/active-tab option in the PDF export form. + $: hasTabGroups = $layoutStore.some((block) => block.kind === "tab-group"); + function onCopy() { navigator.clipboard.writeText(window.location.href).catch(console.error); copied = true; @@ -106,6 +121,7 @@ (isOpen = false)} /> diff --git a/web-common/src/features/canvas/stores/canvas-entity.ts b/web-common/src/features/canvas/stores/canvas-entity.ts index 686517b3f2b8..43db28f65487 100644 --- a/web-common/src/features/canvas/stores/canvas-entity.ts +++ b/web-common/src/features/canvas/stores/canvas-entity.ts @@ -126,6 +126,10 @@ export class CanvasEntity { // data query (see BaseCanvasComponent.dataEnabled) so all components fetch and // render regardless of the lazy-load latch, without mutating that latch. exportMode = writable(false); + // Whether the PDF export renders every tab of each tab group (stacked in strip + // order) or only each group's active tab. Set by exportCanvasPdf alongside + // exportMode; read by CanvasPdfExportView. + exportAllTabs = writable(true); // This is to skip processing the spec the first time the store updates with a value // We've already called it as part of the constructor diff --git a/web-common/src/features/exports/pdf/CanvasPdfExportTab.svelte b/web-common/src/features/exports/pdf/CanvasPdfExportTab.svelte new file mode 100644 index 000000000000..8f715e6c07d5 --- /dev/null +++ b/web-common/src/features/exports/pdf/CanvasPdfExportTab.svelte @@ -0,0 +1,56 @@ + + +
+

{tab.displayName}

+
+ +{#each $rows as row, rowIndex (rowIndex)} + +{/each} + + diff --git a/web-common/src/features/exports/pdf/CanvasPdfExportTabGroup.svelte b/web-common/src/features/exports/pdf/CanvasPdfExportTabGroup.svelte new file mode 100644 index 000000000000..7a1feaf929dc --- /dev/null +++ b/web-common/src/features/exports/pdf/CanvasPdfExportTabGroup.svelte @@ -0,0 +1,32 @@ + + +{#each exportTabs as tab (tab.name)} + +{/each} diff --git a/web-common/src/features/exports/pdf/CanvasPdfExportView.svelte b/web-common/src/features/exports/pdf/CanvasPdfExportView.svelte index 4a11a783165a..ed06c47ddfe6 100644 --- a/web-common/src/features/exports/pdf/CanvasPdfExportView.svelte +++ b/web-common/src/features/exports/pdf/CanvasPdfExportView.svelte @@ -2,23 +2,28 @@ import { getCanvasStore } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; import StaticCanvasRow from "@rilldata/web-common/features/canvas/StaticCanvasRow.svelte"; import CanvasPdfExportHeader from "./CanvasPdfExportHeader.svelte"; + import CanvasPdfExportTabGroup from "./CanvasPdfExportTabGroup.svelte"; // A dedicated, read-only render of the whole canvas used solely as the PDF - // capture target. It reuses the live dashboard's row/component rendering off + // capture target. It reuses the live dashboard's block/component rendering off // the same canvas store, but renders every component eagerly (lazy={false}) so // the capture is complete without touching the live dashboard's lazy-load - // state. See captureCanvasBlocks, which reads from #canvas-pdf-export-view. + // state. Tab groups are flattened for print: every exported tab (all tabs, or + // only each group's active one — see exportAllTabs) renders as a label band + // followed by its rows, stacked in strip order. + // See captureCanvasBlocks, which reads from #canvas-pdf-export-view. export let canvasName: string; export let instanceId: string; // Render width in px; matches the on-screen content width for fidelity. export let width: number; $: ({ - canvasEntity: { componentsStore, _rows }, + canvasEntity: { componentsStore, _rows, layout, exportAllTabs }, } = getCanvasStore(canvasName, instanceId)); $: components = $componentsStore; $: rows = $_rows; + $: blocks = $layout;
- {#each rows as row, rowIndex (rowIndex)} - + {#each blocks as block (block.kind === "tab-group" ? `g-${block.group.name}` : `r-${block.rowIndex}`)} + {#if block.kind === "tab-group"} + + {:else if rows[block.freeRowIndex]} + + {/if} {/each}
diff --git a/web-common/src/features/exports/pdf/ExportDashboardForm.svelte b/web-common/src/features/exports/pdf/ExportDashboardForm.svelte index d10ae3253d63..46169df4d334 100644 --- a/web-common/src/features/exports/pdf/ExportDashboardForm.svelte +++ b/web-common/src/features/exports/pdf/ExportDashboardForm.svelte @@ -1,6 +1,7 @@