Files
RouterOS/RouterOSAssistant/Core/Models/RouterOSSchema.swift
T
KayandClaude Sonnet 5 c9ecd3a0a9 M9/M10: Einfach/Experte-Modus + Experte-Tab (generischer RouterOS-Zugriff)
M9: Einrichten-Wizard bekommt einen Einfach/Experte-Modusschalter
(ModeStepView). Einfach überspringt VLAN, erlaubt nur ein LAN-Netzwerk
ohne Isolation, Firewall-Grundschutz fest an.

M10: neuer "Experte"-Tab mit generischem Motor (RouterOSMenuItem,
RouterOSCommand.remove, ConnectionService.fetchMenuItems, freies
"eigener Menüpfad"-Feld) plus kuratierten Formularen mit Tooltips
(RouterOSSchemaCatalog) für Firewall/NAT/Mangle/Raw/Adress-Listen,
Interfaces, IP, VPN, WLAN, Queues, System, Werkzeuge.

Live gegen einen hEX-Testrouter verifiziert (erst per SSH, dann vom
Nutzer selbst in der App), dabei 7 reale Bugs gefunden und gefixt —
der wichtigste: RouterOS' SSH-CLI gibt bei fehlgeschlagenen Befehlen
Exit-Code 0 zurück, wodurch apply() app-weit Fehler verschluckte statt
sie zu melden. Danach ergänzt: Bestätigungsdialog vor Anlegen/Ändern
+ Auto-Backup vor dem ersten Experte-Tab-Schreibvorgang je Sitzung
(Angleichung an den Wizard), sowie ein Dauer-Editor (Tage/Std/Min/Sek)
für Lease-/Ablaufzeit-Felder statt Freitext.

Details zu allen Bugs/Fixes: HANDOFF.md, CHATLOG.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EW3r6rW1xCf6UT5jNvt6rn
2026-09-14 00:03:50 +02:00

116 lines
4.9 KiB
Swift

import Foundation
/// One configurable field of a curated RouterOS menu — drives the Expert tool's add/edit form
/// (label, input kind, tooltip) instead of a bare key=value box.
struct RouterOSFieldSchema: Identifiable, Equatable {
enum Kind: Equatable {
case text
case bool
case int
/// Fixed choice list, e.g. a chain name or an action.
case enumPick(options: [String])
/// Populated at runtime from the connected device's interfaces.
case interfacePick
/// Populated at runtime from the existing items of another RouterOS menu — e.g. a DHCP
/// server's "address-pool" field should offer the pools already defined under
/// "/ip pool", not require typing the name from memory. `valueField` is which field of
/// that menu's items to show/use (e.g. "name", or "list" for address-lists).
case menuItemPick(menuPath: String, restPath: String, valueField: String)
/// A RouterOS time value (e.g. "1d12h30m" or a bare number of seconds) — edited as
/// separate day/hour/minute/second steppers instead of free text, since the suffix
/// syntax isn't obvious (confirmed live: a bare number is seconds, units combine in one
/// string, e.g. DHCP "lease-time").
case duration
}
var id: String { key }
/// The actual RouterOS parameter name, e.g. "chain", "action", "dst-port".
let key: String
let label: String
let kind: Kind
/// Tooltip: what this field does.
let help: String
let defaultValue: String?
/// Whether a value is required before the item can be added.
let required: Bool
init(key: String, label: String, kind: Kind, help: String, defaultValue: String? = nil, required: Bool = false) {
self.key = key
self.label = label
self.kind = kind
self.help = help
self.defaultValue = defaultValue
self.required = required
}
}
enum RouterOSMenuCategory: String, CaseIterable, Identifiable {
case firewallFilter = "Firewall: Filter-Regeln"
case firewallNat = "Firewall: NAT (Portweiterleitung etc.)"
case firewallMangle = "Firewall: Mangle (Markierung/QoS-Vorbereitung)"
case firewallRaw = "Firewall: Raw (vor Connection-Tracking)"
case firewallAddressLists = "Firewall: Adress-Listen"
case interfaces = "Interfaces (Bridge, VLAN, VPN-Tunnel...)"
case ipAddressing = "IP-Adressierung & Dienste"
case routing = "Routing"
case vpn = "VPN-Server/Clients"
case wireless = "WLAN / CAPsMAN"
case queues = "Queues / Bandbreiten-Steuerung"
case system = "System"
case tools = "Werkzeuge & Überwachung"
var id: String { rawValue }
}
/// Describes one RouterOS menu the Expert tool can browse/edit. `fields` is the curated form;
/// an empty array means "no curated form yet" — the Expert tool falls back to a fully generic
/// key=value editor for that menu, so every menu is still reachable even before it's curated.
struct RouterOSMenuSchema: Identifiable, Equatable {
var id: String { menuPath }
let menuPath: String
let restPath: String
let category: RouterOSMenuCategory
let displayName: String
/// One-line "what is this" shown above the item list.
let summary: String
/// Longer "was passiert, wenn ich hier etwas ändere" explanation.
let explanation: String
/// Dependency/gotcha callout, shown as a warning box when present.
let warning: String?
let fields: [RouterOSFieldSchema]
/// A couple of field keys to show per row in the item list (e.g. ["chain", "action"]) so
/// entries are recognizable without opening each one. Falls back to showing every field.
let listColumns: [String]
/// True for menus that hold exactly one settable item, not a list (e.g. "/ip dns",
/// "/system identity") — confirmed live against RouterOS 7.24.2: these reject
/// "print terse" outright ("bad parameter terse"), only support plain "print" (colon-value
/// output) and a direct "set key=value" with no `[find ...]`, and can't be added to or
/// removed. The Expert tool skips the add/remove UI and the transports fetch/apply them
/// differently for menus flagged this way.
let isSingleton: Bool
init(
menuPath: String,
restPath: String,
category: RouterOSMenuCategory,
displayName: String,
summary: String,
explanation: String,
warning: String? = nil,
fields: [RouterOSFieldSchema] = [],
listColumns: [String] = [],
isSingleton: Bool = false
) {
self.menuPath = menuPath
self.restPath = restPath
self.category = category
self.displayName = displayName
self.summary = summary
self.explanation = explanation
self.warning = warning
self.fields = fields
self.listColumns = listColumns
self.isSingleton = isSingleton
}
}