Fix sidebar project removal

Remove projects through a daemon RPC so the sidebar can delete the project
record after archiving its active workspaces. Reopening a removed directory
recreates the missing project record so local projects keep their derived
basename, and History skips orphaned archived workspace rows.

Fixes #1583.
This commit is contained in:
Mohamed Boudra
2026-06-19 00:46:40 +07:00
parent f876b80f7a
commit 9a09ccb3d6
20 changed files with 736 additions and 29 deletions
@@ -48,6 +48,7 @@ function getTestSessionReferences() {
sessions: state.sessions,
session,
workspaces: session.workspaces,
emptyProjects: session.emptyProjects,
};
}
@@ -448,6 +449,48 @@ describe("removeWorkspace", () => {
});
});
describe("removeEmptyProject", () => {
it("removes an empty project by project id", () => {
const store = useSessionStore.getState();
initializeTestSession();
store.setEmptyProjects("test-server", [
{
projectId: "project-empty",
projectDisplayName: "Empty",
projectCustomName: null,
projectRootPath: "/repo/empty",
projectKind: "git",
},
]);
store.removeEmptyProject("test-server", "project-empty");
expect(getTestSessionReferences().emptyProjects.has("project-empty")).toBe(false);
});
it("preserves identity when removing a missing empty project", () => {
const store = useSessionStore.getState();
initializeTestSession();
store.setEmptyProjects("test-server", [
{
projectId: "project-empty",
projectDisplayName: "Empty",
projectCustomName: null,
projectRootPath: "/repo/empty",
projectKind: "git",
},
]);
const before = getTestSessionReferences();
store.removeEmptyProject("test-server", "project-missing");
const after = getTestSessionReferences();
expect(after.sessions).toBe(before.sessions);
expect(after.session).toBe(before.session);
expect(after.emptyProjects).toBe(before.emptyProjects);
});
});
describe("patchWorkspaceScripts", () => {
it("preserves workspace entry identity when scripts are content-equal", () => {
const script = {
+19
View File
@@ -460,6 +460,7 @@ interface SessionStoreActions {
removeWorkspace: (serverId: string, workspaceId: string) => void;
setEmptyProjects: (serverId: string, emptyProjects: Iterable<EmptyProjectDescriptor>) => void;
addEmptyProject: (serverId: string, emptyProject: EmptyProjectDescriptor) => void;
removeEmptyProject: (serverId: string, projectId: string) => void;
setWorkspaceRestoreStatus: (
serverId: string,
workspaceId: string,
@@ -1265,6 +1266,24 @@ export const useSessionStore = create<SessionStore>()(
});
},
removeEmptyProject: (serverId, projectId) => {
set((prev) => {
const session = prev.sessions[serverId];
if (!session?.emptyProjects.has(projectId)) {
return prev;
}
const next = new Map(session.emptyProjects);
next.delete(projectId);
return {
...prev,
sessions: {
...prev.sessions,
[serverId]: { ...session, emptyProjects: next },
},
};
});
},
setWorkspaceRestoreStatus: (serverId, workspaceId, status) => {
set((prev) => {
const session = prev.sessions[serverId];