mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-30 19:09:28 +00:00
Merge pull request #74640 from NousResearch/bb/undo-close-tab-focus
fix(desktop): focus the tab restored by undo-close (⌘⇧T)
This commit is contained in:
commit
05f5df6bdb
2 changed files with 96 additions and 4 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { ClientSessionState } from '@/app/types'
|
||||
import { group, split } from '@/components/pane-shell/tree/model'
|
||||
import { findGroupOfPane, group, split } from '@/components/pane-shell/tree/model'
|
||||
import { $layoutTree } from '@/components/pane-shell/tree/store'
|
||||
import { $selectedStoredSessionId } from '@/store/session'
|
||||
import type { SessionTile } from '@/store/session-states'
|
||||
|
|
@ -138,3 +138,92 @@ describe('blankDraftTile', () => {
|
|||
expect(blankDraftTile([], {})).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
// ⌘⇧T used to only restore `$sessionTiles`. Adoption inserts silently
|
||||
// (activate:false), so the tab came back behind the still-fronted workspace.
|
||||
// Real path: register, adopt, focus — same as paneMirror + reopen.
|
||||
describe('reopenLastClosedTile focuses the restored tab', () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear()
|
||||
vi.resetModules()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.resetModules()
|
||||
})
|
||||
|
||||
async function setup() {
|
||||
const tree = await import('@/components/pane-shell/tree/store')
|
||||
const model = await import('@/components/pane-shell/tree/model')
|
||||
const { registry } = await import('@/contrib/registry')
|
||||
const session = await import('@/store/session')
|
||||
const states = await import('@/store/session-states')
|
||||
|
||||
registry.register({
|
||||
area: 'panes',
|
||||
data: { placement: 'main', uncloseable: true },
|
||||
id: 'workspace',
|
||||
render: () => null,
|
||||
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)
|
||||
tree.watchContributedPanes()
|
||||
session.$selectedStoredSessionId.set('primary')
|
||||
tree.declareDefaultTree(model.group(['workspace'], { active: 'workspace', id: 'grp-main' }))
|
||||
|
||||
states.openSessionTile('closed', 'center', 'workspace')
|
||||
states.focusOpenSession('closed')
|
||||
tree.noteActiveTreeGroup('grp-main')
|
||||
expect(findGroupOfPane(tree.$layoutTree.get()!, tilePane('closed'))?.active).toBe(tilePane('closed'))
|
||||
|
||||
return { states, tree }
|
||||
}
|
||||
|
||||
it('fronts the restored tab after ⌘⇧T', async () => {
|
||||
const { states, tree } = await setup()
|
||||
|
||||
states.closeSessionTile('closed')
|
||||
expect(states.$sessionTiles.get().some(t => t.storedSessionId === 'closed')).toBe(false)
|
||||
expect(findGroupOfPane(tree.$layoutTree.get()!, 'workspace')?.active).toBe('workspace')
|
||||
|
||||
states.reopenLastClosedTile()
|
||||
|
||||
expect(states.$sessionTiles.get().some(t => t.storedSessionId === 'closed')).toBe(true)
|
||||
expect(findGroupOfPane(tree.$layoutTree.get()!, tilePane('closed'))?.active).toBe(tilePane('closed'))
|
||||
expect(tree.$activeTreeGroup.get()).toBe('grp-main')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -702,8 +702,10 @@ export function discardSessionTile(storedSessionId: string) {
|
|||
saveTiles($sessionTiles.get().filter(t => t.storedSessionId !== storedSessionId))
|
||||
}
|
||||
|
||||
/** ⌘⇧T — reopen the most recently closed tab where it was. Skips ids that are
|
||||
* live again (reopened, or now the primary). */
|
||||
/** ⌘⇧T — reopen the most recently closed tab where it was, then focus it.
|
||||
* Adoption alone is silent (won't steal the active tab), so restore has to
|
||||
* front the pane explicitly. Skips ids that are live again (reopened / now
|
||||
* the primary). */
|
||||
export function reopenLastClosedTile(): void {
|
||||
const stack = closedStack()
|
||||
|
||||
|
|
@ -716,6 +718,7 @@ export function reopenLastClosedTile(): void {
|
|||
|
||||
if (!$sessionTiles.get().some(t => t.storedSessionId === storedSessionId)) {
|
||||
openSessionTile(storedSessionId, tile.dir, tile.anchor, tile.before)
|
||||
focusOpenSession(storedSessionId)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue