Skip to content

feat: add PR/branch picker to project creation form#400

Merged
matt2e merged 14 commits intomainfrom
open-pr-redo
Mar 17, 2026
Merged

feat: add PR/branch picker to project creation form#400
matt2e merged 14 commits intomainfrom
open-pr-redo

Conversation

@matt2e
Copy link
Contributor

@matt2e matt2e commented Mar 17, 2026

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:

  • New BranchPicker.svelte component with PR/branch search, filtering, and 'New branch' badge for unmatched input
  • Auto-derive project name from the selected PR title or branch name
  • Display matched PR info (number, title) in the branch picker
  • Save associated PR metadata on project creation
  • Fix worktree creation to start from remote tracking branch when one exists
  • Backend: new list_pull_requests command and updated branch/worktree logic

matt2e added 5 commits March 17, 2026 12:58
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.
@matt2e matt2e requested review from baxen and wesbillman as code owners March 17, 2026 03:07
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

matt2e added 9 commits March 17, 2026 14:13
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.
@matt2e matt2e merged commit d0a6638 into main Mar 17, 2026
4 checks passed
@matt2e matt2e deleted the open-pr-redo branch March 17, 2026 04:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant