Skip to content

feat(dashboard): two-level nav, live ticker, and polish (PR-A)#151

Merged
surpradhan merged 3 commits into
mainfrom
feat/dashboard-nav-polish
Jun 25, 2026
Merged

feat(dashboard): two-level nav, live ticker, and polish (PR-A)#151
surpradhan merged 3 commits into
mainfrom
feat/dashboard-nav-polish

Conversation

@surpradhan

Copy link
Copy Markdown
Owner

What does this PR do?

Redesigns src/public/dashboard.html across two axes: navigation structure and interaction polish. No backend changes, no new CI job.

Changes

Nav restructure — flat 8-tab bar → 3 primary tabs (Observe / Analyze / Ops) with contextual sub-navs revealed per group. switchGroup() handles primary-tab clicks; syncPrimaryNav() keeps both levels in sync. Hash routing (#sessions, #analytics, etc.) preserved unchanged — existing deep-links continue to work.

Live pill — replaced static "Live" / "Reconnecting…" with a real setInterval ticker: Live · updated Xs ago / Disconnected · last seen Xs ago. Timestamp resets on every event.received SSE tick.

Honest export — export buttons show Preparing… (disabled) for 1.8s then revert. Previously no feedback was given even though window.location.href has no JS completion event.

Clickable metric cards — Sessions, Rejected, Workflows cards act as deep-links to their respective views. Events Received and Accepted have no corresponding view and remain non-clickable.

Actionable empty states — sessions empty state now shows the emit command; workflows empty state explains trace_id grouping.

Type floor.k (metric card label) and .panel-title raised from 10px → 11px.

Title — "AEP Demo Dashboard" → "AEP Dashboard".

Why?

Part of the UX redesign initiative (PR-A of 4). Reduces cognitive load from a flat 10-item tab bar and fixes several small interaction honesty issues.

How to test?

ADMIN_TOKEN=dev-admin npm run ingest
open http://localhost:8787/dashboard
  1. Verify three primary tabs (Observe/Analyze/Ops) with contextual sub-navs
  2. Click each primary tab — correct sub-nav appears, correct view loads
  3. Navigate to #analytics, #anomalies, #rejected directly — correct tab highlighted
  4. Wait 10s idle — live pill shows "Live · updated Xs ago"
  5. Click Sessions / Rejected / Workflows metric cards — navigates correctly
  6. Select a session and click Export JSON — buttons show "Preparing…" briefly

Checklist

  • Tests pass (239/239)
  • Single file changed (src/public/dashboard.html)
  • No new CI job (stays at 14 required checks)
  • Hash routing backward-compatible
  • No breaking changes

surpradhan and others added 2 commits June 25, 2026 22:39
- Replace flat 8-tab bar with 3 primary tabs (Observe/Analyze/Ops)
  and contextual sub-navs; hash routing preserved unchanged
- Add syncPrimaryNav()/switchGroup() to keep primary and sub-nav
  in sync on direct tab clicks and hash-driven navigation
- Live pill now shows "Live · updated Xs ago" / "Disconnected ·
  last seen Xs ago" via real setInterval ticker
- Export buttons show "Preparing…" (honest; window.location.href
  gives no JS completion event)
- Sessions/Workflows/Rejected metric cards are clickable deep-links
- Actionable empty states (emit command hint, trace_id hint)
- Type floor: .k and .panel-title raised from 10px to 11px
- Drop "Demo" from page title and h1

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Revert role=tablist/role=tab (no paired tabpanels — incomplete ARIA)
  keeping flat aria-selected hint approach with a follow-up note
- Wire pdot-ops in setBadge() and pdot-analyze in renderAnomalies()
  so primary-nav alert dots actually light up on rejections/anomalies
- Remove redundant syncPrimaryNav() call from switchGroup() — switchMain
  already calls it; add comment explaining active-tab click reset behavior
- Add role=status/aria-live=polite to live-label for screen reader support
- Restore "Policy Analytics" and "Custom Analytics" sub-tab labels

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

@surpradhan surpradhan left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R1 review response

Finding #1 — ARIA tablist without tabpanels (Major → Fixed)
Reverted role="tablist" and role="tab" from all elements. Restored the flat aria-selected hint approach that was on main, with a comment noting the full WAI-ARIA tablist pattern (roving tabindex, arrow keys, tabpanel wiring) remains a tracked follow-up.

Finding #2 — Alert dots unwired (Major → Fixed)
setBadge(total) now sets pdot-ops to alert-warn when total > 0. renderAnomalies(a) now sets pdot-analyze to alert-warn when a.anomaly_count > 0. Both clear the class when the count returns to zero.

Finding #3 — Redundant syncPrimaryNav in switchGroup (Minor → Fixed)
Removed the extra call. switchMain handles it. Added a comment explaining the intentional "clicking an active primary tab resets to group default" behavior.

Finding #4_tickerInterval never cleared (Minor → Comment added)
Added a comment in the interval guard noting the single-page context. A full teardown path is not in scope for this PR.

Finding #5live-label missing aria-live (Minor → Fixed)
Added role="status" aria-live="polite" aria-atomic="true" to #live-label.

Finding #6/#7 — "Policy" / "Custom" ambiguous labels (Nit → Fixed)
Restored "Policy Analytics" and "Custom Analytics" as sub-tab labels.

@surpradhan surpradhan left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round-2 code review: Approve. All R1 findings correctly addressed. Alert dots now wire up in setBadge/renderAnomalies (single source of truth for each count). switchGroup simplified — no redundant syncPrimaryNav call. ARIA role regression reverted. live-label gets role=status. Zero new issues introduced. Gates 239/239.

@surpradhan surpradhan merged commit 86695ed into main Jun 25, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant