Skip to content

feat: prw dashboard, a live table of your PRs grouped by task - #25

Merged
devblac merged 1 commit into
mainfrom
feat/dashboard
Oct 30, 2026
Merged

devblac merged 1 commit into
mainfrom
feat/dashboard

Conversation

@devblac

@devblac devblac commented Oct 30, 2026

Copy link
Copy Markdown
Owner

prw dashboard (alias prw top): your PRs across every repository on GitHub and Bitbucket Cloud, as a live table refreshed every minute — like top for PRs. No need to watch them first: prw finds them.

Your PRs (incl. merged in the last 1d) (11)
TASK       REPO                dev            rc              main|master      UPDATED  TITLE
PROJ-123   acme/billing-api    #12 🟣 merged  #15 ⏳ 3/5 ✓1    —                12m      Add spending limits
           acme/web            #7 🟣 merged   #8 ✅ CI ok ✓2   #9 ❌ CI failed  20m      Add spending limits
PROJ-98    acme/accounts       —              —               #31 ⛔ conflict  12d      Fix login timeout

Built for workflows where a change is opened on dev and cherry-picked to rc and master across many repositories — but generic:

  • Tasks: issue key in branch/title (PROJ-123, configurable issue_pattern), else the source branch without cherry-pick/backport decorations; --group-by issue|branch|title|none.
  • Columns: target branches in promotion order, merged by tier (dev|develop, rc|release|release/*, main|master) so different naming across repos lines up; stacked PRs' targets share an other column; branch_order overrides.
  • Cells: PR number as a clickable OSC 8 link + most pressing state (❌ ⛔ 📝 ⏳ ✅ 🚀 🟣, ✓N approvals).
  • Filters: yours by default, --review, --merged --since 24h, --mine=false; --once, --json.

Discovery & request budget

GitHub Bitbucket Cloud
yours search author:@me 1 request per workspace (/workspaces/{ws}/pullrequests/{user}, partial response incl. participants)
merged search is:merged merged:>= same endpoint, state=MERGED, q=updated_on > …
to review search review-requested:@me reviewer query per repository active in the last 30 days, every 10 min (Bitbucket can't do it per workspace)

CI is re-read only when a PR's head changes, while it runs, or every 15 min; Bitbucket merge checks are reused 30 min while a PR is unchanged; 4 requests in flight. Clients now count their requests; the footer shows them per hour.

Atlassian removed the cross-workspace /pullrequests/{user} endpoint (verified: 404), hence per-workspace discovery (bitbucket_workspaces, default: all of the token owner's).

Test plan

  • go test ./... -race, go vet ./..., cross-compiles for linux/darwin/windows/freebsd (CGO_ENABLED=0)
  • Unit: grouping (keys, cherry-pick decorations, custom pattern, modes), columns (tiers, your two jobs' branch names, custom order, other), rendering (states, emoji/hyperlink width, alignment), collector CI policy (finished cached, running/new head/15 min re-read, failed read keeps last state), sources against fakes, command view / JSON / flags
  • Live: the owner's GitHub PRs (open, merged, stacked, a fresh CI failure); Bitbucket discovery endpoints anonymously on a public Atlassian user/workspace (yours, merged since, recent repos, reviewer filter)
  • Bitbucket /user and /user/workspaces with a real token (owner to try)

🤖 Generated with Claude Code

`prw dashboard` (alias `prw top`) shows your pull requests across every
repository on GitHub and Bitbucket Cloud as a table refreshed every minute,
like top for PRs. It finds them itself: GitHub's search (yours, to review,
recently merged), and on Bitbucket one request per workspace for yours and a
reviewer query per recently active repository (every 10 minutes) for the
ones to review.

- internal/dashboard: rows are tasks — the issue key in the branch or title
  (PROJ-123, overridable with issue_pattern), else the source branch without
  cherry-pick / backport decorations — so a change and its cherry-picks share
  a row, across repositories. Columns are target branches in promotion order
  (dev → staging/qa → rc/release → main/master), merged by tier so naming
  differences line up; stacked PRs' targets share an "other" column. Cells
  show the PR (an OSC 8 hyperlink) and its most pressing state. group_by and
  branch_order override the heuristics.
- Request budget: a PR's CI is only re-read when its head changes, while it
  runs, or every 15 minutes; Bitbucket merge checks are reused for 30 minutes
  while the PR is unchanged; enrichment runs 4 at a time. Clients count their
  requests and the footer shows them per hour.
- Bitbucket client: CurrentUser, Workspaces, UserPullRequests (per workspace,
  partial responses incl. participants), RecentRepos, ReviewPullRequests,
  MergeStateWithin. PRs carry source/target branches on both services.
- Flags: --review, --merged --since 24h, --mine=false, --interval, --once,
  --json, --group-by, --width, --no-links. Config: group_by, issue_pattern,
  branch_order, bitbucket_workspaces, bitbucket_user.
- Terminal width and ANSI escapes via the standard library only (Windows
  console API, Unix ioctl).

Verified live: the owner's GitHub PRs (open, merged, stacked, a fresh CI
failure) and public Bitbucket PRs of an Atlassian user across a workspace.
The Bitbucket /user and /user/workspaces calls need a real token to verify.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T02:33:47.828580Z 9296510 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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

Copy link
Copy Markdown

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: 9296510518

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cmd/prw/dashboard.go
Comment on lines +127 to +128
for {
items, warnings := collector.Refresh(ctx, filter)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Advance the merged cutoff on each live refresh

When the dashboard runs live with --merged, MergedSince is calculated only at startup and the same filter is reused for every refresh. PRs therefore never age out of the selected window: a dashboard left running for several days still includes merges from its first day while labeling them as merged in the last 24 hours. Recompute the cutoff from the selected duration before each refresh and update the view's filter accordingly.

Useful? React with 👍 / 👎.

Comment on lines +106 to +107
if q.state == StateMerged && it.UpdatedAt.Before(f.MergedSince) {
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter merged PRs by their merge timestamp

For a cutoff partway through a UTC day, the date-only search also retrieves PRs merged earlier that day. Comparing UpdatedAt does not exclude those PRs if they received a comment or another update after the cutoff, so --merged --since can show PRs merged outside the requested window even on a single refresh. Read the PR's merged_at value and use that for the exact cutoff comparison instead.

Useful? React with 👍 / 👎.

func (c *Collector) storeCI(it Item) {
c.mu.Lock()
defer c.mu.Unlock()
c.ci[it.Key()] = ciSnapshot{sha: it.HeadSHA, item: it, readAt: c.Now(), running: it.CI == "pending" || it.CI == ""}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep polling CI when failed checks coexist with running checks

When one check has failed but others are still running, github.SummarizeCI returns failure or error because those states take precedence over pending. This snapshot consequently marks the entire suite as finished and suppresses CI reads for 15 minutes, even though CIDone < CITotal. Completion and successful retries on the same head can remain invisible throughout that interval. Include unfinished check counts in the running predicate so partially running suites continue to refresh.

Useful? React with 👍 / 👎.

@devblac
devblac merged commit 00fbc39 into main Oct 30, 2026
2 checks passed
@devblac
devblac deleted the feat/dashboard branch October 30, 2026 21:37
@devblac devblac mentioned this pull request Oct 31, 2026
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