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

92 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 5: Frontend — Activity tab + smart filtering + live updates
**Status:** ⬜ Not Started
**Parent plan:** [PLAN.md](./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
<!-- Filled in by the implementer: the activity-log render/append functions Phase 6's
Dashboard widget can reuse, the i18n namespace, and the settings endpoint shape used. -->