feat(dashboard): a curated default layout, merged duplicate widgets, a labelled Overview (#5213)
- New installs start from widgets.RECOMMENDED, packed row by row for the enabled plugins; the edit drawer can reset a dashboard to it. - Host Agent — Resources folds into Hosts — Overview (which gains load 1m), UniFi — Devices into UniFi — Overview; migration 0032 moves existing dashboards onto the survivors. - The Overview labels what it counts (hosts, monitors up/down/pending, alerts firing) and lists firing alerts and down monitors with since-times. - Uptime polls every 5 minutes (poll_seconds) instead of every cycle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
"""Integration: "Reset to the recommended layout" replaces a dashboard's
|
||||
widgets with widgets.RECOMMENDED, and only for someone who may edit it
|
||||
(#5213), against real Postgres."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
if not os.environ.get("STEWARD_DATABASE_URL"):
|
||||
pytest.skip("needs Postgres")
|
||||
from steward.app import create_app
|
||||
return create_app(testing=False)
|
||||
|
||||
|
||||
async def _client(app, role):
|
||||
from steward.models.users import User, UserRole
|
||||
uid, tag = str(uuid.uuid4()), uuid.uuid4().hex[:8]
|
||||
async with app.db_sessionmaker() as s:
|
||||
async with s.begin():
|
||||
s.add(User(id=uid, username=f"reset-{tag}", email=f"reset-{tag}@test",
|
||||
password_hash="x", role=UserRole(role), is_active=True))
|
||||
client = app.test_client()
|
||||
async with client.session_transaction() as sess:
|
||||
sess.update(user_id=uid, user_role=role, username=f"reset-{tag}",
|
||||
_csrf="test-token", login_at=time.time())
|
||||
return client, uid
|
||||
|
||||
|
||||
CSRF = {"X-CSRF-Token": "test-token"}
|
||||
|
||||
|
||||
def test_reset_puts_back_the_recommended_layout_for_its_owner_only(app):
|
||||
from sqlalchemy import select
|
||||
from steward.core.widgets import recommended_layout
|
||||
from steward.models.dashboard import Dashboard, DashboardWidget
|
||||
|
||||
async def _go():
|
||||
owner, owner_id = await _client(app, "operator")
|
||||
other, _ = await _client(app, "operator")
|
||||
async with app.db_sessionmaker() as s:
|
||||
async with s.begin():
|
||||
dash = Dashboard(name="mine", owner_id=owner_id)
|
||||
s.add(dash)
|
||||
await s.flush()
|
||||
s.add(DashboardWidget(dashboard_id=dash.id, widget_key="monitors",
|
||||
grid_x=3, grid_y=9, grid_w=2, grid_h=2))
|
||||
dash_id = dash.id
|
||||
|
||||
assert (await other.post(f"/d/{dash_id}/edit/reset", headers=CSRF)).status_code == 403
|
||||
resp = await owner.post(f"/d/{dash_id}/edit/reset", headers=CSRF)
|
||||
assert resp.status_code == 302 and resp.headers["Location"].endswith(f"/d/{dash_id}")
|
||||
|
||||
async with app.db_sessionmaker() as s:
|
||||
rows = (await s.execute(select(DashboardWidget).where(DashboardWidget.dashboard_id == dash_id)
|
||||
.order_by(DashboardWidget.grid_y, DashboardWidget.grid_x))).scalars().all()
|
||||
want = recommended_layout(app.config.get("PLUGINS", {}))
|
||||
assert [(w.widget_key, w.grid_x, w.grid_y, w.grid_w, w.grid_h) for w in rows] == \
|
||||
[(i["key"], i["x"], i["y"], i["w"], i["h"]) for i in want]
|
||||
|
||||
asyncio.run(_go())
|
||||
Reference in New Issue
Block a user