From 549043863a3ca1f955c66fd31bda27ea3dc97c18 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 16 Apr 2026 19:36:39 -0700 Subject: [PATCH] fix: guard against missing sidebarProjectGroupingOverrides in client settings (#2099) --- apps/desktop/src/clientPersistence.ts | 17 +++++++++++++++-- apps/web/src/components/Sidebar.tsx | 2 +- apps/web/src/hooks/useSettings.ts | 2 +- apps/web/src/logicalProject.ts | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/desktop/src/clientPersistence.ts b/apps/desktop/src/clientPersistence.ts index 183de1a971b16536f536373e244e42e66a1955bf..ad08a0036f1331a2286c451bc4a44a992609be3b 100644 --- a/apps/desktop/src/clientPersistence.ts +++ b/apps/desktop/src/clientPersistence.ts @@ -1,8 +1,13 @@ import * as FS from "node:fs"; import * as Path from "node:path"; -import type { ClientSettings, PersistedSavedEnvironmentRecord } from "@t3tools/contracts"; +import { + ClientSettingsSchema, + type ClientSettings, + type PersistedSavedEnvironmentRecord, +} from "@t3tools/contracts"; import { Predicate } from "effect"; +import * as Schema from "effect/Schema"; interface ClientSettingsDocument { readonly settings: ClientSettings; @@ -83,7 +88,15 @@ function toPersistedSavedEnvironmentRecord( } export function readClientSettings(settingsPath: string): ClientSettings | null { - return readJsonFile(settingsPath)?.settings ?? null; + const raw = readJsonFile(settingsPath)?.settings; + if (!raw) { + return null; + } + try { + return Schema.decodeUnknownSync(ClientSettingsSchema)(raw); + } catch { + return null; + } } export function writeClientSettings(settingsPath: string, settings: ClientSettings): void { diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 1c66af57be040258d034b31c0a42906b73b2b801..c3fae158b149739b1ab20683a0cbba3b88a9601e 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -1379,7 +1379,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec const overrideKey = deriveProjectGroupingOverrideKey(member); setProjectGroupingTarget(member); setProjectGroupingSelection( - projectGroupingSettings.sidebarProjectGroupingOverrides[overrideKey] ?? "inherit", + projectGroupingSettings.sidebarProjectGroupingOverrides?.[overrideKey] ?? "inherit", ); }, [projectGroupingSettings.sidebarProjectGroupingOverrides], diff --git a/apps/web/src/hooks/useSettings.ts b/apps/web/src/hooks/useSettings.ts index 664d5ee3bb0140262a8669f6f051285cad2e2881..c2301b23a3fc4b845d2633d42ab3a6d3fd0bc226 100644 --- a/apps/web/src/hooks/useSettings.ts +++ b/apps/web/src/hooks/useSettings.ts @@ -64,7 +64,7 @@ async function hydrateClientSettings(): Promise { try { const persistedSettings = await ensureLocalApi().persistence.getClientSettings(); if (persistedSettings) { - replaceClientSettingsSnapshot(persistedSettings); + replaceClientSettingsSnapshot({ ...DEFAULT_CLIENT_SETTINGS, ...persistedSettings }); } } catch (error) { console.error(`${CLIENT_SETTINGS_PERSISTENCE_ERROR_SCOPE} hydrate failed`, error); diff --git a/apps/web/src/logicalProject.ts b/apps/web/src/logicalProject.ts index 6b84fa6dc342e35135acf86b09fa46e98c61bffa..d30bb60ca06ba7deeaadac98d3071f990e03c70f 100644 --- a/apps/web/src/logicalProject.ts +++ b/apps/web/src/logicalProject.ts @@ -70,7 +70,7 @@ export function resolveProjectGroupingMode( settings: ProjectGroupingSettings, ): SidebarProjectGroupingMode { return ( - settings.sidebarProjectGroupingOverrides[deriveProjectGroupingOverrideKey(project)] ?? + settings.sidebarProjectGroupingOverrides?.[deriveProjectGroupingOverrideKey(project)] ?? settings.sidebarProjectGroupingMode ); } -- 2.54.0