From f48bdf8f59f90114b41b32f2d7484efede59b078 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Mon, 17 Aug 2026 21:47:29 -0700 Subject: [PATCH] fix(new-workspace): keep workspace creation reachable with zero projects (#15234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sidebar +, the landing Create button, the board lane +, the palette create row, and the tour CTA all disabled themselves when repos was empty — a dead end, since the composer's project field can add the first project inline and auto-select it. Drop the repo-count gate from every entry point. Submitting without a project still shows the inline "Choose or add a project" error. --- src/renderer/src/components/Landing.tsx | 12 +-- .../src/components/WorktreeJumpPalette.tsx | 8 +- .../ContextualTourOverlay.tsx | 2 - .../contextual-tour-step-actions.test.ts | 10 +- .../contextual-tour-step-actions.ts | 15 ++- .../components/sidebar/SidebarHeader.test.tsx | 93 +++++++++++++++++++ .../src/components/sidebar/SidebarHeader.tsx | 28 ++---- .../WorkspaceKanbanDrawer.search.test.tsx | 1 - ...paceKanbanDrawer.task-status-sync.test.tsx | 1 - .../sidebar/WorkspaceKanbanDrawer.tsx | 3 +- .../sidebar/WorkspaceKanbanLaneGrid.test.tsx | 1 - .../sidebar/WorkspaceKanbanLaneGrid.tsx | 3 - .../WorkspaceKanbanStatusLane.test.tsx | 1 - .../sidebar/WorkspaceKanbanStatusLane.tsx | 8 +- .../use-workspace-kanban-create-worktree.ts | 4 +- .../worktree-palette-create-action.test.ts | 10 +- .../src/lib/worktree-palette-create-action.ts | 9 +- 17 files changed, 124 insertions(+), 85 deletions(-) create mode 100644 src/renderer/src/components/sidebar/SidebarHeader.test.tsx diff --git a/src/renderer/src/components/Landing.tsx b/src/renderer/src/components/Landing.tsx index 701863a1ef9..99ed596b98f 100644 --- a/src/renderer/src/components/Landing.tsx +++ b/src/renderer/src/components/Landing.tsx @@ -231,7 +231,7 @@ export default function Landing(): React.JSX.Element { const createTargetLabel = repos.length > 0 && repos.every((repo) => isGitRepoKind(repo)) ? 'Worktree' : 'Workspace' - const canCreateWorktree = repos.length > 0 + const hasProjects = repos.length > 0 const hasGitHubProject = useMemo(() => hasGitHubBackedProject(repos), [repos]) const showGitHubSupportFooter = repos.length === 0 || hasGitHubProject @@ -274,7 +274,7 @@ export default function Landing(): React.JSX.Element { {preflightIssues.length > 0 && }

- {canCreateWorktree + {hasProjects ? translate( 'auto.components.Landing.9c00bd4adf', 'Select a workspace from the sidebar to begin.' @@ -292,13 +292,7 @@ export default function Landing(): React.JSX.Element { - {canCreateWorkspace - ? translate( - 'auto.components.sidebar.SidebarHeader.ca6f729da2', - 'New workspace ({{value0}})', - { value0: newWorktreeShortcutLabel } - ) - : translate( - 'auto.components.sidebar.SidebarHeader.5c9c7c16aa', - 'Add a project to create workspaces' - )} + {translate( + 'auto.components.sidebar.SidebarHeader.ca6f729da2', + 'New workspace ({{value0}})', + { value0: newWorktreeShortcutLabel } + )} diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.search.test.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.search.test.tsx index 50052ce6fde..7cb3081474e 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.search.test.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.search.test.tsx @@ -130,7 +130,6 @@ vi.mock('./use-workspace-kanban-column-resize', () => ({ vi.mock('./use-workspace-kanban-create-worktree', () => ({ useWorkspaceKanbanCreateWorktree: () => ({ - canCreateWorktree: true, createWorktreeForStatus: vi.fn() }) })) diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.task-status-sync.test.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.task-status-sync.test.tsx index cf56ebe275f..8f3b86dd119 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.task-status-sync.test.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.task-status-sync.test.tsx @@ -138,7 +138,6 @@ vi.mock('./use-workspace-kanban-column-resize', () => ({ vi.mock('./use-workspace-kanban-create-worktree', () => ({ useWorkspaceKanbanCreateWorktree: () => ({ - canCreateWorktree: true, createWorktreeForStatus: vi.fn() }) })) diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx index 0ddf23f0ed7..eb9614f28d8 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx @@ -203,7 +203,7 @@ function WorkspaceKanbanDrawerContent({ const activeWorktreeIdentity = activeWorktreeId ? composeWorktreeHostIdentity(activeWorkspaceExecutionHostId ?? undefined, activeWorktreeId) : null - const { canCreateWorktree, createWorktreeForStatus } = useWorkspaceKanbanCreateWorktree() + const { createWorktreeForStatus } = useWorkspaceKanbanCreateWorktree() const visibleWorktreeIdSet = useVisibleWorkspaceKanbanWorktreeIds({ allWorktrees, repoMap @@ -944,7 +944,6 @@ function WorkspaceKanbanDrawerContent({ columnWidth={columnWidth} isResizingColumn={isResizingColumn} dragOverStatus={dragOverStatus} - canCreateWorktree={canCreateWorktree} renderCards={renderCards} selectedWorktreeIds={selectedWorktreeIds} selectedWorktrees={renderedSelectedWorktrees} diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.test.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.test.tsx index 8e613d2187b..b6d59e3284d 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.test.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.test.tsx @@ -108,7 +108,6 @@ function makeGrid(activeWorktreeIdentity: string | null = null): React.JSX.Eleme columnWidth={308} isResizingColumn={false} dragOverStatus={null} - canCreateWorktree={true} renderCards={true} selectedWorktreeIds={new Set()} selectedWorktrees={[]} diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.tsx index 2e4a1754657..63a82779a60 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanLaneGrid.tsx @@ -35,7 +35,6 @@ type WorkspaceKanbanLaneGridProps = { columnWidth: number isResizingColumn: boolean dragOverStatus: WorkspaceStatus | null - canCreateWorktree: boolean renderCards: boolean selectedWorktreeIds: ReadonlySet selectedWorktrees: readonly Worktree[] @@ -65,7 +64,6 @@ export default function WorkspaceKanbanLaneGrid({ columnWidth, isResizingColumn, dragOverStatus, - canCreateWorktree, renderCards, selectedWorktreeIds, selectedWorktrees, @@ -210,7 +208,6 @@ export default function WorkspaceKanbanLaneGrid({ columnWidth={columnWidth} isResizingColumn={isResizingColumn} isDragTarget={dragOverStatus === status.id} - canCreateWorktree={canCreateWorktree} renderCards={renderCards && renderedLaneIds.has(status.id)} selectedWorktreeIds={selectedWorktreeIds} selectedWorktrees={selectedWorktrees} diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.test.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.test.tsx index 884313aa7c4..4545f0a66ab 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.test.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.test.tsx @@ -62,7 +62,6 @@ function renderLane(props: { columnWidth={308} isResizingColumn={false} isDragTarget={false} - canCreateWorktree={true} renderCards={true} selectedWorktreeIds={new Set()} selectedWorktrees={[]} diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.tsx index d82ab75014c..15f6ae41715 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanStatusLane.tsx @@ -30,7 +30,6 @@ type WorkspaceKanbanStatusLaneProps = { columnWidth: number isResizingColumn: boolean isDragTarget: boolean - canCreateWorktree: boolean nativeDragEnabled?: boolean renderCards: boolean selectedWorktreeIds: ReadonlySet @@ -61,7 +60,6 @@ function WorkspaceKanbanStatusLane({ columnWidth, isResizingColumn, isDragTarget, - canCreateWorktree, nativeDragEnabled = true, renderCards, selectedWorktreeIds, @@ -94,9 +92,7 @@ function WorkspaceKanbanStatusLane({ undefined ) }, [fullWorktreeIds, hasQuery, items]) - const createTooltip = canCreateWorktree - ? `New workspace in ${status.label}` - : 'Add a project to create workspaces' + const createTooltip = `New workspace in ${status.label}` const createButton = (