feat: add operational Dashboard
This commit is contained in:
1 parent
4a1959ecd6
commit
b8b741ccee
23 files changed
+1278
-59
No files matched your search
@@ -132,13 +132,41 @@ class FrontendShellTests(unittest.TestCase):
|
||||
def test_dashboard_does_not_fabricate_operational_values(self):
|
||||
self.authenticate()
|
||||
response = self.client.get("/dashboard")
|
||||
self.assertIn(
|
||||
"Live health summary not yet connected",
|
||||
response.text,
|
||||
)
|
||||
self.assertIn("No events are fabricated", response.text)
|
||||
for value in (
|
||||
'id="dashboardFleetTotal"',
|
||||
'id="dashboardActiveRepairs"',
|
||||
'id="dashboardSites"',
|
||||
"/assets/minerops-dashboard.js",
|
||||
"Runtime and lifecycle are separate dimensions",
|
||||
):
|
||||
self.assertIn(value, response.text)
|
||||
self.assertIn("Loading operational overview", response.text)
|
||||
self.assertNotIn("Live health summary not yet connected", response.text)
|
||||
self.assertNotIn("100 TH/s", response.text)
|
||||
|
||||
def test_dashboard_html_omits_unauthorized_sections_and_links(self):
|
||||
self.authenticate(permissions=("dashboard.view", "locations.view"))
|
||||
response = self.client.get("/dashboard")
|
||||
self.assertIn("Locations", response.text)
|
||||
self.assertIn("Open Mine Map", response.text)
|
||||
self.assertNotIn("Fleet overview", response.text)
|
||||
self.assertNotIn("Needs attention", response.text)
|
||||
self.assertNotIn("Open Fleet", response.text)
|
||||
self.assertNotIn("Active repair records", response.text)
|
||||
self.assertNotIn("Open Repair Center", response.text)
|
||||
self.assertNotIn("Mapped miners", response.text)
|
||||
self.assertNotIn("Unmapped miners", response.text)
|
||||
|
||||
def test_dashboard_script_dom_contract_matches_authorized_page(self):
|
||||
self.authenticate()
|
||||
response = self.client.get("/dashboard")
|
||||
javascript = (STATIC_ROOT / "dashboard.js").read_text(encoding="utf-8")
|
||||
declared_ids = re.search(r"const ids = \[(.*?)\];", javascript, re.DOTALL)
|
||||
self.assertIsNotNone(declared_ids)
|
||||
required = set(re.findall(r'"([A-Za-z][A-Za-z0-9]+)"', declared_ids.group(1)))
|
||||
rendered = set(re.findall(r'id="([A-Za-z][A-Za-z0-9]+)"', response.text))
|
||||
self.assertEqual(required - rendered, set())
|
||||
|
||||
def test_map_is_a_structured_operational_view(self):
|
||||
self.authenticate()
|
||||
response = self.client.get("/monitoring/map")
|
||||
@@ -230,6 +258,7 @@ class FrontendShellTests(unittest.TestCase):
|
||||
|
||||
def test_live_app_prefers_new_shell_and_preserves_legacy_pages(self):
|
||||
from app.main import app
|
||||
from app.frontend.router import dashboard_page
|
||||
|
||||
first_handlers = {}
|
||||
for route in app.routes:
|
||||
@@ -250,6 +279,55 @@ class FrontendShellTests(unittest.TestCase):
|
||||
with self.subTest(legacy_path=path):
|
||||
self.assertIn(path, first_handlers)
|
||||
|
||||
dashboard_handlers = [
|
||||
route.endpoint
|
||||
for route in app.routes
|
||||
if route.path == "/dashboard" and "GET" in (route.methods or set())
|
||||
]
|
||||
self.assertIs(dashboard_handlers[0], dashboard_page)
|
||||
self.assertEqual(dashboard_handlers.count(dashboard_page), 1)
|
||||
|
||||
def test_live_dashboard_excludes_legacy_dashboard_injections(self):
|
||||
from app.main import app
|
||||
|
||||
current_user = {
|
||||
"id": "00000000-0000-0000-0000-000000000654",
|
||||
"username": "dashboard-reader",
|
||||
"display_name": "Dashboard Reader",
|
||||
"role": "Read Only",
|
||||
"permissions": [
|
||||
"dashboard.view",
|
||||
"miners.view",
|
||||
"locations.view",
|
||||
"repairs.view",
|
||||
],
|
||||
}
|
||||
app.dependency_overrides[get_current_user] = lambda: current_user
|
||||
try:
|
||||
with patch(
|
||||
"app.identity.request_user_or_none",
|
||||
return_value=current_user,
|
||||
):
|
||||
client = TestClient(app)
|
||||
try:
|
||||
response = client.get("/dashboard")
|
||||
finally:
|
||||
client.close()
|
||||
finally:
|
||||
app.dependency_overrides.pop(get_current_user, None)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("<title>Dashboard | MinerOps</title>", response.text)
|
||||
self.assertIn('id="dashboardFleetTotal"', response.text)
|
||||
self.assertEqual(response.text.count('id="dashboardFleetTotal"'), 1)
|
||||
self.assertNotIn("/assets/minerops-repair-quick-nav.js", response.text)
|
||||
self.assertNotIn(
|
||||
"/assets/minerops-dashboard-repair-summary.js",
|
||||
response.text,
|
||||
)
|
||||
self.assertNotIn("mineropsDashboardRepairSummary", response.text)
|
||||
self.assertNotIn("Repair Summary", response.text)
|
||||
|
||||
|
||||
def test_safe_next_path_accepts_only_protected_local_pages(self):
|
||||
valid = (
|
||||
@@ -365,6 +443,7 @@ class FrontendShellTests(unittest.TestCase):
|
||||
for path in (
|
||||
"/assets/minerops-app.css",
|
||||
"/assets/minerops-app.js",
|
||||
"/assets/minerops-dashboard.js",
|
||||
"/assets/minerops-mine-map.js",
|
||||
"/assets/minerops-fleet.js",
|
||||
):
|
||||
|
||||
Reference in new issue
Block a user