"""Valeurs par defaut d'un groupe : appliquees en pre-remplissage a la creation d'une nouvelle session dans ce dossier (voir app.groups).""" from __future__ import annotations from PySide6.QtWidgets import ( QCheckBox, QComboBox, QDialog, QDialogButtonBox, QFormLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSpinBox, QStackedWidget, QVBoxLayout, QWidget, ) from app.groups import GroupSettings, GroupSettingsStore from app.key_manager import KeyManager from app.openssh.config import load_openssh_hosts from app.session_manager import ( AUTH_AGENT, AUTH_AUTO, AUTH_KEY, AUTH_PASSWORD, BASTION_MANUAL, BASTION_NONE, BASTION_OPENSSH, BASTION_SESSION, BastionConfig, SessionStore, ) class GroupSettingsDialog(QDialog): """Meme principe que la section Bastion de SessionDialog, en plus compact : ce sont des valeurs par defaut, pas la configuration d'une connexion reelle.""" def __init__( self, group_path: str, store: GroupSettingsStore, key_manager: KeyManager, session_store: SessionStore, parent=None, ): super().__init__(parent) self.group_path = group_path self.store = store self.key_manager = key_manager self.session_store = session_store self.settings = store.get(group_path) or GroupSettings(path=group_path) self.setWindowTitle(f"Parametres par defaut — {group_path}") self.setMinimumWidth(420) layout = QVBoxLayout(self) info = QLabel( "Ces valeurs pre-remplissent une nouvelle session creee dans ce dossier " "(bouton « Heriter du groupe » dans son editeur). Elles ne changent jamais " "les sessions deja creees." ) info.setWordWrap(True) layout.addWidget(info) form = QFormLayout() self.username_edit = QLineEdit(self.settings.username) self.port_spin = QSpinBox() self.port_spin.setRange(1, 65535) self.port_spin.setValue(self.settings.port or 22) self.auth_combo = QComboBox() self.auth_combo.addItem("Automatique (comme la commande ssh)", AUTH_AUTO) self.auth_combo.addItem("Cle SSH choisie", AUTH_KEY) self.auth_combo.addItem("Mot de passe (saisi a la connexion)", AUTH_PASSWORD) self.auth_combo.addItem("Agent SSH", AUTH_AGENT) idx = self.auth_combo.findData(self.settings.auth_type) self.auth_combo.setCurrentIndex(idx if idx >= 0 else 0) self.key_combo = QComboBox() for entry in self.key_manager.keys: self.key_combo.addItem(f"{entry.name} ({entry.key_type})", entry.private_path) self.browse_key_btn = QPushButton("Parcourir...") key_row = QWidget() key_layout = QHBoxLayout(key_row) key_layout.setContentsMargins(0, 0, 0, 0) key_layout.addWidget(self.key_combo, 1) key_layout.addWidget(self.browse_key_btn) if self.settings.key_path: existing = self.key_combo.findData(self.settings.key_path) if existing >= 0: self.key_combo.setCurrentIndex(existing) else: self.key_combo.addItem(self.settings.key_path, self.settings.key_path) self.key_combo.setCurrentIndex(self.key_combo.count() - 1) form.addRow("Utilisateur :", self.username_edit) form.addRow("Port :", self.port_spin) form.addRow("Authentification :", self.auth_combo) form.addRow("Cle privee :", key_row) layout.addLayout(form) layout.addWidget(self._build_bastion_group()) keepalive_form = QFormLayout() self.keepalive_check = QCheckBox("Keepalive actif") self.keepalive_check.setChecked(self.settings.keepalive_enabled) self.keepalive_interval_spin = QSpinBox() self.keepalive_interval_spin.setRange(5, 3600) self.keepalive_interval_spin.setSuffix(" s") self.keepalive_interval_spin.setValue(self.settings.keepalive_interval or 30) self.keepalive_count_spin = QSpinBox() self.keepalive_count_spin.setRange(1, 20) self.keepalive_count_spin.setValue(self.settings.keepalive_count_max or 3) keepalive_form.addRow(self.keepalive_check) keepalive_form.addRow("Intervalle :", self.keepalive_interval_spin) keepalive_form.addRow("Echecs avant abandon :", self.keepalive_count_spin) layout.addLayout(keepalive_form) self.auth_combo.currentIndexChanged.connect(self._update_key_row) self.browse_key_btn.clicked.connect(self._browse_key) self._update_key_row() buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(self._on_accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) def _update_key_row(self) -> None: is_key_auth = self.auth_combo.currentData() == AUTH_KEY self.key_combo.setEnabled(is_key_auth) self.browse_key_btn.setEnabled(is_key_auth) def _browse_key(self) -> None: from PySide6.QtWidgets import QFileDialog path, _ = QFileDialog.getOpenFileName(self, "Choisir une cle privee") if path: self.key_combo.addItem(path, path) self.key_combo.setCurrentIndex(self.key_combo.count() - 1) # ---------- Bastion (identique dans l'esprit a SessionDialog, en plus compact) ---------- def _build_bastion_group(self): from PySide6.QtWidgets import QGroupBox bastion = self.settings.bastion group = QGroupBox("Bastion / Jump Host par defaut") v = QVBoxLayout(group) self.bastion_mode_combo = QComboBox() self.bastion_mode_combo.addItem("Aucun", BASTION_NONE) self.bastion_mode_combo.addItem("Une session PySSH existante", BASTION_SESSION) self.bastion_mode_combo.addItem("Un Host de ~/.ssh/config", BASTION_OPENSSH) self.bastion_mode_combo.addItem("Configuration manuelle", BASTION_MANUAL) v.addWidget(self.bastion_mode_combo) self.bastion_stack = QStackedWidget() v.addWidget(self.bastion_stack) self.bastion_stack.addWidget(QWidget()) session_page = QWidget() session_form = QFormLayout(session_page) session_form.setContentsMargins(0, 4, 0, 0) self.bastion_session_combo = QComboBox() for s in sorted(self.session_store.sessions, key=lambda s: s.name.lower()): self.bastion_session_combo.addItem(f"{s.name} ({s.username}@{s.host})", s.id) if self.bastion_session_combo.count() == 0: self.bastion_session_combo.addItem("(aucune session enregistree)", "") self.bastion_session_combo.setEnabled(False) session_form.addRow("Session :", self.bastion_session_combo) self.bastion_stack.addWidget(session_page) openssh_page = QWidget() openssh_form = QFormLayout(openssh_page) openssh_form.setContentsMargins(0, 4, 0, 0) self.bastion_openssh_combo = QComboBox() hosts = load_openssh_hosts() for h in hosts: self.bastion_openssh_combo.addItem(f"{h.alias} ({h.display_target})", h.alias) if not hosts: self.bastion_openssh_combo.addItem("(aucun host dans ~/.ssh/config)", "") self.bastion_openssh_combo.setEnabled(False) openssh_form.addRow("Host :", self.bastion_openssh_combo) self.bastion_stack.addWidget(openssh_page) manual_page = QWidget() manual_form = QFormLayout(manual_page) manual_form.setContentsMargins(0, 4, 0, 0) self.bastion_host_edit = QLineEdit(bastion.host if bastion.mode == BASTION_MANUAL else "") self.bastion_port_spin = QSpinBox() self.bastion_port_spin.setRange(1, 65535) self.bastion_port_spin.setValue(bastion.port or 22) self.bastion_user_edit = QLineEdit(bastion.username if bastion.mode == BASTION_MANUAL else "") manual_form.addRow("Hote :", self.bastion_host_edit) manual_form.addRow("Port :", self.bastion_port_spin) manual_form.addRow("Utilisateur :", self.bastion_user_edit) self.bastion_stack.addWidget(manual_page) self.bastion_mode_combo.currentIndexChanged.connect(self.bastion_stack.setCurrentIndex) mode_idx = self.bastion_mode_combo.findData(bastion.mode) self.bastion_mode_combo.setCurrentIndex(mode_idx if mode_idx >= 0 else 0) self.bastion_stack.setCurrentIndex(self.bastion_mode_combo.currentIndex()) if bastion.mode == BASTION_SESSION: found = self.bastion_session_combo.findData(bastion.session_id) if found >= 0: self.bastion_session_combo.setCurrentIndex(found) elif bastion.mode == BASTION_OPENSSH: found = self.bastion_openssh_combo.findData(bastion.openssh_alias) if found >= 0: self.bastion_openssh_combo.setCurrentIndex(found) return group def _result_bastion(self) -> BastionConfig: mode = self.bastion_mode_combo.currentData() bastion = BastionConfig(mode=mode) if mode == BASTION_SESSION: bastion.session_id = self.bastion_session_combo.currentData() or "" elif mode == BASTION_OPENSSH: bastion.openssh_alias = self.bastion_openssh_combo.currentData() or "" elif mode == BASTION_MANUAL: bastion.host = self.bastion_host_edit.text().strip() bastion.port = self.bastion_port_spin.value() bastion.username = self.bastion_user_edit.text().strip() return bastion def _on_accept(self) -> None: self.settings.path = self.group_path self.settings.username = self.username_edit.text().strip() self.settings.port = self.port_spin.value() self.settings.auth_type = self.auth_combo.currentData() self.settings.key_path = self.key_combo.currentData() or "" self.settings.bastion = self._result_bastion() self.settings.keepalive_enabled = self.keepalive_check.isChecked() self.settings.keepalive_interval = self.keepalive_interval_spin.value() self.settings.keepalive_count_max = self.keepalive_count_spin.value() self.store.set(self.settings) self.accept()