Alle RouterOSFieldSchema.help-Texte in RouterOSSchemaCatalog.swift überarbeitet — jedes Adress-/Netz-/Bereichs-Feld hat jetzt ein konkretes Beispiel (z.B. 192.168.88.1/24), vorher leere Hilfetexte gefüllt. Zusätzlich zwei UI-Wünsche umgesetzt: fette Überschrift (Menüname + Kategorie) im Detailbereich, da vorher unklar war, in welcher Sektion man sich befindet; und hellblaue Hervorhebung des aktiven Eintrags in der linken Liste (per Zeileninhalt-Hintergrund statt .listRowBackground, das vom macOS-Sidebar-Stil überschrieben wird). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
83 lines
4.1 KiB
Swift
83 lines
4.1 KiB
Swift
import SwiftUI
|
|
|
|
struct ExpertView: View {
|
|
@ObservedObject var connectionService: ConnectionService
|
|
@StateObject private var viewModel: ExpertViewModel
|
|
|
|
init(connectionService: ConnectionService) {
|
|
self.connectionService = connectionService
|
|
_viewModel = StateObject(wrappedValue: ExpertViewModel(connectionService: connectionService))
|
|
}
|
|
|
|
var body: some View {
|
|
Group {
|
|
if connectionService.credentials == nil {
|
|
ContentUnavailableView(
|
|
"Nicht verbunden",
|
|
systemImage: "network.slash",
|
|
description: Text("Verbinde dich zuerst im Tab \"Verbinden\" mit deinem Router.")
|
|
)
|
|
} else {
|
|
NavigationSplitView {
|
|
List {
|
|
ForEach(RouterOSMenuCategory.allCases) { category in
|
|
let schemas = RouterOSSchemaCatalog.schemas(in: category)
|
|
if !schemas.isEmpty {
|
|
Section(category.rawValue) {
|
|
ForEach(schemas) { schema in
|
|
let isSelected = viewModel.selectedSchema?.menuPath == schema.menuPath
|
|
Button {
|
|
viewModel.open(schema)
|
|
} label: {
|
|
Text(schema.displayName)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(.vertical, 4)
|
|
.padding(.horizontal, 6)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: 6)
|
|
.fill(isSelected ? Color.blue.opacity(0.25) : Color.clear)
|
|
)
|
|
.contentShape(Rectangle())
|
|
}
|
|
.buttonStyle(.plain)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Section("Eigener Menüpfad") {
|
|
Text("Jeder RouterOS-Menüpfad ist erreichbar, auch wenn er oben nicht gelistet ist — die Felder erscheinen dann generisch (Schlüssel/Wert), ohne kuratierte Erklärung.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
TextField("Menüpfad, z.B. /ip firewall filter", text: $viewModel.customMenuPath)
|
|
.help("Der RouterOS-CLI-Pfad, z.B. \"/interface wireguard\" oder \"/routing ospf instance\".")
|
|
TextField("REST-Pfad, z.B. ip/firewall/filter", text: $viewModel.customRestPath)
|
|
.help("Derselbe Pfad in REST-API-Schreibweise: führende \"/\" weg, Leerzeichen zu \"/\".")
|
|
Button("Öffnen") { viewModel.openCustomPath() }
|
|
.disabled(viewModel.customMenuPath.isEmpty || viewModel.customRestPath.isEmpty)
|
|
}
|
|
}
|
|
.navigationTitle("Experte")
|
|
} detail: {
|
|
if let schema = viewModel.selectedSchema {
|
|
ExpertMenuDetailView(
|
|
viewModel: viewModel,
|
|
schema: schema
|
|
)
|
|
} else {
|
|
ContentUnavailableView(
|
|
"Kein Menü ausgewählt",
|
|
systemImage: "list.bullet.rectangle",
|
|
description: Text("Wähle links einen RouterOS-Bereich aus.")
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
ExpertView(connectionService: ConnectionService())
|
|
}
|