Files
manage/frontend
Developer 09b9c45665 SheetForm dirty-state confirm + wire isDirty into all form consumers (R4.5)
SheetForm gains an isDirty prop. When true, any close attempt (Cancel
button, header X, Radix overlay click, Escape) opens a 'Discard changes?'
ConfirmDialog instead of discarding unsaved edits. Radix dismiss callbacks
(onEscapeKeyDown, onPointerDownOutside) are intercepted when dirty so the
guard applies uniformly.

All four form consumers now compute and pass isDirty:
- ServicePage: name/enabled/config differ from the persisted instance.
- Settings machine editor: field-by-field draft vs editingMachine
  (create mode is always dirty; secret write-only fields excluded).
- Message compose: subject non-empty, body differs from default, or
  attachments present.
- WidgetConfigDialog: draft !== null (only draft mode is guarded; list
  mode has nothing to discard).

Tests: 3 new SheetForm dirty-guard cases (prompt on cancel, abort discard,
clean close when not dirty) + one focused dirty-guard test per consumer.
122 tests pass; lint/build green.

Refs openspec/changes/mobile-responsive-parity/verify-report.md residual
risk #1.
2026-06-26 15:31:30 +00:00
..
2026-05-04 16:59:06 +02:00
2026-05-04 13:50:53 +02:00

Manage Frontend

React + TypeScript SPA for Manage, consuming the FastAPI backend.

Tech Stack

  • Vite — Build tool
  • React 18+ — UI framework
  • TypeScript — Type safety
  • @tanstack/react-query — Data fetching/caching
  • @tanstack/react-table — Data tables (media, file browser)
  • react-router-dom — Client-side routing
  • Tailwind CSS + shadcn/ui — Styling

Setup

cd frontend
npm install

Development

npm run dev

Runs on http://localhost:5173 with API requests proxied to http://localhost:8000.

Make sure the backend is running:

cd ../backend
uvicorn media_library_viewer_api.main:app --reload --port 8000

Build

npm run build

Output goes to frontend/dist/.

Pages

  • Dashboard (/) — Now playing, library stats, configurable widgets and shortcuts, frontend/backend version chips in the shell header
  • Observability (/observability) — Thin dashboard: Alertmanager alerts, Prometheus target health, machine status, and Grafana deep-links (no in-app charting)
  • Media (/media) — Full-library table with sort/filter/search
  • Users (/users) — Read-only Jellyfin user list with optional Jellyseerr enrichment
  • File Browser (/files) — Remote directory browsing, ffprobe preview, jobs
  • Settings (/settings) — Persistent monitoring machine definitions, SSH keys, and setup workflow
  • Actions (/actions) — Saved server tasks (shell/python) targeting ssh_tasks services

Environment Variables

Set VITE_API_URL and any OIDC variables directly in your shell or Compose build args if the API is not at http://localhost:8000. The frontend version defaults to the package.json version and can be overridden with VITE_APP_VERSION and VITE_APP_BUILD_INFO when you need explicit deployed labels.

VITE_API_URL=http://your-backend-host:8000

Configuration workflow examples

  • Local development: run docker compose -f docker-compose.dev.yml up --build, then open the app and add monitoring machines in the Settings tab.
  • Production: export the required Compose variables in your shell, run docker compose up --build, and manage local/remote machines from Settings.
  • Observability: Manage only deploys backend + frontend. It connects to existing Grafana/Prometheus/Alertmanager instances; see docker-compose.observability.yml for an optional standalone example stack. A machine can be local (the API host itself) or ssh (a remote host), and the UI treats both the same after configuration.

In development, the Vite proxy handles /api requests automatically. Observability services (Grafana, Prometheus, Alertmanager) are configured in the app on the Services page — there are no observability env vars.