Files
paseo/packages/app/src/components/sidebar/sidebar-projection.test.ts
T
Mohamed BoudraandGitHub 99eca19a76 Keep selected projects when switching hosts (#2700)
* fix(app): preserve project selection across hosts

Rendered project identity and persisted equivalence were conflated after duplicate-project handling. Keep them separate so host changes resolve selectable equivalents deterministically without resetting legacy sidebar identity.

* fix(app): restore selected clone after host round trip

Keep manual origin and current destination placements separately so switching back restores the chosen checkout while archive gaps preserve the active host selection.

* fix(app): key status icons by project view

* fix(app): preserve origin during archive gaps
2026-07-31 15:42:08 +02:00

117 lines
3.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import type {
SidebarProjectEntry,
SidebarWorkspaceEntry,
SidebarWorkspacePlacement,
} from "@/hooks/use-sidebar-workspaces-list";
import { buildSidebarProjection } from "./sidebar-projection";
function makeWorkspace(id: string, statusBucket: SidebarWorkspaceEntry["statusBucket"] = "done") {
const placement: SidebarWorkspacePlacement = {
workspaceKey: `srv:${id}`,
serverId: "srv",
workspaceId: id,
projectViewKey: "project",
projectName: "Project",
projectKind: "git",
workspaceKind: "worktree",
name: id,
};
const entry: SidebarWorkspaceEntry = {
...placement,
title: null,
currentBranch: null,
statusBucket,
statusEnteredAt: null,
archivingAt: null,
diffStat: null,
prHint: null,
archiveHasUncommittedChanges: null,
archiveUnpushedCommitCount: null,
scripts: [],
hasRunningScripts: false,
};
return { placement, entry };
}
function makeProject(workspaces: SidebarWorkspacePlacement[]): SidebarProjectEntry {
return {
viewKey: "project",
projectName: "Project",
projectKind: "git",
iconWorkingDir: "/repo",
hosts: [
{
serverId: "srv",
projectId: "project",
iconWorkingDir: "/repo",
canCreateWorktree: true,
},
],
workspaces,
};
}
function projectionInput(options?: {
groupMode?: "project" | "status";
pinnedCollapsed?: boolean;
}) {
const pinned = makeWorkspace("pinned", "running");
const unpinned = makeWorkspace("unpinned", "needs_input");
return {
projects: [makeProject([pinned.placement, unpinned.placement])],
pinnedKeys: {
pinnedWorkspaceKeys: [pinned.placement.workspaceKey],
pinnedAtByKey: { [pinned.placement.workspaceKey]: "2026-07-12T12:00:00.000Z" },
},
workspaceEntriesByKey: new Map([
[pinned.entry.workspaceKey, pinned.entry],
[unpinned.entry.workspaceKey, unpinned.entry],
]),
projectNamesByViewKey: new Map([["project", "Project"]]),
groupMode: options?.groupMode ?? ("project" as const),
pinnedCollapsed: options?.pinnedCollapsed ?? false,
collapsedProjectKeys: new Set<string>(),
collapsedStatusGroupKeys: new Set<string>(),
};
}
describe("buildSidebarProjection", () => {
it("uses one pin-aware projection for project rows and shortcut order", () => {
const projection = buildSidebarProjection(projectionInput());
expect(projection.pinnedGroups.pinnedChats.map((entry) => entry.workspaceId)).toEqual([
"pinned",
]);
const remainingProject = projection.pinnedGroups.unpinnedProjects[0];
expect(remainingProject?.workspaces.map((entry) => entry.workspaceId)).toEqual(["unpinned"]);
expect(projection.shortcutModel.shortcutTargets).toEqual([
{ serverId: "srv", workspaceId: "pinned" },
{ serverId: "srv", workspaceId: "unpinned" },
]);
});
it("keeps pinned chats above status groups and removes them from those groups", () => {
const projection = buildSidebarProjection(projectionInput({ groupMode: "status" }));
expect(projection.statusGroups.map((group) => group.bucket)).toEqual(["needs_input"]);
expect(projection.statusGroups[0]?.rows.map((entry) => entry.workspaceId)).toEqual([
"unpinned",
]);
expect(projection.shortcutModel.shortcutTargets).toEqual([
{ serverId: "srv", workspaceId: "pinned" },
{ serverId: "srv", workspaceId: "unpinned" },
]);
});
it("does not number pinned chats while the pinned section is collapsed", () => {
const projection = buildSidebarProjection(
projectionInput({ groupMode: "status", pinnedCollapsed: true }),
);
expect(projection.shortcutModel.shortcutTargets).toEqual([
{ serverId: "srv", workspaceId: "unpinned" },
]);
});
});