Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions internal/git/prs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,33 @@ func FetchAndMatchPRs(repos []RepoInfo) {
matchPRs(repos, reposWithPRs)
}

// FetchAndMatchPRForRepo fetches open PRs authored by the current user for a
// single repo and updates the repo's PR fields to match its currently
// checked-out branch. It queries the repo directly with `gh pr list` rather than
// the broad cross-repo search, so it stays fast for a single-repo refresh.
func FetchAndMatchPRForRepo(repo *RepoInfo) {
prs := fetchPRDetails([]RepoInfo{*repo})

repo.PRNumber = 0
repo.PRUrl = ""
repo.PRState = ""

var best *prDetail
for i := range prs {
if prs[i].HeadRefName != repo.Branch {
continue
}
if best == nil || prs[i].Number < best.Number {
best = &prs[i]
}
}
if best != nil {
repo.PRNumber = best.Number
repo.PRUrl = best.URL
repo.PRState = best.State
}
}

// fetchOpenPRs does a broad search to find which repos have open PRs authored by
// the current user. It returns only repo keys (owner/repo), not full PR details,
// because gh search prs does not include headRefName — the branch name needed to
Expand Down
8 changes: 8 additions & 0 deletions internal/ui/tui/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type scanStartedMsg struct {
type repoScannedMsg git.ScanResult
type scanDoneMsg struct{}
type prsLoadedMsg []git.RepoInfo
type singleRepoPRLoadedMsg git.RepoInfo
type commitsLoadedMsg []string
type behindCommitsLoadedMsg []string
type fetchDoneMsg git.RepoInfo
Expand Down Expand Up @@ -385,6 +386,13 @@ func loadPRsCmd(repos []git.RepoInfo) tea.Cmd {
}
}

func loadPRForRepoCmd(repo git.RepoInfo) tea.Cmd {
return func() tea.Msg {
git.FetchAndMatchPRForRepo(&repo)
return singleRepoPRLoadedMsg(repo)
}
}

func loadCommitsCmd(path string) tea.Cmd {
return func() tea.Msg {
return commitsLoadedMsg(git.RecentCommits(path, 15))
Expand Down
32 changes: 32 additions & 0 deletions internal/ui/tui/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,34 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return m, nil

case singleRepoPRLoadedMsg:
updated := git.RepoInfo(msg)
activePath := ""
if m.state == stateDetail && m.cursor < len(m.repos) {
activePath = m.repos[m.cursor].Path
}
for i, r := range m.repos {
if r.Path == updated.Path {
m.repos[i] = updated
break
}
}
m.prsLoading = false
m.prsEverLoaded = true
git.SortReposByCol(m.repos, m.sortCol, m.sortDesc)
if activePath != "" {
for i, r := range m.repos {
if r.Path == activePath {
m.cursor = i
break
}
}
}
if m.state == stateDetail {
m.detailVP.SetContent(m.renderDetailContent())
}
return m, nil

case commitsLoadedMsg:
m.detailCommits = []string(msg)
m.commitsLoaded = true
Expand Down Expand Up @@ -150,6 +178,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else {
m.behindLoaded = true
}
if !m.noPRs {
m.prsLoading = true
cmds = append(cmds, m.spinner.Tick, loadPRForRepoCmd(updated))
}
return m, tea.Batch(cmds...)
}
return m, nil
Expand Down
Loading