Skip to content

Commit 45b2f4f

Browse files
authored
Remove standalone file-view route (#203)
- Redirect legacy file-view navigation into the thread code viewer - Open files in the active side panel and fall back to the latest thread - Stop treating /file-view as a separate sidebar subpage
1 parent 910738b commit 45b2f4f

4 files changed

Lines changed: 88 additions & 47 deletions

File tree

apps/web/src/components/Sidebar.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,7 @@ export default function Sidebar() {
374374
const isOnSubPage =
375375
pathname === "/settings" ||
376376
pathname === "/pr-review" ||
377-
pathname === "/merge-conflicts" ||
378-
pathname === "/file-view";
377+
pathname === "/merge-conflicts";
379378
const { settings: appSettings, updateSettings } = useAppSettings();
380379
const { resolvedTheme } = useTheme();
381380
const { handleNewThread } = useHandleNewThread();

apps/web/src/components/merge-conflicts/MergeConflictShell.tsx

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ import {
2020
ShieldCheckIcon,
2121
WorkflowIcon,
2222
} from "lucide-react";
23-
import { useEffect, useMemo, useState } from "react";
23+
import { useCallback, useEffect, useMemo, useState } from "react";
2424

25+
import { useCodeViewerStore } from "~/codeViewerStore";
2526
import { openInPreferredEditor } from "~/editorPreferences";
2627
import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
2728
import { useLocalStorage } from "~/hooks/useLocalStorage";
@@ -41,6 +42,7 @@ import { cn } from "~/lib/utils";
4142
import { ensureNativeApi } from "~/nativeApi";
4243
import { parsePullRequestReference } from "~/pullRequestReference";
4344
import { findProjectMatchingPullRequestReference } from "~/pullRequestProjectMatch";
45+
import { useStore } from "~/store";
4446
import type { Project } from "~/types";
4547
import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
4648
import { toastManager } from "~/components/ui/toast";
@@ -246,7 +248,26 @@ function MergeConflictGuidanceRail({
246248
status: "done" | "active" | "todo" | "blocked";
247249
}>;
248250
}) {
249-
const navigateToFileView = useNavigate();
251+
const navigate = useNavigate();
252+
const threads = useStore((s) => s.threads);
253+
const openCodeViewer = useCodeViewerStore((s) => s.open);
254+
255+
const navigateToLatestThread = useCallback(
256+
() => {
257+
openCodeViewer();
258+
const sorted = [...threads].sort((a, b) =>
259+
(b.updatedAt ?? b.createdAt).localeCompare(a.updatedAt ?? a.createdAt),
260+
);
261+
const latest = sorted[0];
262+
if (latest) {
263+
void navigate({ to: "/$threadId", params: { threadId: latest.id } });
264+
} else {
265+
void navigate({ to: "/" });
266+
}
267+
},
268+
[navigate, openCodeViewer, threads],
269+
);
270+
250271
return (
251272
<div className="flex min-h-0 min-w-0 flex-col bg-background/96">
252273
<div className="border-b border-border/70 px-4 py-4">
@@ -355,18 +376,10 @@ function MergeConflictGuidanceRail({
355376
className="cursor-pointer rounded-2xl border border-border/70 bg-muted/24 p-3 transition-colors hover:border-border hover:bg-muted/40"
356377
role="button"
357378
tabIndex={0}
358-
onClick={() =>
359-
void navigateToFileView({
360-
to: "/file-view",
361-
search: { cwd: project.cwd },
362-
})
363-
}
379+
onClick={navigateToLatestThread}
364380
onKeyDown={(e) => {
365381
if (e.key === "Enter" || e.key === " ") {
366-
void navigateToFileView({
367-
to: "/file-view",
368-
search: { cwd: project.cwd },
369-
});
382+
navigateToLatestThread();
370383
}
371384
}}
372385
>
@@ -377,18 +390,10 @@ function MergeConflictGuidanceRail({
377390
className="cursor-pointer rounded-2xl border border-border/70 bg-muted/24 p-3 transition-colors hover:border-border hover:bg-muted/40"
378391
role="button"
379392
tabIndex={0}
380-
onClick={() =>
381-
void navigateToFileView({
382-
to: "/file-view",
383-
search: { cwd: preparedWorkspace?.cwd ?? project.cwd },
384-
})
385-
}
393+
onClick={navigateToLatestThread}
386394
onKeyDown={(e) => {
387395
if (e.key === "Enter" || e.key === " ") {
388-
void navigateToFileView({
389-
to: "/file-view",
390-
search: { cwd: preparedWorkspace?.cwd ?? project.cwd },
391-
});
396+
navigateToLatestThread();
392397
}
393398
}}
394399
>
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
1-
import { useNavigate } from "@tanstack/react-router";
1+
import { useNavigate, useParams } from "@tanstack/react-router";
22
import { useCallback } from "react";
33
import { useCodeViewerStore } from "~/codeViewerStore";
4+
import { useStore } from "~/store";
45

6+
/**
7+
* Opens a file in the code-viewer side panel of the active thread.
8+
* If the caller is not on a thread page, navigates to the most recent thread first.
9+
*/
510
export function useFileViewNavigation() {
611
const navigate = useNavigate();
712
const openFile = useCodeViewerStore((s) => s.openFile);
13+
const threadId = useParams({
14+
strict: false,
15+
select: (params) => (params as Record<string, string | undefined>).threadId ?? null,
16+
});
17+
const threads = useStore((s) => s.threads);
818

919
return useCallback(
1020
(cwd: string, relativePath: string) => {
1121
openFile(cwd, relativePath);
12-
void navigate({
13-
to: "/file-view",
14-
search: { cwd, path: relativePath },
15-
});
22+
// If not already on a thread page, navigate to the most recent thread
23+
// so the code-viewer inline sidebar is visible.
24+
if (!threadId) {
25+
const sorted = [...threads].sort((a, b) =>
26+
(b.updatedAt ?? b.createdAt).localeCompare(a.updatedAt ?? a.createdAt),
27+
);
28+
const latest = sorted[0];
29+
if (latest) {
30+
void navigate({ to: "/$threadId", params: { threadId: latest.id } });
31+
} else {
32+
void navigate({ to: "/" });
33+
}
34+
}
1635
},
17-
[navigate, openFile],
36+
[navigate, openFile, threadId, threads],
1837
);
1938
}
Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,46 @@
1-
import { createFileRoute } from "@tanstack/react-router";
2-
import { FileCodeIcon } from "lucide-react";
1+
import { createFileRoute, useNavigate } from "@tanstack/react-router";
2+
import { useEffect } from "react";
33

4-
import { FileViewShell } from "~/components/file-view/FileViewShell";
5-
import { ProjectSubpageShell } from "~/components/review/ProjectSubpageShell";
4+
import { useCodeViewerStore } from "~/codeViewerStore";
5+
import { useStore } from "~/store";
66

77
export interface FileViewSearch {
88
cwd?: string;
99
path?: string;
1010
}
1111

12-
function FileViewRouteView() {
12+
/**
13+
* Legacy route — the standalone file-view page has been removed.
14+
* If a file was requested via search params, open it in the code-viewer
15+
* side panel and redirect to the most recent thread.
16+
*/
17+
function FileViewRouteRedirect() {
1318
const { cwd, path } = Route.useSearch();
19+
const openFile = useCodeViewerStore((s) => s.openFile);
20+
const navigate = useNavigate();
21+
const threads = useStore((s) => s.threads);
1422

15-
return (
16-
<ProjectSubpageShell
17-
emptyMessage="Open a file to view it here."
18-
icon={FileCodeIcon}
19-
title="File View"
20-
>
21-
{({ project }) => (
22-
<FileViewShell initialCwd={cwd ?? project.cwd} initialPath={path ?? null} />
23-
)}
24-
</ProjectSubpageShell>
25-
);
23+
useEffect(() => {
24+
// Open the requested file in the side-panel store
25+
if (cwd && path) {
26+
openFile(cwd, path);
27+
}
28+
29+
// Navigate to the most recent thread (or home)
30+
const sorted = [...threads].sort((a, b) =>
31+
(b.updatedAt ?? b.createdAt).localeCompare(a.updatedAt ?? a.createdAt),
32+
);
33+
const latest = sorted[0];
34+
if (latest) {
35+
void navigate({ to: "/$threadId", params: { threadId: latest.id }, replace: true });
36+
} else {
37+
void navigate({ to: "/", replace: true });
38+
}
39+
// Only run on mount
40+
// eslint-disable-next-line react-hooks/exhaustive-deps
41+
}, []);
42+
43+
return null;
2644
}
2745

2846
export const Route = createFileRoute("/_chat/file-view")({
@@ -38,5 +56,5 @@ export const Route = createFileRoute("/_chat/file-view")({
3856

3957
return validatedSearch;
4058
},
41-
component: FileViewRouteView,
59+
component: FileViewRouteRedirect,
4260
});

0 commit comments

Comments
 (0)