From 05bbbb95826209fd5bdf54ad28d7769af279bfd4 Mon Sep 17 00:00:00 2001
From: Neil <4138956+nwparker@users.noreply.github.com>
Date: Mon, 26 Oct 2026 17:41:12 -0700
Subject: [PATCH] Compact worktree project and host pickers with stacked
details (#34098)
* Compact worktree project and host pickers with stacked details
* Align worktree picker markers and action gutters
* Extract WSL connector fixture to satisfy file length limit
* Restart CI after resolving upstream fixture conflict
---
...orkspaceComposerProjectSection.fixture.tsx | 161 ++++++++++++++++
.../NewWorkspaceComposerProjectSection.tsx | 168 ++++++++---------
.../ProjectCombobox.dialog-handoff.test.tsx | 9 +-
.../new-workspace/ProjectCombobox.test.tsx | 41 +++--
.../new-workspace/ProjectCombobox.tsx | 168 +++++++++--------
.../new-workspace/ProjectComboboxRow.tsx | 31 ++--
.../RunTargetCombobox.host-identity.test.tsx | 7 +-
.../new-workspace/RunTargetComboboxRow.tsx | 15 +-
.../new-workspace/RunTargetField.tsx | 173 +++++++++---------
.../new-workspace/RunTargetSubmenus.tsx | 6 +-
10 files changed, 486 insertions(+), 293 deletions(-)
create mode 100644 src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.fixture.tsx
diff --git a/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.fixture.tsx b/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.fixture.tsx
new file mode 100644
index 00000000000..b4b91dc4cd5
--- /dev/null
+++ b/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.fixture.tsx
@@ -0,0 +1,161 @@
+import { useState } from 'react'
+import { defineFixture } from '../../component-fixtures/component-fixture'
+import type { NewWorkspaceProjectOption } from '@/lib/new-workspace-project-options'
+import {
+ getProjectHostSetupSelectionKey,
+ type ProjectHostSetupOption
+} from '@/lib/project-host-setup-options'
+import { NewWorkspaceComposerProjectSection } from './NewWorkspaceComposerProjectSection'
+
+const projects: NewWorkspaceProjectOption[] = [
+ {
+ kind: 'project',
+ id: 'orca',
+ projectId: 'orca',
+ displayName: 'orca',
+ badgeColor: 'var(--muted-foreground)',
+ detail: 'stablyai/orca'
+ },
+ {
+ kind: 'project',
+ id: 'personal-orca',
+ projectId: 'personal-orca',
+ displayName: 'orca',
+ badgeColor: 'var(--muted-foreground)',
+ detail: 'personal/orca'
+ },
+ {
+ kind: 'project',
+ id: 'api',
+ projectId: 'api',
+ displayName: 'platform-api',
+ badgeColor: 'var(--muted-foreground)',
+ detail: 'stablyai/platform-api'
+ },
+ {
+ kind: 'project-group',
+ id: 'folder',
+ projectGroupId: 'folder',
+ displayName: 'Design workspace',
+ badgeColor: 'var(--muted-foreground)',
+ detail: '/Users/alice/Projects/design',
+ parentPath: '/Users/alice/Projects/design',
+ connectionId: null
+ }
+]
+const hosts: ProjectHostSetupOption[] = [
+ {
+ kind: 'ready',
+ id: 'local',
+ projectId: 'orca',
+ repoId: 'orca-local',
+ hostId: 'local',
+ label: 'MacBook Pro',
+ detail: 'Local',
+ path: '/Users/alice/Projects/orca'
+ },
+ {
+ kind: 'ready',
+ id: 'remote',
+ projectId: 'orca',
+ repoId: 'orca-remote',
+ hostId: 'ssh:devbox',
+ label: 'Dev server',
+ detail: 'SSH',
+ path: '/home/alice/projects/orca'
+ },
+ {
+ kind: 'needs-setup',
+ id: 'windows',
+ projectId: 'orca',
+ hostId: 'runtime:windows',
+ label: 'Windows workstation',
+ detail: 'Project location not set',
+ isAvailable: true,
+ attention: false,
+ canSetLocation: true
+ }
+]
+
+function ProjectAndHostPreview({
+ folderOnly = false
+}: {
+ folderOnly?: boolean
+}): React.JSX.Element {
+ const [project, setProject] = useState(folderOnly ? 'folder' : 'orca')
+ const [host, setHost] = useState('local')
+ return (
+
+
New worktree
+ {}}
+ focusNameInput={() => {}}
+ shouldShowRunTargetPicker={!folderOnly}
+ projectHostSetupOptions={hosts}
+ selectedProjectHostSetupId={host}
+ handleProjectHostSetupChange={(key) => {
+ const option = hosts.find(
+ (candidate) => getProjectHostSetupSelectionKey(candidate) === key
+ )
+ if (option) {
+ setHost(option.id)
+ }
+ }}
+ ephemeralVmRecipes={[]}
+ handleAddSshHost={() => {}}
+ handleAddRemoteServer={() => {}}
+ handleConnectRunTargetHost={async () => {}}
+ handleSetLocation={() => {}}
+ onConnectSelectedRepo={async () => {}}
+ sshStatusLabel="Connected"
+ connectButtonLabel="Connect"
+ selectedProjectName="orca"
+ />
+
+ )
+}
+
+export const closed = defineFixture({ width: 560, render: () => })
+export const narrow = defineFixture({ width: 360, render: () => })
+export const folderOnly = defineFixture({
+ width: 560,
+ render: () =>
+})
+export const projectMenu = defineFixture({
+ ...closed,
+ interact: (frame) => {
+ frame.querySelector('[aria-label="Project"][role="combobox"]')?.focus()
+ }
+})
+export const hostMenu = defineFixture({
+ ...closed,
+ interact: (frame) => {
+ frame.querySelector('[aria-label="Run on"][role="combobox"]')?.focus()
+ }
+})
+
+export const narrowProjectMenu = defineFixture({ ...projectMenu, width: 360 })
+export const narrowHostMenu = defineFixture({ ...hostMenu, width: 360 })
+
+function tooltipFixture(attribute: string) {
+ return defineFixture({
+ ...closed,
+ interact: async (frame) => {
+ frame
+ .querySelector(`div[${attribute}]`)
+ ?.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, pointerType: 'mouse' }))
+ await new Promise((resolve) => setTimeout(resolve, 500))
+ }
+ })
+}
+
+export const projectTooltip = tooltipFixture('data-project-combobox-root')
+export const hostTooltip = tooltipFixture('data-run-target-combobox-root')
diff --git a/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.tsx b/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.tsx
index 111a4446a9e..ee91406df7b 100644
--- a/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.tsx
+++ b/src/renderer/src/components/new-workspace/NewWorkspaceComposerProjectSection.tsx
@@ -5,6 +5,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
import ProjectCombobox from '@/components/new-workspace/ProjectCombobox'
import RunTargetCombobox from '@/components/new-workspace/RunTargetCombobox'
import { translate } from '@/i18n/i18n'
+import { cn } from '@/lib/utils'
import type {
EphemeralVmRecipeOption,
NeedsProjectHostOption,
@@ -85,91 +86,94 @@ export function NewWorkspaceComposerProjectSection({
}: NewWorkspaceComposerProjectSectionProps): React.JSX.Element {
return (