| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- # -*- 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("")
|