Owner tab strip belongs at the top of the page; non-profile tabs must not render the profile header #435

Closed
opened 2026-09-13 04:00:45 +00:00 by crueber · 3 comments
Owner

Follow-up to #422/#430 (tab strip) and #421 (sidebar layout).

Two defects on the owner surface (web/src/pages/Repos.jsx, OwnerPage):

  1. Tab strip is buried mid-page. OwnerTabs renders at Repos.jsx:518-520 inside .profile-main BELOW the identity header block (:434+, username/bio/edit form). A tab strip controls the content below it — sitting under a full identity header it reads as a subsection nav, not the page controller. Move it to the top of the page (directly below the navbar, above the username/identity content) on all three owner routes, keeping the Repo.jsx tab-bar anatomy, active underline, and aria-current.

  2. Non-profile tabs still render the profile. The identity header block is gated only on !isOrg() (:434) with no view gate, so /:owner/repositories and /:owner/organizations render the full profile identity (username, bio, edit affordances) plus sidebar above the tab content. The profile header (and sidebar — verify whether it is view-gated) must render ONLY on view() === 'profile'; the repos/orgs views render the tab strip + their own content only.

Acceptance criteria:

  • Tab strip is the first element of the owner page flow (below navbar, above identity content) on /:owner, /:owner/repositories, and /:owner/organizations; active-tab underline + aria-current correct per route.
  • /:owner/repositories and /:owner/organizations render NO profile identity header and NO profile sidebar — tab strip + view content only.
  • /:owner renders exactly as today (header + sidebar + teaser), with the strip moved to the top.
  • Org variant keeps working (Profile | Repositories, no Organizations tab); gates/fetches/cache keys unchanged — layout/markup only.
  • 390px clean; headless tests updated (active-tab derivation + view-gating pins); vite build green.
Follow-up to #422/#430 (tab strip) and #421 (sidebar layout). Two defects on the owner surface (web/src/pages/Repos.jsx, OwnerPage): 1. Tab strip is buried mid-page. OwnerTabs renders at Repos.jsx:518-520 inside .profile-main BELOW the identity header block (:434+, username/bio/edit form). A tab strip controls the content below it — sitting under a full identity header it reads as a subsection nav, not the page controller. Move it to the top of the page (directly below the navbar, above the username/identity content) on all three owner routes, keeping the Repo.jsx tab-bar anatomy, active underline, and aria-current. 2. Non-profile tabs still render the profile. The identity header block is gated only on !isOrg() (:434) with no view gate, so /:owner/repositories and /:owner/organizations render the full profile identity (username, bio, edit affordances) plus sidebar above the tab content. The profile header (and sidebar — verify whether it is view-gated) must render ONLY on view() === 'profile'; the repos/orgs views render the tab strip + their own content only. Acceptance criteria: - [ ] Tab strip is the first element of the owner page flow (below navbar, above identity content) on /:owner, /:owner/repositories, and /:owner/organizations; active-tab underline + aria-current correct per route. - [ ] /:owner/repositories and /:owner/organizations render NO profile identity header and NO profile sidebar — tab strip + view content only. - [ ] /:owner renders exactly as today (header + sidebar + teaser), with the strip moved to the top. - [ ] Org variant keeps working (Profile | Repositories, no Organizations tab); gates/fetches/cache keys unchanged — layout/markup only. - [ ] 390px clean; headless tests updated (active-tab derivation + view-gating pins); vite build green.
Author
Owner

Fix ready for review: #436 (branch fix/issue-435). Strip leads the page on all three owner routes; identity header + sidebars render only on view()==='profile'. Layout/markup only — no backend change, no new deps. node --test 912 total / 910 pass / 2 fail (pre-existing live-server smoke tests, identical before/after); vite build green.

Fix ready for review: https://git.packden.us/crueber/walhub/pulls/436 (branch fix/issue-435). Strip leads the page on all three owner routes; identity header + sidebars render only on view()==='profile'. Layout/markup only — no backend change, no new deps. node --test 912 total / 910 pass / 2 fail (pre-existing live-server smoke tests, identical before/after); vite build green.
Author
Owner

REVIEW PR #436 (fix/issue-435) — verified in scratch worktree /tmp/pr436 (removed afterward; main worktree untouched, still clean on main).

