Übersicht: Verbindungs-Label klarer, Verbindungszeilen anklickbar

Nutzerfrage: was bedeutet "Optionen" bei einer IP-Adresse verknüpften
DHCP-Netzwerk-Zeile? Umbenannt zu "DHCP-Optionen". Zusätzlich: die
"Verbindungen"-Zeilen im Detailpanel eines Knotens sind jetzt anklickbar
(springt zum verbundenen Element, wie bei Linien-Klicks) und zeigen
beim Hovern eine Klartext-Erklärung als Tooltip (OverviewStyle.
explanation(for:), bereits für EdgeDetailView gebaut).

59 Unit-Tests grün. Manual.md/HANDOFF.md aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
This commit is contained in:
Kay
2026-09-15 14:20:09 +02:00
co-authored by Claude Sonnet 5
parent a7272f059a
commit bd610b0a8c
4 changed files with 33 additions and 10 deletions
+9
View File
@@ -588,6 +588,15 @@ Sichtbarwerden des Tabs neu) — Änderungen aus dem Experte-Tab (z.B. eine
neu angelegte Route) erscheinen jetzt automatisch beim Reinschauen, ohne
manuellen "Aktualisieren"-Klick.
**Verbindungs-Label "Optionen" im Detailpanel unklar, Zeile nicht
anklickbar** — Nutzerfrage nach Klick auf eine IP-Adresse: was bedeutet
"Optionen" bei der verknüpften DHCP-Netzwerk-Zeile? Umbenannt zu
"DHCP-Optionen"; die "Verbindungen"-Zeilen im Detailpanel (`NodeDetailView`)
sind jetzt anklickbar (springt zum verbundenen Knoten, wie schon bei
Linien-Klicks) und zeigen beim Hovern einen Tooltip mit der
Klartext-Erklärung (`OverviewStyle.explanation(for:)`, bereits für
`EdgeDetailView` gebaut, hier wiederverwendet).
## `xcodebuild test` hängt — Gatekeeper, kein Code-Bug
`xcodebuild ... test` kann exakt beim App-Start für ~5 Minuten hängen,
+6 -2
View File
@@ -91,7 +91,9 @@ Grafisches Diagramm des kompletten aktuellen Router-Zustands:
angeklickt wird).
- **Klick auf eine Verbindungslinie** zeigt rechts eine verständliche
Erklärung, was diese Verbindung bedeutet, plus Sprung zu den beiden
verbundenen Elementen.
verbundenen Elementen. Die "Verbindungen"-Liste im Detailpanel eines
Knotens ist ebenfalls klickbar (springt direkt zum verbundenen
Element) und zeigt beim Hovern eine kurze Erklärung als Tooltip.
- **Direktes Bearbeiten**: IP-Adressen, Pools, DHCP-Server/-Netzwerke/
-Clients, Routen, Firewall-Filter-/NAT-Regeln und WireGuard-Peers
lassen sich anklicken und über "Bearbeiten" direkt ändern — schreibt
@@ -213,7 +215,9 @@ Graphical diagram of the router's complete current state:
clicked).
- **Clicking a connection line** shows a plain-language explanation of
what it means in the right-hand panel, plus a jump to both connected
elements.
elements. The "Connections" list in a node's detail panel is also
clickable (jumps straight to the connected element) and shows a short
explanation as a tooltip on hover.
- **Direct editing**: IP addresses, pools, DHCP servers/networks/
clients, routes, firewall filter/NAT rules and WireGuard peers can be
clicked and changed via "Edit" — writes back to the router
@@ -204,7 +204,10 @@ struct OverviewView: View {
viewModel.selectedNodeID = nodeID
}
} else if let id = viewModel.selectedNodeID, let node = viewModel.graph.nodes.first(where: { $0.id == id }) {
NodeDetailView(node: node, graph: viewModel.graph, onEdit: editNode)
NodeDetailView(node: node, graph: viewModel.graph, onEdit: editNode) { nodeID in
selectedEdge = nil
viewModel.selectedNodeID = nodeID
}
} else {
LegendView()
}
@@ -536,6 +539,7 @@ private struct NodeDetailView: View {
let node: OverviewNode
let graph: OverviewGraph
let onEdit: (OverviewNode) -> Void
let onSelectNode: (String) -> Void
var body: some View {
ScrollView {
@@ -578,12 +582,18 @@ private struct NodeDetailView: View {
ForEach(connected) { edge in
let otherID = edge.from == node.id ? edge.to : edge.from
let otherTitle = graph.nodes.first(where: { $0.id == otherID })?.title ?? otherID
Label(
edge.label.map { "\(otherTitle) (\($0))" } ?? otherTitle,
systemImage: edge.from == node.id ? "arrow.right" : "arrow.left"
)
.foregroundStyle(OverviewStyle.color(for: edge.kind))
.font(.caption)
Button {
onSelectNode(otherID)
} label: {
Label(
edge.label.map { "\(otherTitle) (\($0))" } ?? otherTitle,
systemImage: edge.from == node.id ? "arrow.right" : "arrow.left"
)
.foregroundStyle(OverviewStyle.color(for: edge.kind))
.font(.caption)
}
.buttonStyle(.plain)
.help(OverviewStyle.explanation(for: edge.kind))
}
}
}
@@ -189,7 +189,7 @@ final class OverviewViewModel: ObservableObject {
))
let networkPart = address.split(separator: "/").first.map(String.init) ?? address
if let addressID = networkToAddressID[networkPart] {
edges.append(OverviewEdge(from: addressID, to: id, label: "Optionen", kind: .dhcp))
edges.append(OverviewEdge(from: addressID, to: id, label: "DHCP-Optionen", kind: .dhcp))
}
}