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.fix/verification-admin-route-recovery
parent
c18edf4ac0
commit
b5aef05e2c
|
|
@ -1148,6 +1148,14 @@ export function resetLayoutTree() {
|
||||||
resetHandlers.forEach(fn => fn())
|
resetHandlers.forEach(fn => fn())
|
||||||
// Everything still missing (plugin panes) adopts by placement.
|
// Everything still missing (plugin panes) adopts by placement.
|
||||||
adoptContributedPanes()
|
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.
|
// Dev hook for automation.
|
||||||
|
|
|
||||||
|
|
@ -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…
Reference in New Issue