From 4baa37f1cc4a4fc2790f964891fa7f02215b7b9b Mon Sep 17 00:00:00 2001 From: Leonel Rivas Date: Sat, 8 Aug 2026 12:39:59 -0700 Subject: [PATCH] fix(web): persist diff render mode --- apps/web/src/components/DiffPanel.tsx | 4 ++-- apps/web/src/diffPanelStore.test.ts | 28 ++++++++++++++++++++++++++- apps/web/src/diffPanelStore.ts | 7 +++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx index 76191e6d4d76..a62f5edd4dfc 100644 --- a/apps/web/src/components/DiffPanel.tsx +++ b/apps/web/src/components/DiffPanel.tsx @@ -76,7 +76,6 @@ import { reviewEnvironment } from "../state/review"; import { vcsEnvironment } from "../state/vcs"; import { buildBaseRefChoices, filterBaseRefChoices } from "../lib/baseRefChoices"; -type DiffRenderMode = "stacked" | "split"; type DiffThemeType = "light" | "dark"; const AUTOMATIC_BASE_REF = "__automatic_base_ref__"; @@ -312,7 +311,8 @@ export default function DiffPanel({ const { resolvedTheme } = useTheme(); const settings = useClientSettings(); const [initialGitScope] = useState(initialGitScopeProp); - const [diffRenderMode, setDiffRenderMode] = useState("stacked"); + const diffRenderMode = useDiffPanelStore((state) => state.diffRenderMode); + const setDiffRenderMode = useDiffPanelStore((state) => state.setDiffRenderMode); const [wordWrap, setWordWrap] = useState(settings.wordWrap); const [diffIgnoreWhitespace, setDiffIgnoreWhitespace] = useState(settings.diffIgnoreWhitespace); const [baseRefQuery, setBaseRefQuery] = useState(""); diff --git a/apps/web/src/diffPanelStore.test.ts b/apps/web/src/diffPanelStore.test.ts index 607b7c8d5801..7e7c95921f05 100644 --- a/apps/web/src/diffPanelStore.test.ts +++ b/apps/web/src/diffPanelStore.test.ts @@ -7,7 +7,33 @@ import { selectThreadDiffPanelSelection, useDiffPanelStore } from "./diffPanelSt const THREAD_REF = scopeThreadRef(EnvironmentId.make("environment-1"), ThreadId.make("thread-1")); describe("diffPanelStore", () => { - beforeEach(() => useDiffPanelStore.setState({ byThreadKey: {}, branchBaseRefByThreadKey: {} })); + beforeEach(() => + useDiffPanelStore.setState({ + byThreadKey: {}, + branchBaseRefByThreadKey: {}, + diffRenderMode: "stacked", + }), + ); + + it("keeps the selected render mode in panel and persisted state", async () => { + useDiffPanelStore.getState().setDiffRenderMode("split"); + + expect(useDiffPanelStore.getState().diffRenderMode).toBe("split"); + expect( + useDiffPanelStore.persist.getOptions().partialize?.(useDiffPanelStore.getState()), + ).toMatchObject({ diffRenderMode: "split" }); + + const { name, storage } = useDiffPanelStore.persist.getOptions(); + if (!name) throw new Error("Expected diff panel persistence to have a storage name"); + const persisted = await storage?.getItem(name); + expect(persisted?.state).toMatchObject({ diffRenderMode: "split" }); + + useDiffPanelStore.setState({ diffRenderMode: "stacked" }); + if (persisted) await storage?.setItem(name, persisted); + await useDiffPanelStore.persist.rehydrate(); + + expect(useDiffPanelStore.getState().diffRenderMode).toBe("split"); + }); it("defaults each thread to branch changes when the working tree is clean", () => { expect( diff --git a/apps/web/src/diffPanelStore.ts b/apps/web/src/diffPanelStore.ts index 56b5ad23fecc..ebb560a23832 100644 --- a/apps/web/src/diffPanelStore.ts +++ b/apps/web/src/diffPanelStore.ts @@ -10,12 +10,16 @@ export type DiffPanelSelection = | { kind: "unstaged" } | { kind: "turn"; turnId: TurnId; filePath: string | null; revealRequestId: number }; +export type DiffRenderMode = "stacked" | "split"; + const DEFAULT_SELECTION: DiffPanelSelection = { kind: "branch", baseRef: null }; const DEFAULT_WORKING_TREE_SELECTION: DiffPanelSelection = { kind: "unstaged" }; interface DiffPanelStoreState { byThreadKey: Record; branchBaseRefByThreadKey: Record; + diffRenderMode: DiffRenderMode; + setDiffRenderMode: (mode: DiffRenderMode) => void; selectGitScope: (ref: ScopedThreadRef, scope: "branch" | "unstaged") => void; selectBranchBaseRef: (ref: ScopedThreadRef, baseRef: string | null) => void; selectTurn: (ref: ScopedThreadRef, turnId: TurnId, filePath?: string) => void; @@ -33,6 +37,8 @@ export const useDiffPanelStore = create()( (set) => ({ byThreadKey: {}, branchBaseRefByThreadKey: {}, + diffRenderMode: "stacked", + setDiffRenderMode: (diffRenderMode) => set({ diffRenderMode }), selectGitScope: (ref, scope) => set((state) => { const threadKey = scopedThreadKey(ref); @@ -126,6 +132,7 @@ export const useDiffPanelStore = create()( partialize: (state) => ({ byThreadKey: state.byThreadKey, branchBaseRefByThreadKey: state.branchBaseRefByThreadKey, + diffRenderMode: state.diffRenderMode, }), }, ),