Files
ledgrab/plans/activity-log/phase-5-frontend-tab.md
T

5.4 KiB
Raw Blame History

Phase 5: Frontend — Activity tab + smart filtering + live updates

Status: Not Started Parent plan: PLAN.md Domain: frontend · uses the frontend-design skill

Objective

Build the dedicated top-level Activity tab: a read-only, smart-filterable, keyset-paginated log viewer with an entry detail view, live-append of new events, and export. This is a viewer (Dashboard-style), NOT a CRUD card section.

Tasks

  • core/ui.ts: add formatTimestamp(isoOrMs) (Today/Yesterday/Date · HH:MM, i18n-aware) and formatRelativeTime(isoOrMs) ("2m ago"), with tabular-nums styling guidance for the list. Reuse existing time.* i18n key conventions.
  • features/activity-log.ts:
    • export async function loadActivityLog() — fetch first page from GET /activity-log (via fetchWithAuth), render the toolbar + list into the panel.
    • Smart filter toolbar: category (multi, IconSelect/chips), severity (chips), actor (EntitySelect/text), entity type, date range, free-text search (debounced). Quick presets: Today / Errors / Auth / Devices. Filters drive server-side query params (no client-side filtering of a partial page). Re-query on change; reset cursor.
    • List: one row per entry — severity icon, category badge, relative time (title=absolute), actor, message, entity crosslink (use navigateToCard(...) when the referenced entity is resolvable). Keyset "load more" (or infinite scroll) using next_before_seq.
    • Detail: expandable row / drawer showing full metadata JSON, exact timestamp, ids.
    • Live append: document.addEventListener('server:activity_logged', e => …) — prepend the new entry if it passes the active filters; show a subtle "new" affordance. (Depends on the Phase 2 allowlist entry — already shipped.)
    • Export button: triggers GET /activity-log/export?format=… with current filters via an authed blob download (use fetchWithAuth → blob URL, per frontend.md auth rules).
    • Empty / loading / error states; re-render on languageChanged.
  • Tab wiring:
    • core/tab-registry.ts: add activity_log: { loadFnName: 'loadActivityLog', autoRefresh: false }.
    • templates/index.html: sidebar tab button (data-tab, switchTab('activity_log'), history/clock SVG icon, data-i18n) + <div class="tab-panel" id="tab-activity_log">.
    • app.ts: import + Object.assign(window, { loadActivityLog, … }); global.d.ts decls.
  • Icons: add a history/audit icon to core/icon-paths.ts + core/icons.ts; severity icons (info/warning/error) reuse existing constants where possible.
  • i18n: add activity_log.* keys to static/locales/{en,ru,zh}.json (title, filter labels, category/severity names, column labels, presets, empty/error, export, "N entries").
  • Tutorials: add an Activity-tab step to the getting-started tour in features/tutorials.ts + tour.* keys in all 3 locales.

Files to Modify/Create

  • server/src/ledgrab/static/js/core/ui.ts — modify: timestamp/relative-time formatters
  • server/src/ledgrab/static/js/features/activity-log.ts — new: the viewer
  • server/src/ledgrab/static/js/core/tab-registry.ts — modify: register tab
  • server/src/ledgrab/templates/index.html — modify: tab button + panel
  • server/src/ledgrab/static/js/app.ts — modify: import + window globals
  • server/src/ledgrab/static/js/global.d.ts — modify: window decls
  • server/src/ledgrab/static/js/core/icon-paths.ts / core/icons.ts — modify: icons
  • server/src/ledgrab/static/locales/{en,ru,zh}.json — modify: i18n keys
  • server/src/ledgrab/static/js/features/tutorials.ts — modify: tour step
  • server/src/ledgrab/static/css/* — modify/new: list + toolbar styling (follow base.css vars)

Acceptance Criteria

  • New Activity tab loads, lists entries, and paginates via keyset "load more".
  • Filters hit server-side query params; quick presets work; free-text is debounced.
  • New events append live via server:activity_logged and respect active filters.
  • Export downloads CSV/JSON with auth, honoring current filters.
  • Fully localized (en/ru/zh); empty/loading/error states; re-renders on language change.
  • No plain <select> (use IconSelect/EntitySelect/chips); SVG icons only (no emoji).
  • npx tsc --noEmit clean; npm run build succeeds.

Notes

  • Use the frontend-design skill for the viewer layout, filter toolbar, and detail design — aim for a polished, distinctive result consistent with the app's design language and CSS variables in static/css/base.css (--primary-color, --card-bg, etc.).
  • Models to mirror: features/dashboard.ts (non-card live viewer + load pattern), core/events-ws.ts (server:<type> dispatch), core/entity-palette.ts (EntitySelect), core/icon-select.ts (IconSelect). Auth/blob download rules: contexts/frontend.md.
  • Frontend-only phase → run tsc --noEmit + npm run build; do NOT run pytest/ruff.

Review Checklist

  • All tasks completed
  • Code follows frontend conventions (i18n ×3, icons, selectors, auth fetch, CSS vars)
  • No unintended side effects
  • Build passes (tsc --noEmit + npm run build)
  • Manual smoke: tab loads, filters query server, live append, export

Handoff to Next Phase