feat(ui): rename nav items — "Sources" becomes "RAG", "Git sources" becomes "Sources"

Owner request (2026-08-28): the two admin-only nav items read like the
same thing, so they are relabeled — the document-catalog link
(#nav-sources, /sources.html) becomes "RAG" and the source-manager link
(#nav-git-sources, /git-sources.html) becomes "Sources".

Phase 48 (48_nav_rename_sources), label-only per the locked decision:
- all six pages (index, sources, git-sources, tuning, document, login):
  the two <a> texts swap; ids, hrefs, hidden defaults, is-active /
  aria-current placement, and nav order (Chat, RAG, Sources, Tuning)
  are byte-unchanged otherwise.
- header.js: comment/docstring label mentions only — the reveal-by-id
  logic is untouched (ship-hidden/reveal contract intact).
- test_git_sources_admin.py / test_mobile_hamburger_nav.py: the two
  suites that asserted the old label text are updated; comment-only
  label fixes in test_shared_header.py / test_nav_consistency.py.
- tests/e2e/test_nav_rename_sources.py: the story E2E (green in
  isolation) — renamed labels + unchanged hrefs/order/markers on all
  six pages, click navigation with the active marker, the anonymous
  ship-hidden contract, and regression guards for the untouched
  controls (#sync-label "Sync sources", viewer #doc-back "Sources").
- All eight surrounding header/nav suites stay green in isolation;
  unit+integration green, app/ coverage 99% (frontend-only change),
  ruff + pyright clean.

Note: per this phase file-level staging, the six page files and
header.js also carry the same-day in-flight owner rework that was
already in the working tree when phase 48 ran (mobile sign-in dropdown
copy, sync button ship-hidden on the Sources page); the label rename
itself is the two-text swap on each page.
This commit is contained in:
2026-08-28 12:33:18 -04:00
parent 03bead092c
commit 872a07cee7
17 changed files with 785 additions and 118 deletions
+54 -26
View File
@@ -19,19 +19,22 @@ sources, document viewer, global tuning, login): one shared markup block
Per role, the VISIBLE inventory:
* admin: brand + nav [Chat, #nav-sources, #nav-git-sources, #nav-tuning]
(four links, that order — the Git sources link joined in phase 35,
owner permission 2026-08-26) + #sync-btn + #new-chat-btn +
#sign-out-btn (with #sign-in-link hidden) — on all five pages, same
id+class inventory, same DOM order. The #steering-toggle was removed
from the navbar at owner request (2026-08-28); note management lives
on /tuning.html;
(four links, that order — the "Sources" link joined in phase 35 as
"Git sources", owner permission 2026-08-26) + #sign-out-btn (with
#sign-in-link
hidden) — on all five pages, same id+class inventory, same DOM order.
The #sync-btn (Sources page only) and the #new-chat-btn (chat page
only) left the shared bar at owner request (2026-08-28 — they are
page-specific now, so the per-page visible inventory differs for
exactly those two); the #steering-toggle was removed from the navbar
the same day; note management lives on /tuning.html;
* anonymous: brand + nav [Chat] (#nav-sources / #nav-git-sources /
#nav-tuning hidden — locked A10 UI revision) + #new-chat-btn +
#sign-in-link (with #sync-btn hidden, #sign-out-btn hidden) on all
five pages — and the steering toggle (removed at owner request,
2026-08-28) + panel are ABSENT from the DOM (the panel via the phase
16 "absent, not hidden" treatment, carried into phase 34 task 01;
test_admin_auth pins it).
#nav-tuning hidden — locked A10 UI revision) + #sign-in-link (with
#sign-out-btn hidden; the Sources page's #sync-btn stays ship-hidden)
on all five pages — and the steering toggle (removed at owner
request, 2026-08-28) + panel are ABSENT from the DOM (the panel via
the phase 16 "absent, not hidden" treatment, carried into phase 34
task 01; test_admin_auth pins it).
Normalization for the inventory comparison: the current-page ``is-active``
nav marker and the sign-in ``?next=`` value legitimately differ per page,
@@ -47,9 +50,10 @@ Steering off-chat: on /tuning.html (admin, zero notes) the navbar
carries no steering toggle (removed at owner request, 2026-08-28) — the
header #steering-panel section still ships hidden and the Tuning
page's own note list shows the empty state — no chat needed. Sync is
present, not triggered: #sync-btn is visible on /tuning.html but is
never clicked here (a real sync clones real repos — the full state
machine is test_sync_button.py's job).
present, not triggered: #sync-btn is visible on /sources.html (its
home since the owner rework 2026-08-28) but is never clicked here (a
real sync clones real repos — the full state machine is
test_sync_button.py's job).
Determinism note: every assertion is settled-state — each page visit
first waits for the whoami toggle to land (exactly one of Sign in /
@@ -65,7 +69,7 @@ Test → story mapping (Playwright Mapping Rule):
3. ``test_viewer_row1_height_matches_chat_and_titlebar_present``
4. ``test_viewer_back_link_honors_back_param``
5. ``test_steering_surface_off_chat_on_tuning_page``
6. ``test_sync_button_present_on_tuning_page_without_triggering``
6. ``test_sync_button_present_on_sources_page_without_triggering``
"""
from __future__ import annotations
@@ -177,7 +181,11 @@ def _header_inventory(page: Page) -> list[str]:
``page`` is showing (normalized — see _INVENTORY_JS)."""
inv = page.evaluate(_INVENTORY_JS)
assert inv is not None, "no `header .header-inner` on this page"
assert len(inv) >= 8, f"header control inventory unexpectedly short: {inv}"
# Shared bar: brand + the four nav links + Sign in + Sign out = 7
# (the #sync-btn / #new-chat-btn selectors keep matching nothing —
# they left the bar with the owner rework 2026-08-28; the steering
# toggle was removed the same day).
assert len(inv) >= 7, f"header control inventory unexpectedly short: {inv}"
return inv
@@ -220,8 +228,9 @@ def _visit(page: Page, app_url: str, name: str, url: str, admin: bool) -> list[s
expect(page.locator(".app-nav a[href='/']")).to_be_visible() # Chat
if admin:
expect(page.locator("#nav-sources")).to_be_visible()
# Phase 35: the fourth admin-only nav link (Git sources) is
# revealed on every page, between Sources and Tuning.
# Phase 35: the fourth admin-only nav link (now "Sources",
# shipped as "Git sources") is revealed on every page, between
# RAG and Tuning.
expect(page.locator("#nav-git-sources")).to_be_visible()
expect(page.locator("#nav-tuning")).to_be_visible()
# The steering toggle was removed from the navbar at owner
@@ -229,7 +238,15 @@ def _visit(page: Page, app_url: str, name: str, url: str, admin: bool) -> list[s
assert page.locator("#steering-toggle").count() == 0, (
f"{name}: the steering toggle was removed from the navbar"
)
expect(page.locator("#sync-btn")).to_be_visible()
# The Sync button is a page-specific control (Sources page only
# — owner rework 2026-08-28): visible on sources, absent from
# the shared bar everywhere else.
if name == "sources":
expect(page.locator("#sync-btn")).to_be_visible()
else:
assert page.locator("#sync-btn").count() == 0, (
f"{name}: #sync-btn left the shared bar (Sources page only)"
)
expect(page.locator("#sign-out-btn")).to_be_visible()
expect(page.locator("#sign-in-link")).to_be_hidden()
else:
@@ -252,7 +269,14 @@ def _visit(page: Page, app_url: str, name: str, url: str, admin: bool) -> list[s
assert page.locator("#steering-panel").count() == 0, (
f"{name}: the steering panel must be absent for anonymous"
)
expect(page.locator("#new-chat-btn")).to_be_visible()
# The New chat button is chat-page only (moved from the shared bar
# to index.html's .chat-shell at owner request, 2026-08-28).
if name == "chat":
expect(page.locator("#new-chat-btn")).to_be_visible()
else:
assert page.locator("#new-chat-btn").count() == 0, (
f"{name}: #new-chat-btn left the shared bar (chat page only)"
)
_assert_landmarks(page, name)
return _header_inventory(page)
@@ -302,10 +326,12 @@ def _admin_login_page_inventory(page: Page, app_url: str) -> list[str]:
assert page.locator("#steering-toggle").count() == 0, (
"login: the steering toggle was removed from the navbar"
)
expect(page.locator("#sync-btn")).to_be_visible()
# Page-specific controls are NOT on the auth page (owner rework
# 2026-08-28: sync → Sources page, new chat → chat page).
assert page.locator("#sync-btn").count() == 0
assert page.locator("#new-chat-btn").count() == 0
expect(page.locator("#sign-out-btn")).to_be_visible()
expect(page.locator("#sign-in-link")).to_be_hidden()
expect(page.locator("#new-chat-btn")).to_be_visible()
_assert_landmarks(page, "login")
return _header_inventory(page)
finally:
@@ -482,14 +508,16 @@ def test_steering_surface_off_chat_on_tuning_page(
# ---------------------------------------------------------------------------
def test_sync_button_present_on_tuning_page_without_triggering(
def test_sync_button_present_on_sources_page_without_triggering(
page: Page, app_url: str, mock_llm: int, db_ready: None
) -> None:
page.set_viewport_size({"width": 1280, "height": 800})
_seed_db(mock_llm)
login(page, app_url, next=TUNING_URL)
expect(page).to_have_url(app_url + TUNING_URL, timeout=30_000)
# The button's home is the Sources page (owner rework 2026-08-28 —
# it left the shared navbar).
login(page, app_url, next=SOURCES_URL)
expect(page).to_have_url(app_url + SOURCES_URL, timeout=30_000)
expect(page.locator("#sign-out-btn")).to_be_visible(timeout=15_000)
btn = page.locator("#sync-btn")