mirror of
https://github.com/crocofied/CoreControl.git
synced 2025-12-17 23:47:13 +00:00
Updated Flowchart
This commit is contained in:
parent
0e1f9edaab
commit
42e584a381
@ -30,6 +30,8 @@ interface Server {
|
|||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
ip: string;
|
ip: string;
|
||||||
|
host: boolean;
|
||||||
|
hostServer: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Application {
|
interface Application {
|
||||||
@ -43,11 +45,13 @@ const NODE_WIDTH = 220;
|
|||||||
const NODE_HEIGHT = 60;
|
const NODE_HEIGHT = 60;
|
||||||
const APP_NODE_WIDTH = 160;
|
const APP_NODE_WIDTH = 160;
|
||||||
const APP_NODE_HEIGHT = 40;
|
const APP_NODE_HEIGHT = 40;
|
||||||
const HORIZONTAL_SPACING = 280;
|
const HORIZONTAL_SPACING = 400;
|
||||||
const VERTICAL_SPACING = 60;
|
const VERTICAL_SPACING = 100;
|
||||||
const START_Y = 120;
|
const START_Y = 120;
|
||||||
const ROOT_NODE_WIDTH = 300;
|
const ROOT_NODE_WIDTH = 300;
|
||||||
const CONTAINER_PADDING = 40;
|
const CONTAINER_PADDING = 40;
|
||||||
|
const COLUMN_SPACING = 200;
|
||||||
|
const VM_APP_SPACING = 200;
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
@ -60,74 +64,131 @@ export async function GET() {
|
|||||||
}) as Promise<Application[]>,
|
}) as Promise<Application[]>,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Root Node
|
// Level 2: Physical Servers
|
||||||
const rootNode: Node = {
|
const serverNodes: Node[] = servers
|
||||||
id: "root",
|
.filter(server => !server.hostServer)
|
||||||
type: "infrastructure",
|
.map((server, index, filteredServers) => {
|
||||||
data: { label: "My Infrastructure" },
|
const xPos =
|
||||||
position: { x: 0, y: 0 },
|
index * HORIZONTAL_SPACING -
|
||||||
style: {
|
((filteredServers.length - 1) * HORIZONTAL_SPACING) / 2;
|
||||||
background: "#ffffff",
|
|
||||||
color: "#0f0f0f",
|
|
||||||
border: "2px solid #e6e4e1",
|
|
||||||
borderRadius: "8px",
|
|
||||||
padding: "16px",
|
|
||||||
width: ROOT_NODE_WIDTH,
|
|
||||||
height: NODE_HEIGHT,
|
|
||||||
fontSize: "1.2rem",
|
|
||||||
fontWeight: "bold",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Server Nodes
|
return {
|
||||||
const serverNodes: Node[] = servers.map((server, index) => {
|
id: `server-${server.id}`,
|
||||||
const xPos =
|
type: "server",
|
||||||
index * HORIZONTAL_SPACING -
|
data: {
|
||||||
((servers.length - 1) * HORIZONTAL_SPACING) / 2;
|
label: `${server.name}\n${server.ip}`,
|
||||||
|
...server,
|
||||||
|
},
|
||||||
|
position: { x: xPos, y: START_Y },
|
||||||
|
style: {
|
||||||
|
background: "#ffffff",
|
||||||
|
color: "#0f0f0f",
|
||||||
|
border: "2px solid #e6e4e1",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "8px",
|
||||||
|
width: NODE_WIDTH,
|
||||||
|
height: NODE_HEIGHT,
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
lineHeight: "1.2",
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
// Level 3: Services and VMs
|
||||||
id: `server-${server.id}`,
|
const serviceNodes: Node[] = [];
|
||||||
type: "server",
|
const vmNodes: Node[] = [];
|
||||||
data: {
|
|
||||||
label: `${server.name}\n${server.ip}`,
|
|
||||||
...server,
|
|
||||||
},
|
|
||||||
position: { x: xPos, y: START_Y },
|
|
||||||
style: {
|
|
||||||
background: "#ffffff",
|
|
||||||
color: "#0f0f0f",
|
|
||||||
border: "2px solid #e6e4e1",
|
|
||||||
borderRadius: "4px",
|
|
||||||
padding: "8px",
|
|
||||||
width: NODE_WIDTH,
|
|
||||||
height: NODE_HEIGHT,
|
|
||||||
fontSize: "0.9rem",
|
|
||||||
lineHeight: "1.2",
|
|
||||||
whiteSpace: "pre-wrap",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Application Nodes
|
|
||||||
const appNodes: Node[] = [];
|
|
||||||
servers.forEach((server) => {
|
servers.forEach((server) => {
|
||||||
const serverNode = serverNodes.find((n) => n.id === `server-${server.id}`);
|
const serverNode = serverNodes.find((n) => n.id === `server-${server.id}`);
|
||||||
const serverX = serverNode?.position.x || 0;
|
if (serverNode) {
|
||||||
const xOffset = (NODE_WIDTH - APP_NODE_WIDTH) / 2;
|
const serverX = serverNode.position.x;
|
||||||
|
|
||||||
|
// Services (left column)
|
||||||
|
applications
|
||||||
|
.filter(app => app.serverId === server.id)
|
||||||
|
.forEach((app, appIndex) => {
|
||||||
|
serviceNodes.push({
|
||||||
|
id: `service-${app.id}`,
|
||||||
|
type: "service",
|
||||||
|
data: {
|
||||||
|
label: `${app.name}\n${app.localURL}`,
|
||||||
|
...app,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
x: serverX - COLUMN_SPACING,
|
||||||
|
y: START_Y + NODE_HEIGHT + VERTICAL_SPACING + appIndex * (APP_NODE_HEIGHT + 20),
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
background: "#f0f9ff",
|
||||||
|
color: "#0f0f0f",
|
||||||
|
border: "2px solid #60a5fa",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "6px",
|
||||||
|
width: APP_NODE_WIDTH,
|
||||||
|
height: APP_NODE_HEIGHT,
|
||||||
|
fontSize: "0.8rem",
|
||||||
|
lineHeight: "1.1",
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// VMs (middle column) mit dynamischem Abstand
|
||||||
|
const hostVMs = servers.filter(vm => vm.hostServer === server.id);
|
||||||
|
let currentY = START_Y + NODE_HEIGHT + VERTICAL_SPACING;
|
||||||
|
|
||||||
|
hostVMs.forEach(vm => {
|
||||||
|
const appCount = applications.filter(app => app.serverId === vm.id).length;
|
||||||
|
|
||||||
|
vmNodes.push({
|
||||||
|
id: `vm-${vm.id}`,
|
||||||
|
type: "vm",
|
||||||
|
data: {
|
||||||
|
label: `${vm.name}\n${vm.ip}`,
|
||||||
|
...vm,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
x: serverX,
|
||||||
|
y: currentY,
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
background: "#fef2f2",
|
||||||
|
color: "#0f0f0f",
|
||||||
|
border: "2px solid #fecaca",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "6px",
|
||||||
|
width: APP_NODE_WIDTH,
|
||||||
|
height: APP_NODE_HEIGHT,
|
||||||
|
fontSize: "0.8rem",
|
||||||
|
lineHeight: "1.1",
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dynamischer Abstand basierend auf Anzahl Apps
|
||||||
|
currentY += appCount * (APP_NODE_HEIGHT + 20) + 40; // 40px Basisabstand
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Level 4: VM Applications (right column)
|
||||||
|
const vmAppNodes: Node[] = [];
|
||||||
|
vmNodes.forEach((vm) => {
|
||||||
|
const vmX = vm.position.x;
|
||||||
applications
|
applications
|
||||||
.filter((app) => app.serverId === server.id)
|
.filter(app => app.serverId === vm.data.id)
|
||||||
.forEach((app, appIndex) => {
|
.forEach((app, appIndex) => {
|
||||||
appNodes.push({
|
vmAppNodes.push({
|
||||||
id: `app-${app.id}`,
|
id: `vm-app-${app.id}`,
|
||||||
type: "application",
|
type: "application",
|
||||||
data: {
|
data: {
|
||||||
label: `${app.name}\n${app.localURL}`,
|
label: `${app.name}\n${app.localURL}`,
|
||||||
...app,
|
...app,
|
||||||
},
|
},
|
||||||
position: {
|
position: {
|
||||||
x: serverX + xOffset,
|
x: vmX + VM_APP_SPACING,
|
||||||
y: START_Y + NODE_HEIGHT + 30 + appIndex * VERTICAL_SPACING,
|
y: vm.position.y + appIndex * (APP_NODE_HEIGHT + 20),
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
background: "#f5f5f5",
|
background: "#f5f5f5",
|
||||||
@ -145,38 +206,14 @@ export async function GET() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Connections
|
// Calculate dimensions for root node positioning
|
||||||
const connections: Edge[] = [
|
const tempNodes = [...serverNodes, ...serviceNodes, ...vmNodes, ...vmAppNodes];
|
||||||
...servers.map((server) => ({
|
|
||||||
id: `conn-root-${server.id}`,
|
|
||||||
source: "root",
|
|
||||||
target: `server-${server.id}`,
|
|
||||||
type: "straight",
|
|
||||||
style: {
|
|
||||||
stroke: "#94a3b8",
|
|
||||||
strokeWidth: 2,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
...applications.map((app) => ({
|
|
||||||
id: `conn-${app.serverId}-${app.id}`,
|
|
||||||
source: `server-${app.serverId}`,
|
|
||||||
target: `app-${app.id}`,
|
|
||||||
type: "straight",
|
|
||||||
style: {
|
|
||||||
stroke: "#60a5fa",
|
|
||||||
strokeWidth: 2,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Container Box
|
|
||||||
const allNodes = [rootNode, ...serverNodes, ...appNodes];
|
|
||||||
let minX = Infinity;
|
let minX = Infinity;
|
||||||
let maxX = -Infinity;
|
let maxX = -Infinity;
|
||||||
let minY = Infinity;
|
let minY = Infinity;
|
||||||
let maxY = -Infinity;
|
let maxY = -Infinity;
|
||||||
|
|
||||||
allNodes.forEach((node) => {
|
tempNodes.forEach((node) => {
|
||||||
const width = parseInt(node.style.width?.toString() || "0", 10);
|
const width = parseInt(node.style.width?.toString() || "0", 10);
|
||||||
const height = parseInt(node.style.height?.toString() || "0", 10);
|
const height = parseInt(node.style.height?.toString() || "0", 10);
|
||||||
|
|
||||||
@ -186,17 +223,47 @@ export async function GET() {
|
|||||||
maxY = Math.max(maxY, node.position.y + height);
|
maxY = Math.max(maxY, node.position.y + height);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const centerX = (minX + maxX) / 2;
|
||||||
|
const rootX = centerX - ROOT_NODE_WIDTH / 2;
|
||||||
|
|
||||||
|
// Level 1: Root Node (centered at top)
|
||||||
|
const rootNode: Node = {
|
||||||
|
id: "root",
|
||||||
|
type: "infrastructure",
|
||||||
|
data: { label: "My Infrastructure" },
|
||||||
|
position: { x: rootX, y: 0 },
|
||||||
|
style: {
|
||||||
|
background: "#ffffff",
|
||||||
|
color: "#0f0f0f",
|
||||||
|
border: "2px solid #e6e4e1",
|
||||||
|
borderRadius: "8px",
|
||||||
|
padding: "16px",
|
||||||
|
width: ROOT_NODE_WIDTH,
|
||||||
|
height: NODE_HEIGHT,
|
||||||
|
fontSize: "1.2rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update dimensions with root node
|
||||||
|
const allNodes = [rootNode, ...tempNodes];
|
||||||
|
let newMinX = Math.min(minX, rootNode.position.x);
|
||||||
|
let newMaxX = Math.max(maxX, rootNode.position.x + ROOT_NODE_WIDTH);
|
||||||
|
let newMinY = Math.min(minY, rootNode.position.y);
|
||||||
|
let newMaxY = Math.max(maxY, rootNode.position.y + NODE_HEIGHT);
|
||||||
|
|
||||||
|
// Container Node
|
||||||
const containerNode: Node = {
|
const containerNode: Node = {
|
||||||
id: 'container',
|
id: 'container',
|
||||||
type: 'container',
|
type: 'container',
|
||||||
data: { label: '' },
|
data: { label: '' },
|
||||||
position: {
|
position: {
|
||||||
x: minX - CONTAINER_PADDING,
|
x: newMinX - CONTAINER_PADDING,
|
||||||
y: minY - CONTAINER_PADDING
|
y: newMinY - CONTAINER_PADDING
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
width: maxX - minX + 2 * CONTAINER_PADDING,
|
width: newMaxX - newMinX + 2 * CONTAINER_PADDING,
|
||||||
height: maxY - minY + 2 * CONTAINER_PADDING,
|
height: newMaxY - newMinY + 2 * CONTAINER_PADDING,
|
||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
border: '2px dashed #e2e8f0',
|
border: '2px dashed #e2e8f0',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
@ -207,6 +274,116 @@ export async function GET() {
|
|||||||
zIndex: -1,
|
zIndex: -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Connections with hierarchical chaining
|
||||||
|
const connections: Edge[] = [];
|
||||||
|
|
||||||
|
// Root to Servers
|
||||||
|
serverNodes.forEach((server) => {
|
||||||
|
connections.push({
|
||||||
|
id: `conn-root-${server.id}`,
|
||||||
|
source: "root",
|
||||||
|
target: server.id,
|
||||||
|
type: "straight",
|
||||||
|
style: {
|
||||||
|
stroke: "#94a3b8",
|
||||||
|
strokeWidth: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Services chaining
|
||||||
|
const servicesByServer = new Map<number, Node[]>();
|
||||||
|
serviceNodes.forEach(service => {
|
||||||
|
const serverId = service.data.serverId;
|
||||||
|
if (!servicesByServer.has(serverId)) servicesByServer.set(serverId, []);
|
||||||
|
servicesByServer.get(serverId)!.push(service);
|
||||||
|
});
|
||||||
|
servicesByServer.forEach((services, serverId) => {
|
||||||
|
services.sort((a, b) => a.position.y - b.position.y);
|
||||||
|
services.forEach((service, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
connections.push({
|
||||||
|
id: `conn-service-${service.id}`,
|
||||||
|
source: `server-${serverId}`,
|
||||||
|
target: service.id,
|
||||||
|
type: "straight",
|
||||||
|
style: { stroke: "#60a5fa", strokeWidth: 2 },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const prevService = services[index - 1];
|
||||||
|
connections.push({
|
||||||
|
id: `conn-service-${service.id}-${prevService.id}`,
|
||||||
|
source: prevService.id,
|
||||||
|
target: service.id,
|
||||||
|
type: "straight",
|
||||||
|
style: { stroke: "#60a5fa", strokeWidth: 2 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// VMs chaining
|
||||||
|
const vmsByHost = new Map<number, Node[]>();
|
||||||
|
vmNodes.forEach(vm => {
|
||||||
|
const hostId = vm.data.hostServer;
|
||||||
|
if (!vmsByHost.has(hostId)) vmsByHost.set(hostId, []);
|
||||||
|
vmsByHost.get(hostId)!.push(vm);
|
||||||
|
});
|
||||||
|
vmsByHost.forEach((vms, hostId) => {
|
||||||
|
vms.sort((a, b) => a.position.y - b.position.y);
|
||||||
|
vms.forEach((vm, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
connections.push({
|
||||||
|
id: `conn-vm-${vm.id}`,
|
||||||
|
source: `server-${hostId}`,
|
||||||
|
target: vm.id,
|
||||||
|
type: "straight",
|
||||||
|
style: { stroke: "#f87171", strokeWidth: 2 },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const prevVm = vms[index - 1];
|
||||||
|
connections.push({
|
||||||
|
id: `conn-vm-${vm.id}-${prevVm.id}`,
|
||||||
|
source: prevVm.id,
|
||||||
|
target: vm.id,
|
||||||
|
type: "straight",
|
||||||
|
style: { stroke: "#f87171", strokeWidth: 2 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// VM Applications chaining
|
||||||
|
const appsByVM = new Map<number, Node[]>();
|
||||||
|
vmAppNodes.forEach(app => {
|
||||||
|
const vmId = app.data.serverId;
|
||||||
|
if (!appsByVM.has(vmId)) appsByVM.set(vmId, []);
|
||||||
|
appsByVM.get(vmId)!.push(app);
|
||||||
|
});
|
||||||
|
appsByVM.forEach((apps, vmId) => {
|
||||||
|
apps.sort((a, b) => a.position.y - b.position.y);
|
||||||
|
apps.forEach((app, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
connections.push({
|
||||||
|
id: `conn-vm-app-${app.id}`,
|
||||||
|
source: `vm-${vmId}`,
|
||||||
|
target: app.id,
|
||||||
|
type: "straight",
|
||||||
|
style: { stroke: "#f87171", strokeWidth: 2 },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const prevApp = apps[index - 1];
|
||||||
|
connections.push({
|
||||||
|
id: `conn-vm-app-${app.id}-${prevApp.id}`,
|
||||||
|
source: prevApp.id,
|
||||||
|
target: app.id,
|
||||||
|
type: "straight",
|
||||||
|
style: { stroke: "#f87171", strokeWidth: 2 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
nodes: [containerNode, ...allNodes],
|
nodes: [containerNode, ...allNodes],
|
||||||
edges: connections,
|
edges: connections,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user