Files
FabledSteward/tests/test_templates_parse.py
T
bvandeusen 9e4f1983f8
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 51s
CI / integration (push) Successful in 2m21s
CI / publish (push) Successful in 1m10s
feat(host_agent): lazy-load full-metrics charts + live-poll current state
The full-metrics page rendered once server-side with the history query inline,
so the charts blocked first paint and nothing refreshed without a reload (it
reads the latest snapshot the server holds — the agent pushes ~every 30s).

Split it into a shell + two HTMX fragments:
- Shell (host_detail.html): header + shared time-range toggle + two containers;
  paints instantly.
- Current state (/<id>/metrics → _host_metrics.html): identity + gauges +
  per-core + filesystems + interfaces/disks + temps, from the DISTINCT ON latest
  query. hx-trigger "load, every 15s" → live numbers at ~the agent cadence.
- History charts (/<id>/charts → _host_charts.html): the 3 charts + Chart.js,
  from the date_bin history query. hx-trigger "load, every 60s, rangeChange" so
  they lazy-load (never block paint), refresh slowly, and follow the range
  selector. Leak-safe: previous Chart instances are destroyed before re-render.
- Range toggle switched from full-reload links to the shared _time_range.html
  (setTimeRange + rangeChange), so only the fragments refetch.
- routes: host_detail (shell) + host_detail_metrics + host_detail_charts, with a
  _split_host_metrics helper.
- tests/test_templates_parse.py now also parses plugin templates (these
  fragments aren't rendered in the unit lane).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Jg27rgypiW2efULXJDtMC
2026-06-20 12:18:39 -04:00

35 lines
1.2 KiB
Python

"""Syntax-parse every first-party template so a broken tag fails the unit lane.
The app only renders a handful of templates in unit tests (e.g. the login page),
so a Jinja syntax error elsewhere would otherwise ship green. env.parse() checks
syntax without resolving extends/includes/imports — enough to catch an unbalanced
or mistyped tag across the whole template tree (e.g. the base.html layout).
"""
import pathlib
import jinja2
import steward
_REPO = pathlib.Path(steward.__file__).parent.parent
_CORE_TEMPLATES = _REPO / "steward" / "templates"
_PLUGINS = _REPO / "plugins"
def test_all_steward_templates_parse():
env = jinja2.Environment()
files = sorted(_CORE_TEMPLATES.rglob("*.html"))
assert files, "no steward templates found"
for f in files:
env.parse(f.read_text()) # raises TemplateSyntaxError on a bad tag
def test_all_plugin_templates_parse():
# First-party plugins ship templates too (host_agent fragments, docker, …);
# they aren't rendered in the unit lane, so parse them here to catch a bad tag.
env = jinja2.Environment()
files = sorted(_PLUGINS.rglob("templates/**/*.html"))
assert files, "no plugin templates found"
for f in files:
env.parse(f.read_text())