mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Merge branch 'main' of github.com:getpaseo/paseo
This commit is contained in:
@@ -3,6 +3,7 @@ import path from "node:path";
|
|||||||
import { expect, test, type Page } from "./fixtures";
|
import { expect, test, type Page } from "./fixtures";
|
||||||
import { openFileExplorer, openFileFromExplorer, expectFileTabOpen } from "./helpers/file-explorer";
|
import { openFileExplorer, openFileFromExplorer, expectFileTabOpen } from "./helpers/file-explorer";
|
||||||
import { installDaemonWebSocketGate } from "./helpers/daemon-websocket-gate";
|
import { installDaemonWebSocketGate } from "./helpers/daemon-websocket-gate";
|
||||||
|
import { openAgentRoute, seedMockAgentWorkspace } from "./helpers/mock-agent";
|
||||||
|
|
||||||
const RED_PIXEL = Buffer.from(
|
const RED_PIXEL = Buffer.from(
|
||||||
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9ZQmcAAAAASUVORK5CYII=",
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Y9ZQmcAAAAASUVORK5CYII=",
|
||||||
@@ -31,7 +32,69 @@ async function openWorkspaceFile(page: Page, filename: string): Promise<void> {
|
|||||||
await expectFileTabOpen(page, filename);
|
await expectFileTabOpen(page, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function seedAgentWithFileLink(target: string) {
|
||||||
|
const session = await seedMockAgentWorkspace({
|
||||||
|
repoPrefix: "file-editing-chat-link-",
|
||||||
|
title: "Chat file link e2e",
|
||||||
|
initialPrompt: [
|
||||||
|
"Generate a title and a git branch name for a coding agent from the user prompt and attachments.",
|
||||||
|
"Return JSON only with fields 'title' and 'branch'.",
|
||||||
|
"",
|
||||||
|
"<user-prompt>",
|
||||||
|
`Open \`${target}\` now`,
|
||||||
|
"</user-prompt>",
|
||||||
|
].join("\n"),
|
||||||
|
});
|
||||||
|
await writeFile(
|
||||||
|
path.join(session.cwd, "target.ts"),
|
||||||
|
Array.from({ length: 80 }, (_, index) => `export const line${index + 1} = ${index + 1};`).join(
|
||||||
|
"\n",
|
||||||
|
),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
test.describe("CodeMirror workspace file editing", () => {
|
test.describe("CodeMirror workspace file editing", () => {
|
||||||
|
test("opens an assistant file link at its referenced line", async ({ page }) => {
|
||||||
|
const target = "target.ts:42";
|
||||||
|
const session = await seedAgentWithFileLink(target);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await openAgentRoute(page, session);
|
||||||
|
|
||||||
|
const fileLink = page.getByText(target, { exact: true });
|
||||||
|
await expect(fileLink).toBeVisible({ timeout: 15_000 });
|
||||||
|
await fileLink.click();
|
||||||
|
|
||||||
|
await expectFileTabOpen(page, "target.ts");
|
||||||
|
await expect(page.getByTestId("file-source-editor")).toBeVisible();
|
||||||
|
await expect(page.getByLabel("Line 42, column 1")).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId("file-source-editor").locator(".cm-line", { hasText: "line42 = 42" }),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
const sourceEditor = editor(page);
|
||||||
|
await sourceEditor.click();
|
||||||
|
await sourceEditor.press("Control+Home");
|
||||||
|
await expect(page.getByLabel(/^Line 1, column \d+$/)).toBeVisible();
|
||||||
|
|
||||||
|
await page
|
||||||
|
.getByTestId(`workspace-tab-agent_${session.agentId}`)
|
||||||
|
.filter({ visible: true })
|
||||||
|
.click();
|
||||||
|
await expect(fileLink).toBeVisible();
|
||||||
|
await fileLink.click();
|
||||||
|
|
||||||
|
await expect(page.getByLabel("Line 42, column 1")).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId("file-source-editor").locator(".cm-line", { hasText: "line42 = 42" }),
|
||||||
|
).toBeVisible();
|
||||||
|
} finally {
|
||||||
|
await session.cleanup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("shows the full file path and keeps editor controls stable", async ({
|
test("shows the full file path and keeps editor controls stable", async ({
|
||||||
page,
|
page,
|
||||||
withWorkspace,
|
withWorkspace,
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { Text, View } from "react-native";
|
import { Text, View } from "react-native";
|
||||||
import { StyleSheet } from "react-native-unistyles";
|
import { StyleSheet } from "react-native-unistyles";
|
||||||
import type { HighlightStyle } from "@getpaseo/highlight";
|
import type { HighlightStyle } from "@getpaseo/highlight";
|
||||||
|
import type { WorkspaceFileLocation } from "@/workspace/file-open";
|
||||||
import type { FileEditorModel } from "./model";
|
import type { FileEditorModel } from "./model";
|
||||||
|
|
||||||
export function FileEditorView(_props: {
|
export function FileEditorView(_props: {
|
||||||
model: FileEditorModel;
|
model: FileEditorModel;
|
||||||
filename: string;
|
filename: string;
|
||||||
|
location: WorkspaceFileLocation;
|
||||||
|
navigationRevision: number;
|
||||||
vimEnabled: boolean;
|
vimEnabled: boolean;
|
||||||
theme: {
|
theme: {
|
||||||
background: string;
|
background: string;
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ import { Annotation, Compartment, EditorState, Transaction } from "@codemirror/s
|
|||||||
import { EditorView } from "@codemirror/view";
|
import { EditorView } from "@codemirror/view";
|
||||||
import { getLanguageForFile } from "@getpaseo/highlight";
|
import { getLanguageForFile } from "@getpaseo/highlight";
|
||||||
import { getCM, vim } from "@replit/codemirror-vim";
|
import { getCM, vim } from "@replit/codemirror-vim";
|
||||||
|
import type { WorkspaceFileLocation } from "@/workspace/file-open";
|
||||||
import type { FileEditorModel } from "./model";
|
import type { FileEditorModel } from "./model";
|
||||||
import { editorBaseExtensions, editorTheme, type EditorVisualTheme } from "./extensions.web";
|
import { editorBaseExtensions, editorTheme, type EditorVisualTheme } from "./extensions.web";
|
||||||
|
|
||||||
interface FileEditorViewProps {
|
interface FileEditorViewProps {
|
||||||
model: FileEditorModel;
|
model: FileEditorModel;
|
||||||
filename: string;
|
filename: string;
|
||||||
|
location: WorkspaceFileLocation;
|
||||||
|
navigationRevision: number;
|
||||||
vimEnabled: boolean;
|
vimEnabled: boolean;
|
||||||
theme: EditorVisualTheme;
|
theme: EditorVisualTheme;
|
||||||
onCursorChange(position: { line: number; column: number }): void;
|
onCursorChange(position: { line: number; column: number }): void;
|
||||||
@@ -22,6 +25,8 @@ const vimCompartment = new Compartment();
|
|||||||
export function FileEditorView({
|
export function FileEditorView({
|
||||||
model,
|
model,
|
||||||
filename,
|
filename,
|
||||||
|
location,
|
||||||
|
navigationRevision,
|
||||||
vimEnabled,
|
vimEnabled,
|
||||||
theme,
|
theme,
|
||||||
onCursorChange,
|
onCursorChange,
|
||||||
@@ -81,6 +86,19 @@ export function FileEditorView({
|
|||||||
});
|
});
|
||||||
}, [snapshot.content]);
|
}, [snapshot.content]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const view = viewRef.current;
|
||||||
|
if (!view || !location.lineStart) return;
|
||||||
|
const lineStart = Math.min(location.lineStart, view.state.doc.lines);
|
||||||
|
const lineEnd = Math.min(location.lineEnd ?? lineStart, view.state.doc.lines);
|
||||||
|
const from = view.state.doc.line(lineStart).from;
|
||||||
|
const to = view.state.doc.line(Math.max(lineStart, lineEnd)).to;
|
||||||
|
view.dispatch({
|
||||||
|
selection: { anchor: from, head: lineEnd > lineStart ? to : from },
|
||||||
|
effects: EditorView.scrollIntoView(from, { y: "center" }),
|
||||||
|
});
|
||||||
|
}, [location.lineEnd, location.lineStart, navigationRevision]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
viewRef.current?.dispatch({
|
viewRef.current?.dispatch({
|
||||||
effects: languageCompartment.reconfigure(getLanguageForFile(filename)?.extension ?? []),
|
effects: languageCompartment.reconfigure(getLanguageForFile(filename)?.extension ?? []),
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ interface FilePreviewBodyProps {
|
|||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
location: WorkspaceFileLocation;
|
location: WorkspaceFileLocation;
|
||||||
|
navigationRevision: number;
|
||||||
imagePreviewUri: string | null;
|
imagePreviewUri: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +208,7 @@ function FilePreviewBody({
|
|||||||
isLoading,
|
isLoading,
|
||||||
isMobile,
|
isMobile,
|
||||||
location,
|
location,
|
||||||
|
navigationRevision,
|
||||||
imagePreviewUri,
|
imagePreviewUri,
|
||||||
}: FilePreviewBodyProps) {
|
}: FilePreviewBodyProps) {
|
||||||
const theme = UnistylesRuntime.getTheme();
|
const theme = UnistylesRuntime.getTheme();
|
||||||
@@ -257,7 +259,7 @@ function FilePreviewBody({
|
|||||||
});
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}, [lineHeight, lineSelection]);
|
}, [lineHeight, lineSelection, navigationRevision]);
|
||||||
|
|
||||||
if (isLoading && !preview) {
|
if (isLoading && !preview) {
|
||||||
return (
|
return (
|
||||||
@@ -380,10 +382,12 @@ export function FilePane({
|
|||||||
serverId,
|
serverId,
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
location,
|
location,
|
||||||
|
navigationRevision,
|
||||||
}: {
|
}: {
|
||||||
serverId: string;
|
serverId: string;
|
||||||
workspaceRoot: string;
|
workspaceRoot: string;
|
||||||
location: WorkspaceFileLocation;
|
location: WorkspaceFileLocation;
|
||||||
|
navigationRevision: number;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
@@ -476,6 +480,7 @@ export function FilePane({
|
|||||||
isLoading={query.isFetching}
|
isLoading={query.isFetching}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
location={location}
|
location={location}
|
||||||
|
navigationRevision={navigationRevision}
|
||||||
imagePreviewUri={imagePreviewUri}
|
imagePreviewUri={imagePreviewUri}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -518,6 +523,7 @@ function FilePanePresentation({
|
|||||||
isLoading,
|
isLoading,
|
||||||
isMobile,
|
isMobile,
|
||||||
location,
|
location,
|
||||||
|
navigationRevision,
|
||||||
imagePreviewUri,
|
imagePreviewUri,
|
||||||
}: {
|
}: {
|
||||||
serverId: string;
|
serverId: string;
|
||||||
@@ -535,6 +541,7 @@ function FilePanePresentation({
|
|||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
location: WorkspaceFileLocation;
|
location: WorkspaceFileLocation;
|
||||||
|
navigationRevision: number;
|
||||||
imagePreviewUri: string | null;
|
imagePreviewUri: string | null;
|
||||||
}) {
|
}) {
|
||||||
if (!client && readTarget) {
|
if (!client && readTarget) {
|
||||||
@@ -562,6 +569,7 @@ function FilePanePresentation({
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
location={location}
|
location={location}
|
||||||
|
navigationRevision={navigationRevision}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -587,6 +595,7 @@ function FilePanePresentation({
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
location={location}
|
location={location}
|
||||||
|
navigationRevision={navigationRevision}
|
||||||
imagePreviewUri={imagePreviewUri}
|
imagePreviewUri={imagePreviewUri}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -605,6 +614,7 @@ function EditableFilePane({
|
|||||||
isLoading,
|
isLoading,
|
||||||
isMobile,
|
isMobile,
|
||||||
location,
|
location,
|
||||||
|
navigationRevision,
|
||||||
}: {
|
}: {
|
||||||
client: DaemonClient;
|
client: DaemonClient;
|
||||||
cwd: string;
|
cwd: string;
|
||||||
@@ -617,6 +627,7 @@ function EditableFilePane({
|
|||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
location: WorkspaceFileLocation;
|
location: WorkspaceFileLocation;
|
||||||
|
navigationRevision: number;
|
||||||
}) {
|
}) {
|
||||||
const { settings } = useAppSettings();
|
const { settings } = useAppSettings();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -742,6 +753,8 @@ function EditableFilePane({
|
|||||||
<FileEditorView
|
<FileEditorView
|
||||||
model={model}
|
model={model}
|
||||||
filename={filename}
|
filename={filename}
|
||||||
|
location={location}
|
||||||
|
navigationRevision={navigationRevision}
|
||||||
vimEnabled={settings.vimKeybindings}
|
vimEnabled={settings.vimKeybindings}
|
||||||
theme={visualTheme}
|
theme={visualTheme}
|
||||||
onCursorChange={setCursor}
|
onCursorChange={setCursor}
|
||||||
@@ -753,6 +766,7 @@ function EditableFilePane({
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
location={location}
|
location={location}
|
||||||
|
navigationRevision={navigationRevision}
|
||||||
imagePreviewUri={null}
|
imagePreviewUri={null}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function useFilePanelDescriptor(target: { kind: "file"; path: string }) {
|
|||||||
|
|
||||||
function FilePanel() {
|
function FilePanel() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { serverId, workspaceId, target } = usePaneContext();
|
const { serverId, workspaceId, target, fileNavigationRevision } = usePaneContext();
|
||||||
const workspaceDirectory = useWorkspaceDirectory(serverId, workspaceId);
|
const workspaceDirectory = useWorkspaceDirectory(serverId, workspaceId);
|
||||||
invariant(target.kind === "file", "FilePanel requires file target");
|
invariant(target.kind === "file", "FilePanel requires file target");
|
||||||
if (!workspaceDirectory) {
|
if (!workspaceDirectory) {
|
||||||
@@ -40,7 +40,14 @@ function FilePanel() {
|
|||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <FilePane serverId={serverId} workspaceRoot={workspaceDirectory} location={target} />;
|
return (
|
||||||
|
<FilePane
|
||||||
|
serverId={serverId}
|
||||||
|
workspaceRoot={workspaceDirectory}
|
||||||
|
location={target}
|
||||||
|
navigationRevision={fileNavigationRevision ?? 0}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filePanelRegistration: PanelRegistration<"file"> = {
|
export const filePanelRegistration: PanelRegistration<"file"> = {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export interface PaneContextValue {
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
tabId: string;
|
tabId: string;
|
||||||
target: WorkspaceTabTarget;
|
target: WorkspaceTabTarget;
|
||||||
|
fileNavigationRevision?: number;
|
||||||
openTab: (target: WorkspaceTabTarget) => void;
|
openTab: (target: WorkspaceTabTarget) => void;
|
||||||
closeCurrentTab: () => void;
|
closeCurrentTab: () => void;
|
||||||
retargetCurrentTab: (target: WorkspaceTabTarget) => void;
|
retargetCurrentTab: (target: WorkspaceTabTarget) => void;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface BuildWorkspacePaneContentModelInput {
|
|||||||
tab: WorkspaceTabDescriptor;
|
tab: WorkspaceTabDescriptor;
|
||||||
normalizedServerId: string;
|
normalizedServerId: string;
|
||||||
normalizedWorkspaceId: string;
|
normalizedWorkspaceId: string;
|
||||||
|
fileNavigationRevision?: number;
|
||||||
onOpenTab: (target: WorkspaceTabDescriptor["target"]) => void;
|
onOpenTab: (target: WorkspaceTabDescriptor["target"]) => void;
|
||||||
onCloseCurrentTab: () => void;
|
onCloseCurrentTab: () => void;
|
||||||
onRetargetCurrentTab: (target: WorkspaceTabDescriptor["target"]) => void;
|
onRetargetCurrentTab: (target: WorkspaceTabDescriptor["target"]) => void;
|
||||||
@@ -34,6 +35,7 @@ export function buildWorkspacePaneContentModel({
|
|||||||
tab,
|
tab,
|
||||||
normalizedServerId,
|
normalizedServerId,
|
||||||
normalizedWorkspaceId,
|
normalizedWorkspaceId,
|
||||||
|
fileNavigationRevision,
|
||||||
onOpenTab,
|
onOpenTab,
|
||||||
onCloseCurrentTab,
|
onCloseCurrentTab,
|
||||||
onRetargetCurrentTab,
|
onRetargetCurrentTab,
|
||||||
@@ -51,6 +53,7 @@ export function buildWorkspacePaneContentModel({
|
|||||||
workspaceId: normalizedWorkspaceId,
|
workspaceId: normalizedWorkspaceId,
|
||||||
tabId: tab.tabId,
|
tabId: tab.tabId,
|
||||||
target: tab.target,
|
target: tab.target,
|
||||||
|
fileNavigationRevision,
|
||||||
openTab: onOpenTab,
|
openTab: onOpenTab,
|
||||||
closeCurrentTab: onCloseCurrentTab,
|
closeCurrentTab: onCloseCurrentTab,
|
||||||
retargetCurrentTab: onRetargetCurrentTab,
|
retargetCurrentTab: onRetargetCurrentTab,
|
||||||
@@ -85,6 +88,7 @@ export function WorkspacePaneContent({
|
|||||||
workspaceId: paneContextValue.workspaceId,
|
workspaceId: paneContextValue.workspaceId,
|
||||||
tabId: paneContextValue.tabId,
|
tabId: paneContextValue.tabId,
|
||||||
target: paneContextValue.target,
|
target: paneContextValue.target,
|
||||||
|
fileNavigationRevision: paneContextValue.fileNavigationRevision,
|
||||||
openTab,
|
openTab,
|
||||||
closeCurrentTab,
|
closeCurrentTab,
|
||||||
retargetCurrentTab,
|
retargetCurrentTab,
|
||||||
@@ -97,6 +101,7 @@ export function WorkspacePaneContent({
|
|||||||
openImportSheet,
|
openImportSheet,
|
||||||
openTab,
|
openTab,
|
||||||
paneContextValue.serverId,
|
paneContextValue.serverId,
|
||||||
|
paneContextValue.fileNavigationRevision,
|
||||||
paneContextValue.tabId,
|
paneContextValue.tabId,
|
||||||
paneContextValue.target,
|
paneContextValue.target,
|
||||||
paneContextValue.workspaceId,
|
paneContextValue.workspaceId,
|
||||||
|
|||||||
@@ -1773,6 +1773,17 @@ function WorkspaceScreenContent({
|
|||||||
const openWorkspaceChildTabFocused = useWorkspaceLayoutStore(
|
const openWorkspaceChildTabFocused = useWorkspaceLayoutStore(
|
||||||
(state) => state.openChildTabFocused,
|
(state) => state.openChildTabFocused,
|
||||||
);
|
);
|
||||||
|
// File targets stay identity-stable so the same path reuses its tab. Keep navigation
|
||||||
|
// requests separate so clicking an unchanged path:line can still recenter the pane.
|
||||||
|
const [fileNavigationRevisionByTabId, setFileNavigationRevisionByTabId] = useState<
|
||||||
|
Record<string, number>
|
||||||
|
>({});
|
||||||
|
const requestFileNavigation = useCallback((tabId: string) => {
|
||||||
|
setFileNavigationRevisionByTabId((current) => ({
|
||||||
|
...current,
|
||||||
|
[tabId]: (current[tabId] ?? 0) + 1,
|
||||||
|
}));
|
||||||
|
}, []);
|
||||||
const focusWorkspacePane = useWorkspaceLayoutStore((state) => state.focusPane);
|
const focusWorkspacePane = useWorkspaceLayoutStore((state) => state.focusPane);
|
||||||
const hasHydratedWorkspaces = useSessionStore(
|
const hasHydratedWorkspaces = useSessionStore(
|
||||||
(state) => state.sessions[normalizedServerId]?.hasHydratedWorkspaces ?? false,
|
(state) => state.sessions[normalizedServerId]?.hasHydratedWorkspaces ?? false,
|
||||||
@@ -2333,6 +2344,7 @@ function WorkspaceScreenContent({
|
|||||||
? openWorkspaceChildTabFocused(persistenceKey, target, options.parentTabId)
|
? openWorkspaceChildTabFocused(persistenceKey, target, options.parentTabId)
|
||||||
: openWorkspaceTabFocused(persistenceKey, target);
|
: openWorkspaceTabFocused(persistenceKey, target);
|
||||||
if (tabId) {
|
if (tabId) {
|
||||||
|
requestFileNavigation(tabId);
|
||||||
navigateToTabId(tabId);
|
navigateToTabId(tabId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2342,6 +2354,7 @@ function WorkspaceScreenContent({
|
|||||||
openWorkspaceChildTabFocused,
|
openWorkspaceChildTabFocused,
|
||||||
openWorkspaceTabFocused,
|
openWorkspaceTabFocused,
|
||||||
persistenceKey,
|
persistenceKey,
|
||||||
|
requestFileNavigation,
|
||||||
showMobileAgent,
|
showMobileAgent,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -2381,6 +2394,7 @@ function WorkspaceScreenContent({
|
|||||||
? openWorkspaceChildTabFocused(persistenceKey, target, input.parentTabId)
|
? openWorkspaceChildTabFocused(persistenceKey, target, input.parentTabId)
|
||||||
: openWorkspaceTabFocused(persistenceKey, target);
|
: openWorkspaceTabFocused(persistenceKey, target);
|
||||||
if (tabId) {
|
if (tabId) {
|
||||||
|
requestFileNavigation(tabId);
|
||||||
navigateToTabId(tabId);
|
navigateToTabId(tabId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2392,6 +2406,7 @@ function WorkspaceScreenContent({
|
|||||||
openWorkspaceChildTabFocused,
|
openWorkspaceChildTabFocused,
|
||||||
openWorkspaceTabFocused,
|
openWorkspaceTabFocused,
|
||||||
persistenceKey,
|
persistenceKey,
|
||||||
|
requestFileNavigation,
|
||||||
splitWorkspacePaneEmpty,
|
splitWorkspacePaneEmpty,
|
||||||
uiTabs,
|
uiTabs,
|
||||||
workspaceLayout,
|
workspaceLayout,
|
||||||
@@ -3211,6 +3226,7 @@ function WorkspaceScreenContent({
|
|||||||
tab: input.tab,
|
tab: input.tab,
|
||||||
normalizedServerId,
|
normalizedServerId,
|
||||||
normalizedWorkspaceId,
|
normalizedWorkspaceId,
|
||||||
|
fileNavigationRevision: fileNavigationRevisionByTabId[input.tab.tabId] ?? 0,
|
||||||
onOpenTab: (target) => {
|
onOpenTab: (target) => {
|
||||||
if (!persistenceKey) {
|
if (!persistenceKey) {
|
||||||
return;
|
return;
|
||||||
@@ -3245,6 +3261,7 @@ function WorkspaceScreenContent({
|
|||||||
[
|
[
|
||||||
handleCloseTabById,
|
handleCloseTabById,
|
||||||
focusWorkspacePane,
|
focusWorkspacePane,
|
||||||
|
fileNavigationRevisionByTabId,
|
||||||
handleOpenWorkspaceFileFromPane,
|
handleOpenWorkspaceFileFromPane,
|
||||||
navigateToTabId,
|
navigateToTabId,
|
||||||
normalizedServerId,
|
normalizedServerId,
|
||||||
|
|||||||
Reference in New Issue
Block a user