Make a dashboard its widgets: drop the pages and sections nobody drew
This commit is contained in:
@@ -6,8 +6,6 @@ from fluksio.flow.dashboards import (
|
||||
DashboardDef,
|
||||
DashboardNotFound,
|
||||
DashboardStore,
|
||||
PageDef,
|
||||
SectionDef,
|
||||
SettingDef,
|
||||
WidgetDef,
|
||||
default_dashboard,
|
||||
@@ -40,7 +38,7 @@ def test_a_dashboard_survives_a_round_trip(store: DashboardStore):
|
||||
read = store.read("house")
|
||||
|
||||
assert read.name == "house"
|
||||
assert [p.id for p in read.pages] == ["main"]
|
||||
assert read.widgets == []
|
||||
assert read.version == saved.version
|
||||
|
||||
|
||||
@@ -138,20 +136,10 @@ def test_the_deepest_chart_decides_how_much_past_is_kept(store: DashboardStore):
|
||||
store.write(
|
||||
DashboardDef(
|
||||
name="house",
|
||||
pages=[
|
||||
PageDef(
|
||||
id="main",
|
||||
sections=[
|
||||
SectionDef(id="a", widgets=[chart("heating.temp", 400)]),
|
||||
SectionDef(
|
||||
id="b",
|
||||
widgets=[
|
||||
chart("heating.temp", 900),
|
||||
chart("solar.watts", 100),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
widgets=[
|
||||
chart("heating.temp", 400),
|
||||
chart("heating.temp", 900),
|
||||
chart("solar.watts", 100),
|
||||
],
|
||||
)
|
||||
)
|
||||
@@ -163,14 +151,7 @@ def test_a_chart_cannot_ask_for_an_unbounded_series(store: DashboardStore):
|
||||
store.write(
|
||||
DashboardDef(
|
||||
name="house",
|
||||
pages=[
|
||||
PageDef(
|
||||
id="main",
|
||||
sections=[
|
||||
SectionDef(id="a", widgets=[chart("heating.temp", 10**9)])
|
||||
],
|
||||
)
|
||||
],
|
||||
widgets=[chart("heating.temp", 10**9)],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -514,3 +495,49 @@ def test_a_chart_of_runs_must_say_which_runs_and_which_metric():
|
||||
runs_chart(metric="study.loss")
|
||||
with pytest.raises(ValueError, match="between 1 and 5"):
|
||||
runs_chart(metric="study.loss", flow="study", latest=9)
|
||||
|
||||
|
||||
def test_a_document_written_as_pages_is_read_as_one_grid():
|
||||
"""Stored dashboards live in each installation's repository.
|
||||
|
||||
So the old shape is normalised on the way in rather than migrated, and a
|
||||
placed second section keeps its arrangement instead of piling onto the
|
||||
first — which is how the viewer always drew it.
|
||||
"""
|
||||
old = {
|
||||
"name": "house",
|
||||
"pages": [
|
||||
{
|
||||
"id": "main",
|
||||
"sections": [
|
||||
{
|
||||
"id": "a",
|
||||
"widgets": [
|
||||
{
|
||||
"id": "top",
|
||||
"type": "stat",
|
||||
"layout": {"lg": {"x": 0, "y": 0, "w": 3, "h": 2}},
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "b",
|
||||
"widgets": [
|
||||
{
|
||||
"id": "under",
|
||||
"type": "stat",
|
||||
"layout": {"lg": {"x": 0, "y": 1, "w": 3, "h": 2}},
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
read = DashboardDef.model_validate(old)
|
||||
|
||||
assert [w.id for w in read.widgets] == ["top", "under"]
|
||||
# The first section is two rows deep, so the second one starts under it.
|
||||
assert read.widgets[1].layout["lg"].y == 3
|
||||
assert "pages" not in read.model_dump()
|
||||
|
||||
@@ -8,8 +8,6 @@ control or another flow, it pulses a node that did nothing at all.
|
||||
from fluksio.flow.dashboards import (
|
||||
DashboardDef,
|
||||
DashboardStore,
|
||||
PageDef,
|
||||
SectionDef,
|
||||
WidgetDef,
|
||||
)
|
||||
from fluksio.flow.events import EventBus
|
||||
@@ -104,35 +102,25 @@ def test_the_widgets_wired_into_a_flow_are_reported(tmp_path):
|
||||
DashboardDef(
|
||||
name="panel",
|
||||
title="Panel",
|
||||
pages=[
|
||||
PageDef(
|
||||
id="main",
|
||||
sections=[
|
||||
SectionDef(
|
||||
id="main",
|
||||
widgets=[
|
||||
WidgetDef(
|
||||
id="setpoint",
|
||||
type="slider",
|
||||
title="Setpoint",
|
||||
config={"target": "house.setpoint"},
|
||||
),
|
||||
WidgetDef(
|
||||
id="reading",
|
||||
type="stat",
|
||||
title="Reading",
|
||||
config={"message": "house.temp"},
|
||||
),
|
||||
# Another flow's message: not this flow's business.
|
||||
WidgetDef(
|
||||
id="elsewhere",
|
||||
type="stat",
|
||||
config={"message": "garage.temp"},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
widgets=[
|
||||
WidgetDef(
|
||||
id="setpoint",
|
||||
type="slider",
|
||||
title="Setpoint",
|
||||
config={"target": "house.setpoint"},
|
||||
),
|
||||
WidgetDef(
|
||||
id="reading",
|
||||
type="stat",
|
||||
title="Reading",
|
||||
config={"message": "house.temp"},
|
||||
),
|
||||
# Another flow's message: not this flow's business.
|
||||
WidgetDef(
|
||||
id="elsewhere",
|
||||
type="stat",
|
||||
config={"message": "garage.temp"},
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user