Commit Graph

83 Commits

Author SHA1 Message Date
bvandeusen 1ecc831673 build: point alembic at roundtable/migrations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:14:14 -04:00
bvandeusen 2df0d421c2 build: rename package to roundtable in pyproject
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:14:07 -04:00
bvandeusen 94a35da86e refactor: update imports fabledscryer → roundtable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:13:55 -04:00
bvandeusen 8aad2ab43d refactor: rename package directory fabledscryer → roundtable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:10:31 -04:00
bvandeusen fd9c6d941d style(login): placeholder labels instead of field headers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 16:39:06 -04:00
bvandeusen ce43a3900b style(login): larger wordmark + tagline, drop Sign In heading
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 16:37:35 -04:00
bvandeusen c6401d8416 feat(login): Roundtable wordmark above tagline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 16:13:36 -04:00
bvandeusen 6c883e4121 copy: relocate "Under Watch, Under Care" to login tagline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 15:45:05 -04:00
bvandeusen 4d154653ba copy: dashboard hero "Under Watch, Under Care"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:58:38 -04:00
bvandeusen b0d9e9b6ad feat: themed 404 and 500 pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:57:45 -04:00
bvandeusen b6954bd9d2 copy: broader themed empty states + restore DNS CTA
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:56:41 -04:00
bvandeusen 5a701e0558 copy: themed empty states + login tagline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:55:10 -04:00
bvandeusen ba2c698801 style: candlelit glow background replaces star field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:52:27 -04:00
bvandeusen e83c69c6c2 feat: heraldic seal logo (crown & ellipse table)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:51:47 -04:00
bvandeusen 33df0c2f9a style: swap Libertinus Serif → EB Garamond
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:51:19 -04:00
bvandeusen e8691bc7e4 style: pewter & gold palette tokens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:51:12 -04:00
bvandeusen 1f6404f0fd docs: rebrand implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:40:26 -04:00
bvandeusen 39074252d1 docs: rebrand design spec (FabledScryer → Roundtable)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:30:40 -04:00
bvandeusen 00dc4cdc9c feat: per-plugin settings pages and multi-repo plugin catalog
Plugin settings UI:
- Settings → Plugins now shows a clean list (status dot, name, enabled badge)
  with a Settings button per plugin linking to its own detail page
- Per-plugin detail page at /settings/plugins/<name>/ shows enable toggle,
  all config fields, load status, and failure notice if the plugin errored
- Config saving now scoped per-plugin via POST /settings/plugins/<name>/;
  removes the monolithic save-all-plugins form

Plugin repositories:
- Replace single Plugin Index URL field with a managed list of repositories
  (HTMX add/edit/remove per entry, same pattern as Ansible sources)
- plugin_index.py: fetch_catalog() now accepts a list of URLs, caches per-URL,
  and merges results deduplicating by plugin name (first repo wins)
- Legacy plugins.index_url is auto-migrated to the new list format on first
  access so existing installs don't lose their configured URL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:41:31 -04:00
bvandeusen 8558d15eeb feat: plugin fault isolation notices + NUT managed mode fixes
Plugin failures:
- Track load-time failures in _FAILED_PLUGINS dict with human-readable reasons
- Inject plugin_failures into all templates via context processor
- Show admin-only warning banner in base.html when any plugin fails to load
- Show inline failure notice per plugin card in Settings → Plugins

NUT managed mode:
- entrypoint.sh: make nut_setup.py failure non-fatal so the container starts
  even if nut_ups_host isn't set yet (allows fixing config via UI)
- save_plugins: when nut_managed is enabled, auto-set nut_host=localhost so
  the plugin connects to the managed NUT instance without extra manual config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:04:53 -04:00
bvandeusen 56283df5a1 feat: Ansible source manager UI — replace raw JSON textarea
- Replace the raw JSON textarea in Settings → Ansible with a proper
  per-source card UI: add, inline-edit, remove, and git-sync each
  source independently via HTMX without a page reload
- Each source card shows type badge (git/local), URL or path, branch,
  and pull interval; git sources get a Sync button that triggers
  git pull and returns inline status
- Add source form uses a type-aware select that shows URL/branch/interval
  fields for git or path field for local, collapsed in a details accordion
- Add new settings routes: sources/add, sources/<idx>/remove,
  sources/<idx>/save, sources/<idx>/sync
- Update browse.html and run_detail.html to use CSS vars throughout
  (removed hardcoded hex colors); link empty state to Settings page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 17:24:35 -04:00
