From 74106ba7c64cf259e1121e383f95f8613918296f Mon Sep 17 00:00:00 2001 From: Richard Lora Date: Mon, 23 Jun 2025 06:46:10 -0400 Subject: [PATCH] fix(core): persist sidebar open state and width to prevent flash on load (#12743) https://github.com/user-attachments/assets/6b61c9f2-80bd-4f2c-943d-1fd610a69ecf This PR change updates the sidebar initialization so it reads the open and width values from persistent storage. This prevents the UI from flashing open by default on startup. Both left and right sidebars restore correctly from the last known state from storage. ## Summary by CodeRabbit - **New Features** - Sidebar and workbench panels now retain their open/closed status and width based on your previously saved preferences, providing a more personalized and consistent experience across sessions. - **Tests** - Added comprehensive tests to ensure sidebar state persistence and behavior are reliable and consistent. --------- Co-authored-by: Norkz --- .../entities/__tests__/app-sidebar.spec.ts | 54 +++++++++++++++++++ .../app-sidebar/entities/app-sidebar.ts | 4 +- .../modules/workbench/entities/workbench.ts | 6 +-- 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 packages/frontend/core/src/modules/app-sidebar/entities/__tests__/app-sidebar.spec.ts diff --git a/packages/frontend/core/src/modules/app-sidebar/entities/__tests__/app-sidebar.spec.ts b/packages/frontend/core/src/modules/app-sidebar/entities/__tests__/app-sidebar.spec.ts new file mode 100644 index 0000000000..357e662eab --- /dev/null +++ b/packages/frontend/core/src/modules/app-sidebar/entities/__tests__/app-sidebar.spec.ts @@ -0,0 +1,54 @@ +import { Framework, MemoryMemento } from '@toeverything/infra'; +import { beforeEach, describe, expect, test } from 'vitest'; + +import { AppSidebarState } from '../../providers/storage'; +import { AppSidebar } from '../app-sidebar'; + +describe('AppSidebar', () => { + let framework: Framework; + let memento: MemoryMemento; + let sidebar: AppSidebar; + + beforeEach(() => { + framework = new Framework(); + memento = new MemoryMemento(); + framework.entity(AppSidebar, [AppSidebarState]); + framework.impl(AppSidebarState, memento); + sidebar = framework.provider().get(AppSidebar); + }); + + test('default values', () => { + expect(sidebar.open$.value).toBe(true); + expect(sidebar.width$.value).toBe(248); + expect(sidebar.smallScreenMode$.value).toBe(false); + expect(sidebar.hovering$.value).toBe(false); + }); + + test('state setters update live data and storage', () => { + sidebar.setOpen(false); + expect(sidebar.open$.value).toBe(false); + expect(memento.get('open')).toBe(false); + + sidebar.toggleSidebar(); + expect(sidebar.open$.value).toBe(true); + expect(memento.get('open')).toBe(true); + + sidebar.setWidth(260); + expect(sidebar.width$.value).toBe(260); + expect(memento.get('width')).toBe(260); + + sidebar.setSmallScreenMode(true); + expect(sidebar.smallScreenMode$.value).toBe(true); + sidebar.setHovering(true); + expect(sidebar.hovering$.value).toBe(true); + sidebar.setPreventHovering(true); + expect(sidebar.preventHovering$.value).toBe(true); + sidebar.setResizing(true); + expect(sidebar.resizing$.value).toBe(true); + }); + + test('getCachedAppSidebarOpenState', () => { + sidebar.setOpen(false); + expect(sidebar.getCachedAppSidebarOpenState()).toBe(false); + }); +}); diff --git a/packages/frontend/core/src/modules/app-sidebar/entities/app-sidebar.ts b/packages/frontend/core/src/modules/app-sidebar/entities/app-sidebar.ts index 2da8066e96..07d2acf83b 100644 --- a/packages/frontend/core/src/modules/app-sidebar/entities/app-sidebar.ts +++ b/packages/frontend/core/src/modules/app-sidebar/entities/app-sidebar.ts @@ -21,14 +21,14 @@ export class AppSidebar extends Entity { this.appSidebarState .watch(APP_SIDEBAR_STATE.OPEN) .pipe(map(value => value ?? true)), - true + this.appSidebarState.get(APP_SIDEBAR_STATE.OPEN) ?? true ); width$ = LiveData.from( this.appSidebarState .watch(APP_SIDEBAR_STATE.WIDTH) .pipe(map(value => value ?? 248)), - 248 + this.appSidebarState.get(APP_SIDEBAR_STATE.WIDTH) ?? 248 ); /** diff --git a/packages/frontend/core/src/modules/workbench/entities/workbench.ts b/packages/frontend/core/src/modules/workbench/entities/workbench.ts index 1e28c1c02d..4b10270694 100644 --- a/packages/frontend/core/src/modules/workbench/entities/workbench.ts +++ b/packages/frontend/core/src/modules/workbench/entities/workbench.ts @@ -58,14 +58,14 @@ export class Workbench extends Entity { }); sidebarOpen$ = LiveData.from( this.globalState.watch(sidebarOpenKey), - false + this.globalState.get(sidebarOpenKey) ?? false ); setSidebarOpen(open: boolean) { this.globalState.set(sidebarOpenKey, open); } sidebarWidth$ = LiveData.from( this.globalState.watch(sidebarWidthKey), - 320 + this.globalState.get(sidebarWidthKey) ?? 320 ); setSidebarWidth(width: number) { this.globalState.set(sidebarWidthKey, width); @@ -73,7 +73,7 @@ export class Workbench extends Entity { workspaceSelectorOpen$ = LiveData.from( this.globalState.watch(workspaceSelectorOpenKey), - false + this.globalState.get(workspaceSelectorOpenKey) ?? false ); setWorkspaceSelectorOpen(open: boolean) { this.globalState.set(workspaceSelectorOpenKey, open);