49 lines
1.5 KiB
Python
49 lines
1.5 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""Pure status model for the tray applet. No GUI or subprocess imports."""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TrayState:
|
|
running: bool
|
|
total_alerts: int
|
|
high_alerts: int
|
|
last_alert: str | None
|
|
color: str # "green" | "amber" | "grey"
|
|
summary: str
|
|
|
|
@property
|
|
def tooltip(self) -> str:
|
|
return f"Enodia Sentinel — {self.summary}"
|
|
|
|
|
|
def _high_count(counts: dict) -> int:
|
|
# Severity keys are stringified Severity names ("HIGH"/"CRITICAL"); be
|
|
# tolerant of case in case a producer lowercases them.
|
|
total = 0
|
|
for key, value in counts.items():
|
|
if str(key).upper() in ("HIGH", "CRITICAL"):
|
|
total += int(value)
|
|
return total
|
|
|
|
|
|
def parse_status(status: dict | None) -> TrayState:
|
|
if not status:
|
|
return TrayState(False, 0, 0, None, "grey", "Unknown")
|
|
running = bool(status.get("running"))
|
|
total = int(status.get("total_alerts", 0))
|
|
high = _high_count(status.get("counts") or {})
|
|
last = status.get("last_alert")
|
|
if not running:
|
|
return TrayState(False, total, high, last, "grey", "Stopped")
|
|
if high:
|
|
return TrayState(
|
|
True, total, high, last, "amber",
|
|
f"Running — {high} high/critical of {total} alerts",
|
|
)
|
|
if total:
|
|
return TrayState(True, total, high, last, "green",
|
|
f"Running — {total} alerts")
|
|
return TrayState(True, total, high, last, "green", "Running — no alerts")
|