bvandeusen edc9b752d2 feat: drag-and-drop dashboard editing, alert dynamic fields
- Replace up/down arrow reorder buttons on dashboard edit page with
  SortableJS drag handles; add POST /d/<id>/edit/reorder endpoint
  accepting ordered widget ID array
- Add {% block extra_scripts %} hook to base.html for page-specific JS
- Add dynamic alert rule field loading via HTMX partial (_rule_fields)
  so metric/threshold fields update when source is changed
- Add docs/plugins/index.yaml.example showing catalog index format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:16:04 -04:00
bvandeusen 93d5ed8fb0 feat: managed NUT setup, plugin config improvements, migration fix
- Add managed NUT mode: configure NUT daemon from Settings → Plugins
  (UPS plugin), writes /data/nut_managed.json read by entrypoint on
  restart — no env vars or USB passthrough required
- entrypoint.sh: start NUT from /data/nut_managed.json or NUT_MANAGED=1
  env var; drop to app user via gosu after NUT daemons start
- nut_setup.py: support --from-file <json> in addition to env vars
- Dockerfile: add nut, nut-client, gosu packages and entrypoint
- docker-compose.yml: document optional NUT_MANAGED env var block
- Fix plugin hot-reload migration failure: pass all plugin migration
  dirs to Alembic so previously-stamped revisions from other plugins
  remain resolvable (fixes UPS and any plugin with depends_on)
- Fix plugin list-type config (e.g. SNMP devices) rendering as broken
  text input — now shows a read-only note to edit plugin.yaml instead
- Fix _sync_nut_managed_config: only write JSON when nut_ups_host is
  non-empty, preventing NUT startup loop on container restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:15:48 -04:00
bvandeusen ced1eebe1d feat: maintenance windows, reports, uptime widget, alert improvements
- Add maintenance window scheduling to suppress alerts during planned
  downtime (model, routes, templates)
- Add weekly email/webhook reports with host summary (core/reports.py,
  Settings → Reports tab)
- Add host uptime history widget with per-check sparkline view
- Expand alert rules: dynamic metric catalog for plugin sources,
  per-rule HTMX field loading, maintenance window awareness
- Register additional dashboard widgets (uptime, SNMP, UniFi, UPS)
- Add Settings → Reports tab configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:15:30 -04:00
bvandeusen 3c70ac56b3 feat: OIDC/LDAP auth, audit log, maintenance windows, migrations
- Add OIDC (OpenID Connect) authentication with discovery URL support,
  group-based role mapping, and token introspection
- Add LDAP authentication with bind credentials, group-based role
  mapping, and configurable attribute names
- Add audit log (model, routes, templates) tracking settings changes,
  plugin enable/disable, login events
- Add migrations 0009 (widget variants), 0010 (maintenance windows),
  0011 (audit log)
- Add optional dependency groups to pyproject.toml: [ldap], [snmp]
- Add Settings → Auth tab with OIDC and LDAP configuration forms

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:15:15 -04:00
bvandeusen 484da1f263 feat: show update available when catalog version differs from installed
Catalog partial now compares catalog version vs installed plugin.yaml version.
Gold border + "Update available — installed vX.Y.Z" badge when newer.
Update button uses btn-warn styling. Route passes installed_versions dict.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:42:50 -04:00
bvandeusen 3f437141fb chore: update plugin catalog URL to git.fabledsword.com
Default plugins.index_url and all documentation URLs now point to
https://git.fabledsword.com/bvandeusen/FabledScryer-plugins.
Anchor /plugins/ in .gitignore so it only matches the root directory
(not docs/plugins/).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:36:09 -04:00
bvandeusen fa318073f1 chore: move plugins/ to separate repo, gitignore the directory
plugins/ is now tracked at bvandeusen/fabledscryer-plugins.
Removed tracked traefik files from this repo's index (files remain on disk).
Added plugins/ to .gitignore so the directory is ignored going forward.

PLUGIN_DIR in config.yaml still points to plugins/ for local dev and Docker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:33:22 -04:00
bvandeusen 230b542015 feat: rename to FabledScryer, multi-dashboard system, plugin management, branding
- Rename package fablednetmon → fabledscryer throughout
- Multi-dashboard: ownership, per-user defaults, HTMX edit (add/remove/reorder)
- Read-only share tokens scoped to individual dashboards
- Dashboard edit is HTMX-driven (no page reloads)
- Plugin management system: remote catalog, download/install, hot-reload, in-app restart
- plugin_index.py: fetch/cache remote index.yaml; default URL → bvandeusen/fabledscryer-plugins
- plugin_manager.py: download_and_install_plugin, hot_reload_plugin, restart_app
  - ZIP extraction handles GitHub archive formats (name-v1.0.0/, name-main/)
