Bump dashboards: bar, icon, forecast and clock widget types

Plumbing only: the widget-type literal and its dtype table on both sides,
the regenerated client, a curated lucide map and four stubs the renderers
are wired to. Also a latching switch and a segmented dropdown, both a
`style` on the control that already publishes and reads back, plus the
option editor a dropdown never had.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HTsT1isxUjw5gtkJk8WhuA
This commit is contained in:
2026-08-20 08:31:36 +02:00
co-authored by Claude Opus 5
parent c005ea48e1
commit 21b01e2d25
11 changed files with 389 additions and 22 deletions
+36
View File
@@ -213,6 +213,7 @@ def test_a_widget_refuses_a_dtype_it_cannot_carry():
def test_the_structured_widgets_bind_their_shapes():
WidgetDef(id="a", type="agenda", config={"message": "a.b", "dtype": "list"})
WidgetDef(id="n", type="notification", config={"message": "a.b", "dtype": "record"})
WidgetDef(id="f", type="forecast", config={"message": "a.b", "dtype": "list"})
with pytest.raises(ValueError):
WidgetDef(id="a", type="agenda", config={"message": "a.b", "dtype": "json"})
@@ -220,6 +221,41 @@ def test_the_structured_widgets_bind_their_shapes():
WidgetDef(
id="n", type="notification", config={"message": "a.b", "dtype": "list"}
)
with pytest.raises(ValueError):
WidgetDef(id="f", type="forecast", config={"message": "a.b", "dtype": "json"})
def test_a_bar_nests_a_second_number():
WidgetDef(
id="b",
type="bar",
config={
"message": "a.in",
"dtype": "float",
"inner": "a.pv",
"inner_dtype": "int",
},
)
with pytest.raises(ValueError):
WidgetDef(
id="b",
type="bar",
config={"message": "a.in", "dtype": "float", "inner_dtype": "bool"},
)
def test_a_bar_is_drawn_on_both_readings_it_nests():
widget = WidgetDef(id="b", type="bar", config={"message": "a.in", "inner": "a.pv"})
assert widget.messages == ["a.in", "a.pv"]
def test_a_clock_reads_nothing_and_publishes_nothing():
widget = WidgetDef(id="c", type="clock", config={"format": "24h"})
assert widget.messages == []
assert widget.target == ""
def test_a_querying_chart_asks_with_a_record_and_draws_a_series():