Files
RouterOS/RouterOSAssistant/Features/Wizard/Steps/Setup/SetupView.swift
T
KayandClaude Sonnet 5 8a5df3338a M25: Einrichten-Wizard-Politur + SSH-Trust-Persistenz endlich verifiziert
- WAN-Schritt: fehlenden "Zurück"-Button ergänzt (beide Modi)
- "Abbrechen"/"Jetzt sichern" prominent gemacht (wie "Neu scannen")
- LAN-/VLAN-Schritt: Adressfelder starten leer, nur Format-Beispiel im
  Feld sichtbar statt vorbelegter Werte. VlanStepView bekam dafür eine
  Validierungssperre auf "Weiter" (fehlte bisher, war ok solange
  Defaults immer gültig waren). Zwei Tests entsprechend angepasst.
- SSH-Host-Key-Trust aus M24 hatte sich entgegen der Live-Bestätigung
  nie tatsächlich persistiert (defaults read zeigte leeren Schlüssel,
  Ursache ungeklärt) — betraf BackupServices dedizierte SSH-Verbindung
  beim ersten Experte-Tab-Schreibversuch pro Sitzung. Erneut über den
  bestehenden Trust-Dialog bestätigt, diesmal per defaults read
  verifiziert statt nur der UI-Bestätigung vertraut.

Alles live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 12:41:47 +02:00

89 lines
4.1 KiB
Swift

import SwiftUI
struct SetupView: View {
@ObservedObject var connectionService: ConnectionService
@StateObject private var viewModel: SetupViewModel
@AppStorage("appLanguage") private var appLanguage: String = "de"
@State private var showCancelConfirmation = false
init(connectionService: ConnectionService) {
self.connectionService = connectionService
_viewModel = StateObject(wrappedValue: SetupViewModel(connectionService: connectionService))
}
var body: some View {
NavigationStack {
Group {
if connectionService.credentials == nil {
ContentUnavailableView(
LocalizedStringKey(L10n.t("Nicht verbunden", appLanguage)),
systemImage: "network.slash",
description: Text(L10n.t("Verbinde dich zuerst im Tab \"Verbinden\" mit deinem Router.", appLanguage))
)
} else {
switch viewModel.step {
case .mode:
ModeStepView(viewModel: viewModel)
case .wan:
WanStepView(viewModel: viewModel, availableInterfaces: configurableInterfaces)
case .lan:
LanStepView(viewModel: viewModel, availableInterfaces: configurableInterfaces)
case .vlan:
VlanStepView(viewModel: viewModel, availableInterfaces: configurableInterfaces)
case .wifi:
WifiStepView(viewModel: viewModel)
case .firewall:
FirewallStepView(viewModel: viewModel)
case .review:
ReviewApplyView(viewModel: viewModel, credentials: connectionService.credentials)
}
}
}
.toolbar {
if connectionService.credentials != nil {
ToolbarItem(placement: .cancellationAction) {
Button(L10n.t("Abbrechen", appLanguage)) {
showCancelConfirmation = true
}
// Same reasoning/precedent as LAN-Scanner's "Neu scannen" button
// (Bug/Nutzerwunsch: "wird übersehen") — a plain text toolbar button
// blends into the window chrome; `.borderedProminent` gives it a
// filled, colored background so it's actually noticeable. Applied
// consistently to every standalone toolbar action button in the app
// per explicit request ("für die gesamte App fixen").
.buttonStyle(.borderedProminent)
.disabled(viewModel.isApplying)
}
}
}
.confirmationDialog(
L10n.t("Einrichten abbrechen?", appLanguage),
isPresented: $showCancelConfirmation,
titleVisibility: .visible
) {
Button(L10n.t("Abbrechen", appLanguage), role: .destructive) {
viewModel.cancel()
}
Button(L10n.t("Weiter ausfüllen", appLanguage), role: .cancel) {}
} message: {
Text(L10n.t("Alle in diesem Assistenten eingegebenen Werte gehen verloren.", appLanguage))
}
}
.onAppear {
viewModel.prepareDefaults(from: configurableInterfaces)
}
}
/// Loopback is never something a person should pick as WAN/LAN/VLAN base interface —
/// excluded here (not just via defaults) so a parsing hiccup elsewhere can't offer it as
/// a selectable option, which on a real hEX device caused every WAN/firewall command to
/// silently reference "lo" instead of the real WAN port. Found via live testing.
private var configurableInterfaces: [NetworkInterface] {
connectionService.interfaces.filter { $0.type.lowercased() != "loopback" }
}
}
#Preview {
SetupView(connectionService: ConnectionService())
}