| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- # -*- coding: utf-8 -*-
- """
- Trainer-View: Tabellarische Liste aller verfuegbaren Trainer.
- Zeigt Trainer in einer DataTable mit Name, Typ, Modell, Version.
- Enter/Klick auf eine Zeile oeffnet die Trainer-Detailansicht.
- """
- from __future__ import annotations
- from textual.app import ComposeResult
- from textual.widgets import Static, DataTable
- from trixy_core.tui.views.base import MainView
- class TrainerView(MainView):
- """
- F7: Trainer-Ansicht.
- Zeigt alle verfuegbaren ML-Trainer tabellarisch.
- Zeilen-Auswahl oeffnet Detail-Sub-Navigation.
- """
- TITLE = "Trainer"
- VIEW_ID = "trainer"
- def __init__(self, **kwargs) -> None:
- super().__init__(**kwargs)
- self._trainers: list[dict] = []
- self._refresh_counter: int = 0
- def compose(self) -> ComposeResult:
- yield Static("", id="trainer-header")
- yield DataTable(id="trainer-table", cursor_type="row")
- yield Static("", id="trainer-status")
- async def on_activate(self) -> None:
- """Laedt die Trainer-Liste."""
- table = self.query_one("#trainer-table", DataTable)
- if not table.columns:
- table.add_columns("Name", "Typ", "Modell-Typ", "Version", "Autor")
- await self._load_trainers()
- async def refresh_data(self) -> None:
- """Periodisches Update (alle 20 Sekunden)."""
- self._refresh_counter += 1
- if self._refresh_counter % 10 == 0:
- await self._load_trainers()
- async def _load_trainers(self) -> None:
- """Laedt die Trainer-Liste vom Server."""
- if not self.connection:
- return
- try:
- response = await self.connection.request_trainers()
- except Exception:
- self._set_status("Fehler beim Laden der Trainer", error=True)
- return
- if response is None:
- return
- self._trainers = response.trainers
- self._update_header()
- self._update_table()
- def _update_header(self) -> None:
- """Aktualisiert die Kopfzeile."""
- header = self.query_one("#trainer-header", Static)
- total = len(self._trainers)
- core = sum(1 for t in self._trainers if t.get("trainer_type") == "core")
- plugin = total - core
- header.update(f"[bold]Trainer:[/bold] {total} verfuegbar ({core} Core, {plugin} Plugin)")
- def _update_table(self) -> None:
- """Aktualisiert die Trainer-Tabelle."""
- table = self.query_one("#trainer-table", DataTable)
- table.clear()
- for trainer in sorted(self._trainers, key=lambda t: t.get("name", "")):
- name = trainer.get("name", "")
- trainer_type = trainer.get("trainer_type", "")
- model_type = trainer.get("model_type", "")
- version = trainer.get("version", "")
- author = trainer.get("author", "")
- type_label = "[cyan]Core[/cyan]" if trainer_type == "core" else "[green]Plugin[/green]"
- table.add_row(
- name, type_label, model_type, version, author,
- key=trainer.get("trainer_id", name),
- )
- async def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
- """Enter auf einer Zeile: Oeffnet die Detail-Ansicht."""
- row_key = str(event.row_key.value) if event.row_key else ""
- trainer_data = None
- for t in self._trainers:
- if t.get("trainer_id") == row_key:
- trainer_data = t
- break
- if not trainer_data:
- return
- try:
- app = self.app
- if hasattr(app, "open_trainer_detail"):
- await app.open_trainer_detail(trainer_data)
- except Exception:
- pass
- def _set_status(self, text: str, error: bool = False) -> None:
- """Setzt die Statuszeile."""
- status = self.query_one("#trainer-status", Static)
- if error:
- status.update(f"[red]{text}[/red]")
- else:
- status.update(f"[green]{text}[/green]")
|