Ü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:
@@ -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
|
neu angelegte Route) erscheinen jetzt automatisch beim Reinschauen, ohne
|
||||||
manuellen "Aktualisieren"-Klick.
|
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` hängt — Gatekeeper, kein Code-Bug
|
||||||
|
|
||||||
`xcodebuild ... test` kann exakt beim App-Start für ~5 Minuten hängen,
|
`xcodebuild ... test` kann exakt beim App-Start für ~5 Minuten hängen,
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ Grafisches Diagramm des kompletten aktuellen Router-Zustands:
|
|||||||
angeklickt wird).
|
angeklickt wird).
|
||||||
- **Klick auf eine Verbindungslinie** zeigt rechts eine verständliche
|
- **Klick auf eine Verbindungslinie** zeigt rechts eine verständliche
|
||||||
Erklärung, was diese Verbindung bedeutet, plus Sprung zu den beiden
|
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/
|
- **Direktes Bearbeiten**: IP-Adressen, Pools, DHCP-Server/-Netzwerke/
|
||||||
-Clients, Routen, Firewall-Filter-/NAT-Regeln und WireGuard-Peers
|
-Clients, Routen, Firewall-Filter-/NAT-Regeln und WireGuard-Peers
|
||||||
lassen sich anklicken und über "Bearbeiten" direkt ändern — schreibt
|
lassen sich anklicken und über "Bearbeiten" direkt ändern — schreibt
|
||||||
@@ -213,7 +215,9 @@ Graphical diagram of the router's complete current state:
|
|||||||
clicked).
|
clicked).
|
||||||
- **Clicking a connection line** shows a plain-language explanation of
|
- **Clicking a connection line** shows a plain-language explanation of
|
||||||
what it means in the right-hand panel, plus a jump to both connected
|
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/
|
- **Direct editing**: IP addresses, pools, DHCP servers/networks/
|
||||||
clients, routes, firewall filter/NAT rules and WireGuard peers can be
|
clients, routes, firewall filter/NAT rules and WireGuard peers can be
|
||||||
clicked and changed via "Edit" — writes back to the router
|
clicked and changed via "Edit" — writes back to the router
|
||||||
|
|||||||
@@ -204,7 +204,10 @@ struct OverviewView: View {
|
|||||||
viewModel.selectedNodeID = nodeID
|
viewModel.selectedNodeID = nodeID
|
||||||
}
|
}
|
||||||
} else if let id = viewModel.selectedNodeID, let node = viewModel.graph.nodes.first(where: { $0.id == id }) {
|
} 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 {
|
} else {
|
||||||
LegendView()
|
LegendView()
|
||||||
}
|
}
|
||||||
@@ -536,6 +539,7 @@ private struct NodeDetailView: View {
|
|||||||
let node: OverviewNode
|
let node: OverviewNode
|
||||||
let graph: OverviewGraph
|
let graph: OverviewGraph
|
||||||
let onEdit: (OverviewNode) -> Void
|
let onEdit: (OverviewNode) -> Void
|
||||||
|
let onSelectNode: (String) -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@@ -578,12 +582,18 @@ private struct NodeDetailView: View {
|
|||||||
ForEach(connected) { edge in
|
ForEach(connected) { edge in
|
||||||
let otherID = edge.from == node.id ? edge.to : edge.from
|
let otherID = edge.from == node.id ? edge.to : edge.from
|
||||||
let otherTitle = graph.nodes.first(where: { $0.id == otherID })?.title ?? otherID
|
let otherTitle = graph.nodes.first(where: { $0.id == otherID })?.title ?? otherID
|
||||||
Label(
|
Button {
|
||||||
edge.label.map { "\(otherTitle) (\($0))" } ?? otherTitle,
|
onSelectNode(otherID)
|
||||||
systemImage: edge.from == node.id ? "arrow.right" : "arrow.left"
|
} label: {
|
||||||
)
|
Label(
|
||||||
.foregroundStyle(OverviewStyle.color(for: edge.kind))
|
edge.label.map { "\(otherTitle) (\($0))" } ?? otherTitle,
|
||||||
.font(.caption)
|
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
|
let networkPart = address.split(separator: "/").first.map(String.init) ?? address
|
||||||
if let addressID = networkToAddressID[networkPart] {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user