"""Vista de alarmas activas (Sprint 6). Renderiza eventos `alarm_event` y `tag_update` para mantener el contador. ACK individual emite signal `acknowledged(alarm_id)`. """ from __future__ import annotations from PySide6.QtCore import Signal from PySide6.QtGui import QColor from PySide6.QtWidgets import ( QAbstractItemView, QHBoxLayout, QHeaderView, QLabel, QPushButton, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget, ) from vmssailor.studio.theme import ( C_EMERGENCY, C_FOG, C_HIGH, C_INFO, C_WARN, mono_font, ui_font, ) _PRIORITY_COLORS = { "emergency": C_EMERGENCY, "high": C_HIGH, "low": C_WARN, "info": C_INFO, } class AlarmsView(QWidget): """Panel de alarmas: tabla + botones ACK.""" acknowledged = Signal(str) """Emite el `alarm_id` al solicitar ACK.""" def __init__(self, parent: QWidget | None = None) -> None: super().__init__(parent) self._alarms: dict[str, dict] = {} outer = QVBoxLayout(self) outer.setContentsMargins(20, 20, 20, 20) outer.setSpacing(12) title_row = QHBoxLayout() title = QLabel("Alarmas") title.setFont(ui_font(20)) title.setStyleSheet(f"color: {C_EMERGENCY}; font-weight: 600;") title_row.addWidget(title) title_row.addStretch(1) self._counter = QLabel("0 activas") self._counter.setFont(mono_font(11)) self._counter.setStyleSheet(f"color: {C_FOG};") title_row.addWidget(self._counter) outer.addLayout(title_row) # Table self._table = QTableWidget(0, 6) self._table.setHorizontalHeaderLabels( ["ID", "Tag", "Prioridad", "Estado", "Mensaje", "Acción"] ) self._table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch) self._table.verticalHeader().setVisible(False) self._table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self._table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) outer.addWidget(self._table, 1) def handle_event(self, event: dict) -> None: if event.get("type") != "alarm_event": return alarm_id = event.get("alarm_id") or event.get("id") if not alarm_id: return state = event.get("state", "active") if state == "cleared": # Quitar self._alarms.pop(alarm_id, None) else: self._alarms[alarm_id] = event self._refresh_table() def _refresh_table(self) -> None: self._table.setRowCount(0) for alarm_id, a in self._alarms.items(): row = self._table.rowCount() self._table.insertRow(row) self._table.setItem(row, 0, QTableWidgetItem(alarm_id[:24])) self._table.setItem(row, 1, QTableWidgetItem(str(a.get("tag_id", "")))) priority = a.get("priority", "—") prio_item = QTableWidgetItem(priority) prio_item.setForeground(QColor(_PRIORITY_COLORS.get(priority, C_FOG))) self._table.setItem(row, 2, prio_item) self._table.setItem(row, 3, QTableWidgetItem(a.get("state", ""))) self._table.setItem(row, 4, QTableWidgetItem(a.get("message", ""))) btn = QPushButton("ACK") btn.clicked.connect(lambda _checked=False, aid=alarm_id: self.acknowledged.emit(aid)) self._table.setCellWidget(row, 5, btn) self._counter.setText(f"{len(self._alarms)} activas")