M30: Experte-Tab Mode-Taste-Menü + SSH-Trust-/REST-Fixes
Neues Schema für /system routerboard mode-button (enabled/on-event/ hold-time), live gegen echte Hardware verifiziert. Dabei drei echte Bugs gefunden und gefixt: - SSH-Trust-Dead-End beim ersten Experte-Tab-Schreiben (Backup-vor- Schreiben-Pfad hatte keinen Weg, den Trust-Dialog auszulösen) — ConnectionService.noteUntrustedSSHHostKey - RouterOSFieldSchema.clearable: optionale Felder senden nie mehr einen expliziten Leer-Wert, wenn das RouterOS ablehnt - RouterOSMenuSchema.writesRequireSSH + ConnectionService.applyViaSSH: für Menüs ohne REST-Anbindung (bewiesen per direktem SSH-Test) wird zwingend eine dedizierte SSH-Verbindung genutzt statt REST Live Ende-zu-Ende bestätigt: Skript anlegen, Mode-Taste zuweisen, Tastendruck löst Skript korrekt aus. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -115,21 +115,52 @@ Umsetzung (komplett neuer Mechanismus, `AppTextSize.dynamicTypeSize` entfernt):
|
||||
- Alle ~110 `.font(...)`-Aufrufe in der App auf `.appFont(...)` umgestellt (automatisiert per Scratchpad-Skript, textbasierte 1:1-Ersetzung pro bekanntem Font-Ausdruck) — **außer** zwei Stellen mit fest-breiten Pixel-Layouts, die beim Skalieren brechen würden: `OverviewView.NodeCardView` (Diagramm-Knotenkarten, feste `nodeWidth`/`nodeHeight`) und `DevicesView.DeviceRow`/`DeviceColumnHeader` (LAN-Scanner-Tabellenspalten mit festen `DeviceColumn`-Breiten + `lineLimit(1)`). Diese bleiben bewusst fix, sonst Text-Clipping/Überlappung.
|
||||
- Mechanismus per `ImageRenderer`-Snapshot verifiziert (Basis-Text bei Skalierungsfaktor 0,85 vs. 1,4 rendert nachweislich unterschiedlich groß), bevor erneut um Live-Test gebeten wurde.
|
||||
|
||||
Build grün, alle 98 Unit-Tests grün.
|
||||
Build grün, alle 98 Unit-Tests grün. Bitte nochmal live testen — diesmal an Form-lastigen Stellen (z.B. Settings-Fenster selbst, LAN-Scanner-Überschriften/Fehlertexte, nicht die zwei bewusst fixen Ausnahmen).
|
||||
|
||||
Nachbesserung 3 (Live-Test: "textgröße funktioniert, die Farbschemas nicht"): Textgröße bestätigt. Farbschema noch kaputt — beim Fix in Nachbesserung 1 nur die Übersicht-Diagrammfarben (Node-Kategorien/Kanten) überarbeitet, die LAN-Scanner-eigenen Theme-Farben (`trafficActive`/`staticLease`/`dynamicLease`/`portOpen`/`portClosed`) dabei übersehen — die waren weiterhin zu ähnliche SwiftUI-Nachbarfarben (grün/mint, orange/gelb, rot/pink), an einem kleinen Punkt/Icon praktisch nicht unterscheidbar. User fragte, ob selbst am Router geprüft werden kann — nein (kein Zugang/Tool dafür), aber Bug sitzt ohnehin rein im App-Rendering, nicht am Router: per `ImageRenderer`-Snapshot der tatsächlichen Farbwerte selbst verifiziert (Swatch-Vergleich beider Themes, sichtbar unterschiedlich) statt nur zu behaupten, es sei jetzt richtig. Neue Werte: `trafficActive`/`dynamicLease`/`portClosed` grün→blau, `staticLease` orange→lila, `portOpen` rot→orange.
|
||||
### 6. Mode-Button Setup
|
||||
**Status:** fixed (live bestätigt)
|
||||
|
||||
Bitte nochmal live testen — diesmal auch LAN-Scanner-Statuspunkte (Fest/Dynamisch, Port-Scan) einschließen, nicht nur Übersicht-Diagramm.
|
||||
Wunsch: an der Seite des Router ist eine Taste "Mode", diese ist belegbar (Scripte, Deaktivierung, etc). Einlesen, was geht, und bauen.
|
||||
|
||||
Nachbesserung 4 (Live-Test: "Lan-scanner und Übersicht funktionieren" — Farbschema damit bestätigt; aber "Experte-Tab zeigt noch keine Änderung" bei Textgröße): Ursache gefunden — die komplette Sidebar-Liste (`Text(schema.displayName)` in `ExpertView.swift`) und jedes einzelne Parameter/Wert-`TextField` in `ExpertMenuDetailView.swift` hatten von Anfang an **gar kein** `.font(...)`. Die automatisierte `.appFont(...)`-Umstellung ersetzte nur vorhandene `.font(...)`-Aufrufe — unstyled Text/TextField (SwiftUI-Systemstandard, fix) blieb dadurch unangetastet. Fix: `.environment(\.font, .system(size: 13 * scale))` einmal an der `WindowGroup`-Wurzel als Fallback — wirkt nur dort, wo kein eigenes `.appFont(...)`/`.font(...)` bereits einen Font setzt (der gewinnt lokal weiterhin), deckt aber jede unstyled Stelle app-weit ab, nicht nur den Experte-Tab.
|
||||
Recherche (help.mikrotik.com, nicht geraten): `/system routerboard mode-button` ist ein Singleton-Einstellungsmenü (kein Listen-Menü) mit drei echten Feldern:
|
||||
- `enabled` (yes/no, Standard no)
|
||||
- `on-event` (Name eines Skripts aus `/system script`)
|
||||
- `hold-time` (Zeitspanne Min..Max, z.B. `3s..5s`, verfügbar ab RouterOS 6.47beta60)
|
||||
|
||||
Build grün, alle 98 Unit-Tests grün.
|
||||
Wichtiger Fund: ab RouterOS 7.1rc4 muss jede Aktivierung/Änderung dieser Einstellung zusätzlich per physischem Tastendruck (Reset- oder Mode-Taste) am Gerät selbst innerhalb von 60 Sekunden bestätigt werden — eine Änderung allein über die App reicht nicht. Als `warning` im Schema hinterlegt, damit das im Experte-Tab sichtbar ist.
|
||||
|
||||
Nachbesserung 5 (User-Feedback: "keine Änderung beim Farbschema unter Experte") — war kein Bug, sondern Scope: Farbschema war nie für den Experte-Tab verdrahtet, dort gab's schlicht keine kategorie-eingefärbten Elemente (Sidebar/Icons alle `.secondary`). Rückfrage: soll das ausgeweitet werden? User: ja. Umsetzung: `ColorTheme.color(for: RouterOSMenuCategory)` (neu, `AppPreferences.swift`) bucketet die 13 `RouterOSMenuCategory`-Fälle auf die bestehende 5-Farb-Palette (alle 5 Firewall-Untermenüs → `.firewall`, VPN/WLAN/Queues/System/Tools → `.service`) — dieselben Farben wie im Übersicht-Diagramm, keine zweite Palette. `ExpertView.sectionHeader(...)` bekommt neuen optionalen `categoryColor`-Parameter, zeigt bei Kategorie-Sektionen einen 8pt-Farbpunkt vor dem Titel (bei "Eigener Menüpfad" weiterhin `nil`, keine Farbe).
|
||||
Umsetzung: neuer Eintrag in `RouterOSSchemaCatalog.systemFamily` (`/system routerboard mode-button`, `category: .system`, `isSingleton: true`). `on-event` nutzt `.menuItemPick(menuPath: "/system script", ...)` (wie beim bestehenden Zeitplaner) statt Freitext — zeigt eine Auswahl der bereits angelegten Skripte. `hold-time` als `.text` (kein eigener Range-Editor gebaut, dafür wäre ein neuer `RouterOSFieldSchema.Kind` nötig — Skalierungsaufwand für ein einzelnes Feld aktuell nicht gerechtfertigt, Format steht im Hilfetext). DE/EN-Übersetzungen ergänzt. Erreichbar direkt im Experte-Tab unter "System".
|
||||
|
||||
Build grün, alle 98 Unit-Tests grün.
|
||||
Build grün, alle 98 Unit-Tests grün. Nicht live geprüft (kein Router mit Mode-Taste hier erreichbar) — bitte am echten Gerät: Skript unter "Skripte" anlegen, dann unter "Mode-Taste" auswählen + aktivieren, danach die physische Bestätigung am Gerät nicht vergessen (siehe Warnhinweis).
|
||||
|
||||
6. Mode-Button Setup: an der Seite des Router ist eine Taste "Mode" diese ist belegbar (Scripte, Deaktivierung, etc). einlesen, was geht und bauen.
|
||||
7. Manual direkt in die App integrieren.
|
||||
8. Abwechselnde ´Farbkombis bei Tabellenansichten - besser Lesbarkeit
|
||||
9. Settings → Darstellung: anpassbare Farben — freie Farbwahl pro Kategorie/Status statt nur der 2 vordefinierten Themes (Standard/Kontrastreich aus Punkt 5). Beim ursprünglichen Rückfrage bewusst auf 2 Themes beschränkt; falls später gewünscht, bräuchte es ColorPicker pro `OverviewNode.Category`/`OverviewEdgeKind`/LAN-Scanner-Status/`RouterOSMenuCategory` statt der festen `ColorTheme`-Switch-Statements in `AppPreferences.swift`.
|
||||
Nachbesserung 1 (Live-Test beim Skript-Anlegen, nicht Mode-Taste selbst — Bug 40): Skript-Anlegen im Experte-Tab hing dauerhaft an "Unbekannter SSH-Schlüssel ... Bitte bestätigen", auch nach mehrfachem "Anlegen"-Klick. Ursache gefunden (Code gelesen, nicht geraten): `ExpertViewModel.saveEditingItem()`/`confirmRemoval()` und `DevicesViewModel.confirmStaticAssignment()`/`confirmStaticRemoval()` rufen vor dem eigentlichen Schreiben `ensureSessionBackup()` — die erste Sicherung pro Sitzung läuft über `BackupService`s eigene, dedizierte SSH-Verbindung. `ConnectionService.verifySSHTrust` prüft den SSH-Host-Key zwar proaktiv direkt nach jedem erfolgreichen REST-Connect (Bug 13/37-Fix), aber wenn dieser proaktive Check aus irgendeinem Grund nicht (mehr) greift, hatte der Schreibpfad selbst keine Möglichkeit, `pendingSSHTrustFingerprint` zu setzen — der Fehler landete nur als toter Text in `applyError`, ohne Trust-Dialog, exakt derselbe Grundfehler wie Bug 13/37, nur diesmal beim Schreiben statt beim Verbinden.
|
||||
|
||||
Fix: neue `ConnectionService.noteUntrustedSSHHostKey(_:)` — alle vier oben genannten Catch-Blöcke rufen sie bei `RouterOSError.untrustedSSHHostKey` auf, wodurch derselbe Trust-Dialog im Verbinden-Tab erscheint, den `verifySSHTrust` auch nutzt. Bitte nach Rebuild: nochmal "Anlegen" versuchen, diesmal im Verbinden-Tab nach einer Trust-Bestätigung schauen, dort bestätigen, dann im Experte-Tab erneut "Anlegen".
|
||||
|
||||
Build grün, alle 98 Unit-Tests grün. Nicht live geprüft (kein Router hier erreichbar).
|
||||
|
||||
Nachbesserung 2 (Live-Test: Mode-Taste speichern → "Fehlermeldung HTTP 500", gesendeter Befehl laut Vorschau-Anzeige `hold-time=""`): mit echtem Diagnose-Unit-Test nachgestellt statt weiter spekuliert — bei realistischer Datenlage (Router-GET ohne "hold-time"-Feld) entsteht kein leerer Wert, also kein einfacher "Feld war nie gesetzt"-Fall. Tatsächliche Ursache bleibt ungeklärt (kein Router zum Nachstellen erreichbar), aber der Effekt ist reproduzierbar sichtbar: ein leeres `hold-time=""` geht raus und lässt RouterOS' REST-API mit HTTP 500 abbrechen (Time-Interval-Range-Typ akzeptiert wohl keinen leeren String, anders als ein reines Textfeld).
|
||||
|
||||
Fix: neuer `RouterOSFieldSchema.clearable`-Parameter (Default `true`, bestehendes Verhalten für alle anderen Felder unverändert) — ein Feld mit `clearable: false` schickt nie ein explizites Leeren (`feld=""`), selbst wenn die Diff-Logik das sonst täte. `hold-time` ist jetzt `clearable: false`. Neuer Test `testNonClearableFieldNeverSendsExplicitEmptyValue` deckt das ab, bestehender `testClearingACuratedFieldSendsExplicitEmptyValue` (Kommentar-Feld leeren) bleibt unverändert grün — betrifft also nur `hold-time`, nicht die generelle "Feld leeren"-Funktion.
|
||||
|
||||
Build grün, alle 99 Unit-Tests grün. Bitte nochmal live testen: Mode-Taste mit "Aktiviert" + Skript speichern, "Haltedauer" leer lassen.
|
||||
|
||||
Nachbesserung 3 (Live-Test: Fehler blieb identisch, obwohl `hold-time` laut Vorschau-Anzeige jetzt korrekt weggelassen wurde — bewies, dass Nachbesserung 2 zwar wirkt, aber nicht die Ursache war): User führte denselben Befehl direkt per SSH-Terminal am Router aus (`/system routerboard mode-button set enabled=yes on-event="Button test"`) — dort lief er sofort fehlerfrei, `print` bestätigte alle drei Felder korrekt gesetzt (inkl. Werks-Default `hold-time: 0s..1m`, den es demnach doch gibt — passt zur ursprünglichen Vermutung in Nachbesserung 2, war aber am Ende nicht die eigentliche Fehlerursache). Damit zweifelsfrei bewiesen: `/system routerboard mode-button` funktioniert über SSH einwandfrei, aber nicht über REST — eine echte Deckungslücke in RouterOS' REST-API für dieses Hardware-Menü, kein App-seitiger Datenfehler.
|
||||
|
||||
Fix: neuer `RouterOSMenuSchema.writesRequireSSH`-Parameter (Default `false`) + `ConnectionService.applyViaSSH(_:)` (dedizierte SSH-Verbindung, exakt dasselbe Muster wie `BackupService`/`UpdateService`). `ExpertViewModel.saveEditingItem()` nutzt für als `writesRequireSSH: true` markierte Schemas jetzt immer diese dedizierte SSH-Verbindung statt der Session-Transport (REST oder SSH, je nachdem wie verbunden wurde). Mode-Taste-Schema entsprechend markiert.
|
||||
|
||||
Build grün, alle 99 Unit-Tests grün. Live bestätigt: Mode-Taste-Speichern über die App lief jetzt fehlerfrei (kein HTTP 500 mehr).
|
||||
|
||||
Nachbesserung 4 (Log zeigte nach Tastendruck: `script,error executing script Button test from sys2 failed, please check it manually (not enough permissions)`) — separates, tieferes RouterOS-Problem, nicht mehr die App/REST-Frage: Skripte, die vom Mode-Button ("sys2"-Kontext) ausgelöst werden, laufen mit eingeschränkten Rechten, nicht mit den vollen Standard-Skript-Rechten. Zwei Versuche schlugen fehl, weil sie nie wirklich beim Router ankamen: der Skriptname war tatsächlich "Button test" (großes B), meine Terminal-Befehle zielten auf "button test" (klein) bzw. nutzten ungültige `set`-Syntax ohne `[find ...]`/Index — RouterOS matchte nichts, `print detail` zeigte danach unverändert `dont-require-permissions=no`. Mit korrektem Index-Befehl (`/system script set 0 dont-require-permissions=yes`) griff es sofort — Log zeigt seither saubere `script,info Mode-Taste gedrückt: ...`-Einträge bei jedem Tastendruck.
|
||||
|
||||
**Fazit für jedes künftige Mode-Taste-Skript**: `dont-require-permissions=yes` setzen, sonst schlägt die Ausführung vom Button aus mit "not enough permissions" fehl, obwohl dasselbe Skript manuell/per Scheduler einwandfrei liefe. Die App hat dafür aktuell noch kein Feld im "Skripte"-Schema (`/system script` kennt nur Name+Inhalt) — bei Bedarf als eigener Punkt ergänzbar (`policy`/`dont-require-permissions`-Felder).
|
||||
|
||||
Mode-Taste (Fund #6) ist damit vollständig live verifiziert: Anlegen über App → Skript korrekt zugewiesen → Speichern ohne Fehler → Tastendruck löst Skript korrekt aus.
|
||||
|
||||
### 7. Manual direkt in die App integrieren
|
||||
**Status:** offen
|
||||
|
||||
### 8. Abwechselnde Farbkombis bei Tabellenansichten
|
||||
**Status:** offen
|
||||
|
||||
Bessere Lesbarkeit durch alternierende Zeilenfarben in Tabellenansichten (LAN-Scanner, Experte-Listen, etc.).
|
||||
|
||||
Reference in New Issue
Block a user