feat(workspace): set project location from the create-worktree host picker (#14868)

* feat(workspace): set project location from the create-worktree host picker

Hosts that still say "Project location not set" now get an inline Set location action. It opens a nested dialog over Create worktree so the in-progress form stays put.

* fix(workspace): replace unset-location status copy with a button

Drop the redundant "Project location not set" caption and show a Set project location action with a hover tooltip instead.

* refactor(workspace): tighten the set-project-location dialog

- reuse CreateProjectParentBrowser instead of a second host-filesystem browse view
- drop ProjectLocationBrowseTarget; parseExecutionHostId already models it
- single setLocation path in RunTargetCombobox (row, button, Enter)
- memoize the default clone URL instead of scanning on every store update
- fix missing required props in the new composer-card test

* fix(workspace): close the correctness gaps in set-project-location

- Escape in the host browser now backs out to the form instead of dismissing
  the dialog and discarding the half-filled path/clone URL. Radix dismisses
  from a document-capture listener, so only preventDefault can stop it.
- Drop the stopPropagation guards: window-capture (the composer's Escape
  handler) already ran by then, so they never protected it — the nestedDialogOpen
  gate does. They did silently kill RemoteFileBrowser's own key handling.
- Hide Set project location for host-local repo:<id> projects (folder projects,
  git repos with no remote). Linking on another host matches by project identity,
  which those have none of, so the call could only ever toast an error.
- Drop a standalone placeholder setup once a repo projection covers the same
  project+host, restoring the (projectId, hostId) uniqueness invariant. Setting a
  location on a host with a pending setup was leaving a ghost that sorts first and
  reads back as 'not set up'.
- Existing-folder submit label matched a catalog string reading 'Importing...'

* test(composer): follow the renamed local in the host-retarget source assertion
This commit is contained in:
Neil
2026-08-16 03:30:47 -07:00
committed by GitHub
parent 757fae28d7
commit e4e54a17d0
18 changed files with 1243 additions and 26 deletions
+12 -1
View File
@@ -93,6 +93,8 @@ export function isProjectRemoteIdentityPending(
return repo.gitRemoteIdentity === undefined && !hasProjectRemoteIdentity(repo)
}
const HOST_LOCAL_PROJECT_ID_PREFIX = 'repo:'
export function getProjectIdentityKey(
repo: Pick<Repo, 'id' | 'upstream' | 'repoIcon' | 'gitRemoteIdentity'>
): string {
@@ -104,7 +106,16 @@ export function getProjectIdentityKey(
if (gitRemoteIdentity) {
return `git:${gitRemoteIdentity.canonicalKey}`
}
return `repo:${repo.id}`
return `${HOST_LOCAL_PROJECT_ID_PREFIX}${repo.id}`
}
/**
* True for the `repo:<id>` fallback above — a folder project, or a git repo with no
* remote. The id is a per-host repo id, so the same project on another host derives a
* different one and can never be matched there.
*/
export function isHostLocalProjectId(projectId: string): boolean {
return projectId.startsWith(HOST_LOCAL_PROJECT_ID_PREFIX)
}
export function getProjectIdForProviderIdentity(identity: ProjectProviderIdentity): string {