Summary
Add PR merge-state visibility so a reviewer can judge whether an open PR is ready to
merge without leaving the terminal. Two related parts:
- A compact
State column in every PR table (All PRs / Inbox / per-repo).
- A detail-on-highlight pane (
d) showing the freshly computed merge state, CI
check rollup, and recent commits (git log) for the highlighted PR.
Motivation / key constraint
GitHub computes mergeable lazily — it only runs the merge check when a PR is
accessed, and until then GraphQL returns UNKNOWN. ghdash's list views come from the
search API, which never triggers that computation, so a plain column would show
UNKNOWN for almost every row.
The fix: the list column is a best-effort hint, and the authoritative value comes from a
per-PR detail fetch when a row is highlighted — which also naturally carries the git
log and CI rollup. The two features are one coherent flow.
Change 1 — merge-state column
Before
┌ Navigation ──────────┐┌ All Open PRs (13) ─────────────────────────────────────┐
│ Inbox ││ # Title Author Repo Updated │
│ All PRs (13) ││ #62 feat(ui): page-lvl sashml catalyst 7m ago │
│▼ AITechCraft (18) ││ #40 [Draft] feat(e2e) sashml catalyst 2h ago │
│ zs-beads-rust [2] ││ #9 deps: bump depbot zs-beads-rust 1d ago │
└──────────────────────┘└────────────────────────────────────────────────────────┘
After — new State column between # and Title
┌ Navigation ──────────┐┌ All Open PRs (13) ─────────────────────────────────────┐
│ Inbox ││ # State Title Author Repo Updated│
│ All PRs (13) ││ #62 ✓ ok feat(ui): page sashml catalyst 7m ago │
│▼ AITechCraft (18) ││ #40 ✗ cf [Draft] feat(e2 sashml catalyst 2h ago │
│ zs-beads-rust [2] ││ #9 ? deps: bump depbot zs-beads-rust 1d ago │
└──────────────────────┘└─────────────────────────────────────────────────────────┘
legend: ✓ ok = mergeable ✗ cf = conflicting ? = unknown (not yet computed)
Glyphs pair a shape/letter with color, so the signal survives colorblindness and
monochrome terminals.
Change 2 — detail-on-highlight pane (press d)
Highlight a PR and press d. A pane fetches the PR directly (forcing a fresh mergeable),
plus statusCheckRollup and the last 5 commits:
┌ PR #62 — feat(ui): page-level layout ─────────────────────────┐
│ Merge: ✓ mergeable (CLEAN) CI: ✓ passing │
│ │
│ Recent commits: │
│ a1b2c3d feat(ui): page-level layout (7m ago) │
│ 9f8e7d6 fix: sidebar overflow on narrow view (1h ago) │
│ 1122334 test: add layout snapshots (3h ago) │
│ │
│ Press d or Esc to close │
└───────────────────────────────────────────────────────────────┘
- Conflicting example →
Merge: ✗ conflicting (DIRTY) CI: ✗ failing
- Fetch is debounced ~200ms and cached per PR, so holding
j/k never sprays
API calls and nav stays responsive. r (refresh) clears the cache to recompute fresh.
- Once detail resolves, the list column upgrades from
? to the authoritative value.
Implementation notes
- New GraphQL:
mergeable + mergeStateStatus on the search/repo PR queries; a new
PR_DETAIL_QUERY (mergeable, mergeStateStatus, commits(last:5) + per-commit
statusCheckRollup).
PullRequest gains mergeable / merge_state_status as Option<String> with
#[serde(default)] so existing disk-cache entries still deserialize.
- Detail lives in an in-memory
pr_details map (kept out of disk cache on purpose, for
freshness). Debounce is implemented in the event loop's tokio::select!.
- New key
d toggles the pane; status-bar hint updated.
Tracking (beads)
zombo-sash-eco-rpjg — merge-state column (implemented)
zombo-sash-eco-zkk5 — detail-on-highlight pane (implemented)
zombo-sash-eco-9h3o — CI/checks glyph in the list column (follow-up)
zombo-sash-eco-pp0u — filter/sort by merge state + legend (follow-up)
Summary
Add PR merge-state visibility so a reviewer can judge whether an open PR is ready to
merge without leaving the terminal. Two related parts:
Statecolumn in every PR table (All PRs / Inbox / per-repo).d) showing the freshly computed merge state, CIcheck rollup, and recent commits (git log) for the highlighted PR.
Motivation / key constraint
GitHub computes
mergeablelazily — it only runs the merge check when a PR isaccessed, and until then GraphQL returns
UNKNOWN. ghdash's list views come from thesearch API, which never triggers that computation, so a plain column would show
UNKNOWNfor almost every row.The fix: the list column is a best-effort hint, and the authoritative value comes from a
per-PR detail fetch when a row is highlighted — which also naturally carries the git
log and CI rollup. The two features are one coherent flow.
Change 1 — merge-state column
Before
After — new
Statecolumn between#andTitleGlyphs pair a shape/letter with color, so the signal survives colorblindness and
monochrome terminals.
Change 2 — detail-on-highlight pane (press
d)Highlight a PR and press
d. A pane fetches the PR directly (forcing a freshmergeable),plus
statusCheckRollupand the last 5 commits:Merge: ✗ conflicting (DIRTY) CI: ✗ failingj/knever spraysAPI calls and nav stays responsive.
r(refresh) clears the cache to recompute fresh.?to the authoritative value.Implementation notes
mergeable+mergeStateStatuson the search/repo PR queries; a newPR_DETAIL_QUERY(mergeable,mergeStateStatus,commits(last:5)+ per-commitstatusCheckRollup).PullRequestgainsmergeable/merge_state_statusasOption<String>with#[serde(default)]so existing disk-cache entries still deserialize.pr_detailsmap (kept out of disk cache on purpose, forfreshness). Debounce is implemented in the event loop's
tokio::select!.dtoggles the pane; status-bar hint updated.Tracking (beads)
zombo-sash-eco-rpjg— merge-state column (implemented)zombo-sash-eco-zkk5— detail-on-highlight pane (implemented)zombo-sash-eco-9h3o— CI/checks glyph in the list column (follow-up)zombo-sash-eco-pp0u— filter/sort by merge state + legend (follow-up)