Files
RouterOS/RouterOSAssistant/Features/Overview/OverviewLayout.swift
T
KayandClaude Sonnet 5 10f30a8a7f M11: Übersicht-Tab — IST-Zustand-Diagramm des Routers
Neuer Tab zeigt die komplette aktuelle Router-Konfiguration als grafisches
Diagramm: Interfaces, IP-Adressen, DHCP/Pools, Routen und Firewall/NAT in
Spalten, verbunden durch Linien, die RouterOS' eigene Referenzfelder
abbilden (VLAN->Basis-Interface, DHCP-Server->Pool, Firewall-Regel->
Interface/Adress-Liste usw.), nicht geraten. Rein lesend, kein apply().

Verbindungsarten sind farblich getrennt (8 Kategorien), Hover/Klick auf
eine Karte hebt ihre Linien hervor und blendet den Rest ab. Detail-Panel
zeigt Rohfelder + Verbindungen; Legende erklärt Spalten, Farben und listet
bewusst nicht gegraphte Bereiche (VPN, WLAN-Sicherheitsprofile, Queues,
System, Werkzeuge, Mangle/Raw), die weiterhin im Experte-Tab erreichbar
bleiben.

OverviewViewModel.buildGraph ist eine reine, nonisolated Funktion,
getestet in OverviewGraphTests (6 Fälle: IP/Interface, VLAN-Parent,
DHCP->Pool, DHCP-Netzwerk->passende IP-Adresse über RouterOS' eigenes
"network"-Feld, Route nur bei Interface-Gateway, Firewall->Interface/
Adress-Liste).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
2026-09-14 10:05:39 +02:00

42 lines
1.9 KiB
Swift

import CoreGraphics
/// Fixed column/row grid layout for the Übersicht diagram — pure geometry, no SwiftUI. Columns
/// follow the dependency order left-to-right (interfaces are the foundation everything else
/// attaches to); nodes within a column are stacked top-to-bottom, sorted so repeated runs render
/// in a stable order across reloads.
struct OverviewLayoutResult {
var positions: [String: CGPoint] = [:]
var canvasSize: CGSize = .zero
}
enum OverviewLayout {
static let columnOrder: [OverviewNode.Category] = [.interface, .ipAddress, .service, .route, .firewall]
static let columnWidth: CGFloat = 220
static let rowHeight: CGFloat = 64
static let nodeWidth: CGFloat = 180
static let nodeHeight: CGFloat = 50
static let topInset: CGFloat = 44
static let leftInset: CGFloat = 40
static func layout(for graph: OverviewGraph) -> OverviewLayoutResult {
var positions: [String: CGPoint] = [:]
var maxRows = 0
for (columnIndex, category) in columnOrder.enumerated() {
let nodesInColumn = graph.nodes
.filter { $0.category == category }
.sorted { lhs, rhs in
lhs.kind == rhs.kind ? lhs.title < rhs.title : lhs.kind < rhs.kind
}
maxRows = max(maxRows, nodesInColumn.count)
let x = leftInset + CGFloat(columnIndex) * columnWidth + nodeWidth / 2
for (row, node) in nodesInColumn.enumerated() {
let y = topInset + CGFloat(row) * rowHeight + nodeHeight / 2
positions[node.id] = CGPoint(x: x, y: y)
}
}
let width = leftInset * 2 + CGFloat(columnOrder.count) * columnWidth
let height = topInset * 2 + CGFloat(max(maxRows, 1)) * rowHeight
return OverviewLayoutResult(positions: positions, canvasSize: CGSize(width: width, height: height))
}
}