Rework PR page right column into one sectioned panel and PR list into flat divider rows (issues-surface idioms) — supersedes #521's structure #531

Closed
opened 2026-09-14 19:07:51 +00:00 by crueber · 3 comments
Owner

What's requested

Two structural reworks of the pull-request surfaces, both converging on idioms the issues surfaces already define. This supersedes the structure #521 introduced (its markdown/state/header work stands; only the right-column and list shapes are reworked).

1. PR page right column: ONE sectioned panel, not stacked sibling cards.

web/src/pages/Pull.jsx renders the right column (landed for #521) as a narrow rail of separate cards (Pull.jsx:864 <aside … class="grid content-start gap-3"> containing ReviewSummaryBar, a Mergeability .card (870), ReviewersPanel, a Checks .card (887), and MergeBox — each its own boxed card with its own card-header <h2>). The issues page solved exactly this shape in #107: one container, divided sections — web/src/pages/Issue.jsx:549 <section class="card divide-y divide-zinc-200 text-sm dark:divide-zinc-800" aria-label="Issue metadata"> with each section a p-3 block whose uppercase micro-label sits above its value. Rework the PR sidebar to the same idiom: one card divide-y panel whose sections are Mergeability / Reviewers / Checks / Merge (Review summary composing in first, as #521 already does). Each section keeps the issues-sidebar section anatomy: tiny uppercase label header + value directly beneath, so a "none" reads as that section's value.

Mergeability is a value, not a heading. Currently Pull.jsx:871 makes Mergeability an <h2 class="card-header"> with the status underneath as the content. In the sectioned panel it becomes a section's value: label row "Mergeability" (uppercase micro-label like Labels/Assignees/Milestone), and the value line carries mergeableText(mergeable()) (state-mapped wording from Pull.jsx:52) — keeping the existing sub-lines (base/head refs at Pull.jsx:878–884, pending-branch warning at 873, commits/files links at 886) inside the same section, as secondary value detail rather than card body prose.

2. PR list: flat hr-separated rows, not boxed cards.

web/src/pages/Pulls.jsx:116–133 renders the list as <ul class="card-list"> of <li class="card"> — one bordered box per PR, each with its own card-title / card-meta. The issues list is the established row idiom (web/src/pages/Issues.jsx:351–358, per #135): divider-separated rows, never boxed — border-t border-zinc-200 … first:border-t-0 rows inside a single container, echoing the ThreadTimeline comment-entry dividers from #109. Rework the PR list to those flat rows: one container, per-PR row = title link, state chip, label/reviewed affordances inline, right-aligned meta (branch refs or updated time, consistent with the issues row's right meta). Row anatomy mirrors Issues.jsx:359+ (truncation safety: min-w-0/max-w-full truncate title, wrapping chips, ml-auto right meta).

Evidence (static read of the current tree, at 0fdf7ab)

  • Pull.jsx:863–925: aside = grid content-start gap-3 of five sibling blocks; Mergeability card at 868–886 with h2.card-header at 871; Checks card 887–907 with its own card-header; ReviewSummaryBar and MergeBox are separate sibling cards.
  • Issue.jsx:549–552 and comment at 542–548: the #107 one-container/divided-sections idiom, including the "a none reads as that section's value" rationale — the reference implementation to copy.
  • Pulls.jsx:116–119: card-list of li.card; contrast Issues.jsx:358 li class="border-t border-zinc-200 py-3 first:border-t-0 …".
  • The app already establishes "divided sections, never stacked boxes" twice (#109 timeline, #135 list, #107 sidebar) — the PR surfaces are the remaining outliers after #521 landed its other work.

Architecture notes

  • No wire/API change: everything reworked is client-side composition of data both pages already fetch (pr, getView().mergeable, checks, reviewers, summary). No ETag concern — no cached payload changes.
  • MergeBox and ReviewSummaryBar keep their components/logic; only their container/context changes (sections of the panel instead of sibling cards). Checks section keeps CheckPill, ContextRows, ZeroChecksBlock, required/blocking sub-lines.
  • The card-header class usage in Pull.jsx shrinks to nothing in the sidebar (or only where a section truly needs an action row, like the Issues sidebar's label/milestone picker rows that sit in the section header flex).
  • Keep the merged-state chip work from #521 (chip-merged vocabulary, Pulls.jsx:124 interpolation) — the row rework reuses the same chip, not a new state treatment.

Acceptance criteria

  • PR page right column is ONE card divide-y sectioned panel in the Issue.jsx:549 idiom; no stacked sibling .card blocks remain in the aside.
  • Mergeability renders as a section value under an uppercase micro-label; no Mergeability card-header heading.
  • Sections carry the issues-sidebar anatomy (label + value + "none" fallbacks); Review summary, Reviewers, Checks, Merge all present as sections.
  • PR list rows are flat border-t-separated rows inside one container; no per-PR li.card boxes; truncation/wrapping safety matches the issues row.
  • Both surfaces match the sibling issues surfaces visually at desktop and mobile widths.
## What's requested Two structural reworks of the pull-request surfaces, both converging on idioms the issues surfaces already define. This supersedes the *structure* #521 introduced (its markdown/state/header work stands; only the right-column and list shapes are reworked). **1. PR page right column: ONE sectioned panel, not stacked sibling cards.** `web/src/pages/Pull.jsx` renders the right column (landed for #521) as a narrow rail of separate cards (`Pull.jsx:864` `<aside … class="grid content-start gap-3">` containing ReviewSummaryBar, a Mergeability `.card` (870), ReviewersPanel, a Checks `.card` (887), and MergeBox — each its own boxed card with its own `card-header` `<h2>`). The issues page solved exactly this shape in #107: one container, divided sections — `web/src/pages/Issue.jsx:549` `<section class="card divide-y divide-zinc-200 text-sm dark:divide-zinc-800" aria-label="Issue metadata">` with each section a `p-3` block whose uppercase micro-label sits above its value. Rework the PR sidebar to the same idiom: one `card divide-y` panel whose sections are Mergeability / Reviewers / Checks / Merge (Review summary composing in first, as #521 already does). Each section keeps the issues-sidebar section anatomy: tiny uppercase label header + value directly beneath, so a "none" reads as that section's value. **Mergeability is a value, not a heading.** Currently `Pull.jsx:871` makes `Mergeability` an `<h2 class="card-header">` with the status underneath as the content. In the sectioned panel it becomes a section's *value*: label row "Mergeability" (uppercase micro-label like Labels/Assignees/Milestone), and the value line carries `mergeableText(mergeable())` (state-mapped wording from `Pull.jsx:52`) — keeping the existing sub-lines (base/head refs at `Pull.jsx:878–884`, pending-branch warning at 873, commits/files links at 886) inside the same section, as secondary value detail rather than card body prose. **2. PR list: flat hr-separated rows, not boxed cards.** `web/src/pages/Pulls.jsx:116–133` renders the list as `<ul class="card-list">` of `<li class="card">` — one bordered box per PR, each with its own `card-title` / `card-meta`. The issues list is the established row idiom (`web/src/pages/Issues.jsx:351–358`, per #135): divider-separated rows, never boxed — `border-t border-zinc-200 … first:border-t-0` rows inside a single container, echoing the ThreadTimeline comment-entry dividers from #109. Rework the PR list to those flat rows: one container, per-PR row = title link, state chip, label/reviewed affordances inline, right-aligned meta (branch refs or updated time, consistent with the issues row's right meta). Row anatomy mirrors `Issues.jsx:359+` (truncation safety: `min-w-0`/`max-w-full truncate` title, wrapping chips, `ml-auto` right meta). ## Evidence (static read of the current tree, at 0fdf7ab) - `Pull.jsx:863–925`: aside = `grid content-start gap-3` of five sibling blocks; Mergeability card at 868–886 with `h2.card-header` at 871; Checks card 887–907 with its own `card-header`; ReviewSummaryBar and MergeBox are separate sibling cards. - `Issue.jsx:549–552` and comment at 542–548: the #107 one-container/divided-sections idiom, including the "a none reads as that section's value" rationale — the reference implementation to copy. - `Pulls.jsx:116–119`: `card-list` of `li.card`; contrast `Issues.jsx:358` `li class="border-t border-zinc-200 py-3 first:border-t-0 …"`. - The app already establishes "divided sections, never stacked boxes" twice (#109 timeline, #135 list, #107 sidebar) — the PR surfaces are the remaining outliers after #521 landed its other work. ## Architecture notes - No wire/API change: everything reworked is client-side composition of data both pages already fetch (`pr`, `getView().mergeable`, checks, reviewers, summary). No ETag concern — no cached payload changes. - `MergeBox` and `ReviewSummaryBar` keep their components/logic; only their container/context changes (sections of the panel instead of sibling cards). Checks section keeps `CheckPill`, `ContextRows`, `ZeroChecksBlock`, required/blocking sub-lines. - The `card-header` class usage in Pull.jsx shrinks to nothing in the sidebar (or only where a section truly needs an action row, like the Issues sidebar's label/milestone picker rows that sit in the section header flex). - Keep the merged-state chip work from #521 (`chip-merged` vocabulary, `Pulls.jsx:124` interpolation) — the row rework reuses the same chip, not a new state treatment. ## Acceptance criteria - [ ] PR page right column is ONE `card divide-y` sectioned panel in the `Issue.jsx:549` idiom; no stacked sibling `.card` blocks remain in the aside. - [ ] Mergeability renders as a section value under an uppercase micro-label; no `Mergeability` `card-header` heading. - [ ] Sections carry the issues-sidebar anatomy (label + value + "none" fallbacks); Review summary, Reviewers, Checks, Merge all present as sections. - [ ] PR list rows are flat `border-t`-separated rows inside one container; no per-PR `li.card` boxes; truncation/wrapping safety matches the issues row. - [ ] Both surfaces match the sibling issues surfaces visually at desktop and mobile widths.
crueber added this to the v1 milestone 2026-09-14 19:08:02 +00:00
Author
Owner

Fix ready for review: PR #542 (branch fix/issue-531) — one sectioned sidebar panel + flat PR-list rows, structure only, tests/build green.

Fix ready for review: PR #542 (branch fix/issue-531) — one sectioned sidebar panel + flat PR-list rows, structure only, tests/build green.
Author
Owner

Review: PR #542 (fix/issue-531 @ d880c65) — ready to merge

Reviewed the full diff (7 files, +274/-100) against every #531 acceptance criterion plus the #521/#274/#319/#328/#530 non-regression surface. Verified in a scratch worktree (symlinked node_modules, since removed); main worktree left untouched (still clean on main).

Acceptance criteria — all met

  • One sectioned panel: Pull.jsx:874 is a single section.card divide-y divide-zinc-200 text-sm dark:divide-zinc-800 (aria-label="Pull request metadata", the Issue.jsx:549 idiom). Grep of the aside confirms zero .card/card-list/card-header strings remain in the sidebar; remaining Pull.jsx .card/card-header hits (129-134 Reviews, 365 diff, 519-520 Finish review, 834/837 Files) are all conversation-column, as intended.
  • Mergeability as value: Pull.jsx:885-886 micro-label span + {mergeableText(mergeable())} value line; no Mergeability heading. Sub-lines intact: base/head refs (890-893), #328 fork line (895-898), pending-branch warning (887-888), commits/files links (900-903).
  • Section anatomy + order: Review summary first (875-878), then Mergeability / Reviewers / Checks / Merge — all p-3 with the uppercase micro-label, none-as-value fallbacks pinned (no reviews yet, none requested, ZeroChecksBlock, write-role gate note).
  • Flat list rows: Pulls.jsx:130-157 — bare <ul>, per-PR li.border-t … first:border-t-0 first:pt-0, byte-identical divider classes to Issues.jsx:368. Row anatomy mirrors Issues.jsx:369+: truncating title link (min-w-0 max-w-full truncate), #530 pullListChip unchanged, refs inline, ml-auto shrink-0 author · updated meta. Container parity holds (section[aria-label] + bare <ul> on both pages).
  • Shell shedding safe: ReviewSummaryBar + ReviewersPanel (Pull.jsx locals) and MergeBox shed .card/card-header and render as fragments/section values. Merge a11y kept: form[aria-label=Merge], merge-task aria-live + aria-label, machine-state value line. Checks keeps CheckPill/ContextRows/ZeroChecksBlock + required/blocking lines with fetch key + combined call byte-identical.

Non-regressions

  • #521 intact: renderBody+mdCtx at all 5 Pull.jsx call sites, pullBadgeView/closeVisibility/Close-Reopen/comment-and-close wiring untouched (diff never goes near them); conversation-column .card-header treatment pinned by the updated pull-event-text-521 test.
  • #274/#319 intact: Repo.jsx/tab bar/badges untouched (not in diff).
  • Gates/fetch/cache: every MergeBox prop (checksBlockers, reviewDecision, role, canUpdateBranch), checks: key, pulls.list(query()) identical — structural JSX/comment/test/doc change only.
  • Laws: no backend change, no new deps, no ui.css change (law 1); no tasks/concurrency surface (law 7); no extensibility-seam touch (law 8); 12_web_ui.md decision appended in the same commit, claims verified accurate — incl. the .card-meta leaves the Pulls list, stays on the ReviewsList card note (Pull.jsx:135 is now the only .card-meta) (law 12).

Verification (scratch worktree @ d880c65, removed afterward)

  • node --test web/test/unit/*.test.js: 1241 total / 1240 pass / 1 fail — all 10 new pr-structure-531 tests green; the 1 failure is the live-server smoke subtest (/setup 403 vs 200), proven pre-existing by running smoke.test.js head-to-head on pristine origin/main (identical 403 failure).
  • vite build: green (exit 0, 2.24s).
  • No browser drive per review instructions (node tests + reasoning from the shared row/panel classes); browser proof stays open as the PR description already notes. Two cosmetic non-blockers noted for follow-up, not merge gates: summary section uses plain p-3 while siblings use grid gap-1 p-3, and the aside keeps a single-child grid … gap-3 wrapper — both harmless.

MERGE RECOMMENDATION: ready to merge (no fixes pushed — nothing blocking found; not merging per instructions).

## Review: PR #542 (fix/issue-531 @ d880c65) — ready to merge Reviewed the full diff (7 files, +274/-100) against every #531 acceptance criterion plus the #521/#274/#319/#328/#530 non-regression surface. Verified in a scratch worktree (symlinked node_modules, since removed); main worktree left untouched (still clean on main). ### Acceptance criteria — all met - [x] **One sectioned panel**: Pull.jsx:874 is a single `section.card divide-y divide-zinc-200 text-sm dark:divide-zinc-800` (`aria-label="Pull request metadata"`, the Issue.jsx:549 idiom). Grep of the aside confirms zero `.card`/`card-list`/`card-header` strings remain in the sidebar; remaining Pull.jsx `.card`/`card-header` hits (129-134 Reviews, 365 diff, 519-520 Finish review, 834/837 Files) are all conversation-column, as intended. - [x] **Mergeability as value**: Pull.jsx:885-886 micro-label span + `{mergeableText(mergeable())}` value line; no Mergeability heading. Sub-lines intact: base/head refs (890-893), #328 fork line (895-898), pending-branch warning (887-888), commits/files links (900-903). - [x] **Section anatomy + order**: Review summary first (875-878), then Mergeability / Reviewers / Checks / Merge — all `p-3` with the uppercase micro-label, none-as-value fallbacks pinned (`no reviews yet`, `none requested`, ZeroChecksBlock, write-role gate note). - [x] **Flat list rows**: Pulls.jsx:130-157 — bare `<ul>`, per-PR `li.border-t … first:border-t-0 first:pt-0`, byte-identical divider classes to Issues.jsx:368. Row anatomy mirrors Issues.jsx:369+: truncating title link (`min-w-0 max-w-full truncate`), #530 `pullListChip` unchanged, refs inline, `ml-auto shrink-0` author · updated meta. Container parity holds (`section[aria-label]` + bare `<ul>` on both pages). - [x] **Shell shedding safe**: ReviewSummaryBar + ReviewersPanel (Pull.jsx locals) and MergeBox shed `.card`/`card-header` and render as fragments/section values. Merge a11y kept: `form[aria-label=Merge]`, merge-task `aria-live` + `aria-label`, machine-state value line. Checks keeps CheckPill/ContextRows/ZeroChecksBlock + required/blocking lines with fetch key + combined call byte-identical. ### Non-regressions - **#521 intact**: renderBody+mdCtx at all 5 Pull.jsx call sites, pullBadgeView/closeVisibility/Close-Reopen/comment-and-close wiring untouched (diff never goes near them); conversation-column `.card-header` treatment pinned by the updated pull-event-text-521 test. - **#274/#319 intact**: Repo.jsx/tab bar/badges untouched (not in diff). - **Gates/fetch/cache**: every MergeBox prop (`checksBlockers`, `reviewDecision`, `role`, `canUpdateBranch`), `checks:` key, `pulls.list(query())` identical — structural JSX/comment/test/doc change only. - **Laws**: no backend change, no new deps, no ui.css change (law 1); no tasks/concurrency surface (law 7); no extensibility-seam touch (law 8); 12_web_ui.md decision appended in the same commit, claims verified accurate — incl. the `.card-meta leaves the Pulls list, stays on the ReviewsList card` note (Pull.jsx:135 is now the only `.card-meta`) (law 12). ### Verification (scratch worktree @ d880c65, removed afterward) - `node --test web/test/unit/*.test.js`: **1241 total / 1240 pass / 1 fail** — all 10 new pr-structure-531 tests green; the 1 failure is the live-server smoke subtest (`/setup 403 vs 200`), proven pre-existing by running smoke.test.js head-to-head on pristine origin/main (identical 403 failure). - `vite build`: green (exit 0, 2.24s). - No browser drive per review instructions (node tests + reasoning from the shared row/panel classes); browser proof stays open as the PR description already notes. Two cosmetic non-blockers noted for follow-up, not merge gates: summary section uses plain `p-3` while siblings use `grid gap-1 p-3`, and the aside keeps a single-child `grid … gap-3` wrapper — both harmless. **MERGE RECOMMENDATION: ready to merge** (no fixes pushed — nothing blocking found; not merging per instructions).
Author
Owner

Fixed by PR #542 (review clean — all 5 criteria pass, #521 intact, gates untouched), merged. Closing.

Fixed by PR #542 (review clean — all 5 criteria pass, #521 intact, gates untouched), merged. Closing.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
crueber/walhub#531
No description provided.