From 559883dbabee6ca99a26f3fe81b9a138ed85ad61 Mon Sep 17 00:00:00 2001 From: Hugh Kaznowski Date: Sat, 5 Sep 2026 18:54:52 +0100 Subject: [PATCH] Add "All dashboards" print-friendly stacked view (ticket 009) Adds an "All dashboards" selector alongside the existing click-to-select single-dashboard view. Selecting it stacks every dashboard vertically in normal document flow, each preceded by a heading naming it, with no fixed-height or scroll-clipping containers, so the browser's native print function can render the full stack across pages. Verified in-browser: single-dashboard editing still works unchanged, and "All dashboards" renders all dashboards (including an empty one) stacked with named separators; confirmed via computed layout that only the pre-existing app-level scroll container grows to fit the content, with no clipping container inside the Dashboards section itself. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o --- .../009-all-dashboards-print-friendly-view.md | 9 ---- webapp/src/components/Dashboards.tsx | 50 ++++++++++++++++++- 2 files changed, 49 insertions(+), 10 deletions(-) delete mode 100644 tickets/009-all-dashboards-print-friendly-view.md diff --git a/tickets/009-all-dashboards-print-friendly-view.md b/tickets/009-all-dashboards-print-friendly-view.md deleted file mode 100644 index 8215b50..0000000 --- a/tickets/009-all-dashboards-print-friendly-view.md +++ /dev/null @@ -1,9 +0,0 @@ -# Add "All dashboards" option with print-friendly stacked layout - -The dashboards part should keep the click-to-select dashboards, however it should have an "All dashboards" option. In that situation, the dashboards are displayed one after another with named separators. This is important so that it is possible to print the page or print the dashboards section. Printing itself is a browser capability we don't need to implement, but the page should be laid out in a way that's compatible with it. - -## Acceptance criteria -- Existing click-to-select single-dashboard view is preserved. -- New "All dashboards" option stacks all dashboards vertically, one after another, each preceded by a named separator (dashboard name/title). -- The stacked layout uses normal document flow (no fixed-height scroll containers that would clip content) so the browser's native print function can render the full stacked content across pages. -- Verified visually in browser, including a print-preview check. diff --git a/webapp/src/components/Dashboards.tsx b/webapp/src/components/Dashboards.tsx index fbe9bf8..4b5ec57 100644 --- a/webapp/src/components/Dashboards.tsx +++ b/webapp/src/components/Dashboards.tsx @@ -26,6 +26,9 @@ import { HelpIcon } from './HelpIcon' const CHART_TYPES: ChartType[] = ['line', 'bar', 'pie'] +/// Virtual selection id for the "All dashboards" stacked/print view; distinct from any real dashboard id. +const ALL_DASHBOARDS_ID = '__all__' + /// Long enough that rapid typing doesn't spam the save endpoint, short enough that a pause reads as "done" and commits promptly. const AUTOSAVE_DEBOUNCE_MS = 600 @@ -96,6 +99,36 @@ function AutosaveStatus({ status, error }: { status: SaveStatus; error: string | return null } +/// Read-only, print-friendly view of every dashboard stacked one after another, each preceded by a heading naming it. +/// Deliberately uses normal document flow (no scroll containers, no fixed heights) so the browser's native print +/// function can lay the full stack out across as many pages as it needs. +function AllDashboardsView({ dashboards, range }: { dashboards: Dashboard[]; range: TimeRange | null }) { + if (dashboards.length === 0) { + return
No dashboards saved yet.
+ } + return ( +
+ {dashboards.map((d) => ( +
+

{d.name}

+ {d.panels.length === 0 ? ( +
No panels in this dashboard.
+ ) : ( +
+ {d.panels.map((panel) => ( +
+ {panel.title &&
{panel.title}
} + +
+ ))} +
+ )} +
+ ))} +
+ ) +} + export function Dashboards({ range }: { range: TimeRange | null }) { const [activeProfile, setActiveProfile] = useState(null) const [dashboards, setDashboards] = useState([]) @@ -281,6 +314,19 @@ export function Dashboards({ range }: { range: TimeRange | null }) {
+ {dashboards.length > 0 && ( + + )} {dashboards.length === 0 &&
No dashboards saved yet.
} {dashboards.map((d) => (
- {!draft ? ( + {selectedId === ALL_DASHBOARDS_ID ? ( + + ) : !draft ? (
Select or create a dashboard to edit its panels.
) : (