From bb8c9fa0b4efcc7e6746161794d1218e6a987b5f Mon Sep 17 00:00:00 2001 From: arookieofc Date: Mon, 9 Nov 2026 20:14:28 +0800 Subject: [PATCH] fix(vcs): remember the diff window's size between openings (#2328) (#2353) The modal-commit diff dialog always reopened at its default 1100x720. Pass the persisted size as the dialog's initialSize and save it when a resize ends, like the Find in Files popup already does. --- .../vcs/__tests__/diffDialog.test.tsx | 24 +++++++++++++- src/features/vcs/diffDialog.tsx | 31 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/features/vcs/__tests__/diffDialog.test.tsx b/src/features/vcs/__tests__/diffDialog.test.tsx index 8b8b65eaa..3cc108aee 100644 --- a/src/features/vcs/__tests__/diffDialog.test.tsx +++ b/src/features/vcs/__tests__/diffDialog.test.tsx @@ -23,7 +23,7 @@ import { ChangesTree, nodeMenu } from "../CommitView"; import type { ChangeNode } from "../changes"; import { VcsDialogHost } from "../dialogs"; import { useVcs } from "../store"; -import { openDiffDialog } from "../diffDialog"; +import { loadDiffDialogSize, openDiffDialog } from "../diffDialog"; const modified = (path: string) => ({ path, @@ -116,6 +116,28 @@ describe("Commit dialog diff window (#1863)", () => { await screen.findByRole("dialog", { name: "b.ts (HEAD ↔ Your version)" }); }); + it("remembers the resized size for the next opening (#2328)", async () => { + render(); + let close: () => void = () => {}; + act(() => { + close = openDiffDialog({ path: "/p/a.ts", left: { type: "rev", rev: "HEAD" }, right: { type: "worktree" } }); + }); + await diffDialogs(); + // Drag the corner grip; jsdom reports a zero rect so the dialog clamps to its + // minimums — what matters is that the resize end is persisted. + fireEvent.pointerDown(screen.getByRole("separator", { name: "Resize" }), { button: 0, clientX: 0, clientY: 0 }); + fireEvent.pointerMove(window, { buttons: 1, clientX: 100, clientY: 80 }); + fireEvent.pointerUp(window); + expect(loadDiffDialogSize()).toEqual({ w: 480, h: 280 }); + act(() => close()); + // A fresh open starts at the remembered size rather than the default. + act(() => { + close = openDiffDialog({ path: "/p/a.ts", left: { type: "rev", rev: "HEAD" }, right: { type: "worktree" } }); + }); + const reopened = await diffDialogs(); + expect([reopened.style.width, reopened.style.height]).toEqual(["480px", "280px"]); + }); + it("closes on Jump to Source so the editor it opens is not hidden behind it", async () => { render( <> diff --git a/src/features/vcs/diffDialog.tsx b/src/features/vcs/diffDialog.tsx index e7aeed4a4..d7944d28b 100644 --- a/src/features/vcs/diffDialog.tsx +++ b/src/features/vcs/diffDialog.tsx @@ -15,6 +15,26 @@ import { diffInput, diffTitle, type DiffData } from "./diffInput"; import { openDialog } from "./dialogs"; import { GitMergeDiff } from "./GitMergeDiff"; +const SIZE_KEY = "openidea.vcs.diffDialogSize"; + +/** The diff window's last size (#2328); null on first run, clamped to the window by Dialog. */ +export function loadDiffDialogSize(): { w: number; h: number } | null { + try { + const v = JSON.parse(localStorage.getItem(SIZE_KEY) ?? "null") as { w?: unknown; h?: unknown } | null; + return typeof v?.w === "number" && typeof v.h === "number" ? { w: v.w, h: v.h } : null; + } catch { + return null; + } +} + +export function saveDiffDialogSize(size: { w: number; h: number }) { + try { + localStorage.setItem(SIZE_KEY, JSON.stringify(size)); + } catch { + // Private mode etc. — the size just isn't remembered. + } +} + /** The open diff dialog's close function (one diff window at a time, as in IDEA). */ let shown: (() => void) | null = null; @@ -52,6 +72,14 @@ export function openMergeDiffDialog(input: EditorInput): () => void { function FrontWindow({ title, onClose, children }: { title: string; onClose: () => void; children: ReactNode }) { const body = useRef(null); + // The size the user last resized the diff window to (#2328), else the usual default. + const [initialSize] = useState( + () => + loadDiffDialogSize() ?? { + w: Math.min(1100, globalThis.innerWidth - 64), + h: Math.min(720, globalThis.innerHeight - 64), + }, + ); useEffect( () => registerKeyClaim((e, stroke) => { @@ -74,7 +102,8 @@ function FrontWindow({ title, onClose, children }: { title: string; onClose: () resizable="both" minWidth={480} minHeight={280} - initialSize={{ w: Math.min(1100, globalThis.innerWidth - 64), h: Math.min(720, globalThis.innerHeight - 64) }} + initialSize={initialSize} + onResized={saveDiffDialogSize} buttons={[{ label: "Close", role: "cancel" }]} >