**Phase 20 final verification pass — all four tasks already complete; verified in full.** - Verified: three-row masthead CSS (`.masthead` flex-wrap + two `flex-basis: 100%`, `min-height`, no `margin-inline-start`), un-sticky `position: relative` + `z-index: 40`, 180 ms `visibility/opacity/transform` slide (closed `nav.tabs` / open `.is-open`, both states in the file's single reduced-motion block), both admin links on all 8 signed-in pages, `/login` neither. - `uv run pytest` → **1464 passed, 15 skipped** · `uv run pytest --cov --cov-fail-under=94` → **98.94%** (floor 94, unchanged) · `ruff check src tests agent` clean · `pyright` 0 errors · **`bash .agents/validate.sh` EXIT=0** (incl. `node --check` + repo hygiene) · `uv run pytest -m live --live` → **11 passed**. - Browser (live dev server, invariant 10): `20-task01-rows.cjs` 121 PASS/0 FAIL · `20-task02-unsticky.cjs` 81/0 · `20-task03-slide.cjs` 32/0 · `20-task04-admin-links.cjs` 87/0 · phase-18 `nav-final-pass.cjs` 45/45, `nav-task03-verify` 77, `nav-task04-verify` 24/24 · phase-19 scripts 11/22/24/29 all pass. Screenshots refreshed in `data/logs/` (`masthead-rows*`, `masthead-unsticky*`, `slide-*`, `admin-links-*`). Dev server restarted; `/api/health` all nine sources `ok`. - Completion criteria: 3-row bar @1280/360 ✓ · scroll leaves bar behind + dropdown under whole bar ✓ · slide out/in 180 ms, reduced-motion snap ✓ · `/certs`→`⚷ Certs`, `/settings`→`⚙ Account` before theme toggle, outside `.tabs` ✓ · pytest/coverage/ruff/pyright ✓ · validate ✓ · no regression in tab structure, token reveal, safe-area padding, four close paths, status dots, theme toggle ✓. - Docs: **AGENTS.md** gap 12 still said phase 20 was "in `todo/`… admin-link half has landed" and attributed the wrap to the old fixed 58 px row — rewritten to the completed state (three rows/un-sticky/slide/both links; 24 still todo; 21's `/certs` `.scroll` noted as not reaching `/`'s table). **README.md** `web/` bullet enumerated the controls row without `⏸ Pause` and omitted `/login` from the two-row list — both fixed. Everything else (setup, commands, env table vs `config.py`, routes vs `api.py`, agent/installer flags, testing policy) verified consistent. - Deviations: no dependency bump — `uv pip list --outdated` still reports the pre-existing advisory `fastapi 0.153.0 → 0.156.4` (deps untouched this phase, validate treats it as advisory); `NOTES.md` is empty in the working tree from an operator edit outside these tasks (both items live in phases 20/24) — left as-is; no live-infra changes made or needed. - Next pending phase: `21_page_cleanups` (pause button removal, `/system` GPU values, `/certs` table scroll).
5.0 KiB
Phase 20 — Masthead & navigation polish
Source: TODO.md L4, L5, L6, L10, L11 — "masthead row layout, un-sticky bar, hamburger animation, always-visible admin links"
Story: n/a
Context: src/dashboards/web/static/dash.css (.masthead at line 99 — position: sticky; top: 0; z-index: 40; display: flex; height: var(--header-h); .masthead-right at line 148 — margin-inline-start: auto; #nav-toggle at line 190 — the --nav-toggle-display token reveal; the ≤640px block at lines 208–280 — masthead wrap, masthead-right { justify-content: flex-end }, the nav.tabs dropdown at top: 100% under the sticky bar, the env(safe-area-inset-top, 0px) padding line), src/dashboards/web/static/app.js (the setNavMenu() funnel at lines 695–722 — four close paths, matchMedia('(max-width: 640px)')), src/dashboards/web/pages/*.html (the masthead in every page: brand, #nav-toggle, nav.tabs#nav-tabs, .masthead-right holding #nav-status + clock + ⚷ Certs + ⚙ Account + theme toggle; certs.html lacks ⚷ Certs, settings.html lacks ⚙ Account — the phase-15 "no self-link" rule this phase inverts), tests/test_api.py (test_every_page_links_to_both_admin_pages at line 999, test_the_disks_tab_is_in_the_masthead_of_every_page at line 3913, test_the_nav_toggle_is_in_the_masthead_of_every_tabbed_page at line 3957)
Objective
The masthead becomes a three-row bar at all widths — row 1 the brand and the five dashboard tabs, row 2 the per-source status indicators left-justified in their own row, row 3 the ⚷ Certs / ⚙ Account / ☾ Dark controls left-justified in their own row under the indicators — the bar stops being sticky (it scrolls away, maximising data screen space), the hamburger menu slides out and back in (180 ms, the brain_of_reese pattern, stilled under prefers-reduced-motion), and both admin links stay visible on every page including the two admin pages themselves. The served page markup is unchanged except the two added admin links; the tab structure (five links, one aria-current), the #nav-toggle token reveal, the safe-area padding line and the four close paths all stay exactly as phase 18 pinned them.
Dependencies
19_ups_events_expandable(todo) — both phases touchups.html(the masthead, the events card); landing 19 first keeps this phase's diff confined to the masthead.
Tasks
01_two_row_masthead.md— the three-row left-justified masthead at all widths (CSS-only reflow; the mobile block re-cut for the new rows)02_unsticky_masthead.md— the bar scrolls away:sticky→relative, the dropdown anchor kept03_hamburger_slide.md— the 180 ms slide+fade on the ≤640px dropdown, stilled underprefers-reduced-motion04_admin_links_visible.md—⚷ Certson/certs,⚙ Accounton/settings; the "no self-link" pin inverted to "all eight pages link to both"
Testing & Quality
- Unit/integration:
tests/test_api.py— the served-page pins (task 04's rewritten admin-link test over all eight non-login pages, the unchanged tab-structure pins at lines 3913/3957, the CSS pins for the row layout and the un-sticky change), the unchangedsetNavMenubehaviour - Coverage: >90% on new/modified code (the phase is markup + JS + CSS; the gate applies to the changed Python test files)
- The phase is "Complete" only when the entire project test suite passes 100% (every test in the project, not just this phase's)
Documentation & Consistency
- The final pass reviews
README.mdandAGENTS.mdin full against the project as it stands after this phase — fixing every inconsistency found, including pre-existing ones not caused by this phase. AGENTS.md's masthead paragraph (the phase-18 "specificity ladder" and thetop: 100%-under-the-sticky-bar wording) and the phase-15 "neither admin page links to itself" sentence (gap 12's "now questioned" item — this phase is the decision) both get rewritten to the new state in the section's voice.
Completion Criteria
- at 1280 px and at 360 px, every tabbed page and both admin pages render the three-row masthead: brand + tabs, left-justified indicators row, left-justified controls row under it (screenshots in
data/logs/, invariant 10) - scrolling any page at 1280 px and 360 px leaves the bar behind (no sticky offset), while the mobile dropdown still opens directly under the bar
- at 360 px the hamburger menu slides out and back in (180 ms); with
prefers-reduced-motionit snaps /certsrenders⚷ Certsand/settingsrenders⚙ Account, before the theme toggle and outside.tabs, exactly like the five dashboardsuv run pytestgreen, coverage not down,ruff+pyrightcleanbash .agents/validate.shgreen (includingnode --checkof the modifiedapp.js)- no behavior change in completed work: the tab structure, the token reveal, the safe-area padding line, the four close paths, the status dots and the theme toggle are all unchanged