@@ -245,6 +245,106 @@ foreach ($rackLinksByKey as $entry) {
|
||||
'sample_connection_id' => (int)($entry['sample_connection_id'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
$deviceIdByDevicePort = [];
|
||||
foreach ($sql->get(
|
||||
"SELECT id, device_id
|
||||
FROM device_ports",
|
||||
"",
|
||||
[]
|
||||
) as $row) {
|
||||
$portId = (int)($row['id'] ?? 0);
|
||||
$deviceId = (int)($row['device_id'] ?? 0);
|
||||
if ($portId <= 0 || $deviceId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$deviceIdByDevicePort[$portId] = $deviceId;
|
||||
}
|
||||
|
||||
$deviceIdByModulePort = [];
|
||||
foreach ($sql->get(
|
||||
"SELECT mp.id AS port_id, MIN(dp.device_id) AS device_id
|
||||
FROM module_ports mp
|
||||
JOIN modules m ON m.id = mp.module_id
|
||||
JOIN device_port_modules dpm ON dpm.module_id = m.id
|
||||
JOIN device_ports dp ON dp.id = dpm.device_port_id
|
||||
GROUP BY mp.id",
|
||||
"",
|
||||
[]
|
||||
) as $row) {
|
||||
$portId = (int)($row['port_id'] ?? 0);
|
||||
$deviceId = (int)($row['device_id'] ?? 0);
|
||||
if ($portId <= 0 || $deviceId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$deviceIdByModulePort[$portId] = $deviceId;
|
||||
}
|
||||
|
||||
$resolveDeviceId = static function (string $endpointType, int $endpointId) use ($deviceIdByDevicePort, $deviceIdByModulePort): int {
|
||||
if ($endpointId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$type = strtolower(trim($endpointType));
|
||||
if ($type === 'device' || $type === 'device_ports') {
|
||||
return (int)($deviceIdByDevicePort[$endpointId] ?? 0);
|
||||
}
|
||||
if ($type === 'module' || $type === 'module_ports') {
|
||||
return (int)($deviceIdByModulePort[$endpointId] ?? 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
$deviceLinksByKey = [];
|
||||
foreach ($sql->get(
|
||||
"SELECT id, port_a_type, port_a_id, port_b_type, port_b_id
|
||||
FROM connections",
|
||||
"",
|
||||
[]
|
||||
) as $row) {
|
||||
$deviceA = $resolveDeviceId((string)($row['port_a_type'] ?? ''), (int)($row['port_a_id'] ?? 0));
|
||||
$deviceB = $resolveDeviceId((string)($row['port_b_type'] ?? ''), (int)($row['port_b_id'] ?? 0));
|
||||
if ($deviceA <= 0 || $deviceB <= 0 || $deviceA === $deviceB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$from = min($deviceA, $deviceB);
|
||||
$to = max($deviceA, $deviceB);
|
||||
$key = $from . ':' . $to;
|
||||
if (!isset($deviceLinksByKey[$key])) {
|
||||
$deviceLinksByKey[$key] = [
|
||||
'from_device_id' => $from,
|
||||
'to_device_id' => $to,
|
||||
'count' => 0,
|
||||
'sample_connection_id' => (int)($row['id'] ?? 0)
|
||||
];
|
||||
}
|
||||
$deviceLinksByKey[$key]['count']++;
|
||||
}
|
||||
|
||||
$deviceNameById = [];
|
||||
foreach ($topologyPayload as $entry) {
|
||||
$deviceId = (int)($entry['device_id'] ?? 0);
|
||||
if ($deviceId <= 0 || isset($deviceNameById[$deviceId])) {
|
||||
continue;
|
||||
}
|
||||
$deviceNameById[$deviceId] = (string)($entry['device_name'] ?? ('Gerät #' . $deviceId));
|
||||
}
|
||||
|
||||
$deviceLinkPayload = [];
|
||||
foreach ($deviceLinksByKey as $entry) {
|
||||
$fromId = (int)($entry['from_device_id'] ?? 0);
|
||||
$toId = (int)($entry['to_device_id'] ?? 0);
|
||||
$deviceLinkPayload[] = [
|
||||
'from_device_id' => $fromId,
|
||||
'to_device_id' => $toId,
|
||||
'count' => (int)($entry['count'] ?? 0),
|
||||
'from_device_name' => (string)($deviceNameById[$fromId] ?? ('Gerät #' . $fromId)),
|
||||
'to_device_name' => (string)($deviceNameById[$toId] ?? ('Gerät #' . $toId)),
|
||||
'sample_connection_id' => (int)($entry['sample_connection_id'] ?? 0),
|
||||
];
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="dashboard">
|
||||
@@ -343,6 +443,7 @@ foreach ($rackLinksByKey as $entry) {
|
||||
|
||||
<script id="dashboard-topology-data" type="application/json"><?php echo json_encode($topologyPayload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?></script>
|
||||
<script id="dashboard-topology-links" type="application/json"><?php echo json_encode($rackLinkPayload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?></script>
|
||||
<script id="dashboard-topology-device-links" type="application/json"><?php echo json_encode($deviceLinkPayload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?></script>
|
||||
<script>
|
||||
(function () {
|
||||
const root = document.getElementById('dashboard-topology-wall');
|
||||
@@ -366,8 +467,10 @@ foreach ($rackLinksByKey as $entry) {
|
||||
|
||||
const dataTag = document.getElementById('dashboard-topology-data');
|
||||
const linkTag = document.getElementById('dashboard-topology-links');
|
||||
const deviceLinkTag = document.getElementById('dashboard-topology-device-links');
|
||||
let nodes = [];
|
||||
let rackLinks = [];
|
||||
let deviceLinks = [];
|
||||
try {
|
||||
nodes = JSON.parse((dataTag && dataTag.textContent) || '[]');
|
||||
} catch (error) {
|
||||
@@ -378,6 +481,11 @@ foreach ($rackLinksByKey as $entry) {
|
||||
} catch (error) {
|
||||
rackLinks = [];
|
||||
}
|
||||
try {
|
||||
deviceLinks = JSON.parse((deviceLinkTag && deviceLinkTag.textContent) || '[]');
|
||||
} catch (error) {
|
||||
deviceLinks = [];
|
||||
}
|
||||
|
||||
const scene = { width: 2400, height: 1400 };
|
||||
let view = { x: 0, y: 0, width: scene.width, height: scene.height };
|
||||
@@ -513,6 +621,7 @@ foreach ($rackLinksByKey as $entry) {
|
||||
|
||||
const positioned = [];
|
||||
const rackCenters = new Map();
|
||||
const deviceCenters = new Map();
|
||||
let maxY = 1400;
|
||||
let locationIndex = 0;
|
||||
|
||||
@@ -607,6 +716,9 @@ foreach ($rackLinksByKey as $entry) {
|
||||
port_count: Number(device.port_count || 0),
|
||||
port_preview: Array.isArray(device.port_preview) ? device.port_preview : []
|
||||
});
|
||||
if (Number(device.device_id || 0) > 0) {
|
||||
deviceCenters.set(Number(device.device_id || 0), { x, y });
|
||||
}
|
||||
});
|
||||
|
||||
rackCursorY += rackHeight + 16;
|
||||
@@ -651,7 +763,7 @@ foreach ($rackLinksByKey as $entry) {
|
||||
|
||||
const width = Math.max(2400, 220 + locationIndex * 760);
|
||||
const height = Math.max(1400, Math.ceil(maxY));
|
||||
return { entries: positioned, rackCenters, width, height };
|
||||
return { entries: positioned, rackCenters, deviceCenters, width, height };
|
||||
}
|
||||
|
||||
function showOverlay(item) {
|
||||
@@ -898,6 +1010,30 @@ foreach ($rackLinksByKey as $entry) {
|
||||
});
|
||||
});
|
||||
|
||||
deviceLinks.forEach((link) => {
|
||||
const fromDeviceId = Number(link.from_device_id || 0);
|
||||
const toDeviceId = Number(link.to_device_id || 0);
|
||||
const count = Math.max(1, Number(link.count || 1));
|
||||
const fromPoint = layout.deviceCenters.get(fromDeviceId);
|
||||
const toPoint = layout.deviceCenters.get(toDeviceId);
|
||||
if (!fromPoint || !toPoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
const line = svgElement('line');
|
||||
line.setAttribute('x1', String(fromPoint.x));
|
||||
line.setAttribute('y1', String(fromPoint.y));
|
||||
line.setAttribute('x2', String(toPoint.x));
|
||||
line.setAttribute('y2', String(toPoint.y));
|
||||
line.setAttribute('class', 'topology-device-link-line');
|
||||
line.setAttribute('stroke-width', String(Math.min(5, 1 + (count * 0.4))));
|
||||
|
||||
const title = svgElement('title');
|
||||
title.textContent = `${link.from_device_name || `Gerät ${fromDeviceId}`} <-> ${link.to_device_name || `Gerät ${toDeviceId}`}: ${count} Verbindungen`;
|
||||
line.appendChild(title);
|
||||
connectionLayer.appendChild(line);
|
||||
});
|
||||
|
||||
rackLinks.forEach((link) => {
|
||||
const fromRackId = Number(link.from_rack_id || 0);
|
||||
const toRackId = Number(link.to_rack_id || 0);
|
||||
@@ -1262,6 +1398,13 @@ foreach ($rackLinksByKey as $entry) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.topology-device-link-line {
|
||||
stroke: #56a17f;
|
||||
stroke-opacity: 0.5;
|
||||
stroke-linecap: round;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.topology-connection-line:hover,
|
||||
.topology-connection-line:focus,
|
||||
.topology-connection-line.active {
|
||||
|
||||
Reference in New Issue
Block a user