Skip to content

feat(hub): add dock grouping (groupId + type:'group')#29

Merged
antfu merged 1 commit into
devframes:mainfrom
antfubot:feat/dock-grouping
Jun 10, 2026
Merged

feat(hub): add dock grouping (groupId + type:'group')#29
antfu merged 1 commit into
devframes:mainfrom
antfubot:feat/dock-grouping

Conversation

@antfubot

Copy link
Copy Markdown
Contributor

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 existing devframe:docks shared state.

What this adds

A deliberately flat pointer model, not a recursive entry tree:

  • groupId?: string on every dock entry — "I belong to group X" (membership, not containment).
  • A new type: 'group' entry (DevframeViewGroup) that is itself a dock-bar button, carrying its own title/icon/category/order/when plus an optional defaultChildId.

Members stay independently-registered, top-level entries in the views map and devframe:docks; a group is just another entry. Because everything stays keyed by id, the existing register/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 whose groupId equals its own id (self-grouping).
  • DF8104 — a type:'group' entry that itself sets groupId (nested groups, unsupported in v1; the shape stays forward-compatible so the gate can be relaxed later).

Orphan members — a groupId that 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. groupId is optional; existing flat entries are unchanged and valid. type:'group' is a new union member, surfaced to downstream exhaustive switches by the API snapshot + TS.

Changes

  • packages/hub/src/types/docks.tsgroupId? on DevframeDockEntryBase, new DevframeViewGroup, widened DevframeDockUserEntry.
  • packages/hub/src/node/host-docks.tsvalidateGroupMembership() invoked from register()/update().
  • packages/hub/src/node/diagnostics.tsDF8103, DF8104 (in the DF81xx docks 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 preserves type:'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 build all pass (360/360 tests).


This PR was created with the help of an agent.

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.
@netlify

netlify Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit c3c24f4
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a28f56b42c555000870b95a
😎 Deploy Preview https://deploy-preview-29--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@antfu antfu merged commit 1c239e5 into devframes:main Jun 10, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants