feat(dashboard): widgets fit their content; wide screens get more grid columns (#5249)
CI / lint (push) Successful in 4s
CI / integration (push) Successful in 55s
CI / unit (push) Successful in 1m18s
CI / publish (push) Successful in 1m28s

Each widget is as tall as its content, never taller than its saved height
(where it scrolls). The dashboard is capped at 2400px instead of 1400px.
Past 12 columns' worth of width it adds columns (one per 110px, up to 24)
and places widgets again in reading order at their saved widths, so more sit
side by side instead of stretching. Edit mode shows and saves the
12-column layout, so a layout doesn't depend on the screen it was edited on.

The share view uses the same layout code (static/dash-layout.js).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 13:10:42 -04:00
co-authored by Claude Opus 5.5
parent 3737d08fd9
commit 4dcf958022
8 changed files with 225 additions and 12 deletions
+11
View File
@@ -106,3 +106,14 @@ async def test_a_widget_polls_at_its_own_pace(app):
async with app.test_request_context("/"):
page = await render_template("dashboard/_grid_item.html", item=item, can_edit=False, poll_interval=30)
assert "every 30s" in page
async def test_a_grid_item_carries_its_saved_layout(app):
"""#5249: the saved 12-column place and height, which the page fits to
content in view mode and restores in edit mode."""
item = SimpleNamespace(db=SimpleNamespace(id=7, grid_x=6, grid_y=3, grid_w=6, grid_h=5),
title="Uptime", defn={"poll": False, "detail_url": "/x"}, hx_url="/uptime/widget")
async with app.test_request_context("/"):
page = await render_template("dashboard/_grid_item.html", item=item, can_edit=False, poll_interval=30)
assert 'data-x="6" data-y="3"' in page and 'data-w="6" data-h="5"' in page
assert 'gs-x="6" gs-y="3"' in page