"""Tab del Dashboard.""" from PySide6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QGroupBox, QTableWidget, QTableWidgetItem, QPushButton, QGridLayout ) from PySide6.QtCore import Qt from PySide6.QtGui import QFont from ..db.job_repository import JobRepository class DashboardTab(QWidget): """Tab del Dashboard con estadísticas y estado.""" def __init__(self, engine): """Inicializa el tab.""" super().__init__() self.engine = engine self._setup_ui() self._load_initial_stats() def _setup_ui(self): """Configura la interfaz.""" layout = QVBoxLayout(self) layout.setSpacing(15) # Título title = QLabel("Dashboard - Estado del Sistema") title_font = QFont() title_font.setPointSize(16) title_font.setBold(True) title.setFont(title_font) layout.addWidget(title) # Grid de estadísticas stats_group = QGroupBox("Estadísticas de Jobs") stats_layout = QGridLayout() self.stats_labels = {} stats_items = [ ("total", "Total de Jobs", 0, 0), ("queued", "En Cola", 0, 1), ("running", "Ejecutando", 0, 2), ("completed", "Completados", 1, 0), ("failed", "Fallados", 1, 1), ("active_threads", "Threads Activos", 1, 2) ] for key, label_text, row, col in stats_items: label = QLabel(label_text + ":") value = QLabel("0") value_font = QFont() value_font.setPointSize(18) value_font.setBold(True) value.setFont(value_font) value.setAlignment(Qt.AlignmentFlag.AlignCenter) stats_layout.addWidget(label, row * 2, col) stats_layout.addWidget(value, row * 2 + 1, col) self.stats_labels[key] = value stats_group.setLayout(stats_layout) layout.addWidget(stats_group) # Tiempos promedio times_group = QGroupBox("Tiempos Promedio (completados)") times_layout = QHBoxLayout() self.time_labels = {} time_items = [ ("total_ms", "Total"), ("extract_ms", "Extracción"), ("restore_ms", "Restauración") ] for key, label_text in time_items: vbox = QVBoxLayout() label = QLabel(label_text + ":") value = QLabel("0 s") value_font = QFont() value_font.setPointSize(14) value_font.setBold(True) value.setFont(value_font) value.setAlignment(Qt.AlignmentFlag.AlignCenter) vbox.addWidget(label) vbox.addWidget(value) times_layout.addLayout(vbox) self.time_labels[key] = value times_group.setLayout(times_layout) layout.addWidget(times_group) # Estado del motor motor_group = QGroupBox("Estado del Motor") motor_layout = QHBoxLayout() self.motor_status_label = QLabel("Detenido") motor_status_font = QFont() motor_status_font.setPointSize(14) motor_status_font.setBold(True) self.motor_status_label.setFont(motor_status_font) self.motor_status_label.setStyleSheet("color: red;") motor_layout.addWidget(QLabel("Estado:")) motor_layout.addWidget(self.motor_status_label) motor_layout.addStretch() motor_group.setLayout(motor_layout) layout.addWidget(motor_group) # Últimos jobs recent_group = QGroupBox("Últimos 10 Jobs") recent_layout = QVBoxLayout() self.recent_table = QTableWidget() self.recent_table.setColumnCount(5) self.recent_table.setHorizontalHeaderLabels([ "Job ID", "Archivo", "Nodo", "DB", "Estado" ]) self.recent_table.horizontalHeader().setStretchLastSection(True) recent_layout.addWidget(self.recent_table) refresh_btn = QPushButton("🔄 Actualizar") refresh_btn.clicked.connect(self._refresh_recent_jobs) recent_layout.addWidget(refresh_btn) recent_group.setLayout(recent_layout) layout.addWidget(recent_group) layout.addStretch() def _load_initial_stats(self): """Carga las estadísticas iniciales.""" stats = self.engine.get_stats() self.update_stats(stats) self._refresh_recent_jobs() def update_stats(self, stats: dict): """Actualiza las estadísticas en la UI.""" # Contadores for key in ["total", "queued", "running", "completed", "failed", "active_threads"]: if key in stats: self.stats_labels[key].setText(str(stats[key])) # Tiempos for key in ["total_ms", "extract_ms", "restore_ms"]: if key in stats: ms = stats[key] seconds = ms / 1000 if seconds >= 60: minutes = seconds / 60 text = f"{minutes:.1f} min" else: text = f"{seconds:.1f} s" self.time_labels[key].setText(text) # Estado del motor if stats.get("running"): if stats.get("paused"): self.motor_status_label.setText("Pausado") self.motor_status_label.setStyleSheet("color: orange;") else: self.motor_status_label.setText("Corriendo") self.motor_status_label.setStyleSheet("color: green;") else: self.motor_status_label.setText("Detenido") self.motor_status_label.setStyleSheet("color: red;") def _refresh_recent_jobs(self): """Refresca la tabla de jobs recientes.""" jobs = JobRepository.get_all(limit=10) self.recent_table.setRowCount(len(jobs)) for i, job in enumerate(jobs): self.recent_table.setItem(i, 0, QTableWidgetItem(job.job_id[:8])) self.recent_table.setItem(i, 1, QTableWidgetItem(job.source_name)) self.recent_table.setItem(i, 2, QTableWidgetItem(job.node_name or "N/A")) self.recent_table.setItem(i, 3, QTableWidgetItem(job.db_name or "N/A")) status_item = QTableWidgetItem(job.status) # Colorear según estado if job.status == "completed": status_item.setForeground(Qt.GlobalColor.darkGreen) elif "failed" in job.status: status_item.setForeground(Qt.GlobalColor.red) self.recent_table.setItem(i, 4, status_item) self.recent_table.resizeColumnsToContents()