feat: add PR/branch picker to project creation form#400
Conversation
Add a BranchPicker component that appears under the subpath field when a repo is selected. It fetches open PRs and remote branches for the repo, then filters them as the user types. Selecting a PR uses its head ref as the branch name; selecting a branch uses its name directly. The backend create_project command now accepts an optional branch_name parameter so the chosen branch is used instead of inferring one from the project name. Changes: - New BranchPicker.svelte with search dropdown (PRs + branches) - NewProjectForm.svelte wires up branchName state and passes it through - commands.ts createProject accepts optional branchName - lib.rs create_project accepts optional branch_name, falls back to infer_branch_name when not provided
When creating a project from an existing PR, setup_worktree_sync would always create the new local branch from base_branch (e.g. origin/main), discarding all the PR's commits. The worktree ended up at the same commit as main, so the branch card showed zero commits. Now, before creating a new worktree, we check whether the remote tracking ref (origin/<branch_name>) exists. If it does — which is the case for branches backing open PRs — we use it as the start point so the local branch includes all the PR's commits. For genuinely new branches that don't exist on the remote yet, the behaviour is unchanged (start from base_branch). Changes: - git/worktree.rs: add remote_branch_exists() helper - git/mod.rs: export the new function - branches.rs: use origin/<branch> as start point when available
When the project name field is empty and the user selects a PR or branch in the BranchPicker, automatically populate the name: - PR selected: use the PR title directly - Branch selected: take the last path component after splitting on '/', replace '-' and '_' with spaces, and capitalize the first letter BranchPicker now exports a BranchSelection type and accepts an optional onSelect callback that fires with the selection kind, branch name, and a human-friendly label. NewProjectForm wires this up to fill the name field only when it is currently empty.
When the user types into the PR or Branch field and the value doesn't match any known remote branch or PR head ref, the badge on the field label switches from 'Optional' to 'New branch' (with accent styling). BranchPicker now exposes a bindable isNewBranch prop that is true when the trimmed input is non-empty and not found in the set of known remote branch names. NewProjectForm binds to this prop and conditionally renders the badge text and CSS class.
…eation When the user selects a PR from the BranchPicker dropdown, display a compact info card below the input showing the PR number, title, author, base ref, and draft status. Typing into the field clears the card so stale PR info doesn't linger when the user switches to a different branch. The matched PR number is threaded through the project creation flow: - BranchPicker exposes a bindable matchedPr prop - NewProjectForm binds to it and passes the PR number to createProject - commands.ts forwards the optional prNumber parameter - The backend create_project command accepts pr_number and calls .with_pr() on the branch record for both local and remote projects This ensures that when a project is created from an existing PR, the branch's pr_number is set in the database from the start, enabling PR status features (checks, review decision, mergeable) to work without requiring the user to manually link the PR afterwards.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e0ee552200
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| // Update matched PR: set when selecting a PR item, clear for branches | ||
| if (item.kind === 'pr') { | ||
| matchedPr = pullRequests.find((pr) => pr.headRef === item.branchName) ?? null; |
There was a problem hiding this comment.
Match selected PR by its identity, not head branch
When a PR item is selected, matchedPr is recovered with pullRequests.find((pr) => pr.headRef === item.branchName), which is ambiguous if multiple open PRs share the same branch name (common across forks, e.g. patch-1). In that case the UI can attach the wrong PR metadata/number to the project even though the user clicked a different PR entry, so project creation can persist an incorrect prNumber.
Useful? React with 👍 / 👎.
| { | ||
| &remote_ref | ||
| } else { | ||
| &branch.base_branch |
There was a problem hiding this comment.
Use PR ref when remote branch is absent
For PR-backed branches whose head is not on origin (notably fork PRs), remote_branch_exists is false and this path falls back to branch.base_branch, so the created worktree starts from base instead of the selected PR commits. Since project creation now stores pr_number, this produces projects that claim to target a PR but are checked out to unrelated code in this scenario.
Useful? React with 👍 / 👎.
When a GitHub PR URL (e.g. github.com/owner/repo/pull/123) or branch URL (e.g. github.com/owner/repo/tree/feat/my-feature) is pasted into the repository search field, the repo is selected and the PR or branch is automatically populated in the BranchPicker. For PR URLs, the PR number is matched against fetched PRs to show the full PR info card. For branch URLs, the branch name is matched against remote branches (or PRs backed by that branch); if no match is found it appears as a new branch. Changes: - RepoSearchInput: parseGitHubUrl now returns a RepoSelection object with optional prNumber and branchName fields. onSelect callback updated to pass the full selection. - BranchPicker: new initialPrNumber and initialBranchName bindable props that auto-select after data loads, then clear themselves. - NewProjectForm: threads pending PR/branch state from RepoSearchInput through to BranchPicker via the new props.
When a GitHub PR, branch, or repo URL is pasted into the Name field of the project creation form, it is detected on input, the repo is auto-selected (with PR/branch info populated in the BranchPicker), and the name field is cleared so the user can type a real project name. This mirrors the existing URL-paste behaviour in the Repository search field, giving users a convenient shortcut from whichever field they happen to focus first. Changes: - Extract parseGitHubUrl from RepoSearchInput into shared/githubUrl.ts - RepoSearchInput imports the shared function instead of defining its own - NewProjectForm adds an oninput handler on the name field that parses URLs and delegates to handleRepoSelected
Replace the local parseGitHubUrl in GitHubRepoPicker with the shared version from githubUrl.ts, which correctly handles PR URLs (github.com/owner/repo/pull/123) and branch URLs (github.com/owner/repo/tree/branch-name) in addition to plain repo URLs. The local version only extracted the repo name and was a duplicated, less capable copy. Update the search placeholder from 'Search or paste a repository...' to 'Search or paste a repo or PR link...' so users know they can paste PR URLs directly into the Add Repo field.
Move the RepoSelection interface from RepoSearchInput.svelte into shared/githubUrl.ts, eliminating the upward dependency from shared/ into features/projects/. Remove the duplicate RepoPickerSelection interface from GitHubRepoPicker.svelte and re-export RepoSelection under the old name to preserve downstream imports. Also fix the tree-URL regex to handle # fragments (e.g. github.com/owner/repo/tree/main#readme would previously capture 'main#readme' as the branch name). Changes: - shared/githubUrl.ts: define RepoSelection here, fix regex [?#] - RepoSearchInput.svelte: import and re-export from shared - GitHubRepoPicker.svelte: import from shared, re-export as alias
- BranchPicker: gate isNewBranch on !loading to prevent flash of
'New branch' badge while PR/branch data is still being fetched
- BranchPicker: add generation counter to fetchData so stale async
responses are discarded when the repo changes rapidly
- BranchPicker: fix misleading comment about skipping default branch
(the code only deduplicates branches that share a name with a PR)
- GitHubRepoPicker: remove unused RepoPickerSelection re-export
(consumers already import RepoSelection from shared/githubUrl)
- NewProjectForm: guard nameFromBranch against branch names ending
with '/' where split('/').pop() yields an empty string
- githubUrl.ts: add comment noting that the plain-repo regex also
matches PR/tree URLs, so the ordering of checks is load-bearing
When a GitHub URL was pasted into the Name or Repository field, the
BranchPicker would appear with its dropdown open because:
1. The source input stayed focused, or focus jumped to the BranchPicker
2. BranchPicker's auto-select (from initialPrNumber/initialBranchName)
called selectItem which focused the picker input and opened the dropdown
Fix by:
- Adding a focus option to BranchPicker.selectItem (default true) and
passing { focus: false } for all programmatic auto-selections triggered
by initialPrNumber/initialBranchName
- Blurring the active element in NewProjectForm.handleNameInput after a
URL is detected and processed
- Blurring the input in RepoSearchInput.handleInput after a URL is
detected and processed
…ri command The remote branch check added in setup_worktree_sync (MCP path) was missing from the main setup_worktree Tauri command used by the frontend. When creating a project from an existing PR, the worktree was always started from base_branch (e.g. origin/main), discarding all PR commits and showing zero commits on the branch card. Now setup_worktree checks whether origin/<branch_name> exists before creating the worktree, matching the existing logic in setup_worktree_sync. If the remote tracking ref exists (as it does for branches backing open PRs), it is used as the start point so the local branch includes the PR's full commit history.
Add a new BranchPicker component to the project creation flow that lets users search and select from existing PRs or branches, or type a new branch name.
Key changes:
BranchPicker.sveltecomponent with PR/branch search, filtering, and 'New branch' badge for unmatched inputlist_pull_requestscommand and updated branch/worktree logic