fix(desktop): focus opened sessions and restore closed tab positions

This commit is contained in:
brooklyn!
2026-09-11 05:34:39 -07:00
parent 22b4b49aa7
commit b08a26791f
4 changed files with 60 additions and 37 deletions
+2
View File
@@ -162,6 +162,8 @@ export function openSession(
openSessionTile(storedSessionId, 'center')
}
focusOpenSession(storedSessionId, workspaceScope)
return
}
@@ -111,6 +111,7 @@ import {
$sessionTiles,
closeSessionTile,
dropSessionState,
focusOpenSession,
holdSessionOwnerUntilForeground,
openSessionTile,
patchSessionTile,
@@ -850,7 +851,7 @@ export function useSessionActions({
setWorkspaceCwdOwner(stored)
}
revealTreePane(`session-tile:${stored}`)
focusOpenSession(stored, workspaceScope)
if (listed) {
broadcastSessionsChanged()
+39 -34
View File
@@ -1136,40 +1136,19 @@ describe('reopenLastClosedTile focuses the restored tab', () => {
title: 'chat'
})
// panes ← $sessionTiles (paneMirror stub). Adoption is synchronous on
// register, so openSessionTile + focusOpenSession works the same tick.
const registered = new Map<string, () => void>()
const syncTiles = () => {
const wanted = new Set(states.$sessionTiles.get().map(t => t.storedSessionId))
for (const id of wanted) {
if (registered.has(id)) {
continue
}
registered.set(
id,
registry.register({
area: 'panes',
data: { dock: { pane: 'workspace', pos: 'center' }, placement: 'main' },
id: tilePane(id),
render: () => null,
title: id
})
)
}
for (const [id, dispose] of registered) {
if (!wanted.has(id)) {
dispose()
registered.delete(id)
tree.removeTreePane(tilePane(id))
}
}
}
states.$sessionTiles.listen(syncTiles)
const { paneMirror } = await import('@/app/chat/pane-mirror')
paneMirror({
source: states.$sessionTiles,
key: tile => tile.storedSessionId,
prefix: 'session-tile',
dir: tile => tile.dir,
anchor: tile => tile.anchor,
before: tile => tile.before,
minWidth: '10rem',
title: id => id,
render: () => null,
close: states.closeSessionTile
})()
tree.watchContributedPanes()
session.$selectedStoredSessionId.set('primary')
tree.declareDefaultTree(model.group(['workspace'], { active: 'workspace', id: 'grp-main' }))
@@ -1182,6 +1161,32 @@ describe('reopenLastClosedTile focuses the restored tab', () => {
return { states, tree }
}
it('restores the live strip slot after reordering and retains the exact owner', async () => {
const { states, tree } = await setup()
states.openSessionTile('after', 'center', 'workspace')
tree.moveTreePane(tilePane('closed'), { groupId: 'grp-main', pos: 'center', before: 'workspace' })
const order = findGroupOfPane(tree.$layoutTree.get()!, 'workspace')!.panes
const ownerRoute = { connectionId: 'cloud', profile: 'agent' }
states.patchSessionTile('closed', { ownerRoute })
states.closeSessionTile('closed')
tree.noteActiveTreeGroup(null)
states.reopenLastClosedTile()
expect(findGroupOfPane(tree.$layoutTree.get()!, 'workspace')!.panes).toEqual(order)
expect(states.$focusedStoredSessionId.get()).toBe('closed')
expect(states.sessionTileOwnerRoute('closed')).toEqual(ownerRoute)
})
it('fronts a palette-opened tab from sidebar focus without replacing main', async () => {
const { states, tree } = await setup()
const { openSession } = await import('@/app/open-session')
const navigate = vi.fn()
tree.noteActiveTreeGroup('sidebar')
openSession('palette-result', navigate, 'stack')
expect(states.$focusedStoredSessionId.get()).toBe('palette-result')
expect(findGroupOfPane(tree.$layoutTree.get()!, 'workspace')!.active).toBe(tilePane('palette-result'))
expect(navigate).not.toHaveBeenCalled()
})
it('fronts the restored tab after ⌘⇧T', async () => {
const { states, tree } = await setup()
+17 -2
View File
@@ -1729,7 +1729,20 @@ export function closeSessionTile(storedSessionId: string) {
const tile = $sessionTiles.get().find(t => t.storedSessionId === storedSessionId)
if (tile) {
closedStack().push(toStored(tile))
const tree = $layoutTree.get()
const paneId = `${TILE_PANE_PREFIX}${storedSessionId}`
const group = tree ? findGroupOfPane(tree, paneId) : null
const siblings = group?.panes.filter(id => id !== paneId) ?? []
closedStack().push({
...toStored(tile),
...(group && siblings.length
? {
anchor: siblings[0],
before: group.panes[group.panes.indexOf(paneId) + 1] ?? null,
dir: 'center'
}
: {})
})
}
saveTiles($sessionTiles.get().filter(t => t.storedSessionId !== storedSessionId))
@@ -1905,7 +1918,9 @@ export function reopenLastClosedTile(): void {
if (!$sessionTiles.get().some(t => t.storedSessionId === storedSessionId)) {
openSessionTile(storedSessionId, tile.dir, tile.anchor, tile.before, {
workspaceMode: tile.workspaceMode ?? 'sessions',
workspaceOwnerKey: tile.workspaceOwnerKey
workspaceOwnerKey: tile.workspaceOwnerKey,
workspaceTabTitle: tile.workspaceTabTitle,
ownerRoute: tile.ownerRoute
})
focusOpenSession(storedSessionId)