diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 3c8a0a1529..ae239f210c 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -52,7 +52,11 @@ import { projectSearchEntriesQueryOptions } from "~/lib/projectReactQuery"; import { serverConfigQueryOptions, serverQueryKeys } from "~/lib/serverReactQuery"; import { isElectron } from "../env"; -import { parseDiffRouteSearch, stripDiffSearchParams } from "../diffRouteSearch"; +import { + clearDiffSearchParams, + parseDiffRouteSearch, + stripDiffSearchParams, +} from "../diffRouteSearch"; import { type ComposerSlashCommand, type ComposerTrigger, @@ -1400,7 +1404,7 @@ export default function ChatView({ threadId }: ChatViewProps) { replace: true, search: (previous) => { const rest = stripDiffSearchParams(previous); - return diffOpen ? rest : { ...rest, diff: "1" }; + return diffOpen ? clearDiffSearchParams(previous) : { ...rest, diff: "1" }; }, }); }, [diffOpen, navigate, threadId]); diff --git a/apps/web/src/diffRouteSearch.test.ts b/apps/web/src/diffRouteSearch.test.ts index ef00874bd2..fc971c548f 100644 --- a/apps/web/src/diffRouteSearch.test.ts +++ b/apps/web/src/diffRouteSearch.test.ts @@ -1,6 +1,10 @@ import { describe, expect, it } from "vitest"; -import { parseDiffRouteSearch } from "./diffRouteSearch"; +import { + clearDiffSearchParams, + parseDiffRouteSearch, + stripDiffSearchParams, +} from "./diffRouteSearch"; describe("parseDiffRouteSearch", () => { it("parses valid diff search values", () => { @@ -72,3 +76,40 @@ describe("parseDiffRouteSearch", () => { }); }); }); + +describe("stripDiffSearchParams", () => { + it("removes diff search keys", () => { + const stripped = stripDiffSearchParams({ + diff: "1", + diffFilePath: "src/app.ts", + diffTurnId: "turn-1", + project: "demo", + }); + + expect(stripped).toEqual({ project: "demo" }); + expect("diff" in stripped).toBe(false); + expect("diffTurnId" in stripped).toBe(false); + expect("diffFilePath" in stripped).toBe(false); + }); +}); + +describe("clearDiffSearchParams", () => { + it("keeps explicit undefined tombstones for diff keys", () => { + const cleared = clearDiffSearchParams({ + diff: "1", + diffFilePath: "src/app.ts", + diffTurnId: "turn-1", + project: "demo", + }); + + expect(cleared).toEqual({ + diff: undefined, + diffFilePath: undefined, + diffTurnId: undefined, + project: "demo", + }); + expect("diff" in cleared).toBe(true); + expect("diffTurnId" in cleared).toBe(true); + expect("diffFilePath" in cleared).toBe(true); + }); +}); diff --git a/apps/web/src/diffRouteSearch.ts b/apps/web/src/diffRouteSearch.ts index f310b74b78..450b41cd2c 100644 --- a/apps/web/src/diffRouteSearch.ts +++ b/apps/web/src/diffRouteSearch.ts @@ -1,9 +1,9 @@ import { TurnId } from "@t3tools/contracts"; export interface DiffRouteSearch { - diff?: "1"; - diffTurnId?: TurnId; - diffFilePath?: string; + diff?: "1" | undefined; + diffTurnId?: TurnId | undefined; + diffFilePath?: string | undefined; } function isDiffOpenValue(value: unknown): boolean { @@ -25,6 +25,22 @@ export function stripDiffSearchParams>( return rest as Omit; } +export function clearDiffSearchParams>( + params: T, +): Omit & { + diff: undefined; + diffTurnId: undefined; + diffFilePath: undefined; +} { + const rest = stripDiffSearchParams(params); + return { + ...rest, + diff: undefined, + diffTurnId: undefined, + diffFilePath: undefined, + }; +} + export function parseDiffRouteSearch(search: Record): DiffRouteSearch { const diff = isDiffOpenValue(search.diff) ? "1" : undefined; const diffTurnIdRaw = diff ? normalizeSearchString(search.diffTurnId) : undefined; diff --git a/apps/web/src/routes/_chat.$threadId.tsx b/apps/web/src/routes/_chat.$threadId.tsx index b85aeab0d9..e610d7b7db 100644 --- a/apps/web/src/routes/_chat.$threadId.tsx +++ b/apps/web/src/routes/_chat.$threadId.tsx @@ -5,6 +5,7 @@ import { Suspense, lazy, type ReactNode, useCallback, useEffect } from "react"; import ChatView from "../components/ChatView"; import { useComposerDraftStore } from "../composerDraftStore"; import { + clearDiffSearchParams, type DiffRouteSearch, parseDiffRouteSearch, stripDiffSearchParams, @@ -133,10 +134,17 @@ const DiffPanelInlineSidebar = (props: { className="w-auto min-h-0 flex-none bg-transparent" style={{ "--sidebar-width": DIFF_INLINE_DEFAULT_WIDTH } as React.CSSProperties} > + {diffOpen ? ( +