mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
fix(app): traverse workspaces beyond nine (#6586)
Relative navigation shared the list capped for digit shortcuts, so it wrapped at the ninth workspace. Keep all sidebar targets and cap only numbered badges. Carry forward #4128 with keyboard-routing and browser regressions. Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: Raisal P Wardana <IEatCodeDaily@users.noreply.github.com>
This commit is contained in:
co-authored by
Raisal P Wardana
parent
938c4e2632
commit
cafa04d3fb
@@ -0,0 +1,74 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
import { test, expect } from "../support/fixtures";
|
||||
import { gotoAppShell } from "../support/helpers/app";
|
||||
import { seedWorkspace } from "../support/helpers/seed-client";
|
||||
import { getServerId } from "../support/helpers/server-id";
|
||||
import {
|
||||
expectSidebarWorkspaceSelected,
|
||||
switchWorkspaceViaSidebar,
|
||||
} from "../support/helpers/workspace-ui";
|
||||
|
||||
async function readVisibleWorkspaceOrder(page: Page): Promise<string[]> {
|
||||
const rows = page.getByRole("button", { name: /^Workspace \d{2}$/ });
|
||||
await expect(rows).toHaveCount(12);
|
||||
return rows.evaluateAll(
|
||||
(elements, prefix) =>
|
||||
elements.map((element) => element.getAttribute("data-testid")!.slice(prefix.length)),
|
||||
`sidebar-workspace-row-${getServerId()}:`,
|
||||
);
|
||||
}
|
||||
|
||||
async function navigateWorkspace(
|
||||
page: Page,
|
||||
direction: "next" | "previous",
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
await page.keyboard.press(direction === "next" ? "Alt+]" : "Alt+[");
|
||||
await expectSidebarWorkspaceSelected({ page, serverId: getServerId(), workspaceId });
|
||||
await expect(page).toHaveURL(new RegExp(`/workspace/${workspaceId}$`));
|
||||
}
|
||||
|
||||
test("previous and next traverse every visible workspace while digit shortcuts stop at nine", async ({
|
||||
page,
|
||||
}) => {
|
||||
test.setTimeout(120_000);
|
||||
const project = await seedWorkspace({
|
||||
repoPrefix: "relative-navigation-",
|
||||
title: "Workspace 01",
|
||||
});
|
||||
try {
|
||||
for (let index = 2; index <= 12; index += 1) {
|
||||
const created = await project.client.createWorkspace({
|
||||
source: { kind: "directory", path: project.repoPath },
|
||||
title: `Workspace ${String(index).padStart(2, "0")}`,
|
||||
});
|
||||
expect(created.error).toBeNull();
|
||||
}
|
||||
await page.setViewportSize({ width: 1440, height: 1100 });
|
||||
await gotoAppShell(page);
|
||||
const order = await readVisibleWorkspaceOrder(page);
|
||||
|
||||
await test.step("next crosses the ninth workspace and previous returns to it", async () => {
|
||||
await switchWorkspaceViaSidebar({ page, serverId: getServerId(), workspaceId: order[8] });
|
||||
await navigateWorkspace(page, "next", order[9]);
|
||||
await navigateWorkspace(page, "previous", order[8]);
|
||||
});
|
||||
|
||||
await test.step("wrapping uses the true first and last visible workspace", async () => {
|
||||
await switchWorkspaceViaSidebar({ page, serverId: getServerId(), workspaceId: order[0] });
|
||||
await navigateWorkspace(page, "previous", order[11]);
|
||||
await navigateWorkspace(page, "next", order[0]);
|
||||
});
|
||||
|
||||
await test.step("the ninth digit shortcut still selects the ninth workspace", async () => {
|
||||
await page.keyboard.press("Alt+9");
|
||||
await expectSidebarWorkspaceSelected({
|
||||
page,
|
||||
serverId: getServerId(),
|
||||
workspaceId: order[8],
|
||||
});
|
||||
});
|
||||
} finally {
|
||||
await project.cleanup();
|
||||
}
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
SidebarWorkspaceEntry,
|
||||
} from "@/hooks/use-sidebar-workspaces-list";
|
||||
import { buildStatusGroups } from "@/hooks/sidebar-status-view-model";
|
||||
import { routeKeyboardShortcut } from "@/keyboard/route-shortcut";
|
||||
|
||||
import {
|
||||
buildSidebarShortcutModel,
|
||||
@@ -65,6 +66,46 @@ function project(projectKey: string, workspaces: SidebarWorkspaceEntry[]): Sideb
|
||||
}
|
||||
|
||||
describe("buildSidebarShortcutModel", () => {
|
||||
it.each([
|
||||
[9, 1, 10],
|
||||
[10, -1, 9],
|
||||
[12, 1, 1],
|
||||
[1, -1, 12],
|
||||
] as const)(
|
||||
"navigates from workspace %i by %i to workspace %i across the full visible sidebar",
|
||||
(current, delta, next) => {
|
||||
const workspaces = Array.from({ length: 12 }, (_, index) =>
|
||||
workspace({
|
||||
serverId: "s",
|
||||
workspaceId: `ws-${index + 1}`,
|
||||
workspaceDirectory: `/repo/w${index + 1}`,
|
||||
name: `w${index + 1}`,
|
||||
}),
|
||||
);
|
||||
const model = buildSidebarShortcutModel({
|
||||
projects: [project("p", workspaces)],
|
||||
collapsedProjectKeys: new Set<string>(),
|
||||
});
|
||||
|
||||
expect(
|
||||
routeKeyboardShortcut(
|
||||
{ action: "workspace.navigate.relative", payload: { delta } },
|
||||
{
|
||||
pathname: `/h/s/workspace/ws-${current}`,
|
||||
isMobile: false,
|
||||
sidebarShortcutTargets: model.shortcutTargets,
|
||||
navigationActiveWorkspace: null,
|
||||
commandCenterOpen: false,
|
||||
shortcutsDialogOpen: false,
|
||||
},
|
||||
),
|
||||
).toEqual({ kind: "navigate-workspace", serverId: "s", workspaceId: `ws-${next}` });
|
||||
expect(model.shortcutIndexByWorkspaceKey.size).toBe(9);
|
||||
expect(model.shortcutIndexByWorkspaceKey.get("s:ws-9")).toBe(9);
|
||||
expect(model.shortcutIndexByWorkspaceKey.has("s:ws-10")).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
it("builds shortcut targets in visual order and excludes collapsed projects", () => {
|
||||
const projects = [
|
||||
project("p1", [
|
||||
@@ -111,7 +152,7 @@ describe("buildSidebarShortcutModel", () => {
|
||||
expect(model.shortcutIndexByWorkspaceKey.get("s1:ws-repo2-main")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("limits shortcuts to 9", () => {
|
||||
it("keeps all traversal targets while numbering only the first 9", () => {
|
||||
const workspaces = Array.from({ length: 20 }, (_, index) =>
|
||||
workspace({
|
||||
serverId: "s",
|
||||
@@ -127,9 +168,11 @@ describe("buildSidebarShortcutModel", () => {
|
||||
collapsedProjectKeys: new Set<string>(),
|
||||
});
|
||||
|
||||
expect(model.shortcutTargets).toHaveLength(9);
|
||||
expect(model.shortcutTargets[0]).toEqual({ serverId: "s", workspaceId: "ws-1" });
|
||||
expect(model.shortcutTargets).toHaveLength(20);
|
||||
expect(model.shortcutTargets[8]).toEqual({ serverId: "s", workspaceId: "ws-9" });
|
||||
expect(model.shortcutTargets[9]).toEqual({ serverId: "s", workspaceId: "ws-10" });
|
||||
expect(model.shortcutIndexByWorkspaceKey.get("s:ws-9")).toBe(9);
|
||||
expect(model.shortcutIndexByWorkspaceKey.get("s:ws-10")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("excludes a collapsed project's workspaces regardless of project kind", () => {
|
||||
|
||||
@@ -70,13 +70,10 @@ export function buildSidebarShortcutSections(input: {
|
||||
}
|
||||
|
||||
for (const workspace of section.workspaces) {
|
||||
if (shortcutTargets.length >= maxShortcuts) {
|
||||
break;
|
||||
}
|
||||
|
||||
const shortcutNumber = shortcutTargets.length + 1;
|
||||
shortcutTargets.push(createShortcutTarget(workspace));
|
||||
shortcutIndexByWorkspaceKey.set(workspace.workspaceKey, shortcutNumber);
|
||||
if (shortcutTargets.length <= maxShortcuts) {
|
||||
shortcutIndexByWorkspaceKey.set(workspace.workspaceKey, shortcutTargets.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user