All 5 acceptance criteria hold:

  1. Strip first in flow (Repos.jsx:422): is the first element inside .repos-page, before the identity layout (:446), header (:449), and h1, outside every (no view()/isOrg() gate between page root and strip). OwnerTabs itself untouched — nav anatomy (owner-tabs mb-4 flex max-w-full overflow-x-auto whitespace-nowrap border-b), three-way pathname derivation, per-tab active underline + aria-current intact. Spacing note (non-blocking): the old mid-page
    wrapper is gone; top spacing now comes from the app shell (App.jsx:126) + nav's own mb-4 — correct at the top.
  2. View-gating (Repos.jsx:428-636): one outer <Show when={view()==='profile'}> wraps the whole identity layout — header, teaser, AND both sidebars (Profile actions :565, Organization actions :615). Repos branch (:640) and orgs branch (:695) contain none of profile-header/profile-sidebar/Profile actions/Organization actions/

    /View-all; repos keeps toolbar+grid, orgs keeps orgs-rail.

  3. Byte-identical moves: normalized (comment/whitespace-insensitive) comparison of the toolbar+grid+import block and the orgs-rail section vs main → both IDENTICAL. Inner redundant <Show when={view()==='profile'}> teaser gate (:531) inside the outer gate is harmless.
  4. /:owner as today: profile branch keeps header+h1+displayName+both sidebars+teaser deep-link; no toolbar/grid/rail inside. Org variant keeps Profile|Repositories (isOrg gate on third tab intact), org identity + Manage in profile branch.
  5. Pins are REAL, not weakened: confirmed the admitted vacuous case by analysis (old slice from isOrg-Show to strip would return '' post-move, passing trivially). Rewrite slices from page root with balanced-Show + no-view/no-variant + strip-before-layout pins. profile-header retargets verified sane: org-Show at main+2899 < teaser-gate at main+4259, toolbar/RepoRow confirmed ABSENT from main column; sidebar-421 now asserts absence (stronger, correct post-move).
  6. Gates/fetches/keys/routes unchanged: 0 .go files; changed files are exactly Repos.jsx + 12_web_ui.md + 5 test files; index.jsx routes untouched; new test pins all six cache keys + nine gates byte-identical.
  7. 390px: strip max-w-full/overflow-x-auto/whitespace-nowrap/shrink-0 pinned; toolbar flex-wrap, grid-cols-1 stacking, no w-[ fixed widths in any branch. No new deps (no package.json change). Docs entry numbers match my measured results exactly.

TESTS (scratch worktree, node_modules symlinked from main): full node --test web/test/unit/*.test.js → 912 total / 910 pass / 2 fail; the 2 failures are the pre-existing live-server smoke tests (identical 2 fail on pristine main, smoke.test.js 1/3 pass). Touched files (435+422+430+421+header+header-403) → 49/49 pass. vite build green (2.35s). No browser drive per review instructions (node tests + source reasoning only).

No fixes needed — nothing pushed. MERGE RECOMMENDATION: ready to merge.

REVIEW PR #436 (fix/issue-435) — verified in scratch worktree /tmp/pr436 (removed afterward; main worktree untouched, still clean on main). All 5 acceptance criteria hold: 1. Strip first in flow (Repos.jsx:422): <OwnerTabs> is the first element inside .repos-page, before the identity layout (:446), header (:449), and h1, outside every <Show> (no view()/isOrg() gate between page root and strip). OwnerTabs itself untouched — nav anatomy (owner-tabs mb-4 flex max-w-full overflow-x-auto whitespace-nowrap border-b), three-way pathname derivation, per-tab active underline + aria-current intact. Spacing note (non-blocking): the old mid-page <div class=mt-6> wrapper is gone; top spacing now comes from the app shell <main px-4 py-6> (App.jsx:126) + nav's own mb-4 — correct at the top. 2. View-gating (Repos.jsx:428-636): one outer <Show when={view()==='profile'}> wraps the whole identity layout — header, teaser, AND both sidebars (Profile actions :565, Organization actions :615). Repos branch (:640) and orgs branch (:695) contain none of profile-header/profile-sidebar/Profile actions/Organization actions/<h1>/View-all; repos keeps toolbar+grid, orgs keeps orgs-rail. 3. Byte-identical moves: normalized (comment/whitespace-insensitive) comparison of the toolbar+grid+import block and the orgs-rail section vs main → both IDENTICAL. Inner redundant <Show when={view()==='profile'}> teaser gate (:531) inside the outer gate is harmless. 4. /:owner as today: profile branch keeps header+h1+displayName+both sidebars+teaser deep-link; no toolbar/grid/rail inside. Org variant keeps Profile|Repositories (isOrg gate on third tab intact), org identity + Manage in profile branch. 5. Pins are REAL, not weakened: confirmed the admitted vacuous case by analysis (old slice from isOrg-Show to strip would return '' post-move, passing trivially). Rewrite slices from page root with balanced-Show + no-view/no-variant + strip-before-layout pins. profile-header retargets verified sane: org-Show at main+2899 < teaser-gate at main+4259, toolbar/RepoRow confirmed ABSENT from main column; sidebar-421 now asserts absence (stronger, correct post-move). 6. Gates/fetches/keys/routes unchanged: 0 .go files; changed files are exactly Repos.jsx + 12_web_ui.md + 5 test files; index.jsx routes untouched; new test pins all six cache keys + nine gates byte-identical. 7. 390px: strip max-w-full/overflow-x-auto/whitespace-nowrap/shrink-0 pinned; toolbar flex-wrap, grid-cols-1 stacking, no w-[ fixed widths in any branch. No new deps (no package.json change). Docs entry numbers match my measured results exactly. TESTS (scratch worktree, node_modules symlinked from main): full node --test web/test/unit/*.test.js → 912 total / 910 pass / 2 fail; the 2 failures are the pre-existing live-server smoke tests (identical 2 fail on pristine main, smoke.test.js 1/3 pass). Touched files (435+422+430+421+header+header-403) → 49/49 pass. vite build green (2.35s). No browser drive per review instructions (node tests + source reasoning only). No fixes needed — nothing pushed. MERGE RECOMMENDATION: ready to merge.
Author
Owner

Fixed by PR #436 (review clean — strip-first verified, both sidebars view-gated, byte-identical moves, pins real), merged. Closing.

Fixed by PR #436 (review clean — strip-first verified, both sidebars view-gated, byte-identical moves, pins real), 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#435
No description provided.