"""Fenêtre d'historique des sessions WGSecure.""" from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QPushButton, QLabel, QHeaderView, QMessageBox, QWidget, ) from PyQt6.QtCore import Qt from PyQt6.QtGui import QColor, QFont from app.core import history as hist from app.ui import theme def _css() -> str: """Feuille de style de la fenêtre d'historique. Fonction et non constante : bâtie à l'import, elle retenait les couleurs du thème chargé à ce moment-là et ignorait celui appliqué au démarrage. """ return f""" QDialog {{ background: {theme.BG_SUNKEN}; }} QLabel {{ color: {theme.TEXT}; background: transparent; }} QTableWidget {{ background: {theme.BG}; color: {theme.TEXT}; gridline-color: {theme.BG_RAISED}; border: none; font-size: 11px; }} QHeaderView::section {{ background: {theme.BG_RAISED}; color: {theme.TEXT}; padding: 5px; border: none; font-weight: bold; font-size: 11px; }} QTableWidget::item:selected {{ background: {theme.ACCENT}; color: {theme.ON_SOLID}; }} QPushButton {{ background: {theme.BG_RAISED}; color: {theme.TEXT}; border-radius: 5px; padding: 6px 14px; border: none; }} QPushButton:hover {{ background: {theme.ACCENT_HOVER}; color: {theme.ON_SOLID}; }} """ class HistoryDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("WGSecure — Historique des sessions") self.setMinimumSize(680, 420) self.setStyleSheet(_css()) self._build_ui() self._load() def _build_ui(self): layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # Bannière banner = QLabel(" 📊 Historique des sessions VPN") banner.setFixedHeight(40) banner.setStyleSheet( f"background: {theme.BG_SUNKEN}; color: {theme.TEXT}; font-size: 14px; font-weight: bold;" ) layout.addWidget(banner) # Tableau self._table = QTableWidget(0, 6) self._table.setHorizontalHeaderLabels([ "Date début", "Serveur", "Profil", "Durée", "↓ Reçu", "↑ Envoyé" ]) self._table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) self._table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents) self._table.verticalHeader().setVisible(False) self._table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows) self._table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) self._table.setAlternatingRowColors(True) self._table.setStyleSheet( _css() + f"QTableWidget {{ alternate-background-color: {theme.BG_RAISED}; }}" ) layout.addWidget(self._table) # Barre infos + boutons bar = QLabel("") bar.setFixedHeight(1) bar.setStyleSheet(f"background: {theme.BG_RAISED};") layout.addWidget(bar) btn_row_w = QVBoxLayout() btn_row_w.setContentsMargins(0, 0, 0, 0) bottom = QHBoxLayout() bottom.setContentsMargins(14, 8, 14, 12) self._summary_lbl = QLabel("") self._summary_lbl.setStyleSheet(f"color: {theme.TEXT_FAINT}; font-size: 11px;") bottom.addWidget(self._summary_lbl) bottom.addStretch() btn_clear = QPushButton("🗑️ Effacer l'historique") btn_clear.setStyleSheet( f"QPushButton {{ background: {theme.FAIL_SOLID}; color: {theme.TEXT}; border-radius: 5px;" " padding: 6px 14px; border: none; }" "QPushButton:hover { background: #e74c3c; }" ) btn_clear.clicked.connect(self._clear) btn_close = QPushButton("Fermer") btn_close.clicked.connect(self.accept) bottom.addWidget(btn_clear) bottom.addWidget(btn_close) bottom_w = QWidget() bottom_w.setStyleSheet(f"background: {theme.BG_SUNKEN};") bottom_w.setLayout(bottom) layout.addWidget(bottom_w) def _load(self): self._table.setRowCount(0) sessions = hist.get_sessions(100) total_rx = total_tx = total_s = 0 for row, s in enumerate(sessions): self._table.insertRow(row) end = s.get("end") color = theme.OK_TEXT if end else theme.WARN_TEXT # vert=terminée, jaune=en cours cells = [ s.get("start", "—"), s.get("server", "—"), s.get("profile", "Défaut"), hist.fmt_duration(s.get("duration")), hist.fmt_bytes(s.get("rx", 0)), hist.fmt_bytes(s.get("tx", 0)), ] for col, text in enumerate(cells): item = QTableWidgetItem(text) item.setForeground(QColor(color)) item.setTextAlignment( Qt.AlignmentFlag.AlignVCenter | (Qt.AlignmentFlag.AlignRight if col >= 3 else Qt.AlignmentFlag.AlignLeft) ) self._table.setItem(row, col, item) total_rx += s.get("rx", 0) total_tx += s.get("tx", 0) if s.get("duration"): total_s += s["duration"] n = len(sessions) self._summary_lbl.setText( f"{n} session{'s' if n > 1 else ''} • " f"Total ↓ {hist.fmt_bytes(total_rx)} " f"↑ {hist.fmt_bytes(total_tx)} • " f"Durée cumulée : {hist.fmt_duration(total_s)}" ) def _clear(self): reply = QMessageBox.question( self, "Confirmer", "Effacer tout l'historique des sessions ?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, ) if reply == QMessageBox.StandardButton.Yes: hist.clear() self._load()