13 Commits

Author SHA1 Message Date
bvandeusen c8b6719b37 feat(ui): plugin get_nav() hook → sidebar Infrastructure links (slice 2)
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 46s
CI / integration (push) Successful in 2m20s
CI / publish (push) Successful in 1m16s
Plugin UIs had no nav home (only dashboard widgets / typed URLs). Add an
optional get_nav() plugin export and surface it in the sidebar.

- plugin_manager: _PLUGIN_NAV registry + get_plugin_nav() getter + a tolerant
  _collect_plugin_nav() (missing hook = fine; raising/malformed = logged &
  skipped; idempotent per plugin so hot-reload re-runs cleanly). Collected in
  both the startup load path and the hot-reload path.
- app.py: inject plugin_nav into the template context, filtered to enabled
  plugins so a hot-disabled plugin's link can't linger before restart.
- base.html: render plugin links under the Infrastructure group, with the same
  request.path active-state treatment as core links.
- docker/snmp/unifi/traefik: each exports get_nav() → its /plugins/<name>/ view.
- Tests: collector behavior (collect, missing hook, reload-replace, malformed
  item, raising hook, sorted output).

With docker enabled, "Docker" now appears under Infrastructure → its fleet view.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Jg27rgypiW2efULXJDtMC
2026-06-19 18:00:12 -04:00
bvandeusen af60ca446d fix(plugins): complete steward rename across bundled plugins; clear lint debt
CI / lint (push) Successful in 3s
CI / unit (push) Successful in 7s
CI / integration (push) Successful in 2m8s
The fabledscryer->steward rename had only ever reached host_agent. The other
five bundled plugins (http, snmp, traefik, unifi, docker) still imported
`from fabledscryer.*` (package no longer exists) and read FABLEDSCRYER_* env
vars — so every one of them was broken at import since the original rebrand.
CI stayed green only because none are enabled by default and migrations don't
import plugin modules. Now that they version in-tree, complete the rename:
- fabledscryer.* -> steward.* imports across all five plugins
- FABLEDSCRYER_* -> STEWARD_* in plugin migration env.py files
- author/repository/homepage + user-facing 'Fabled Scryer' strings -> Steward
- snmp/scheduler.py: also drop dead `now`/datetime; record_metric from steward

Adds tests/test_no_legacy_names.py — fails if 'scryer'/'roundtable' ever
reappear in shipped code (the drift bit twice; this stops a third time).

Also clears pre-existing ruff lint debt (unused imports, semicolon statements,
mid-file import) surfaced by the new lint lane.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 11:22:20 -04:00
bvandeusen a7a281cb11 feat(plugins): fold first-party plugins in-tree; bundled + external roots
First-party plugins (host_agent, http, snmp, traefik, unifi, docker) are now
tracked under plugins/ and baked into the image, so they version atomically
with core — ending the cross-repo import drift the roundtable->steward rename
exposed. History for these files is preserved in the archived Roundtable-plugins
repo.

Plugin discovery becomes multi-root: PLUGIN_DIR (single) -> PLUGIN_DIRS
(bundled first, then external) + PLUGIN_INSTALL_DIR. Bundled ships in the image;
third-party plugins still mount at runtime into the external root
(STEWARD_PLUGIN_DIR, default /data/plugins) and downloads/installs land there.
Bundled shadows external on a name collision.

- config.py: load_bootstrap returns plugin_dirs + plugin_install_dir
- app.py: iterate PLUGIN_DIRS at the migration + load sites
- migration_runner.py: discover_all_in() unions every plugin root
- plugin_manager.py: resolve_plugin_path() (pure, first-root-wins); load /
  install / hot-reload span all roots; installs target the external root
- settings/routes.py: _discover_plugins scans all roots, dedup bundled-first
- Dockerfile: COPY plugins/ ; docker-compose: drop host bind, document external
- tests/test_plugin_dirs.py: resolution, multi-root discovery, bootstrap split

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 08:37:24 -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 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 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 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
bvandeusen 6fde57f63e feat: traefik plugin scaffold (plugin.yaml, model, __init__ stub) 2026-03-17 21:32:14 -04:00