Files
dashboards/.agents/phases/todo/19_ups_events_expandable/00_phase.md
T
ducoterra 4b0f53c499 chore(agent): phase roadmap from TODO.md, 2 phases
Convert the two TODO items into append-mode phases (Protocol B):
18_nav_hamburger (TODO L3) and 19_ups_events_expandable (TODO L4),
numbered after the existing todo phases. TODO.md is cleared to an
empty list; its items now live in .agents/phases/todo/.

LLM-Generated: true
2026-10-20 10:37:30 -04:00

4.7 KiB
Raw Blame History

Phase 19 — Expandable UPS power-events list

Source: TODO.md L4 — "The UPS tab should have an expandable, clear list of last incidents with dates/times" Story: n/a Context: src/dashboards/web/pages/ups.html lines 72–76 (the Power events card: <header><h3> + a ul.events#events holding a loading… placeholder), src/dashboards/web/static/page-ups.js (refreshEvents() at line 430 — fetches /api/events?limit=200&source=ups and hands the rows to Dash.eventsPager with the date/time + severity-chip + host row shape; called unconditionally from refresh() at line 427, which the page's poll(refresh, state.pollMs) loop drives, state.pollMs from config.ups.poll_ms || 5000), src/dashboards/web/static/app.js (Dash.eventsPager — 50 rows a page, paging state in a WeakMap keyed by the <ul>, rows re-written only when their markup changed), src/dashboards/web/static/dash.css (details.charts-box at lines 714–727 — the summary marker ▸/▾, hidden webkit marker, hover; the .events bounded 320px scroll and .events-pager strip), and the pattern this phase mirrors — /system's per-host Charts disclosure (system.html line 81, page-system.js line 315: "a <details> renders nothing, so … nothing is built or drawn while the stack is shut") and its pin test_system_history_charts_are_collapsed_behind_a_toggle

Objective

The /ups power-events list becomes what the TODO asks for — expandable: the card is collapsed by default behind a <details> disclosure in the repo's own charts-box style, nothing is fetched or drawn while it is shut (the /system rule), the first expand fetches and builds, a re-expand paints from the data in hand unless it is stale, and the page's poll loop refreshes the list only while the disclosure is open. The "clear" half already ships and stays: every row carries its date/time, the severity chip, and the host, and the 50-per-page pager bounds the list. No new API surface — the existing /api/events?source=ups is the whole backend.

Dependencies

  • 18_nav_hamburger (todo) — both phases touch ups.html (the masthead, the events card); landing 18 first keeps this phase's diff confined to the events section. No shared code between them.

Tasks

  1. 01_events_disclosure.md — the ups.html markup: the card body becomes a collapsed-by-default <details class="events-box">
  2. 02_events_lazy_loading.md — page-ups.js: no fetch while closed, first-expand fetch, re-expand stale rule, poll-while-open
  3. 03_disclosure_css.md — dash.css: the details.events-box summary styling in the charts-box shape, pager and bounded list inside
  4. 04_tests_and_verification.md — the served-page pins (disclosure present and unopened, the lazy rule, the unchanged row shape) and the closed/open browser verification

Testing & Quality

  • Unit/integration: tests/test_api.py — the served-page pins (see task 04), alongside the untouched Dash.eventsPager behaviour (a re-paint with the same data keeps the reader's page — the WeakMap rule, pinned by the existing event-feed tests)
  • 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.md and AGENTS.md in 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 UI conventions section already documents the event pager ("An event feed is a window, not a printout") and the /system Charts disclosure; it gains the /ups disclosure's sentence (collapsed by default, lazy-built, poll-while-open, the stale rule) in the section's voice. The README's /ups table row ("power events") stays true — the list is on the page, now behind a summary.

Completion Criteria

  • /ups loads with the Power events card collapsed (a summary line, no list visible, no /api/events request in the page's first poll) and the expand shows the bounded, paged list with date/time rows
  • closing and re-opening within one poll interval paints the cached rows without a refetch; a stale cache refetches on open; while open, the poll loop keeps the list current
  • uv run pytest green, coverage not down, ruff + pyright clean
  • bash .agents/validate.sh green (including node --check of the modified page-ups.js)
  • closed- and open-state screenshots in data/logs/ against the running dev server (invariant 10)
  • no behavior change in completed work: every other element on /ups (cards, charts, dialog, pager behaviour) is unchanged