# -*- coding: utf-8 -*- """ Plugin SubView: Konfiguration (F2). Zeigt und bearbeitet die Konfiguration des ausgewaehlten Plugins. Aehnlich wie die Server- und Satellite-Konfiguration mit Baumstruktur. """ from __future__ import annotations from textual.app import ComposeResult from textual.containers import Vertical from textual.widgets import Static, Tree from textual.widgets.tree import TreeNode from trixy_core.tui.views.base import MainView from trixy_core.tui.config.field_registry import ( FieldMeta, infer_field_meta, ) from trixy_core.tui.widgets.config_editors import ConfigEditorPanel class PluginConfigView(MainView): """F2 im Plugin-Kontext: Plugin-Konfiguration.""" TITLE = "Konfiguration" VIEW_ID = "plugin_config" def __init__(self, **kwargs) -> None: super().__init__(**kwargs) self._plugin_data: dict = {} self._config_data: dict = {} self._modified: dict[str, object] = {} self._selected_path: str = "" def set_plugin(self, plugin_data: dict) -> None: """Setzt die Plugin-Basisdaten.""" self._plugin_data = plugin_data self._config_data = {} self._modified = {} def compose(self) -> ComposeResult: yield Tree("Plugin-Konfiguration", id="plugin-config-tree") yield ConfigEditorPanel(id="plugin-config-editor") yield Static("", id="plugin-config-status") async def on_activate(self) -> None: """Laedt die Plugin-Konfiguration.""" await self._load_config() async def _load_config(self) -> None: """Laedt die Konfiguration des Plugins.""" if not self.connection or not self._plugin_data: return name = self._plugin_data.get("name", "") if not name: self._set_status("Kein Plugin ausgewaehlt", error=True) return try: detail = await self.connection.request_plugin_detail(name) except Exception: self._set_status("Fehler beim Laden der Konfiguration", error=True) return if detail is None or detail.error: self._set_status( detail.error if detail else "Keine Antwort", error=True ) return self._config_data = detail.config or {} self._build_tree() self._set_status("") def _build_tree(self) -> None: """Baut den Konfigurationsbaum auf.""" tree = self.query_one("#plugin-config-tree", Tree) tree.clear() name = self._plugin_data.get("name", "Plugin") tree.root.set_label(f"[bold]{name}[/bold] — Konfiguration") self._add_tree_nodes(tree.root, self._config_data, "") tree.root.expand() def _add_tree_nodes(self, parent: TreeNode, data: dict, prefix: str) -> None: """Fuegt Knoten rekursiv zum Baum hinzu.""" for key, value in sorted(data.items()): path = f"{prefix}.{key}" if prefix else key if isinstance(value, dict): node = parent.add( f"[bold]{key}[/bold]", data={"path": path, "is_section": True}, ) self._add_tree_nodes(node, value, path) node.expand() else: if path in self._modified: display = f"[yellow]{key}[/yellow] = [yellow]{value}[/yellow] *" else: display = f"{key} = {value}" parent.add_leaf( display, data={"path": path, "value": value, "is_section": False}, ) async def on_tree_node_selected(self, event: Tree.NodeSelected) -> None: """Wird aufgerufen wenn ein Baum-Knoten selektiert wird.""" node_data = event.node.data if not node_data or node_data.get("is_section"): return path = node_data.get("path", "") value = node_data.get("value", "") self._selected_path = path # FieldMeta per Auto-Inferenz ermitteln meta = infer_field_meta(value) # Editor anzeigen editor = self.query_one("#plugin-config-editor", ConfigEditorPanel) await editor.show_editor(path, value, meta) self._set_status(f"Bearbeite: {path}") async def on_config_editor_panel_submitted( self, event: ConfigEditorPanel.Submitted ) -> None: """Verarbeitet validierte Werte vom Editor-Panel.""" if event.error: self._set_status(f"Fehler: {event.error}", error=True) return if not self.connection or not self._plugin_data: return name = self._plugin_data.get("name", "") if not name: return try: result = await self.connection.write_plugin_config( plugin_name=name, key_path=event.path, value=event.validated_value, ) if result and result.success: self._modified[event.path] = event.validated_value self._set_status("Gespeichert") await self._load_config() else: error = result.error if result else "Unbekannter Fehler" self._set_status(f"Fehler: {error}", error=True) except Exception as e: self._set_status(f"Fehler: {e}", error=True) def _set_status(self, text: str, error: bool = False) -> None: """Setzt die Statuszeile.""" status = self.query_one("#plugin-config-status", Static) if error: status.update(f"[red]{text}[/red]") elif text: status.update(f"[green]{text}[/green]") else: status.update("")