feat: Dashboard groups with tabs, collapsible/bordered options, and panel organization#1972
feat: Dashboard groups with tabs, collapsible/bordered options, and panel organization#1972alex-fedotyev wants to merge 8 commits intomainfrom
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Knip - Unused Code Analysis⚪ No changes detected (231 issues on both main and PR) What is this?Knip finds unused files, dependencies, and exports in your codebase. Run |
PR Review
|
E2E Test Results✅ All tests passed • 92 passed • 3 skipped • 1012s
Tests ran across 4 shards in parallel. |
9d1a5c2 to
0d2b11f
Compare
a7afc78 to
fd8799e
Compare
fd8799e to
20a628e
Compare
d65d046 to
0fb0522
Compare
0fb0522 to
e38c98b
Compare
e38c98b to
74ee92a
Compare
74ee92a to
4aee30f
Compare
4aee30f to
ae5981a
Compare
ae5981a to
82579ce
Compare
7c646bb to
d7cd008
Compare
d7cd008 to
24f3b5f
Compare
24f3b5f to
d1c641a
Compare
1b87b14 to
ca82900
Compare
Add 'group' type alongside 'section'. Groups always have tabs array (min 1 tab). 1 tab = plain group, 2+ = tab bar. Tiles get optional tabId for tab assignment. activeTabId persisted like collapsed state (Grafana/Kibana shared view state pattern).
DashboardDndContext (116 lines): sortable container reorder provider. DashboardDndComponents (98 lines): EmptyContainerPlaceholder with full-width [+ Add] button, SortableSectionWrapper.
1 tab = plain header (group identity IS the first tab). 2+ tabs = tab bar with hover-only x, inline +, double-click rename. stopPropagation on rename inputs to prevent Cmd+Left bubbling. Render-prop children(activeTabId). Theme-aware borders.
Grip icon on hover. stopPropagation on rename input keyboard events. Theme-aware var(--mantine-color-default-border).
useDashboardContainers (280 lines): section/group CRUD, tab management. Groups created with 1 tab. Add Tab creates 2nd. Delete to 1 keeps tab. Header rename syncs tabs[0]. Always-confirm delete. handleTabChange intentionally persists activeTabId (documented). useTileSelection (76 lines): Shift+click + Cmd+G grouping. Clears tabId on grouped tiles to prevent orphaned tab assignments.
Fill-right-then-wrap tile positioning via calculateNextTilePosition (w=8, h=10 matching original defaults). Floating drag bar on hover (no content shift). Move dropdown: tab targets shown as pipe-separated siblings with target in normal weight, others dimmed (Logs | Metrics). Section empty state wired with onAddTile. Cross-container moves via dropdown. Delete confirmation always shown. Select-and-group Cmd+G. makeId uses larger ID space to reduce collision probability.
ca82900 to
c363674
Compare
54 tests: group always has 1 tab, add tab creates 2nd, title syncs from tabs[0], delete to 1 keeps tab, fill-right positioning, tabId cleanup on grouping, section reorder, tile grouping.
c363674 to
62f8b3d
Compare
Temporary — remove before merge.
|
Hey, sorry not going to get to this today. I'll follow up after the weekend |
|
@alex-fedotyev one thing that wasn't clear to me when checking out is what the main difference between groups and sections are. I understand sections can collapse, and groups can't. But is there a reason why we don't have collapsible groups (and then no longer need sections?) |
@MikeShi42 - Great question — I've been thinking through this and I see two real options: Option A: Two types, better namesRename "Section" → "Row". Keep "Group" as the bordered container with optional tabs.
Benefits:
Tradeoff: two concepts to learn, but the names make the distinction obvious. Option B: One type, always borderedDrop section/row entirely. Just "Group" — always bordered, always collapsible, optionally tabbed. Benefits:
Tradeoff: every organizational element is a bordered box, which makes dashboards visually heavier. Users who just want a collapsible label to divide their dashboard into logical areas (the most common organizational pattern in dashboarding tools) are forced into bordered containers. Variable-driven repeat would need to handle both row-style duplication and tab-style generation within a single type, making the automation model more complex. Conditional tabs that filter out all visible tabs leave an empty bordered box — either shown (looks broken) or hidden (implicit disappearance is confusing). Stretch: A My recommendation: Option AThe real issue isn't that there are two types — it's that "section" and "group" sound like synonyms. Renaming section to "row" makes the distinction self-evident. And keeping a lightweight option matters — not every dashboard needs boxes, but almost every large dashboard needs collapsible dividers. |
Summary
Dashboard organization feature: tiles can be organized into Groups — collapsible, optionally bordered containers with smart tab support, reordering via drag handles, and cross-container tile moves.
Concepts
Group — A container for tiles. Always has at least 1 tab internally. Configurable:
tabId.Container schema — No
typediscriminator. Containers are defined by properties (collapsible,bordered,tabs). Designed to be extensible via discriminated union if other container types are needed in the future (e.g. markdown blocks, alert rows, embeds).Features
+ Add→ "New Group"Implementation
DashboardContainerSchemaincommon-utils/types.tswithcollapsible,bordered,tabs(optional),activeTabIdGroupContainer— unified component (replaced separateSectionHeader)useDashboardContainers(container CRUD + tab lifecycle),useTileSelection(multi-select + Cmd+G)@dnd-kitfor container reordering, customDashboardDndContextPRs
References