feat(*): Add ports and lines

This commit is contained in:
Josh Creek
2025-04-15 20:04:37 +01:00
parent 4247212d1a
commit a80fa4adbf
8 changed files with 303 additions and 140 deletions
+27 -2
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import type { Device } from '../../stores/networkStore';
export let device: Device;
import type { NetworkDevice } from '../../lib/types';
export let device: NetworkDevice;
</script>
<div class="device-card">
@@ -10,6 +10,20 @@
{#if device.notes}
<p><em>{device.notes}</em></p>
{/if}
{#if device.ports && device.ports.length}
<h4>Ports:</h4>
<div class="ports-container">
{#each device.ports as port}
<div class="port-item" data-port-key={device.name + '-' + port.portName}>
<p>{port.portName} ({port.speedGbps ?? 1}GbE)</p>
{#if port.connectedTo}
<p>Connected to: {port.connectedTo}</p>
{/if}
</div>
{/each}
</div>
{/if}
</div>
<style>
@@ -17,5 +31,16 @@
border: 1px dashed #aaa;
padding: 1rem;
border-radius: 5px;
max-width: 300px;
}
.ports-container {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.port-item {
background-color: #ffe7d6;
padding: 0.5rem;
border-radius: 4px;
}
</style>
+22 -6
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import type { Machine } from '../../stores/networkStore';
import type { Machine } from '../../lib/types';
import VMCard from './VMCard.svelte';
export let machine: Machine;
@@ -11,6 +11,21 @@
<p><strong>IP Address:</strong> {machine.ipAddress}</p>
<p><strong>OS:</strong> {machine.operatingSystem}</p>
{#if machine.ports && machine.ports.length}
<h4>Ports:</h4>
<div class="ports-container">
{#each machine.ports as port}
<div class="port-item" data-port-key="{machine.machineName}-{port.portName}">
<p>{port.portName} ({port.speedGbps ?? 1}GbE)</p>
{#if port.connectedTo}
<p>Connected to: {port.connectedTo}</p>
{/if}
</div>
{/each}
</div>
{/if}
<!-- VMs -->
{#if machine.software?.vms?.length}
<details>
<summary>Show VMs (Total: {machine.software.vms.length})</summary>
@@ -31,13 +46,14 @@
max-width: 300px;
background-color: #f9f9f9;
}
.machine-card h2 {
margin: 0 0 0.5rem;
}
.vm-list {
margin-top: 0.5rem;
.ports-container {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.port-item {
background-color: #e7f1f9;
padding: 0.5rem;
border-radius: 4px;
}
</style>
+114 -11
View File
@@ -2,34 +2,137 @@
import { onMount } from 'svelte';
import { networkStore, loadNetworkData } from '../../stores/networkStore';
import { get } from 'svelte/store';
import MachineCard from './MachineCard.svelte';
import DeviceCard from './DeviceCard.svelte';
// Optionally pass in a JSON path as a prop
import type { NetworkData, Port } from '../../lib/types';
export let jsonPath: string = '/data/network.json';
// Local state
let data: any;
let data: NetworkData;
// We'll store all port references in one big map for easy access
let lines: any[] = [];
onMount(async () => {
// Load data into the store
await loadNetworkData(jsonPath);
// Subscribe once or use the $ syntax in markup
data = get(networkStore);
// Wait for DOM to render fully
setTimeout(() => {
createLines();
}, 0);
});
/**
* Called after child components have rendered.
* We gather all port references and draw lines using global LeaderLine
*/
async function createLines() {
// Use global UMD version from window
const LeaderLine = (window as any).LeaderLine;
if (!LeaderLine) {
console.error('LeaderLine is not loaded.');
return;
}
// Clear any previous lines
for (const ln of lines) {
ln.remove();
}
lines = [];
type PortInfo = {
parentName: string;
port: Port;
element: HTMLDivElement;
};
const portDataMap: Map<string, PortInfo> = new Map();
// GATHER MACHINE PORTS
for (const machine of data.machines) {
if (machine.ports) {
for (const p of machine.ports) {
const key = `${machine.machineName}-${p.portName}`;
const elem = document.querySelector(`[data-port-key="${key}"]`) as HTMLDivElement;
if (elem) {
portDataMap.set(key, {
parentName: machine.machineName,
port: p,
element: elem
});
}
}
}
}
// GATHER DEVICE PORTS
for (const dev of data.devices) {
if (dev.ports) {
for (const p of dev.ports) {
const key = `${dev.name}-${p.portName}`;
const elem = document.querySelector(`[data-port-key="${key}"]`) as HTMLDivElement;
if (elem) {
portDataMap.set(key, {
parentName: dev.name,
port: p,
element: elem
});
}
}
}
}
// DRAW CONNECTIONS
for (const [key, info] of portDataMap.entries()) {
const localPort = info.port;
if (!localPort.connectedTo) continue;
const remoteKey = localPort.connectedTo;
const remoteInfo = portDataMap.get(remoteKey);
if (!remoteInfo) continue;
if (key > remoteKey) continue; // Avoid duplicates
const localSpeed = localPort.speedGbps ?? 1;
const remoteSpeed = remoteInfo.port.speedGbps ?? 1;
const cableSpeed = Math.min(localSpeed, remoteSpeed);
const color = getLineColor(cableSpeed);
const line = new LeaderLine(info.element, remoteInfo.element, {
path: 'straight',
startPlug: 'behind',
endPlug: 'behind',
color,
size: 4,
middleLabel: LeaderLine.captionLabel({
text: `${cableSpeed}GbE`,
fontSize: 12,
color: 'white',
outlineColor: 'black',
outlineSize: 2
})
});
lines.push(line);
}
}
function getLineColor(speed: number): string {
if (speed >= 10) return 'orange';
if (speed >= 2.5) return 'green';
if (speed >= 1) return 'blue';
return 'gray';
}
</script>
<main>
{#if data}
<div class="diagram-container">
<!-- Render Machines -->
{#each data.machines as machine}
<MachineCard {machine} />
{/each}
<!-- Render Other Devices -->
{#each data.devices as device}
<DeviceCard {device} />
{/each}
@@ -39,10 +142,10 @@
<style>
.diagram-container {
/* Example layout style - customize as needed */
display: flex;
flex-wrap: wrap;
gap: 1rem;
padding: 1rem;
position: relative; /* required for leader-line positioning */
}
</style>
+13 -5
View File
@@ -1,4 +1,10 @@
interface Hardware {
export interface Port {
portName: string;
speedGbps?: number; // default to 1 if not provided
connectedTo?: string; // e.g. "Router-LAN2"
}
export interface Hardware {
cpu: string;
ram: string;
networkPorts: number;
@@ -6,30 +12,32 @@ interface Hardware {
gpu?: string;
}
interface VM {
export interface VM {
name: string;
role: string;
ipAddress: string;
}
interface Software {
export interface Software {
vms: VM[];
}
interface Machine {
export interface Machine {
machineName: string;
ipAddress: string;
role: string;
operatingSystem: string;
software: Software;
hardware: Hardware;
ports?: Port[];
}
interface NetworkDevice {
export interface NetworkDevice {
name: string;
ipAddress: string;
type: string;
notes?: string;
ports?: Port[];
}
export interface NetworkData {