feat(hub): add dock grouping (groupId + type:'group')#29
Merged
Conversation
Let a hub collapse related dock entries under a single dock-bar button when many integrations share one UI. Grouping only makes sense once a hub combines tools, so the data model and host validation land here while the hub continues to ship no UI — downstream kits derive the visual collapse from the existing 'devframe:docks' shared state. - Add an optional `groupId` pointer to every dock entry (membership, not containment) and a new `type:'group'` entry (`DevframeViewGroup`) with an optional `defaultChildId`. This is a flat pointer model: members stay independently-registered top-level entries, so register/update/values, the views map, settings, and shared-state sync all keep working unchanged. - Validate in the host: reject self-grouping (DF8103) and nested groups (DF8104, one level only). Orphan members whose group is unregistered are tolerated and render as normal top-level entries, keeping registration order-independent.
✅ Deploy Preview for devfra ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
antfu
approved these changes
Jun 10, 2026
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.
Intent
When a hub combines many integrations into one UI, related dock entries should be able to collapse under a single dock-bar button instead of crowding the bar. Grouping is meaningless for a single standalone devframe — it only matters once a hub combines tools — so per devframe's positioning the data model + host validation live in
@devframes/hub, while the hub continues to ship no UI. Downstream kits (e.g.@vitejs/devtools-kit) derive the visual collapse from the existingdevframe:docksshared state.What this adds
A deliberately flat pointer model, not a recursive entry tree:
groupId?: stringon every dock entry — "I belong to group X" (membership, not containment).type: 'group'entry (DevframeViewGroup) that is itself a dock-bar button, carrying its owntitle/icon/category/order/whenplus an optionaldefaultChildId.Members stay independently-registered, top-level entries in the
viewsmap anddevframe:docks; a group is just another entry. Because everything stays keyed byid, the existingregister/update/values, settings (pin/hide/order), and shared-state sync keep working with zero new plumbing — a tree would have forced tree-traversal into all of them for a use case that is one level deep.Host behavior
The host's job ends at "store valid entries + emit updates"; grouping derivation is a downstream concern. The only additions are two structured-diagnostic guards (devframe forbids ad-hoc
throw/console):DF8103— an entry whosegroupIdequals its ownid(self-grouping).DF8104— atype:'group'entry that itself setsgroupId(nested groups, unsupported in v1; the shape stays forward-compatible so the gate can be relaxed later).Orphan members — a
groupIdthat no registered group matches — are intentionally not an error: membership is resolved at render time downstream, and load-order independence requires tolerating a member that registers before (or without) its group. The host stays silent and downstream falls back to flat rendering.Backward compatibility
Purely additive.
groupIdis optional; existing flat entries are unchanged and valid.type:'group'is a new union member, surfaced to downstream exhaustiveswitches by the API snapshot + TS.Changes
packages/hub/src/types/docks.ts—groupId?onDevframeDockEntryBase, newDevframeViewGroup, widenedDevframeDockUserEntry.packages/hub/src/node/host-docks.ts—validateGroupMembership()invoked fromregister()/update().packages/hub/src/node/diagnostics.ts—DF8103,DF8104(in theDF81xxdocks range).docs/errors/DF8103.md,docs/errors/DF8104.md— error reference pages.packages/hub/src/node/__tests__/host-docks.test.ts— group registration, membership round-trip, orphan tolerance, self-group/nesting throws, update preservestype:'group'.docs/guide/hub.md— grouping documented (one-level scope, orphan fallback).tests/__snapshots__/tsnapi/@devframes/hub/*— regenerated API snapshot (additive).Verification
pnpm lint && pnpm test && pnpm typecheck && pnpm buildall pass (360/360 tests).This PR was created with the help of an agent.