forked from kay/RouterOS
Bug 25/26: geleerte Felder blieben bestehen, Route-Bearbeiten scheiterte an nur-lesbarem Feld
Beide Bugs in ExpertViewModel.pendingCommand, betreffen Experte-Tab direkt (nicht nur den neuen Übersicht-Bearbeiten-Weg): - Bug 25: ein geleertes Textfeld (z.B. Kommentar löschen) wurde beim Speichern aus den Argumenten gefiltert statt explizit als "" gesendet — RouterOS' `set` ändert nur übergebene Parameter, ein weggelassener bleibt unangetastet statt geleert. Fix: Feld bleibt im Argument-Set, wenn es vorher einen Wert hatte; RouterOSCommand's SSH-Zeilen-Rendering gibt einen leeren Wert jetzt als `""` statt als nacktes `feld=` aus. - Bug 26: eine Route bearbeiten (z.B. nur Kommentar ändern) scheiterte mit "bad parameter immediate-gw" — dieses von RouterOS mitgelieferte, nur lesbare/berechnete Feld landete unkuratiert in den freien "Weiteren Parametern" und wurde bei jedem Speichern blind mitgeschickt. Fix: ein unkuratiertes Feld wird nur noch gesendet, wenn sein Wert sich gegenüber dem ursprünglich geladenen Item tatsächlich geändert hat. 54 Unit-Tests grün (neue ExpertViewModelTests + eine Ergänzung in RouterOSCommandBuilderTests). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
This commit is contained in:
@@ -135,6 +135,9 @@ struct RouterOSCommand: Equatable, Identifiable {
|
||||
}
|
||||
|
||||
private static func quoteIfNeeded(_ value: String) -> String {
|
||||
value.contains(" ") ? "\"\(value)\"" : value
|
||||
// An empty value must render as an explicit `""`, not a bare `key=` with nothing after
|
||||
// the `=` — that's how RouterOS' CLI represents "clear this field" versus a syntax error.
|
||||
if value.isEmpty { return "\"\"" }
|
||||
return value.contains(" ") ? "\"\(value)\"" : value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,13 @@ final class ExpertViewModel: ObservableObject {
|
||||
/// actually executes, consistent with the rest of the app never applying silently.
|
||||
var pendingCommand: RouterOSCommand? {
|
||||
guard let schema = selectedSchema, let editingItem else { return nil }
|
||||
var arguments = formValues.filter { !$0.value.isEmpty }
|
||||
// Keep a curated field even when now empty if it previously held a value — RouterOS'
|
||||
// `set` only touches parameters it's given, so simply omitting a cleared field (the
|
||||
// naive "drop empty values" rule) leaves the old value in place instead of clearing it.
|
||||
// Confirmed live (2026-09-15): deleting a comment's text and saving left the old comment
|
||||
// on the router. Still drop fields that were already empty/unset, same as before — no
|
||||
// point sending e.g. an untouched optional field as "" on every save.
|
||||
var arguments = formValues.filter { !$0.value.isEmpty || !(editingItem.fields[$0.key] ?? "").isEmpty }
|
||||
// RouterOS' CLI parser rejects "true"/"false" for boolean parameters — it only accepts
|
||||
// "yes"/"no" (confirmed live: "disabled=false" on "/interface vlan add" produced
|
||||
// "syntax error (line 1 column 30)"; "disabled=no" succeeded). Schema defaults are
|
||||
@@ -161,8 +167,18 @@ final class ExpertViewModel: ObservableObject {
|
||||
if value == "true" { arguments[field.key] = "yes" }
|
||||
else if value == "false" { arguments[field.key] = "no" }
|
||||
}
|
||||
// Only resend an uncurated ("Weitere Parameter") field if the user actually changed it
|
||||
// (or added a brand-new one) — RouterOS' `print`/REST GET returns some fields that are
|
||||
// computed/read-only and rejected on `set` (confirmed live: a route's "immediate-gw",
|
||||
// "bad parameter immediate-gw"). Since `startEditing` pre-fills every uncurated field
|
||||
// from the live item for visibility, blindly resending all of them on every save — even
|
||||
// to change one unrelated curated field like a comment — resent that computed value
|
||||
// unchanged and broke the whole edit. Comparing against `editingItem.fields` (the
|
||||
// untouched original) tells "user touched this" apart from "just showing what's there".
|
||||
for extra in extraFields where !extra.key.isEmpty {
|
||||
arguments[extra.key] = extra.value
|
||||
if extra.value != editingItem.fields[extra.key] {
|
||||
arguments[extra.key] = extra.value
|
||||
}
|
||||
}
|
||||
let isNew = editingItem.id.isEmpty
|
||||
let summary = "\(isNew ? "Neu anlegen" : "Ändern") unter \(schema.menuPath)"
|
||||
|
||||
Reference in New Issue
Block a user