fix(new-workspace): polish Project and Run-on pickers in create dialog (#10120)

- Tighten combobox row padding (py-2 -> py-1.5) in the Project and Run-on
  lists so items aren't so vertically loose.
- Use a Monitor glyph (not a server) for the local machine in Run-on.
- Pin 'Add host' as a compact single-row footer with one clean divider,
  matching the Project picker's 'Add a new project' footer (removes the
  taller two-line in-list row and its extra separator).
- Give the smart name field a solid bg-background so it matches the other
  inputs on light mode instead of reading translucent over the dialog.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil 2026-07-22 23:56:53 -07:00 committed by GitHub
parent 0b344425eb
commit a29c487200
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 52 additions and 41 deletions

View File

@ -287,9 +287,10 @@ function openRunTargetPicker(container: HTMLElement): void {
}
function findRunTargetItem(label: string): HTMLElement | undefined {
return [...document.body.querySelectorAll<HTMLElement>('[cmdk-item]')].find((item) =>
item.textContent?.includes(label)
)
// Why: "Add host" is a pinned footer button (mirrors the Project combobox), not a cmdk row.
return [
...document.body.querySelectorAll<HTMLElement>('[cmdk-item], [data-run-target-add-host]')
].find((item) => item.textContent?.includes(label))
}
let current: { container: HTMLDivElement; root: Root } | null = null

View File

