From fafcfbefacb2f88a62158fd11218c83caf08c4fa Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Thu, 13 Aug 2026 07:30:17 +0000 Subject: [PATCH] fix(hub-ui): show the built-in Settings dock by default The Settings view was ported but its dock entry only appeared when a host registered ~settings server-side. hub-ui, as the reference viewer, now owns the ~settings ~builtin dock and injects it into its entries when absent, so Settings is visible in the dock bar and reachable via devframes:open-settings in every consumer. A host that registers its own ~settings still wins the merge, so no duplicate appears. --- packages/hub-ui/src/client/constants.ts | 18 ++++++++++ packages/hub-ui/src/client/state/context.ts | 38 ++++++++++++++------- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/packages/hub-ui/src/client/constants.ts b/packages/hub-ui/src/client/constants.ts index 0864513a..f5f8691d 100644 --- a/packages/hub-ui/src/client/constants.ts +++ b/packages/hub-ui/src/client/constants.ts @@ -38,8 +38,26 @@ export const BUILTIN_ENTRY_CLIENT_AUTH_NOTICE: DevframeViewBuiltin = Object.free icon: 'ph:warning-duotone', }) +/** + * The viewer's own Settings view. hub-ui owns this `~builtin` dock rather than + * leaning on a host to register it server-side — so the Settings tab is visible + * by default in every consumer of the reference UI (the standalone viewer and + * the embedded dock alike). A `~builtin` view defaults its category to + * `~builtin`, so it groups and sorts last on the bar. A host that registers its + * own `~settings` dock (node-side, into `devframe:docks`) still wins the merge; + * this entry only fills the gap when none is present. + */ +export const BUILTIN_ENTRY_SETTINGS: DevframeViewBuiltin = Object.freeze({ + type: '~builtin', + category: '~builtin', + id: '~settings', + title: 'Settings', + icon: 'ph:gear-duotone', +}) + export const BUILTIN_ENTRIES: readonly DevframeViewBuiltin[] = Object.freeze([ BUILTIN_ENTRY_CLIENT_AUTH_NOTICE, + BUILTIN_ENTRY_SETTINGS, ]) export { DEFAULT_CATEGORIES_ORDER } from '@devframes/hub/constants' diff --git a/packages/hub-ui/src/client/state/context.ts b/packages/hub-ui/src/client/state/context.ts index 3ff9382e..3c3ec61c 100644 --- a/packages/hub-ui/src/client/state/context.ts +++ b/packages/hub-ui/src/client/state/context.ts @@ -7,7 +7,7 @@ import type { HubDocksUserSettings } from './dock-settings' import { attachFrameNavClient } from '@devframes/hub/client' import { DEFAULT_STATE_USER_SETTINGS } from '@devframes/hub/constants' import { computed, markRaw, reactive, ref, toRefs, watch, watchEffect } from 'vue' -import { BUILTIN_ENTRIES, HUB_UI_HIDE_EVENT } from '../constants' +import { BUILTIN_ENTRIES, BUILTIN_ENTRY_SETTINGS, HUB_UI_HIDE_EVENT } from '../constants' import { useBranding } from './branding' import { createCommandsContext } from './commands' import { docksGroupByCategories, getCategoryLabel, getGroupMembers, getGroupMembersGrouped, getRegisteredGroupIds, resolveCommandIcon, resolveGroupDefaultChild } from './dock-settings' @@ -36,20 +36,32 @@ export async function createDocksContext( const clientDocks = reactive(new Map()) const entries = computed(() => { const server = dockEntries.value - if (clientDocks.size === 0) - return server - const seen = new Set() - const merged: DevframeDockEntry[] = [] - for (const entry of server) { - seen.add(entry.id) - // a client dock sharing a server id overrides it in the local merge - merged.push(clientDocks.get(entry.id) ?? entry) + let base: DevframeDockEntry[] + if (clientDocks.size === 0) { + base = server } - for (const [id, entry] of clientDocks) { - if (!seen.has(id)) - merged.push(entry) + else { + const seen = new Set() + const merged: DevframeDockEntry[] = [] + for (const entry of server) { + seen.add(entry.id) + // a client dock sharing a server id overrides it in the local merge + merged.push(clientDocks.get(entry.id) ?? entry) + } + for (const [id, entry] of clientDocks) { + if (!seen.has(id)) + merged.push(entry) + } + base = merged } - return merged + // Surface the viewer's own built-in Settings tab by default. hub-ui owns it + // rather than depending on a host to register `~settings` server-side, so + // Settings is always reachable (dock bar + `devframes:open-settings`). A host + // that registered its own `~settings` entry wins — we only add ours when the + // merged list has none. + if (base.some(entry => entry.id === BUILTIN_ENTRY_SETTINGS.id)) + return base + return [...base, BUILTIN_ENTRY_SETTINGS] }) const selectedId = ref(null)