From aa64ab9fded5317b937df3377d20829fade5dffc Mon Sep 17 00:00:00 2001 From: luvs01 Date: Sun, 9 Aug 2026 14:43:18 +0900 Subject: [PATCH] fix(gui): tolerate unavailable model preference storage --- gui/src/pages/models-shared.ts | 11 ++++++----- gui/tests/models-storage.test.ts | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 gui/tests/models-storage.test.ts diff --git a/gui/src/pages/models-shared.ts b/gui/src/pages/models-shared.ts index ab845a13c4..76c0290d06 100644 --- a/gui/src/pages/models-shared.ts +++ b/gui/src/pages/models-shared.ts @@ -101,10 +101,11 @@ export function activeModelOptions( } /** `null` = no preference yet → caller should default to all groups collapsed. */ -export function readCollapsedProviders(storage: StorageLike = localStorage): Set | null { +export function readCollapsedProviders(storage?: StorageLike): Set | null { try { + const target = storage ?? localStorage; // v2 only — older keys defaulted to "all open". - const saved = storage.getItem(COLLAPSED_KEY_V2); + const saved = target.getItem(COLLAPSED_KEY_V2); if (saved === null) return null; const parsed = JSON.parse(saved) as unknown; return Array.isArray(parsed) @@ -115,12 +116,12 @@ export function readCollapsedProviders(storage: StorageLike = localStorage): Set } } -export function writeCollapsedProviders(collapsed: Set, storage: StorageLike = localStorage): void { +export function writeCollapsedProviders(collapsed: Set, storage?: StorageLike): void { try { - storage.setItem(COLLAPSED_KEY_V2, JSON.stringify([...collapsed])); + const target = storage ?? localStorage; + target.setItem(COLLAPSED_KEY_V2, JSON.stringify([...collapsed])); } catch { /* quota / private-mode */ } } - diff --git a/gui/tests/models-storage.test.ts b/gui/tests/models-storage.test.ts new file mode 100644 index 0000000000..312db2324f --- /dev/null +++ b/gui/tests/models-storage.test.ts @@ -0,0 +1,22 @@ +import { expect, test } from "bun:test"; +import { readCollapsedProviders, writeCollapsedProviders } from "../src/pages/models-shared"; + +test("model preferences tolerate unavailable global storage", () => { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, "localStorage"); + + try { + delete (globalThis as { localStorage?: Storage }).localStorage; + expect(readCollapsedProviders()).toBeNull(); + expect(() => writeCollapsedProviders(new Set(["openai"]))).not.toThrow(); + + Object.defineProperty(globalThis, "localStorage", { + configurable: true, + get: () => { throw new Error("SecurityError"); }, + }); + expect(readCollapsedProviders()).toBeNull(); + expect(() => writeCollapsedProviders(new Set(["openai"]))).not.toThrow(); + } finally { + if (descriptor) Object.defineProperty(globalThis, "localStorage", descriptor); + else delete (globalThis as { localStorage?: Storage }).localStorage; + } +});