Keep projects visible after archiving workspaces (#1631)
This commit is contained in:
@@ -16,7 +16,11 @@ import {
|
||||
workspaceEqualityFns,
|
||||
type SidebarOrderSnapshot,
|
||||
} from "./selectors";
|
||||
import { useSessionStore, type WorkspaceDescriptor } from "../session-store";
|
||||
import {
|
||||
useSessionStore,
|
||||
type EmptyProjectDescriptor,
|
||||
type WorkspaceDescriptor,
|
||||
} from "../session-store";
|
||||
|
||||
const SERVER_ID = "test-server";
|
||||
|
||||
@@ -87,6 +91,12 @@ function emptySidebarOrder(): SidebarOrderSnapshot {
|
||||
};
|
||||
}
|
||||
|
||||
function selectWorkspaceStructureProjectKeys(
|
||||
state: Parameters<typeof selectWorkspaceStructureProjects>[0],
|
||||
): string[] {
|
||||
return selectWorkspaceStructureProjects(state, SERVER_ID).map((project) => project.projectKey);
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
useSessionStore.getState().clearSession(SERVER_ID);
|
||||
});
|
||||
@@ -208,6 +218,38 @@ describe("workspace structure composition", () => {
|
||||
});
|
||||
}
|
||||
|
||||
it("keeps a project parent visible throughout the last workspace archive transition", () => {
|
||||
const workspace = createWorkspace({
|
||||
id: "workspace-a",
|
||||
projectId: "project-a",
|
||||
projectDisplayName: "Project A",
|
||||
projectRootPath: "/repo/a",
|
||||
workspaceDirectory: "/repo/a",
|
||||
});
|
||||
const emptyProject: EmptyProjectDescriptor = {
|
||||
projectId: "project-a",
|
||||
projectDisplayName: "Project A",
|
||||
projectCustomName: null,
|
||||
projectRootPath: "/repo/a",
|
||||
projectKind: "git",
|
||||
};
|
||||
initializeWorkspaces([workspace]);
|
||||
|
||||
const emittedProjectKeys = [selectWorkspaceStructureProjectKeys(useSessionStore.getState())];
|
||||
const stop = useSessionStore.subscribe((state) => {
|
||||
emittedProjectKeys.push(selectWorkspaceStructureProjectKeys(state));
|
||||
});
|
||||
|
||||
try {
|
||||
useSessionStore.getState().removeWorkspace(SERVER_ID, workspace.id);
|
||||
useSessionStore.getState().addEmptyProject(SERVER_ID, emptyProject);
|
||||
} finally {
|
||||
stop();
|
||||
}
|
||||
|
||||
expect(emittedProjectKeys).toEqual([["project-a"], ["project-a"]]);
|
||||
});
|
||||
|
||||
it("changes for membership updates but not status-only updates", () => {
|
||||
const workspaceA = createWorkspace({ id: "workspace-a", name: "A" });
|
||||
const workspaceB = createWorkspace({ id: "workspace-b", name: "B" });
|
||||
|
||||
@@ -229,6 +229,30 @@ function preserveWorkspaceMapIdentity(
|
||||
return changed ? next : existing;
|
||||
}
|
||||
|
||||
function emptyProjectDescriptorFromWorkspace(
|
||||
workspace: WorkspaceDescriptor,
|
||||
): EmptyProjectDescriptor {
|
||||
return {
|
||||
projectId: workspace.projectId,
|
||||
projectDisplayName: workspace.projectDisplayName,
|
||||
projectCustomName: workspace.projectCustomName ?? null,
|
||||
projectRootPath: workspace.projectRootPath,
|
||||
projectKind: workspace.projectKind,
|
||||
};
|
||||
}
|
||||
|
||||
function hasWorkspaceInProject(
|
||||
workspaces: ReadonlyMap<string, WorkspaceDescriptor>,
|
||||
projectId: string,
|
||||
): boolean {
|
||||
for (const workspace of workspaces.values()) {
|
||||
if (workspace.projectId === projectId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export type ExplorerEntryKind = "file" | "directory";
|
||||
export type ExplorerFileKind = "text" | "image" | "binary";
|
||||
export type ExplorerEncoding = "utf-8" | "base64" | "none";
|
||||
@@ -1393,13 +1417,31 @@ export const useSessionStore = create<SessionStore>()(
|
||||
if (!session || !workspaceKey) {
|
||||
return prev;
|
||||
}
|
||||
const removedWorkspace = session.workspaces.get(workspaceKey);
|
||||
if (!removedWorkspace) {
|
||||
return prev;
|
||||
}
|
||||
const next = new Map(session.workspaces);
|
||||
next.delete(workspaceKey);
|
||||
let nextEmptyProjects = session.emptyProjects;
|
||||
if (hasWorkspaceInProject(next, removedWorkspace.projectId)) {
|
||||
if (nextEmptyProjects.has(removedWorkspace.projectId)) {
|
||||
nextEmptyProjects = new Map(nextEmptyProjects);
|
||||
nextEmptyProjects.delete(removedWorkspace.projectId);
|
||||
}
|
||||
} else {
|
||||
const emptyProject = emptyProjectDescriptorFromWorkspace(removedWorkspace);
|
||||
const existing = nextEmptyProjects.get(emptyProject.projectId);
|
||||
if (!existing || !equal(existing, emptyProject)) {
|
||||
nextEmptyProjects = new Map(nextEmptyProjects);
|
||||
nextEmptyProjects.set(emptyProject.projectId, emptyProject);
|
||||
}
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
sessions: {
|
||||
...prev.sessions,
|
||||
[serverId]: { ...session, workspaces: next },
|
||||
[serverId]: { ...session, workspaces: next, emptyProjects: nextEmptyProjects },
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user