mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-02 22:52:58 +00:00
fix(app): reuse file tabs opened from nested-project Changes
Changes paths are relative to the current worktree. Resolve file actions from that root, then give file tabs and chat attachments the existing workspace-relative target for files inside the project. Keep absolute targets for changed files outside it so both paths remain addressable. The contributor's root-path fix opened inside-project files with absolute targets, which differed from Files and created duplicate retained tabs. A failing-first browser journey covers navigation between both views. Co-authored-by: 3ae3ae <ogyshjsm@naver.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { daemonWsRoutePattern } from "../support/helpers/daemon-port";
|
||||
import { getServerId } from "../support/helpers/server-id";
|
||||
import { connectSeedClient } from "../support/helpers/seed-client";
|
||||
import { createTempGitRepo } from "../support/helpers/workspace";
|
||||
import { openFileExplorer, openFileFromExplorer } from "../support/helpers/file-explorer";
|
||||
import { openChangesPanel, waitForWorkspaceTabsVisible } from "../support/helpers/workspace-tabs";
|
||||
|
||||
interface DirtyWorkspace {
|
||||
@@ -506,6 +507,44 @@ for (const { workspaceSubdirectory, filePath, content, visibleContent } of [
|
||||
});
|
||||
}
|
||||
|
||||
test("Changes and Files reuse a retained file tab in a subfolder project", async ({ page }) => {
|
||||
const workspace = await createWorkspaceWithMountedTabDiff({ workspaceSubdirectory: "src" });
|
||||
await openWorkspaceChanges(page, workspace);
|
||||
await openChangedFile(page, "src/use-mounted-tab-set.ts");
|
||||
await editAndSaveChangedFile(page, workspace);
|
||||
await openChangesPanel(page);
|
||||
await openFileExplorer(page);
|
||||
await openFileFromExplorer(page, "use-mounted-tab-set.ts");
|
||||
|
||||
await expect(page.getByTestId(/^workspace-tab-file_/).filter({ visible: true })).toHaveCount(1);
|
||||
await expect(page.getByTestId("workspace-tab-file_use-mounted-tab-set.ts")).toHaveAttribute(
|
||||
"aria-selected",
|
||||
"true",
|
||||
);
|
||||
await expect(visibleFileEditor(page)).toContainText("// retained file tab");
|
||||
});
|
||||
|
||||
async function openChangedFile(page: Page, filePath: string): Promise<void> {
|
||||
const panel = page.getByTestId("working-diff-panel").filter({ visible: true });
|
||||
await diffHeaderForPath(panel, filePath)
|
||||
.getByTestId(/^diff-file-\d+-toggle$/)
|
||||
.click({ button: "right" });
|
||||
await page.getByRole("menuitem", { name: "Open file", exact: true }).click();
|
||||
await expect(visibleFileEditor(page)).toContainText("interface DeriveRenderMountedTabIdsInput");
|
||||
}
|
||||
|
||||
function visibleFileEditor(page: Page): Locator {
|
||||
return page.getByTestId("workspace-file-pane").filter({ visible: true }).locator(".cm-content");
|
||||
}
|
||||
|
||||
async function editAndSaveChangedFile(page: Page, workspace: DirtyWorkspace): Promise<void> {
|
||||
const content = "// retained file tab\n" + AFTER;
|
||||
await visibleFileEditor(page).fill(content);
|
||||
await expect
|
||||
.poll(() => readFile(path.join(workspace.repoPath, "src/use-mounted-tab-set.ts"), "utf8"))
|
||||
.toBe(content);
|
||||
}
|
||||
|
||||
test("canvas file headers select without toggling for context menu and long press", async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
@@ -56,7 +56,7 @@ import * as Clipboard from "expo-clipboard";
|
||||
import { useFileDownload } from "@/hooks/use-file-download";
|
||||
import { useIsLocalDaemon } from "@/hooks/use-is-local-daemon";
|
||||
import { buildAbsoluteExplorerPath } from "@/utils/explorer-paths";
|
||||
import { isWorkspaceRootPath } from "@/workspace/file-open";
|
||||
import { resolveWorkspaceFilePaths } from "@/workspace/file-open";
|
||||
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||
import { GitActionsSplitButton } from "@/git/actions-split-button";
|
||||
import type { GitActions } from "@/git/policy";
|
||||
@@ -1637,14 +1637,17 @@ export function ChangesSurface({
|
||||
[appSettings.monoFontFamily, codeFontSize, effectiveLayout, wrapLines],
|
||||
);
|
||||
const fileRoot = resolveChangesFileRoot(status, cwd);
|
||||
const isRootWorkspace = isWorkspaceRootPath({ path: fileRoot, workspaceRoot: cwd });
|
||||
const resolveFilePath = useCallback(
|
||||
(path: string) => buildAbsoluteExplorerPath({ workspaceRoot: fileRoot, entryPath: path }),
|
||||
[fileRoot],
|
||||
);
|
||||
const resolveFileTargetPath = useCallback(
|
||||
(path: string) => (isRootWorkspace ? path : resolveFilePath(path)),
|
||||
[isRootWorkspace, resolveFilePath],
|
||||
(path: string) => {
|
||||
const absolutePath = resolveFilePath(path);
|
||||
const resolved = resolveWorkspaceFilePaths({ path: absolutePath, workspaceRoot: cwd });
|
||||
return resolved?.relativePath ?? absolutePath;
|
||||
},
|
||||
[cwd, resolveFilePath],
|
||||
);
|
||||
const handleOpenFile = useCallback(
|
||||
(path: string) => onOpenFile?.(resolveFileTargetPath(path)),
|
||||
|
||||
Reference in New Issue
Block a user