- Settings split into tabbed sections: General, Notifications, Ansible, Plugins
- Plugins tab: catalog browser (HTMX), install/activate/update/restart actions
- UI/branding: dark palette (#07071a), crystal ball SVG logo, animated star field,
  Libertinus Serif applied to headings, nav, labels, and section titles
- Widget registry (core/widgets.py) for dashboard plugin integration
- UPS widget.html (dashboard card) and settings/_tabs.html include
- Migrations 0005–0008: dashboards, is_default, ownership, share tokens
- docs/plugins/: writing-a-plugin.md updated with publishing guide,
  index.yaml.example template for fabledscryer-plugins repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:27:56 -04:00
bvandeusen 165a202ba4 feat: UI redesign (CSS system, DNS widget, Traefik dashboard widget)
- Replace base.html style block with full CSS design system using custom properties (dark theme, cards, tables, badges, dots, widgets)
- Add DNS blueprint (fablednetmon/dns/) with /dns/ and /dns/rows routes + templates
- Add Traefik /widget route and widget.html fragment for dashboard
- Update dashboard: DNS + Traefik widgets, traefik_enabled config detection
- Update all templates to use new CSS classes (page-title, section-title, card-flush, table, badge-*, dot-*, btn-*)
- Register dns_bp in app.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 23:37:46 -04:00
bvandeusen d29c5b3eab fix: suppress debconf frontend warnings during apt-get install 2026-03-18 23:25:44 -04:00
bvandeusen a3a05070e7 fix: upgrade pip, run as non-root user, remove stale FABLEDNETMON_CONFIG env 2026-03-18 23:23:52 -04:00
bvandeusen 7a7ed2185a feat: live ping pill widget (dashboard + /ping/ page with threshold settings) 2026-03-18 23:18:26 -04:00
bvandeusen 791af2d58f feat: ping/DNS status and latency in hosts list and dashboard summary 2026-03-18 23:09:49 -04:00
bvandeusen c26552b670 fix: install iputils-ping in Docker image for ICMP ping support 2026-03-18 23:03:58 -04:00
bvandeusen d8eacffd48 fix: env.py reads FABLEDNETMON_DATABASE_URL and honors URL set by migration_runner 2026-03-18 22:40:05 -04:00
bvandeusen f9ea87187b test: update test_config.py for load_bootstrap API 2026-03-18 22:31:17 -04:00
bvandeusen 242398dc52 chore: remove config.yaml mount from docker-compose; update config example
- Replace individual volume mounts (playbook_cache, plugins) with single app_data:/data mount
- Change FABLEDNETMON_DATABASE__URL to FABLEDNETMON_DATABASE_URL (underscore to hyphen)
- Simplify config.example.yaml to focus on required database URL setting
- Document that other settings are now managed via the Settings UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:36:26 -04:00
bvandeusen dfb433e779 feat: settings UI (admin-only, live-updates app.config)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:35:39 -04:00
bvandeusen c5dff7ec8c feat: two-phase migrations, DB settings loading in create_app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:33:36 -04:00
bvandeusen 03bbd8d0fa feat: strip config.py to bootstrap only (db_url + auto-gen secret_key) 2026-03-18 20:32:02 -04:00
bvandeusen 80ce703a15 feat: settings service (get/set/load helpers, load_settings_sync) 2026-03-18 20:29:52 -04:00
bvandeusen e6fa8baed1 feat: AppSetting model and migration 0004
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:22:23 -04:00
bvandeusen 38416b412a fix: dockerfile install order; add .dockerignore; update .gitignore 2026-03-18 19:57:05 -04:00
bvandeusen 4cc83c8a19 fix: use relative imports in traefik plugin to prevent double-registration; resolve PLUGIN_DIR path 2026-03-18 18:46:02 -04:00
bvandeusen 2164ea28f2 feat: traefik UI (per-router dashboard with SVG sparklines) 2026-03-18 18:43:05 -04:00
bvandeusen aacfcd420e feat: traefik scrape task (delta tracking, DB write, record_metric) 2026-03-18 18:38:54 -04:00
bvandeusen 8ea2b09d05 fix: cap percentile at last finite bucket when target falls in open +Inf bucket 2026-03-18 18:38:03 -04:00
bvandeusen c336f1f774 feat: traefik prometheus scraper (parse, compute rates and percentiles) 2026-03-17 21:37:34 -04:00
bvandeusen 0af38016cd feat: traefik plugin migration (traefik_001_initial, depends_on core head)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 21:34:40 -04:00