@ -13,6 +13,7 @@ import {
CornerDownLeft,
FolderPlus,
LoaderCircle,
Monitor,
PlugZap,
Plus,
Settings2,
@ -26,7 +27,7 @@ import {
CommandList,
CommandSeparator
} from '@/components/ui/command'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { SettingsSwitch } from '@/components/settings/SettingsFormControls'
import type RepoCombobox from '@/components/repo/RepoCombobox'
@ -71,6 +72,7 @@ import type {
ReadyProjectHostSetupOption
} from '@/lib/project-host-setup-options'
import type { WorkspaceCreateErrorDisplay } from '@/lib/workspace-create-error-format'
import { LOCAL_EXECUTION_HOST_ID, type ExecutionHostId } from '../../../shared/execution-host'
import type { SshConnectionStatus } from '../../../shared/ssh-types'
import type { TaskSourceContext } from '../../../shared/task-source-context'
import type { RuntimeStatus } from '../../../shared/runtime-types'
@ -355,6 +357,12 @@ function HostPathTooltip({ path }: { path: string }): React.JSX.Element {
)
}
// Why: the local machine isn't a server — give it a monitor glyph so it reads as "this computer".
function HostRowIcon({ hostId }: { hostId: ExecutionHostId }): React.JSX.Element {
const Icon = hostId === LOCAL_EXECUTION_HOST_ID ? Monitor : Server
return <Icon className="size-3.5 shrink-0 text-muted-foreground" />
}
function WorkspaceRunTargetCombobox({
hostOptions,
hostValue,
@ -501,7 +509,7 @@ function WorkspaceRunTargetCombobox({
</span>
) : selectedHost ? (
<span className="inline-flex min-w-0 items-center gap-1.5">
<Server className="size-3.5 shrink-0 text-muted-foreground" />
<HostRowIcon hostId={selectedHost.hostId} />
<span className="truncate">{selectedHost.label}</span>
</span>
) : (
@ -534,7 +542,7 @@ function WorkspaceRunTargetCombobox({
onSelect={() => handleHostSelect(option.id)}
onPointerEnter={closeSubmenus}
onFocus={closeSubmenus}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<Check
className={cn(
@ -542,7 +550,7 @@ function WorkspaceRunTargetCombobox({
!selectedRecipe && option.id === selectedHost?.id ? 'opacity-100' : 'opacity-0'
)}
/>
<Server className="size-3.5 shrink-0 text-muted-foreground" />
<HostRowIcon hostId={option.hostId} />
<div className="min-w-0 flex-1">
<div className="truncate text-sm">{option.label}</div>
<HostPathTooltip path={option.path} />
@ -564,7 +572,7 @@ function WorkspaceRunTargetCombobox({
onSelect={() => {}}
onPointerEnter={closeSubmenus}
onFocus={closeSubmenus}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<div className="flex min-w-0 flex-1 items-center gap-2 opacity-60">
<Check className="size-4 opacity-0" />
@ -576,7 +584,7 @@ function WorkspaceRunTargetCombobox({
) : option.attention ? (
<AlertTriangle className="size-3.5 shrink-0 text-muted-foreground" />
) : (
<Server className="size-3.5 shrink-0 text-muted-foreground" />
<HostRowIcon hostId={option.hostId} />
)}
<div className="min-w-0 flex-1">
<div className="truncate text-sm">{option.label}</div>
@ -626,10 +634,10 @@ function WorkspaceRunTargetCombobox({
))}
</>
) : null}
{/* Why: separate the host list from the environment/add-host actions below, mirroring
the divider above the not-connected group so the two action rows read as their own
section rather than trailing the hosts. */}
{readyHostOptions.length > 0 || needsSetupHostOptions.length > 0 ? (
{/* Why: separate the host list from the per-workspace-env row; the "Add host" action
is pinned below the list with its own border, so it needs no separator here. */}
{recipes.length > 0 &&
(readyHostOptions.length > 0 || needsSetupHostOptions.length > 0) ? (
<CommandSeparator />
) : null}
{recipes.length > 0 ? (
@ -641,7 +649,7 @@ function WorkspaceRunTargetCombobox({
onSelect={openVmRecipesSubmenu}
onPointerEnter={openVmRecipesSubmenu}
onFocus={openVmRecipesSubmenu}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<Check
className={cn(
@ -671,7 +679,7 @@ function WorkspaceRunTargetCombobox({
key={recipe.id}
value={`recipe:${recipe.id}`}
onSelect={() => handleRecipeSelect(recipe.id)}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<Check
className={cn(
@ -698,31 +706,31 @@ function WorkspaceRunTargetCombobox({
</PopoverContent>
</Popover>
) : null}
</CommandList>
{/* Why: pin "Add host" below the scrollable list mirrors the Project combobox's
"Add a new project" footer so it keeps a compact single-row height and one clean
divider instead of a taller in-list row above the popover edge. */}
<div className="border-t border-border">
<Popover open={hostActionsOpen} onOpenChange={setHostActionsOpen}>
<PopoverTrigger asChild>
<CommandItem
value="add-host"
onSelect={openHostActionsSubmenu}
{/* Why: an Anchor (not a Trigger) so click/hover/focus all just open the submenu
a Trigger's own toggle would fight the hover-open and close it on the same click. */}
<PopoverAnchor asChild>
<Button
type="button"
variant="ghost"
data-run-target-add-host="true"
onClick={openHostActionsSubmenu}
onPointerEnter={openHostActionsSubmenu}
onFocus={openHostActionsSubmenu}
className="items-center gap-2 px-3 py-2"
className="h-8 w-full justify-start gap-2 rounded-none px-3 text-xs font-normal"
>
<Check className="size-4 opacity-0" />
<Plus className="size-3.5 shrink-0 text-muted-foreground" />
<div className="min-w-0 flex-1">
<div className="truncate text-sm">
{translate('auto.components.NewWorkspaceComposerCard.addHost', 'Add host')}
</div>
<div className="mt-0.5 truncate text-[11px] text-muted-foreground">
{translate(
'auto.components.NewWorkspaceComposerCard.addHostHint',
'Register another machine or Orca server'
)}
</div>
</div>
<ChevronRight className="size-3.5 shrink-0 text-muted-foreground" />
</CommandItem>
</PopoverTrigger>
<span>
{translate('auto.components.NewWorkspaceComposerCard.addHost', 'Add host')}
</span>
<ChevronRight className="ml-auto size-3.5 shrink-0 text-muted-foreground" />
</Button>
</PopoverAnchor>
<PopoverContent side="right" align="start" sideOffset={6} className="w-72 p-0">
{/* Why: pin an empty value so cmdk doesn't auto-highlight the first row on open
matches the recipes submenu, which leaves nothing highlighted by default. */}
@ -731,7 +739,7 @@ function WorkspaceRunTargetCombobox({
<CommandItem
value="add-ssh-host"
onSelect={handleAddSshHost}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<Server className="size-3.5 shrink-0 text-muted-foreground" />
<div className="min-w-0 flex-1">
@ -752,7 +760,7 @@ function WorkspaceRunTargetCombobox({
<CommandItem
value="add-remote-orca-server"
onSelect={handleAddRemoteServer}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<Cloud className="size-3.5 shrink-0 text-muted-foreground" />
<div className="min-w-0 flex-1">
@ -774,7 +782,7 @@ function WorkspaceRunTargetCombobox({
</Command>
</PopoverContent>
</Popover>
</CommandList>
</div>
</Command>
</PopoverContent>
</Popover>

View File

@ -199,7 +199,7 @@ export default function ProjectCombobox({
key={option.id}
value={option.id}
onSelect={() => handleSelect(option.id)}
className="items-center gap-2 px-3 py-2"
className="items-center gap-2 px-3 py-1.5"
>
<Check
className={cn(

View File

@ -1377,7 +1377,7 @@ export default function SmartWorkspaceNameField({
event.preventDefault()
onPlainEnter?.()
}}
className="flex h-9 w-full min-w-0 items-center gap-2 rounded-md border border-input bg-transparent px-2.5 text-sm shadow-xs outline-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50"
className="flex h-9 w-full min-w-0 items-center gap-2 rounded-md border border-input bg-background px-2.5 text-sm shadow-xs outline-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 dark:bg-input/30"
>
<SelectionIcon kind={selectedSource.kind} />
<span className="min-w-0 flex-1 truncate font-medium leading-none text-foreground">
@ -1508,7 +1508,9 @@ export default function SmartWorkspaceNameField({
}}
placeholder={placeholder}
disabled={disabled}
className="h-9 pl-8 text-sm"
// Why: match the project/run-on comboboxes' solid `bg-background` — the input's
// default transparent fill made it read a different color on light mode.
className="h-9 bg-background pl-8 text-sm"
/>
</>
)}