Summary
As dashboards grow in complexity, users need a way to organize related tiles into collapsible sections. This is a standard expectation for observability dashboards — it reduces visual clutter, improves navigation on dense dashboards, and provides a performance benefit by skipping data queries for collapsed sections.
This issue covers the core mechanics: data model, layout engine changes, section header rendering, and lazy loading.
Scope
Data model
- Add a
section concept to the dashboard tile system. A section has:
id, title, collapsed (boolean, persisted default state)- References to child tile IDs (or tiles reference their parent section)
- Keep tiles flat in the array — sections reference children, children are never moved/nested in the JSON. This avoids known pitfalls with inconsistent serialization based on collapsed state.
- Update Zod schemas in
packages/common-utils/src/types.ts - MongoDB model already uses
Mixed for tiles — no migration needed
Layout engine
- Section headers render as full-width (24-col), 1-unit-high bars in the react-grid-layout grid
- On collapse: remove child tiles from the layout array, shift y-positions of everything below
- On expand: re-insert child tiles, restore y-positions
- Collapsed children are not mounted by React — their query hooks don't fire (lazy loading for free)
Section header component
- Displays section title and collapse/expand toggle
- Visually distinct from chart tiles (thin horizontal bar)
- Supports both collapsed and expanded states
Lazy loading
- Tiles in collapsed sections are unmounted → no API calls, no rendering
- On expand, tiles mount and fetch data with the current time range
- Auto-refresh and time range changes do not affect collapsed tiles
Out of scope (see follow-up issue)
- Add/rename/delete section authoring UX
- Drag-to-assign tiles to sections
- Section settings (default collapsed state toggle in edit mode)
Technical notes
- Key files:
DBDashboardPage.tsx, dashboard.ts, packages/common-utils/src/types.ts, packages/api/src/models/dashboard.ts - Layout uses
react-grid-layout with 24-col grid, 32px row height - The layout offset math (y-shifting on collapse/expand) is the trickiest part
Summary
As dashboards grow in complexity, users need a way to organize related tiles into collapsible sections. This is a standard expectation for observability dashboards — it reduces visual clutter, improves navigation on dense dashboards, and provides a performance benefit by skipping data queries for collapsed sections.
This issue covers the core mechanics: data model, layout engine changes, section header rendering, and lazy loading.
Scope
Data model
sectionconcept to the dashboard tile system. A section has:id,title,collapsed(boolean, persisted default state)packages/common-utils/src/types.tsMixedfor tiles — no migration neededLayout engine
Section header component
Lazy loading
Out of scope (see follow-up issue)
Technical notes
DBDashboardPage.tsx,dashboard.ts,packages/common-utils/src/types.ts,packages/api/src/models/dashboard.tsreact-grid-layoutwith 24-col grid, 32px row height