Keep projects visible after archiving workspaces (#1631)
This commit is contained in:
@@ -16,7 +16,11 @@ import {
|
|||||||
workspaceEqualityFns,
|
workspaceEqualityFns,
|
||||||
type SidebarOrderSnapshot,
|
type SidebarOrderSnapshot,
|
||||||
} from "./selectors";
|
} from "./selectors";
|
||||||
import { useSessionStore, type WorkspaceDescriptor } from "../session-store";
|
import {
|
||||||
|
useSessionStore,
|
||||||
|
type EmptyProjectDescriptor,
|
||||||
|
type WorkspaceDescriptor,
|
||||||
|
} from "../session-store";
|
||||||
|
|
||||||
const SERVER_ID = "test-server";
|
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(() => {
|
afterEach(() => {
|
||||||
useSessionStore.getState().clearSession(SERVER_ID);
|
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", () => {
|
it("changes for membership updates but not status-only updates", () => {
|
||||||
const workspaceA = createWorkspace({ id: "workspace-a", name: "A" });
|
const workspaceA = createWorkspace({ id: "workspace-a", name: "A" });
|
||||||
const workspaceB = createWorkspace({ id: "workspace-b", name: "B" });
|
const workspaceB = createWorkspace({ id: "workspace-b", name: "B" });
|
||||||
|
|||||||
@@ -229,6 +229,30 @@ function preserveWorkspaceMapIdentity(
|
|||||||
return changed ? next : existing;
|
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 ExplorerEntryKind = "file" | "directory";
|
||||||
export type ExplorerFileKind = "text" | "image" | "binary";
|
export type ExplorerFileKind = "text" | "image" | "binary";
|
||||||
export type ExplorerEncoding = "utf-8" | "base64" | "none";
|
export type ExplorerEncoding = "utf-8" | "base64" | "none";
|
||||||
@@ -1393,13 +1417,31 @@ export const useSessionStore = create<SessionStore>()(
|
|||||||
if (!session || !workspaceKey) {
|
if (!session || !workspaceKey) {
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
const removedWorkspace = session.workspaces.get(workspaceKey);
|
||||||
|
if (!removedWorkspace) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
const next = new Map(session.workspaces);
|
const next = new Map(session.workspaces);
|
||||||
next.delete(workspaceKey);
|
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 {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
sessions: {
|
sessions: {
|
||||||
...prev.sessions,
|
...prev.sessions,
|
||||||
[serverId]: { ...session, workspaces: next },
|
[serverId]: { ...session, workspaces: next, emptyProjects: nextEmptyProjects },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user