diff --git a/apps/desktop/src/renderer/stores/tabs/store.ts b/apps/desktop/src/renderer/stores/tabs/store.ts index b1e37ec2747..98d576192f7 100644 --- a/apps/desktop/src/renderer/stores/tabs/store.ts +++ b/apps/desktop/src/renderer/stores/tabs/store.ts @@ -966,8 +966,13 @@ export const useTabsStore = create()( // If clicking the same file that's already in preview, just focus it if (isSameFile) { - const nextViewMode = - options.viewMode ?? existingFileViewer.viewMode; + // Conflicted files must default to the conflict viewer even + // when callers do not pass an explicit viewMode. + const conflictFallbackViewMode = + options.diffCategory === "conflicted" + ? "conflict" + : existingFileViewer.viewMode; + const nextViewMode = options.viewMode ?? conflictFallbackViewMode; const shouldUpdateViewerState = nextViewMode !== existingFileViewer.viewMode || options.line !== undefined || diff --git a/apps/desktop/src/renderer/stores/tabs/utils.test.ts b/apps/desktop/src/renderer/stores/tabs/utils.test.ts index eaded10ba4d..fe075f50da9 100644 --- a/apps/desktop/src/renderer/stores/tabs/utils.test.ts +++ b/apps/desktop/src/renderer/stores/tabs/utils.test.ts @@ -595,6 +595,53 @@ describe("applyFileViewerOpenOptionsToPane", () => { initialColumn: 7, }); }); + + it("forces conflict viewer for conflicted files when no explicit viewMode is provided", () => { + const pane: Pane = { + id: "pane-a", + tabId: "tab-a", + type: "file-viewer", + name: "file.ts", + fileViewer: { + filePath: "/repo/file.ts", + viewMode: "raw", + isPinned: false, + diffLayout: "inline", + diffCategory: "conflicted", + }, + }; + + const result = applyFileViewerOpenOptionsToPane(pane, { + filePath: "/repo/file.ts", + diffCategory: "conflicted", + }); + + expect(result.fileViewer?.viewMode).toBe("conflict"); + }); + + it("preserves explicit viewMode for conflicted files", () => { + const pane: Pane = { + id: "pane-a", + tabId: "tab-a", + type: "file-viewer", + name: "file.ts", + fileViewer: { + filePath: "/repo/file.ts", + viewMode: "raw", + isPinned: false, + diffLayout: "inline", + diffCategory: "conflicted", + }, + }; + + const result = applyFileViewerOpenOptionsToPane(pane, { + filePath: "/repo/file.ts", + diffCategory: "conflicted", + viewMode: "raw", + }); + + expect(result.fileViewer?.viewMode).toBe("raw"); + }); }); describe("activatePaneInWorkspace", () => { diff --git a/apps/desktop/src/renderer/stores/tabs/utils.ts b/apps/desktop/src/renderer/stores/tabs/utils.ts index ae697442db0..93eb1cefcc0 100644 --- a/apps/desktop/src/renderer/stores/tabs/utils.ts +++ b/apps/desktop/src/renderer/stores/tabs/utils.ts @@ -980,9 +980,17 @@ export const applyFileViewerOpenOptionsToPane = ( return pane; } + // Conflicted files must render in the conflict viewer. If the reused pane + // has a stale non-conflict viewMode (e.g. was opened as raw before the + // merge marked the file as conflicted), force it back to "conflict" when + // no explicit override is provided. + const fallbackViewMode = + options.diffCategory === "conflicted" + ? "conflict" + : pane.fileViewer.viewMode; const nextFileViewer: FileViewerState = { ...pane.fileViewer, - viewMode: options.viewMode ?? pane.fileViewer.viewMode, + viewMode: options.viewMode ?? fallbackViewMode, isPinned: pane.fileViewer.isPinned || (options.isPinned ?? false), oldPath: options.oldPath ?? pane.fileViewer.oldPath, initialLine: options.line ?? pane.fileViewer.initialLine,