feat(FN-3711): consolidate graph position storage and remove scopedStorage

Consolidated graph position storage into a canonical shared helper (`projectStorage.ts`) with hardened persistence logic and removed the duplicate `scopedStorage` module. Updated integration tests and documented the canonical storage approach. A smaller fix (`FN-3628`) addressed mobile touch targets

Fusion-Task-Id: FN-3711
This commit is contained in:
Fusion
2026-05-07 13:29:26 -07:00
committed by gsxdsm
parent 4f495fcc77
commit 7b6bc2e531
11 changed files with 79 additions and 132 deletions

View File

@@ -1,4 +1,4 @@
import { describe, expect, it, beforeEach } from "vitest";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
GLOBAL_STORAGE_KEYS,
@@ -115,6 +115,24 @@ describe("projectStorage", () => {
expect(getScopedItem("kb-dashboard-working-branch-filter", "proj-3")).toBeNull();
});
it("getScopedItem returns null when localStorage.getItem is unavailable", () => {
vi.stubGlobal("window", { localStorage: {} });
expect(getScopedItem("kb-dashboard-list-columns", "proj-abc")).toBeNull();
vi.unstubAllGlobals();
});
it("setScopedItem is a no-op when localStorage.setItem is unavailable", () => {
vi.stubGlobal("window", { localStorage: {} });
expect(() => setScopedItem("kb-dashboard-list-columns", "value", "proj-abc")).not.toThrow();
vi.unstubAllGlobals();
});
it("removeScopedItem is a no-op when localStorage.removeItem is unavailable", () => {
vi.stubGlobal("window", { localStorage: {} });
expect(() => removeScopedItem("kb-dashboard-list-columns", "proj-abc")).not.toThrow();
vi.unstubAllGlobals();
});
it("has no overlap between global and project-scoped keys", () => {
const globalSet = new Set(GLOBAL_STORAGE_KEYS);
const overlap = PROJECT_STORAGE_KEYS.filter((key) => globalSet.has(key));

View File

@@ -47,7 +47,12 @@ export function getScopedItem(baseKey: string, projectId?: string): string | nul
return null;
}
return window.localStorage.getItem(scopedKey(baseKey, projectId));
const getItem = window.localStorage?.getItem;
if (typeof getItem !== "function") {
return null;
}
return getItem.call(window.localStorage, scopedKey(baseKey, projectId));
}
export function setScopedItem(baseKey: string, value: string, projectId?: string): void {
@@ -55,7 +60,12 @@ export function setScopedItem(baseKey: string, value: string, projectId?: string
return;
}
window.localStorage.setItem(scopedKey(baseKey, projectId), value);
const setItem = window.localStorage?.setItem;
if (typeof setItem !== "function") {
return;
}
setItem.call(window.localStorage, scopedKey(baseKey, projectId), value);
}
export function removeScopedItem(baseKey: string, projectId?: string): void {
@@ -63,5 +73,10 @@ export function removeScopedItem(baseKey: string, projectId?: string): void {
return;
}
window.localStorage.removeItem(scopedKey(baseKey, projectId));
const removeItem = window.localStorage?.removeItem;
if (typeof removeItem !== "function") {
return;
}
removeItem.call(window.localStorage, scopedKey(baseKey, projectId));
}