feat(frontend): slice 8 — remove MUI/@emotion deps + update REQUIREMENTS
Web UI rework. Final slice.
- Remove from package.json: @mui/material, @mui/icons-material,
@mui/x-data-grid, @emotion/react, @emotion/styled (zero consumers
remain in src after slices 1-7b; grep-verified).
- Update docs/REQUIREMENTS.md (+63 lines): single design system
(shadcn/ui + Tailwind v4 + lucide-react), thin-dashboard observability
model (no in-app charts; Grafana deep-links), TanStack tables
(visibility-only parity), reconciled IA (Backups top-level nav;
Media at /media with /applications redirect), repurposed chart-*
status cues, removed deps list.
- Note: AGENTS.md 'node --test tests' invocation is a pre-existing
broken command (treats tests/ as a module); correct form is
'node --test' (auto-discover, 5/5 pass) — verified identical at
pre-rework baseline ef5311b.
Gate: build + lint + vitest (23/64) + node --test (5/5) green.
Web UI rework complete.
This commit is contained in:
+63
-2
@@ -10,6 +10,61 @@ Build Manage, a compact web application for browsing a remote Jellyfin media lib
|
||||
|
||||
Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server monitoring, and safe job templates.
|
||||
|
||||
## Frontend Design System & Architecture
|
||||
|
||||
The Manage frontend is a React + TypeScript SPA built on a **single design system**.
|
||||
The legacy Material UI (MUI v9) / Emotion / recharts / D3 / `theme.ts` stack has been
|
||||
fully removed (web-ui-rework; see decision log 2026-06-17).
|
||||
|
||||
### Design system
|
||||
|
||||
- **shadcn/ui** components + **Tailwind CSS v4** + **lucide-react** icons are the only UI layer.
|
||||
- Design tokens live as CSS `@theme` tokens in `frontend/src/index.css` (light + `.dark`),
|
||||
with the primary brand color `#4f8cff`.
|
||||
- The `chart-1`..`chart-5` color tokens are **repurposed as status / Grafana-link color
|
||||
cues** (not charts): `chart-1`=info/brand, `chart-2`=success/healthy, `chart-3`=warning,
|
||||
`chart-4`=destructive, `chart-5`=neutral accent. No token value changed.
|
||||
- Removed from the frontend dependency tree: `@mui/material`, `@mui/icons-material`,
|
||||
`@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`, `recharts`, `d3`, and the
|
||||
no-op `src/theme.ts` shim.
|
||||
|
||||
### Thin-dashboard observability model
|
||||
|
||||
- The app does **no in-app charting**. Metrics, charts, and logs live in the external,
|
||||
decoupled observability stack (Prometheus / Loki / Grafana / Alertmanager).
|
||||
- In-app observability surfaces (`/observability`) show **Alertmanager alerts, Prometheus
|
||||
target health, machine health, and Grafana deep-links** (per-machine metric/log panels),
|
||||
not rendered graphs.
|
||||
- The legacy in-app D3 monitoring charts and the POSIX remote resource collector are
|
||||
superseded by this Grafana-based model (see decision log 2026-06-13 and 2026-06-17).
|
||||
|
||||
### Tables
|
||||
|
||||
- Tabular surfaces use **TanStack Table** (`@tanstack/react-table`) behind a `DataTable`
|
||||
wrapper (`components/ui/data-table.tsx`).
|
||||
- Parity is **visibility-only**: pagination, row selection, row click, and column
|
||||
visibility are supported. There is **no client sorting and no column resizing**.
|
||||
- Media uses **server-driven pagination** (`manualPagination` + `rowCount`); the File
|
||||
Browser renders the full listing without pagination.
|
||||
- The Media and File Browser tables previously used `@mui/x-data-grid`; both now use the
|
||||
TanStack `DataTable` (earlier "AG Grid" / `@mui/x-data-grid` references are superseded).
|
||||
|
||||
### Reconciled information architecture
|
||||
|
||||
- **Backups** is a top-level navigation item at `/backups`.
|
||||
- The media/applications surface is named **Media** and lives at `/media`; `/applications`
|
||||
redirects to `/media`, mirroring the existing `/monitoring` → `/observability` redirect.
|
||||
- User deep-links (`/users?user=<id>`), dashboard shortcut deep-links, and the Media →
|
||||
File Browser row-click navigation are preserved under the reconciled routes.
|
||||
|
||||
### Frontend testing
|
||||
|
||||
- Component tests run on **Vitest + @testing-library/react** (`npm test`), with the
|
||||
`@testing-library/jest-dom` matchers.
|
||||
- Legacy plain-Node suites (`frontend/tests/*.test.mjs`) run via
|
||||
`node --test tests/*.test.mjs` (npm script `test:node`).
|
||||
- The build/lint gate is `npm run build` (`tsc -b` + `vite build`) + `npm run lint` (ESLint).
|
||||
|
||||
## Core Requirements
|
||||
|
||||
### Jellyfin Library
|
||||
@@ -82,7 +137,7 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
|
||||
- Support manual path entry and refresh.
|
||||
- Remote file listing must be compact, structured, and navigable.
|
||||
- The file table should be read-only.
|
||||
- The file table should use row selection (single-select) in an AG Grid format consistent with the Media tab.
|
||||
- The file table should use row selection (single-select) in a TanStack `DataTable` format consistent with the Media tab (both migrated off the legacy `@mui/x-data-grid`/AG Grid).
|
||||
- The file table should not expose a visible checkbox selection column.
|
||||
- The file table should not show a visible `selected` column.
|
||||
- Include a top `[UP] ..` row, when not at `/`, to navigate to the parent directory.
|
||||
@@ -166,7 +221,7 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
|
||||
- The dashboard should present disk space as a single combined card with the progress/fill bar embedded inside the card and the size breakdown laid out clearly, with centered sub-card text for the Used/Free/Total breakdown and consistent vertical spacing across the dashboard cards.
|
||||
- The disk usage bar should change color as usage increases so high utilization is easy to notice at a glance.
|
||||
- The disk usage card should avoid redundant percentage labels next to the bar if the bar itself already communicates the value.
|
||||
- Render Monitoring charts directly with D3 so the UI can support brush-based range selection, hover tooltips with a moving vertical cursor and snapped point markers, summary chips, and moving averages without a separate wrapper library.
|
||||
- (Superseded by the thin-dashboard observability model — 2026-06-17.) The app no longer renders in-app monitoring charts with D3; metrics/charts/logs live in the external Grafana stack, and the in-app Observability page surfaces Alertmanager alerts, Prometheus target health, and Grafana deep-links.
|
||||
- Use a lightweight remote collector that reads Linux `/proc`, `/sys/block`, and `df` data into a JSONL file under `/tmp`.
|
||||
- The collector should rotate/prune its JSONL metrics file so it does not grow unbounded; default retention is 7 days with a 70,000-line safety cap.
|
||||
- The collector should be startable/stoppable/restartable from the dashboard and should not require installing a full monitoring stack.
|
||||
@@ -197,6 +252,7 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
|
||||
|
||||
## Decision Log
|
||||
|
||||
- 2026-06-17: Completed the web UI rework to a single design system. The frontend now uses **shadcn/ui + Tailwind CSS v4 + lucide-react** exclusively, with CSS `@theme` tokens in `src/index.css` (primary `#4f8cff`; `chart-1..5` repurposed as status/Grafana-link cues). Removed `@mui/material`, `@mui/icons-material`, `@mui/x-data-grid`, `@emotion/react`, `@emotion/styled`, `recharts`, `d3`, and the `src/theme.ts` shim. Tables moved from `@mui/x-data-grid`/AG Grid to a visibility-only TanStack `DataTable` wrapper (pagination, row selection, row click, column visibility — no sorting/resizing). Adopted the thin-dashboard observability model (no in-app charts; Alertmanager alerts + Prometheus target health + Grafana deep-links). Reconciled the information architecture: Backups is a top-level nav item at `/backups`, and the media surface is named Media at `/media` with `/applications` redirecting to `/media` (mirroring `/monitoring` → `/observability`). Frontend tests moved to Vitest + @testing-library/react (`npm test`), with legacy node suites in `frontend/tests`.
|
||||
- 2026-06-13: Adopted a dedicated, self-hosted observability subsystem based on Prometheus, Grafana Loki, Grafana, and Alertmanager. Metrics will be pulled from Node Exporter on machines and from application exporters in containers; logs will be structured JSON shipped by Promtail/Grafana Alloy. The existing POSIX remote collector will be removed and backup alerts migrated to Alertmanager rules. See `docs/monitoring-logging-design.md`.
|
||||
- 2026-06-13 (Phase 1): Added Prometheus, Loki, Grafana Alloy, Grafana, Alertmanager, and Node Exporter services to `docker-compose.yml` and `docker-compose.dev.yml`. Provisioned Grafana datasources and an initial `Manage Overview` dashboard as code. Configured Alloy to tail Docker logs and ship to Loki. Added Grafana generic OAuth configuration via `monitoring/grafana/grafana.ini` and a dedicated Traefik host rule. Added Alertmanager email routing with env-var interpolation. Added `/grafana` proxy to the Vite dev server for iframe embedding.
|
||||
- 2026-06-13 (Phase 2): Extended machine settings with `node_exporter_enabled`, `node_exporter_port`, and `node_exporter_scrape_host`. Added Node Exporter install/restart/status job templates to `jobs.py`. Implemented `media_library_viewer_api.services.targets` to generate Prometheus file-SD target files and wired target regeneration into machine create/update/delete. Added `/api/monitoring/prometheus-targets` for live target previews. Configured Prometheus with a `node-exporter-remote` job reading file SD from the backend cache volume. Added a minimal `Node Exporter Overview` Grafana dashboard. Added unit and integration tests for target generation and the new endpoint.
|
||||
@@ -289,9 +345,11 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
|
||||
## Backup Monitoring
|
||||
|
||||
### Overview
|
||||
|
||||
The system receives backup execution reports from an external backup tool via HTTP API, stores job and run history, and provides alerting on failures, missed schedules, and anomalies.
|
||||
|
||||
### API
|
||||
|
||||
- `POST /api/backups/report` — Submit backup run (Bearer token auth)
|
||||
- `POST /api/backups/report/start` — Mark backup as in_progress
|
||||
- `GET /api/backups/jobs` — List jobs
|
||||
@@ -301,16 +359,19 @@ The system receives backup execution reports from an external backup tool via HT
|
||||
- `GET /api/dashboard/backups` — Dashboard summary
|
||||
|
||||
### Data Model
|
||||
|
||||
- **BackupJob**: id, name, source, target, schedule_interval_seconds, created_at
|
||||
- **BackupRun**: id, job_id, started_at, ended_at, status, bytes_transferred, duration_ms, error_message, details_json
|
||||
- **BackupAlert**: id, job_id, run_id, alert_type, severity, message, acknowledged, resolved_at
|
||||
|
||||
### Alert Types
|
||||
|
||||
- `failed_status` — Backup reported failure (critical)
|
||||
- `missed_schedule` — No run within 1.5x expected interval (warning)
|
||||
- `anomaly_size` — Size is 0 or <10% / >300% of 7-day median (warning)
|
||||
- `anomaly_duration` — Duration >300% of 7-day median (warning)
|
||||
|
||||
### Authentication
|
||||
|
||||
- Backup tool uses auto-generated Bearer API key
|
||||
- Frontend uses existing OIDC/JWT auth
|
||||
|
||||
Reference in New Issue
Block a user