feat(web): add workspace-aware session flow
This commit is contained in:
@@ -164,7 +164,7 @@ class SlotErrorBoundary extends Component<
|
||||
|
||||
/**
|
||||
* Standard-kit synthesis shared by both scope branches: the global
|
||||
* useSessions hook, the session pair, the store pair when declared, the
|
||||
* useSessions/useWorkspaces hooks, the session pair, the store pair when declared, the
|
||||
* renderSlot binding when children are declared, and the SessionProvider
|
||||
* seat when the children declare a session-scope slot. Hosts hand out BARE
|
||||
* observable sources (hooks never cross the host contract); every hook is
|
||||
@@ -174,7 +174,10 @@ class SlotErrorBoundary extends Component<
|
||||
function standardKit(host: SlotRendererHost, entry: StoredEntry, cell: SessionCell | undefined): {
|
||||
kit: InjectedProps; actions: object | undefined
|
||||
} {
|
||||
const kit: InjectedProps = { useSessions: observableHook(host.sessions.list) }
|
||||
const kit: InjectedProps = {
|
||||
useSessions: observableHook(host.sessions.list),
|
||||
useWorkspaces: observableHook(host.workspaces.list),
|
||||
}
|
||||
if (cell !== undefined) {
|
||||
kit['useSession'] = observableHook(cell.session)
|
||||
kit['sessionId'] = cell.sessionId
|
||||
|
||||
@@ -38,6 +38,9 @@ function hostOver(core: SlotCore): SlotRendererHost {
|
||||
current: { getSnapshot: () => undefined, subscribe: () => () => {} },
|
||||
cell: () => undefined,
|
||||
},
|
||||
workspaces: {
|
||||
list: { getSnapshot: () => ({}), subscribe: () => () => {} },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ function makeHost() {
|
||||
const live = new Set<StoredEntry>()
|
||||
const storeCache = new Map<StoredEntry, Map<string, StoreInstanceLike>>()
|
||||
const list = observable<{ ids: string[] }>({ ids: [] })
|
||||
const workspaces = observable<{ ids: string[] }>({ ids: [] })
|
||||
const current = observable<string | undefined>(undefined)
|
||||
const cells = new Map<string, SessionCell>()
|
||||
|
||||
@@ -122,10 +123,12 @@ function makeHost() {
|
||||
current,
|
||||
cell: (id) => cells.get(id),
|
||||
},
|
||||
workspaces: { list: workspaces },
|
||||
}
|
||||
return {
|
||||
host,
|
||||
list,
|
||||
workspaces,
|
||||
current,
|
||||
declare: (key: string, spec: DeclaredSpec) => { specs.set(key, spec); bump(key) },
|
||||
add: (key: string, partial: Omit<StoredEntry, 'options'> & { options?: StoredEntry['options'] }) => {
|
||||
@@ -483,6 +486,19 @@ describe('standard-kit synthesis', () => {
|
||||
expect(view.container.textContent).toBe('2')
|
||||
})
|
||||
|
||||
it('delivers a live useWorkspaces hook to every slot component', () => {
|
||||
const h = makeHost()
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
h.add('k.single', {
|
||||
component: ({ useWorkspaces }: { useWorkspaces: <S>(sel: (s: { ids: string[] }) => S) => S }) =>
|
||||
<b>{useWorkspaces((s) => s.ids.length)}</b>,
|
||||
})
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, (renderSlot) => renderSlot('k.single', {}))
|
||||
expect(view.container.textContent).toBe('0')
|
||||
act(() => { h.workspaces.set({ ids: ['w1'] }) })
|
||||
expect(view.container.textContent).toBe('1')
|
||||
})
|
||||
|
||||
it('delivers the session pair (bound useSession + sessionId) under SessionProvider', () => {
|
||||
const h = makeHost()
|
||||
h.declare('k.session', SINGLE_SESSION)
|
||||
@@ -710,6 +726,7 @@ describe('inject: execution point, parameter derivation, cache granularity', ()
|
||||
(renderSlot) => renderSlot('k.single', { owner: 'owner', shared: 'owner' }))
|
||||
const props = seen.at(-1)!
|
||||
expect(typeof props['useSessions']).toBe('function') // kit always present
|
||||
expect(typeof props['useWorkspaces']).toBe('function')
|
||||
expect(props['fromInject']).toBe('inject')
|
||||
expect(props['owner']).toBe('owner')
|
||||
expect(props['shared']).toBe('owner') // owner overrides inject
|
||||
|
||||
@@ -52,6 +52,7 @@ function makeHost(bodies: { root: (rp: (key: string, owner: object) => React.Rea
|
||||
current,
|
||||
cell: (id) => cells.get(id),
|
||||
},
|
||||
workspaces: { list: observable<unknown>({ items: [] }) },
|
||||
}
|
||||
return {
|
||||
host,
|
||||
|
||||
@@ -42,6 +42,9 @@ function makeHost() {
|
||||
current: { getSnapshot: () => undefined, subscribe: () => () => {} },
|
||||
cell: () => undefined,
|
||||
},
|
||||
workspaces: {
|
||||
list: { getSnapshot: () => ({}), subscribe: () => () => {} },
|
||||
},
|
||||
}
|
||||
return {
|
||||
host,
|
||||
|
||||
Reference in New Issue
Block a user