Einrichten-Tab: "Abbrechen"-Button ergänzt

Vorher kein Weg aus dem Wizard außer schrittweise "Zurück" bis zu
Modus. Zentral als Toolbar-Button in SetupView (nicht pro Schritt
dupliziert), mit Bestätigungsdialog gegen Datenverlust, deaktiviert
während eines laufenden Apply. SetupViewModel.finish() in gemeinsame
resetToInitialState() plus benannte finish()/cancel()-Wrapper
aufgeteilt. Live bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Kay
2026-09-16 09:34:03 +02:00
co-authored by Claude Sonnet 5
parent 0b557b55e9
commit f34fc0587a
4 changed files with 54 additions and 0 deletions
+15
View File
@@ -1308,6 +1308,21 @@ später dazukommen könnte, da MikroTik-Router in ärmeren Ländern
(Brasilien, spanischsprachige Länder) stark verbreitet sind — siehe
Claude-Memory `future-language-support.md` für Details.
**"Abbrechen"-Button im Einrichten-Tab ergänzt** (2026-09-16, Nutzerwunsch:
"mir fehlt im einrichte-tab (einfach und experte) noch ein
\"Abbrechen\"-Button") — vorher gab es keinen Weg aus dem Wizard außer
sich Schritt für Schritt per "Zurück" bis zu Modus vorzuklicken. Zentral
in `SetupView.swift` als Toolbar-Button gelöst (nicht in jedem der sieben
Schritt-Views einzeln dupliziert), sichtbar auf jedem Schritt in beiden
Modi, mit `.confirmationDialog` ("Einrichten abbrechen?" /
"Weiter ausfüllen") gegen versehentlichen Datenverlust bereits
eingegebener Werte, deaktiviert während `isApplying` (ein laufendes
Apply soll nicht mitten im Ablauf abreißen). `SetupViewModel.finish()`
in eine private `resetToInitialState()` plus zwei benannte Wrapper
(`finish()`/neues `cancel()`) aufgeteilt — gleicher Reset, aber je nach
Aufrufkontext (erfolgreicher Apply vs. Nutzer bricht ab) unter dem
passenden Namen lesbar. Live bestätigt ("sieht gut aus").
## Nächste Schritte
1. ~~M16: restliche `RouterOSSchemaCatalog.swift`-Sektionen übersetzen~~,
@@ -764,6 +764,9 @@ enum L10n {
"Details anzeigen (RouterOS-Befehle)": "Show Details (RouterOS Commands)",
"Vor dem Anwenden wird automatisch eine Sicherung der aktuellen Konfiguration erstellt (Tab \"Sicherungen\"). Ein garantiertes automatisches Zurückrollen bei Verbindungsabbruch gibt es nicht — bei Problemen die Sicherung im Tab \"Sicherungen\" verwenden oder den Router lokal (Ethernet/Konsole) wiederherstellen.":
"Before applying, a backup of the current configuration is automatically created (\"Backups\" tab). There's no guaranteed automatic rollback if the connection drops — if there are problems, use the backup in the \"Backups\" tab, or restore the router locally (Ethernet/console).",
"Einrichten abbrechen?": "Cancel Setup?",
"Weiter ausfüllen": "Keep Going",
"Alle in diesem Assistenten eingegebenen Werte gehen verloren.": "All values entered in this wizard will be lost.",
"Ablauf": "Progress",
"Änderungen erfolgreich angewendet": "Changes Applied Successfully",
"Jetzt anwenden": "Apply Now",
@@ -4,6 +4,7 @@ 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
@@ -38,6 +39,28 @@ struct SetupView: View {
}
}
}
.toolbar {
if connectionService.credentials != nil {
ToolbarItem(placement: .cancellationAction) {
Button(L10n.t("Abbrechen", appLanguage)) {
showCancelConfirmation = true
}
.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)
@@ -254,6 +254,19 @@ final class SetupViewModel: ObservableObject {
/// LAN afterwards) starts from the router's actual current state rather than this session's
/// now-outdated in-memory one.
func finish() {
resetToInitialState()
}
/// User-initiated abort from any step (per explicit request: no "Abbrechen" button existed
/// anywhere in the wizard before this the only way out was clicking through every remaining
/// step to "Zurück" back to Mode, or force-quitting the app). Same reset as `finish()` the
/// distinction is purely which caller/label makes sense in context (a successful apply vs. a
/// user backing out mid-way) kept as separate names so each call site reads correctly.
func cancel() {
resetToInitialState()
}
private func resetToInitialState() {
step = .mode
mode = .simple
wanConfig = WanConfig(interfaceName: "ether1")