24 Commits
Author SHA1 Message Date
Archibold 8048516546 Pin sidebar foot to the page bottom; cap the chip list at 560px 2026-11-07 19:58:02 +11:00
Archibold cc785a0a0d Fixed 560px sidebar; divider moved to main 2026-11-07 19:50:49 +11:00
Archibold a114f31bcf Fix sidebar height; scroll the button list when it overflows 2026-11-07 19:43:29 +11:00
Archibold ee99a164ae Tighten Home banner whitespace 2026-11-07 19:33:43 +11:00
Archibold f1342b8a41 Tint sidebar widget chips by origin; fix widgetSub host 2026-11-07 19:21:58 +11:00
Archibold 4737891997 Tint release cards by origin app (Sonarr/Radarr/Plex) 2026-11-07 19:14:13 +11:00
Archibold 102683363f Name the show on Sonarr and Plex episode cards 2026-11-07 19:01:36 +11:00
Archibold 71d5c68550 Upcoming releases render as a grid of per-release cards 2026-11-07 18:43:00 +11:00
Archibold 34e1b5150a Severity chips, SVG icons, hero artwork tile, uwu masthead 2026-11-07 18:22:52 +11:00
Archibold 24dd017905 Replace notice pages with widgets: pinned text, Sonarr/Radarr calendars, Plex recently-added
WidgetStore keeps the JSON file (same atomic-write/lock pattern as store.py) and
migrates any old pages.json in place. WidgetData fetches each live widget's own
base_url server-side, normalises Sonarr/Radarr/Plex payloads into one row shape,
caches per <id>@<updated_at> behind UWUDASH_WIDGET_CACHE_TTL, and relays artwork
through /api/widgets/{id}/image so the browser never needs the internal host.

Home now renders one merged calendar timeline, one card per recent widget, then
notices; the Settings table carries a Test button that bypasses the cache.
2026-11-07 17:25:54 +11:00
Archibold 298ef9dbf5 Note pages.json among the files living on the data volume 2026-11-07 16:11:59 +11:00
Archibold 3aad88415d Add notice pages with a pinned Home board as the default view
Pages are a second item type beside services: title + icon + plain-text body,
stored in data/pages.json (PageStore mirrors ServiceStore: lock, atomic temp
+ os.replace, slugify-collision ids) and served by the /api/pages family with
the same admin-write / any-session-read gate.

The viewer area opens on the Home notice board instead of "Nothing selected":
state.selected starts at the HOME sentinel, the startup chain ends in openHome(),
and deleting whatever was being viewed falls back to the board via showHome(),
which repaints without touching which section is active so a delete from the
Settings table leaves Home ready for settingsClose.

PUT is omitted on purpose: the UI only posts/patches and pages have no
non-patchable fields.
2026-11-07 16:09:55 +11:00
Archibold 68b9f851ef Document the container registry push alongside the git remote 2026-11-07 15:06:56 +11:00
Archibold f266bc5104 Add container image: two-stage uv build, non-root user, data volume 2026-11-07 15:02:24 +11:00
Archibold a39da9e615 Ignore local scratch and the secrets-carrying start.sh 2026-11-07 14:44:10 +11:00
Archibold b9a92fc482 Handle encrypted/HS256 id_tokens and let an admin claim promote on login 2026-11-07 14:42:56 +11:00
Archibold 27677215bd Handle encrypted and HS256 id_tokens in the OIDC callback
Authlib's parse_id_token only reads a 3-segment JWS, so sign-in 500s
against providers that encrypt the id_token (Authentik with an
Encryption Key issues a 5-segment RSA-OAEP-256/A256CBC-HS512 JWE) or
that sign it with the client secret (Authentik with no Signing Key
issues HS256, which the RS256-only JWKS rejects).

OIDCClient subclasses the starlette OAuth2 client and, when the
standard parse fails on a format problem, falls back to an HS256
decode with the client secret, then to the issuer's
userinfo_endpoint. Claim-level failures (bad nonce, expiry, audience,
issuer) are raised as OAuthError so /auth/callback redirects to
/auth/login?error=... instead of blowing up. /auth/authorize likewise
catches provider/network errors and redirects to the login page.
2026-11-05 16:24:22 +11:00
Archibold 3187b8cf05 Add opt-in OIDC sign-in with session cookie and roles
Auth is enabled only when issuer, client id and client secret are all set;
otherwise the dashboard stays an open LAN dashboard. Provider endpoints are
discovered from <issuer>/.well-known/openid-configuration via Authlib, so no
provider-specific code is needed.

- auth.py: /auth/login, /auth/authorize, /auth/callback, /auth/logout (RP-initiated
  logout when the issuer advertises end_session_endpoint)
- users.py: atomic, lock-guarded data/users.json keyed by the OIDC sub
- role resolution: admin claim wins, else first user bootstraps as admin, else viewer
- api.py/app.py: session middleware and require_login/require_admin gating on every
  route except /health, /auth/* and /static
- config.py/main.py: UWUDASH_OIDC_* / UWUDASH_SESSION_* env vars plus --oidc-issuer
  and --public-url flags
- templates/login.html, static app.js/styles.css: sign-in page and settings UI
2026-10-31 10:36:39 +11:00
Archibold 2e78143812 Add README with usage, proxy mapping and limitations 2026-10-28 21:44:52 +11:00
Archibold 85bad1d0e8 Add dashboard frontend: sidebar, iframe viewer and settings page 2026-10-28 21:44:52 +11:00
Archibold 73315a939e Add service CRUD API, app factory and CLI entrypoint 2026-10-28 21:44:52 +11:00
Archibold 9e6e7745d0 Add reverse proxy: origin mapping, HTML/redirect rewriting, frame-option stripping 2026-10-28 21:44:52 +11:00
Archibold 137d528ad2 Add env-driven config, service models and atomic JSON store 2026-10-28 21:44:52 +11:00
Archibold fc6ee0d748 Add uv project scaffolding and dependency lock 2026-10-28 21:44:52 +11:00