Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages/devframe/src/types/devframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,42 @@ export interface DevframeCliOptions {
flags?: CliFlagsSchema
}

/**
* Default dock attributes for the iframe entry a hub synthesizes when it
* mounts this devframe. Framework-neutral metadata only — the hub layer
* (`mountDevframe`) merges these beneath its per-mount `dock` overrides,
* which in turn sit beneath the locked, derived `id` / `type` / `url`.
*
* Every field is optional. `title` / `icon` default to the definition's
* `name` / `icon` when omitted here; the rest are unset by default.
* Standalone adapters (`cli` / `spa` / `build`) ignore this entirely.
*/
export interface DevframeDockDefaults {
/** Dock entry title. Defaults to the definition's `name`. */
title?: string
/** Dock entry icon. Defaults to the definition's `icon`. */
icon?: string | { light: string, dark: string }
/**
* Sort weight within the dock; higher sorts earlier.
* @default 0
*/
defaultOrder?: number
/**
* Category the entry groups under in the dock.
* @default 'default'
*/
category?: string
/**
* Conditional-visibility expression (same syntax as command `when`
* clauses). Set to `'false'` to hide the entry unconditionally.
*/
when?: string
/** Badge text rendered on the dock icon (e.g. an unread count). */
badge?: string
/** Id of the dock group this entry collapses under, if any. */
groupId?: string
}

export interface DevframeSpaOptions {
base?: string
/**
Expand Down Expand Up @@ -215,6 +251,15 @@ export interface DevframeDefinition {
/** One-line summary of what the tool does. */
description: string
icon?: string | { light: string, dark: string }
/**
* Default dock attributes applied when a hub mounts this devframe as an
* iframe dock entry. Consulted only by hub adapters (`mountDevframe`),
* which merge these beneath the per-mount `dock` overrides; standalone
* adapters (`cli` / `spa` / `build`) ignore it.
*
* @see {@link DevframeDockDefaults}
*/
dock?: DevframeDockDefaults
/**
* Mount path override. Defaults depend on the adapter:
* `/` for standalone (`cli` / `spa` / `build`), `/__<id>/` for hosted
Expand Down
30 changes: 30 additions & 0 deletions packages/hub/src/node/__tests__/mount-devframe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@ describe('mountDevframe', () => {
expect(setup).toHaveBeenCalledTimes(1)
})

it('applies the definition-level dock defaults to the synthesized entry', async () => {
const ctx = createContext()
await mountDevframe(ctx, makeDevframe({
dock: { category: 'framework', defaultOrder: 5, when: 'clientType == embedded' },
}))

expect(ctx.docks.views.get('demo')).toMatchObject({
id: 'demo',
title: 'Demo',
type: 'iframe',
category: 'framework',
defaultOrder: 5,
when: 'clientType == embedded',
})
})

it('lets per-mount dock overrides win over the definition dock defaults', async () => {
const ctx = createContext()
await mountDevframe(
ctx,
makeDevframe({ dock: { category: 'framework', defaultOrder: 5 } }),
{ dock: { category: 'app' } },
)

expect(ctx.docks.views.get('demo')).toMatchObject({
category: 'app',
defaultOrder: 5,
})
})

it('warns and deduplicates by default, keeping the first registration', async () => {
const ctx = createContext()
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
Expand Down
13 changes: 9 additions & 4 deletions packages/hub/src/node/mount-devframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export interface MountDevframeOptions {
*/
base?: string
/**
* Overrides for the auto-synthesized iframe dock entry. Use this to
* customize the entry's `category`, override the icon, hide it via
* `when`, etc. Cannot change `id`, `type`, or `url` — those are
* derived from the devframe definition.
* Per-mount overrides for the auto-synthesized iframe dock entry. Use
* this to customize the entry's `category`, override the icon, hide it
* via `when`, etc. Takes precedence over the definition's own
* {@link DevframeDefinition.dock} defaults. Cannot change `id`, `type`,
* or `url` — those are derived from the devframe definition.
*/
dock?: Partial<Omit<DevframeViewIframe, 'id' | 'type' | 'url'>>
}
Expand Down Expand Up @@ -85,6 +86,10 @@ export async function mountDevframe(
id,
title: d.name,
icon: d.icon ?? 'ph:plug-duotone',
// Definition-level `dock` defaults sit above the name/icon-derived
// defaults; per-mount `options.dock` overrides them; `type`/`url`
// (and `id`) stay locked, derived from the definition.
...d.dock,
...options.dock,
type: 'iframe',
url: base,
Expand Down
1 change: 1 addition & 0 deletions tests/__snapshots__/tsnapi/devframe/index.snapshot.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export { DevframeDeploymentKind }
export { DevframeDiagnosticsDefinition }
export { DevframeDiagnosticsHost }
export { DevframeDiagnosticsLogger }
export { DevframeDockDefaults }
export { DevframeDuplicationStrategy }
export { DevframeHost }
export { DevframeNodeContext }
Expand Down
1 change: 1 addition & 0 deletions tests/__snapshots__/tsnapi/devframe/types.snapshot.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { DevframeDeploymentKind }
export { DevframeDiagnosticsDefinition }
export { DevframeDiagnosticsHost }
export { DevframeDiagnosticsLogger }
export { DevframeDockDefaults }
export { DevframeDuplicationStrategy }
export { DevframeHost }
export { DevframeNodeContext }
Expand Down
Loading