phase: 101_tokens_page_overhaul
All gates verified green — no defects found, nothing to fix. Final report:
## Phase 101 — final verification pass (all tasks already complete; verified, not re-implemented)
**Verified against the working tree** (task files 01–04 present in `complete/`):
- Active/revoked table split (Status column gone, section hidden while 0 revoked, per-table search with query state surviving re-renders) in `frontend/index.html` + `tokens.js`
- `generateToken()` refuses blank/whitespace names (`Give the token a name first.`, no request); `|| "token"` fallback deleted
- Atomic rotation: `regenerate_token` service + `POST /api/tokens/{id}/regenerate` (201 new-plaintext-once / 404 / 409 / router-wide 403) + `TokenListItem.revoked_at` (D5)
- Regenerate two-step confirm UI + CSS (`.token-regenerate`, neutral hover, no new hue); A4 pins intact
**Test / lint / coverage results:**
- `uv run pytest` → **2065 passed**
- `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99%** (>90% ✓)
- `uv run ruff check . && uv run pyright` → clean (0 errors)
- `uv run pytest tests/e2e/test_tokens_page.py -v --no-cov` → **4 passed** (isolation, DB up)
- Regression, each in isolation: `test_api_tokens.py` **9 passed**, `test_admin_auth.py` **6 passed**, `test_shared_header.py` **6 passed**, `test_theme_semantic_completion.py` **8 passed** (its revoked-pill pin was correctly re-scoped to the revoked table in this phase)
**Completion criteria:** 1 ✓ split+search (E2E 1–2) · 2 ✓ required name (E2E 3 + source pin) · 3 ✓ rotation end-to-end, old token refused at gate (E2E 4 + API 404/409 pinned) · 4 ✓ A4 holds (list carries no plaintext/hashes) · 5 ✓ suite/coverage/lint green · 6 ✓ E2E + regressions green in isolation · 7 commit left to the harness per executor rules (all changes uncommitted in the working tree)
**Deviations:** none. Next pending phase: `98_sync_summary_visibility`.
This commit is contained in:
@@ -367,12 +367,12 @@ def test_admin_generates_token_in_ui(page: Page, app_url: str, db_ready: None) -
|
||||
"Token created — copy it now; it won't be shown again."
|
||||
)
|
||||
|
||||
# The table shows the Active row: the em-dash status marker, no
|
||||
# The table shows the Active row (phase 101 D1: the Status column
|
||||
# is gone — the four-column active table IS the status): no
|
||||
# Revoked pill, a Revoke action.
|
||||
row = page.locator("#tokens-tbody tr", has_text="e2e-alice")
|
||||
expect(row).to_have_count(1)
|
||||
expect(row.locator("td.tokens-label-cell")).to_have_text("e2e-alice")
|
||||
expect(row.locator("td").nth(3)).to_have_text("—") # Active = the plain em-dash
|
||||
expect(row.locator(".stale-pill")).to_have_count(0)
|
||||
expect(row.locator("button.token-revoke")).to_have_count(1)
|
||||
|
||||
@@ -603,8 +603,14 @@ def test_revocation_closes_the_door(
|
||||
row.locator("button.token-revoke").click()
|
||||
expect(row.locator(".history-confirm-yes")).to_be_visible()
|
||||
row.locator(".history-confirm-yes").click()
|
||||
revoked = page.locator("#tokens-tbody tr", has_text="e2e-revoke")
|
||||
expect(revoked.locator(".stale-pill")).to_have_text("Revoked", timeout=15_000)
|
||||
# Phase 101 (D1): the row LEAVES the active table and lands in
|
||||
# the revoked table below with its Revoked date cell (the
|
||||
# em-dash / .stale-pill column is gone from both tables — the
|
||||
# table's position IS the status).
|
||||
revoked = page.locator("#tokens-revoked-tbody tr", has_text="e2e-revoke")
|
||||
expect(revoked).to_have_count(1, timeout=15_000)
|
||||
expect(revoked.locator(".stale-pill")).to_have_count(0)
|
||||
expect(revoked.locator("td.tokens-date-cell").last).not_to_be_empty()
|
||||
expect(page.locator("#tokens-status")).to_have_text('Revoked "e2e-revoke".')
|
||||
|
||||
# Enforcement is IMMEDIATE on the holder's next request (the
|
||||
|
||||
Reference in New Issue
Block a user