* 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
88 lines
2.6 KiB
TypeScript
88 lines
2.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type {
|
|
SidebarProjectEntry,
|
|
SidebarWorkspacePlacement,
|
|
} from "@/hooks/sidebar-workspaces-view-model";
|
|
import { splitPinnedSidebarGroups } from "@/hooks/use-sidebar-pins";
|
|
|
|
function placement(workspaceKey: string): SidebarWorkspacePlacement {
|
|
return {
|
|
workspaceKey,
|
|
serverId: "s1",
|
|
workspaceId: workspaceKey,
|
|
projectViewKey: "p1",
|
|
projectName: "Project 1",
|
|
projectKind: "git",
|
|
workspaceKind: "worktree",
|
|
name: workspaceKey,
|
|
};
|
|
}
|
|
|
|
function project(projectKey: string, workspaces: SidebarWorkspacePlacement[]): SidebarProjectEntry {
|
|
return {
|
|
viewKey: projectKey,
|
|
projectName: projectKey,
|
|
projectKind: "git",
|
|
iconWorkingDir: "",
|
|
hosts: [],
|
|
workspaces,
|
|
};
|
|
}
|
|
|
|
describe("splitPinnedSidebarGroups", () => {
|
|
it("drops the empty shell when every chat of a project is pinned", () => {
|
|
const only = placement("w1");
|
|
const projects = [project("p1", [only])];
|
|
const result = splitPinnedSidebarGroups({
|
|
projects,
|
|
keys: {
|
|
pinnedWorkspaceKeys: ["w1"],
|
|
pinnedAtByKey: { w1: "2026-01-01T00:00:00Z" },
|
|
},
|
|
});
|
|
expect(result.pinnedChats).toHaveLength(1);
|
|
expect(result.unpinnedProjects).toHaveLength(0);
|
|
});
|
|
|
|
it("keeps a genuinely empty project so its new-workspace row stays reachable", () => {
|
|
const projects = [project("p1", [])];
|
|
const result = splitPinnedSidebarGroups({
|
|
projects,
|
|
keys: { pinnedWorkspaceKeys: [], pinnedAtByKey: {} },
|
|
});
|
|
expect(result.unpinnedProjects).toHaveLength(1);
|
|
});
|
|
|
|
it("keeps remaining chats when only some are pinned", () => {
|
|
const projects = [project("p1", [placement("w1"), placement("w2")])];
|
|
const result = splitPinnedSidebarGroups({
|
|
projects,
|
|
keys: {
|
|
pinnedWorkspaceKeys: ["w1"],
|
|
pinnedAtByKey: { w1: "2026-01-01T00:00:00Z" },
|
|
},
|
|
});
|
|
expect(result.pinnedChats.map((w) => w.workspaceKey)).toEqual(["w1"]);
|
|
expect(result.unpinnedProjects[0]?.workspaces.map((w) => w.workspaceKey)).toEqual(["w2"]);
|
|
});
|
|
|
|
it("orders pinned chats by most-recently-pinned first", () => {
|
|
const projects = [project("p1", [placement("older"), placement("newer")])];
|
|
const result = splitPinnedSidebarGroups({
|
|
projects,
|
|
keys: {
|
|
pinnedWorkspaceKeys: ["older", "newer"],
|
|
pinnedAtByKey: {
|
|
older: "2026-01-01T00:00:00Z",
|
|
newer: "2026-02-01T00:00:00Z",
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result.pinnedChats.map((workspace) => workspace.workspaceKey)).toEqual([
|
|
"newer",
|
|
"older",
|
|
]);
|
|
});
|
|
});
|