Dashboards: Verteilungen fuer Ringdiagramme (Zustand, Distro, Workspace, Organisation)
_dashboard_verteilungen(): Geraetezustand ausschliessend (nie gemeldet, >7 Tage nicht gemeldet, Ressourcen knapp, in Ordnung), Distro und wirksamer Workspace je Geraet ueber geraete_basis(), Organisationen im Admin-Dashboard. Hoechstens 5 Teile + 'Weitere', Sonderfaelle (ohne Installation/Workspace) immer am Ende. GUI-Runde 10/2026 Punkt 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0561691f20
commit
465910f700
1 file changed
+88
@@ -2519,6 +2519,90 @@ def _dashboard_flotten_gesundheit(geraete_rows) -> dict:
|
||||
}
|
||||
|
||||
|
||||
DASHBOARD_VERTEILUNG_MAX = 5
|
||||
VERTEILUNG_SONDERFAELLE = {"ohne Installation", "ohne Workspace", "unbekannt"}
|
||||
|
||||
|
||||
def _verteilung(zaehler: dict, max_teile: int = DASHBOARD_VERTEILUNG_MAX) -> list[dict]:
|
||||
"""Zähler -> [{name, anzahl}] absteigend; ab max_teile+1 Einträgen werden
|
||||
die kleinsten zu "Weitere" zusammengefasst (Ringdiagramm: höchstens
|
||||
sechs Teile, GUI-Runde 09.10.2026)."""
|
||||
|
||||
# Keine echten Kategorien (grau dargestellt) immer ans Ende, damit die
|
||||
# Kategoriefarben für echte Einträge lückenlos in fester Reihenfolge bleiben.
|
||||
sonder = {n: a for n, a in zaehler.items() if n in VERTEILUNG_SONDERFAELLE}
|
||||
teile = sorted(((n, a) for n, a in zaehler.items() if n not in sonder), key=lambda e: (-e[1], e[0]))
|
||||
if len(teile) + len(sonder) > max_teile + 1:
|
||||
behalten = max(max_teile - len(sonder), 1)
|
||||
rest = sum(anzahl for _, anzahl in teile[behalten:])
|
||||
teile = teile[:behalten] + ([("Weitere", rest)] if rest else [])
|
||||
teile += sorted(sonder.items())
|
||||
return [{"name": name, "anzahl": anzahl} for name, anzahl in teile]
|
||||
|
||||
|
||||
def _dashboard_verteilungen(cur, organization_id: str | None = None) -> dict:
|
||||
"""
|
||||
Verteilungen für die Dashboard-Ringdiagramme (GUI-Runde 09.10.2026,
|
||||
Punkt 6): Gerätezustand, Distro, wirksamer Workspace, bei
|
||||
organisationsübergreifender Sicht auch Organisation. Zustand ist
|
||||
ausschließend (jedes Gerät genau einmal): nicht gemeldet hat Vorrang vor
|
||||
knappen Ressourcen.
|
||||
"""
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT d.id, o.name, d.agent_last_checkin, d.health_disk_used_percent, d.health_ram_used_percent
|
||||
FROM devices d
|
||||
JOIN organizations o ON o.id = d.organization_id
|
||||
WHERE d.archived_at IS NULL AND (%(org)s::uuid IS NULL OR d.organization_id = %(org)s::uuid)
|
||||
""",
|
||||
{"org": organization_id},
|
||||
)
|
||||
geraete = cur.fetchall()
|
||||
|
||||
cur.execute("SELECT id, name FROM backends")
|
||||
backend_namen = {str(i): n for i, n in cur.fetchall()}
|
||||
cur.execute("SELECT v.id, w.name FROM workspace_versionen v JOIN workspaces w ON w.id = v.workspace_id")
|
||||
version_workspace = {str(i): n for i, n in cur.fetchall()}
|
||||
|
||||
schwelle = datetime.now(timezone.utc) - timedelta(days=DASHBOARD_KEIN_CHECKIN_TAGE)
|
||||
zustand = {"in Ordnung": 0, "Ressourcen knapp": 0, f"länger als {DASHBOARD_KEIN_CHECKIN_TAGE} Tage nicht gemeldet": 0, "noch nie gemeldet": 0}
|
||||
distros, workspaces, organisationen = {}, {}, {}
|
||||
|
||||
for device_id, org_name, checkin, disk, ram in geraete:
|
||||
if checkin is None:
|
||||
zustand["noch nie gemeldet"] += 1
|
||||
elif checkin < schwelle:
|
||||
zustand[f"länger als {DASHBOARD_KEIN_CHECKIN_TAGE} Tage nicht gemeldet"] += 1
|
||||
elif (disk or 0) >= DASHBOARD_DISK_KRITISCH_PROZENT or (ram or 0) >= DASHBOARD_RAM_KRITISCH_PROZENT:
|
||||
zustand["Ressourcen knapp"] += 1
|
||||
else:
|
||||
zustand["in Ordnung"] += 1
|
||||
|
||||
basis = geraete_basis(cur, str(device_id))
|
||||
if basis is None:
|
||||
distro, workspace = "ohne Installation", "ohne Installation"
|
||||
else:
|
||||
version_id, backend_id = basis
|
||||
distro = backend_namen.get(str(backend_id), "unbekannt")
|
||||
workspace = version_workspace.get(str(version_id), "ohne Workspace") if version_id else "ohne Workspace"
|
||||
distros[distro] = distros.get(distro, 0) + 1
|
||||
workspaces[workspace] = workspaces.get(workspace, 0) + 1
|
||||
organisationen[org_name] = organisationen.get(org_name, 0) + 1
|
||||
|
||||
ergebnis = {
|
||||
"geraete_gesamt": len(geraete),
|
||||
# feste Reihenfolge (Statusfarben), leere Zustände bleiben drin -
|
||||
# die Oberfläche blendet sie in der Legende aus
|
||||
"zustand": [{"name": n, "anzahl": a} for n, a in zustand.items()],
|
||||
"distros": _verteilung(distros),
|
||||
"workspaces": _verteilung(workspaces),
|
||||
}
|
||||
if organization_id is None:
|
||||
ergebnis["organisationen"] = _verteilung(organisationen)
|
||||
return ergebnis
|
||||
|
||||
|
||||
def fetch_customer_dashboard(organization_id: str):
|
||||
with get_database_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
@@ -2538,6 +2622,7 @@ def fetch_customer_dashboard(organization_id: str):
|
||||
(organization_id,),
|
||||
)
|
||||
geraete_rows = cur.fetchall()
|
||||
verteilungen = _dashboard_verteilungen(cur, organization_id)
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
@@ -2570,6 +2655,7 @@ def fetch_customer_dashboard(organization_id: str):
|
||||
},
|
||||
"flotten_gesundheit": _dashboard_flotten_gesundheit(geraete_rows),
|
||||
"aktivitaeten": fetch_aktivitaeten(organization_id, DASHBOARD_LETZTE_AKTIONEN_LIMIT),
|
||||
"verteilungen": verteilungen,
|
||||
"letzte_aktionen": [
|
||||
{
|
||||
"occurred_at": occurred_at.isoformat(),
|
||||
@@ -2677,6 +2763,7 @@ def fetch_admin_dashboard():
|
||||
"""
|
||||
)
|
||||
geraete_rows = cur.fetchall()
|
||||
verteilungen = _dashboard_verteilungen(cur, None)
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
@@ -2718,6 +2805,7 @@ def fetch_admin_dashboard():
|
||||
for org_id, name, geraete_anzahl, letzte_aktivitaet in organisationen
|
||||
],
|
||||
"aktivitaeten": fetch_aktivitaeten(None, DASHBOARD_LETZTE_AKTIONEN_LIMIT),
|
||||
"verteilungen": verteilungen,
|
||||
"letzte_aktionen": [
|
||||
{
|
||||
"occurred_at": occurred_at.isoformat(),
|
||||
|
||||
Reference in new issue
Block a user