Skip to content

Commit db08151

Browse files
committed
fix(hub-ui): select a visible dock on standalone startup
1 parent 5f6d5be commit db08151

3 files changed

Lines changed: 91 additions & 8 deletions

File tree

‎packages/hub-ui/src/client/components/dock/DockStandalone.vue‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<script setup lang="ts">
22
import type { DocksContext } from '@devframes/hub/client'
3-
import { computed, useTemplateRef, watch } from 'vue'
3+
import { computed, useTemplateRef } from 'vue'
44
import { getEntryGroup } from '../../state/dock-settings'
55
import { getEntryPaneKey, useIframePanes } from '../../utils/useIframePanes'
66
import { useIsRpcTrusted } from '../../utils/useIsRpcTrusted'
7+
import { useStandaloneDefaultDock } from '../../utils/useStandaloneDefaultDock'
78
import CommandPalette from '../command-palette/CommandPalette.vue'
89
import Confirm from '../display/Confirm.vue'
910
import ToastOverlay from '../display/ToastOverlay.vue'
@@ -29,13 +30,7 @@ const isRpcTrusted = useIsRpcTrusted(context, (isTrusted) => {
2930
}
3031
})
3132
32-
watch(
33-
() => context.docks.entries,
34-
() => {
35-
context.docks.selectedId ||= context.docks.entries[0]?.id ?? null
36-
},
37-
{ immediate: true },
38-
)
33+
useStandaloneDefaultDock(context, isRpcTrusted)
3934
4035
const groupedEntries = computed(() => context.docks.groupedEntries)
4136
const activeGroup = computed(() => getEntryGroup(context.docks.entries, context.docks.selected))

‎packages/hub-ui/src/client/state/context.test.ts‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { createEventEmitter } from 'devframe/utils/events'
77
import { createSharedState } from 'devframe/utils/shared-state'
88
import { describe, expect, it, vi } from 'vitest'
99
import { nextTick, ref } from 'vue'
10+
import { useStandaloneDefaultDock } from '../utils/useStandaloneDefaultDock'
1011
import { createDocksContext } from './context'
1112
import { executeSetupScript } from './setup-script'
1213

@@ -430,3 +431,71 @@ describe('dock group command activation', () => {
430431
])
431432
})
432433
})
434+
435+
describe('standalone initial dock', () => {
436+
async function fixture(entries: DevframeDockEntry[]) {
437+
const { rpc, sharedStates, trust } = createStubRpc()
438+
const context = await createDocksContext('standalone', rpc)
439+
sharedStates.get(HUB_EVENTS.sharedState.docks)!.push(entries)
440+
const trusted = ref(false)
441+
const stop = useStandaloneDefaultDock(context, trusted)
442+
return {
443+
context,
444+
stop,
445+
async connect() {
446+
trust()
447+
trusted.value = true
448+
await flushRestore()
449+
},
450+
async publish(next: DevframeDockEntry[]) {
451+
sharedStates.get(HUB_EVENTS.sharedState.docks)!.push(next)
452+
await flushRestore()
453+
},
454+
}
455+
}
456+
457+
it('skips a hidden wrapper and activates the first visible dock through its client script', async () => {
458+
expect.assertions(3)
459+
const { context, connect, stop } = await fixture([
460+
{ id: 'wrapper', title: 'Wrapper', icon: 'ph:box', type: 'iframe', url: '/devframe/', when: 'false' },
461+
gitEntry,
462+
])
463+
expect(context.docks.selectedId).toBeNull()
464+
await connect()
465+
expect(context.docks.selectedId).toBe('git')
466+
expect(executeSetupScript).toHaveBeenCalledWith(gitEntry, expect.anything())
467+
stop()
468+
})
469+
470+
it('waits for an eligible entry without running actions or selecting a built-in fallback', async () => {
471+
expect.assertions(2)
472+
const { context, connect, publish, stop } = await fixture([
473+
{ id: 'command', title: 'Command', icon: 'ph:play', type: 'action', action: { importFrom: '/command.js' } },
474+
])
475+
await connect()
476+
expect(context.docks.selectedId).toBeNull()
477+
await publish([gitEntry])
478+
expect(context.docks.selectedId).toBe('git')
479+
stop()
480+
})
481+
482+
it('keeps an existing selection when the catalog changes', async () => {
483+
expect.assertions(1)
484+
const { context, connect, publish, stop } = await fixture([gitEntry])
485+
await connect()
486+
await publish([{ ...gitEntry, id: 'new-first' }, gitEntry])
487+
expect(context.docks.selectedId).toBe('git')
488+
stop()
489+
})
490+
491+
it('uses normal group routing to open a visible member', async () => {
492+
expect.assertions(1)
493+
const { context, connect, stop } = await fixture([
494+
{ id: 'tools', title: 'Tools', icon: 'ph:folder', type: 'group' },
495+
{ ...gitEntry, groupId: 'tools' },
496+
])
497+
await connect()
498+
expect(context.docks.selectedId).toBe('git')
499+
stop()
500+
})
501+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { DocksContext } from '@devframes/hub/client'
2+
import type { Ref } from 'vue'
3+
import { watch } from 'vue'
4+
5+
/** Pick from the visible dock rail and run normal activation, including client scripts and group routing. */
6+
export function useStandaloneDefaultDock(context: DocksContext, isTrusted: Readonly<Ref<boolean>>) {
7+
return watch(
8+
[() => context.docks.groupedEntries, isTrusted],
9+
([groups, trusted]) => {
10+
if (!trusted || context.docks.selectedId)
11+
return
12+
const entry = groups.flatMap(([, entries]) => entries)
13+
.find(entry => entry.type !== 'action' && entry.type !== '~builtin')
14+
if (entry)
15+
void context.docks.switchEntry(entry.id)
16+
},
17+
{ immediate: true },
18+
)
19+
}

0 commit comments

Comments
 (0)