mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
fix(desktop): layout reset reopens collapsed sidebars
resetLayoutTree() claims to "restore everything" but never reopened collapsed SIDES. A sidebar hidden before a reset survived it, so the next ⌘B toggled from that stale-hidden state into a SHOW — and the user's hide never persisted across reload. Reopen every bound side through its store so the toggles stay truthful. Adds a store-level regression test (real modules, re-import = reload) covering hide→reload and the reset→hide→reload repro.
This commit is contained in:
parent
c18edf4ac0
commit
b5aef05e2c
2 changed files with 72 additions and 0 deletions
|
|
@ -1148,6 +1148,14 @@ export function resetLayoutTree() {
|
|||
resetHandlers.forEach(fn => fn())
|
||||
// Everything still missing (plugin panes) adopts by placement.
|
||||
adoptContributedPanes()
|
||||
|
||||
// "Restore everything" includes collapsed SIDES: reopen every bound side
|
||||
// (through its store, so $sidebarOpen / the toggles stay truthful). Without
|
||||
// this a sidebar hidden before the reset silently survives it, flipping the
|
||||
// next ⌘B into a SHOW — so hiding never appears to persist.
|
||||
for (const side of Object.keys(sideOpeners) as TreeSide[]) {
|
||||
sideOpeners[side]?.(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Dev hook for automation.
|
||||
|
|
|
|||
64
apps/desktop/src/store/sidebar-collapse-persistence.test.ts
Normal file
64
apps/desktop/src/store/sidebar-collapse-persistence.test.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
// Ground-truth repro for "hiding the sidebar doesn't persist on reload": drive
|
||||
// the REAL stores, then re-import them (fresh module state reading persisted
|
||||
// localStorage) to simulate a ⌃R reload. `bind` mirrors the controller wiring.
|
||||
async function loadStores() {
|
||||
const layout = await import('./layout')
|
||||
const tree = await import('@/components/pane-shell/tree/store')
|
||||
|
||||
return {
|
||||
layout,
|
||||
tree,
|
||||
bind: () => tree.bindTreeSideVisibility('left', layout.$sidebarOpen, layout.setSidebarOpen),
|
||||
leftCollapsed: () => tree.$collapsedTreeSides.get().has('left')
|
||||
}
|
||||
}
|
||||
|
||||
const reload = () => vi.resetModules() // fresh modules; localStorage is the carry-over
|
||||
|
||||
describe('sidebar collapse persistence', () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear()
|
||||
vi.resetModules()
|
||||
})
|
||||
|
||||
it('restores a hidden sidebar after a reload', async () => {
|
||||
const s1 = await loadStores()
|
||||
s1.bind()
|
||||
s1.layout.setSidebarOpen(false)
|
||||
expect(s1.leftCollapsed()).toBe(true)
|
||||
|
||||
reload()
|
||||
const s2 = await loadStores()
|
||||
expect(s2.layout.$sidebarOpen.get()).toBe(false) // persisted open:false survives
|
||||
s2.bind()
|
||||
expect(s2.leftCollapsed()).toBe(true) // and re-collapses
|
||||
})
|
||||
|
||||
// The reported repro: a sidebar HIDDEN before a reset must be reopened by the
|
||||
// reset ("restore everything"); otherwise the stale-hidden state flips the
|
||||
// next ⌘B into a SHOW, and the user's hide never persists.
|
||||
it('reset reopens a hidden sidebar, so a later hide persists across reload', async () => {
|
||||
const s1 = await loadStores()
|
||||
const { group, split } = await import('@/components/pane-shell/tree/model')
|
||||
s1.tree.declareDefaultTree(split('row', [group(['sessions']), group(['workspace'])], [1, 3]))
|
||||
s1.bind()
|
||||
|
||||
s1.layout.setSidebarOpen(false) // hidden BEFORE the reset
|
||||
expect(s1.leftCollapsed()).toBe(true)
|
||||
|
||||
s1.tree.resetLayoutTree() // ⌘⇧ reset — restores everything, sidebar shown again
|
||||
expect(s1.layout.$sidebarOpen.get()).toBe(true)
|
||||
expect(s1.leftCollapsed()).toBe(false)
|
||||
|
||||
s1.layout.toggleSidebarOpen() // ⌘B now genuinely hides
|
||||
expect(s1.layout.$sidebarOpen.get()).toBe(false)
|
||||
|
||||
reload()
|
||||
const s2 = await loadStores()
|
||||
expect(s2.layout.$sidebarOpen.get()).toBe(false)
|
||||
s2.bind()
|
||||
expect(s2.leftCollapsed()).toBe(true)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue