feat(widgets): add unit/scale config to chart widget kinds

Graph widgets need consistent value scaling (kB/MB/GB, kbps/Mbps, …). Add
shared `unit` (none/bytes/bytes_per_sec/bits_per_sec/bits/percent/seconds) and
`scale` (auto/k/m/g/t) enum fields to:

- PrometheusChartWidgetConfig (alongside promql/window)
- new QbittorrentSpeedWidgetConfig — the speed widget previously had NO config
  options at all; totals/active keep their empty config.

Declared as Pydantic Literal enums so the widget-kind JSON schema exposes
`enum`, which the frontend config dialog renders as a dropdown. The data
sources are unchanged (raw values); scaling is a display concern handled
client-side. qBittorrent speed defaults to bytes/sec.

Test: chart widget kinds expose the shared unit/scale enums; speed defaults to
bytes_per_sec; totals/active stay option-less. 389/389 backend tests pass.
This commit is contained in:
Developer
2026-07-12 11:45:25 +00:00
parent 39775a82ef
commit 05a9faca3e
5 changed files with 61 additions and 11 deletions
+23
View File
@@ -114,6 +114,29 @@ def test_widget_kind_lookup():
assert get_widget_kind("unknown", "metric") is None
def test_chart_widget_kinds_expose_unit_and_scale_options():
"""Graph widgets share unit/scale options so axes/tooltips can be scaled."""
units = ["none", "bytes", "bytes_per_sec", "bits_per_sec", "bits", "percent", "seconds"]
scales = ["auto", "k", "m", "g", "t"]
prom_chart = get_widget_kind("prometheus", "chart")
assert prom_chart is not None
prom_props = prom_chart.config_schema["properties"]
assert prom_props["unit"]["enum"] == units
assert prom_props["scale"]["enum"] == scales
qbit_speed = get_widget_kind("qbittorrent", "speed")
assert qbit_speed is not None
qbit_props = qbit_speed.config_schema["properties"]
assert qbit_props["unit"]["enum"] == units
assert qbit_props["scale"]["enum"] == scales
# qBittorrent speed data is bytes/sec by default.
assert qbit_speed.default_config["unit"] == "bytes_per_sec"
# totals/active are not graphs and stay option-less.
assert "unit" not in get_widget_kind("qbittorrent", "totals").config_schema["properties"]
assert "unit" not in get_widget_kind("qbittorrent", "active").config_schema["properties"]
def test_service_config_schema_is_json_schema():
schema = get_service_definition("prometheus").config_schema
assert schema["type"] == "object"