From b08a70e36a4b4e32d7a31773ccff72a78d6a76a2 Mon Sep 17 00:00:00 2001 From: Ammar Date: Sun, 21 Dec 2025 14:37:28 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20fix:=20disable=20project=20remov?= =?UTF-8?q?al=20when=20workspaces=20exist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove project button is disabled when project has any workspaces (active or archived) - Shows explanatory tooltip based on workspace type: - 'Delete workspace first' (1 active workspace) - 'Delete all N workspaces first' (multiple active) - 'Delete N archived workspaces first' (archived only) - 'Delete N active + M archived workspaces first' (both) - Added archivedCountByProject to WorkspaceContext for efficient archived count tracking - Button uses aria-disabled and cursor-not-allowed styling when disabled --- _Generated with `mux` • Model: `anthropic:claude-opus-4-5` • Thinking: `high`_ --- src/browser/components/ProjectSidebar.tsx | 94 +++++++++++++++------- src/browser/contexts/WorkspaceContext.tsx | 21 ++++- src/browser/stories/App.errors.stories.tsx | 23 ++---- 3 files changed, 94 insertions(+), 44 deletions(-) diff --git a/src/browser/components/ProjectSidebar.tsx b/src/browser/components/ProjectSidebar.tsx index 4f73c31d66..94c4f2680b 100644 --- a/src/browser/components/ProjectSidebar.tsx +++ b/src/browser/components/ProjectSidebar.tsx @@ -200,6 +200,7 @@ const ProjectSidebarInner: React.FC = ({ archiveWorkspace: onArchiveWorkspace, renameWorkspace: onRenameWorkspace, beginWorkspaceCreation: onAddWorkspace, + archivedCountByProject, } = useWorkspaceContext(); // Get project state and operations from context @@ -518,34 +519,71 @@ const ProjectSidebarInner: React.FC = ({ Manage secrets - - - - - Remove project - + {(() => { + // Compute workspace counts for removal eligibility + const activeCount = + sortedWorkspacesByProject.get(projectPath)?.length ?? 0; + const archivedCount = archivedCountByProject.get(projectPath) ?? 0; + const canDelete = activeCount === 0 && archivedCount === 0; + + // Build tooltip based on what's blocking deletion + let tooltip: string; + if (canDelete) { + tooltip = "Remove project"; + } else if (archivedCount === 0) { + // Only active workspaces + tooltip = + activeCount === 1 + ? "Delete workspace first" + : `Delete all ${activeCount} workspaces first`; + } else if (activeCount === 0) { + // Only archived workspaces + tooltip = + archivedCount === 1 + ? "Delete archived workspace first" + : `Delete ${archivedCount} archived workspaces first`; + } else { + // Both active and archived + tooltip = `Delete ${activeCount} active + ${archivedCount} archived workspaces first`; + } + + return ( + + + + + {tooltip} + + ); + })()}