diff --git a/app/api/flowchart/route.ts b/app/api/flowchart/route.ts index 455bff7..737dbfb 100644 --- a/app/api/flowchart/route.ts +++ b/app/api/flowchart/route.ts @@ -10,6 +10,9 @@ interface Node { }; position: { x: number; y: number }; style: React.CSSProperties; + draggable?: boolean; + selectable?: boolean; + zIndex?: number; } interface Edge { @@ -38,10 +41,13 @@ interface Application { const NODE_WIDTH = 220; const NODE_HEIGHT = 60; +const APP_NODE_WIDTH = 160; +const APP_NODE_HEIGHT = 40; const HORIZONTAL_SPACING = 280; -const VERTICAL_SPACING = 80; +const VERTICAL_SPACING = 60; const START_Y = 120; const ROOT_NODE_WIDTH = 300; +const CONTAINER_PADDING = 40; export async function GET() { try { @@ -54,11 +60,12 @@ export async function GET() { }) as Promise, ]); + // Root Node const rootNode: Node = { id: "root", type: "infrastructure", data: { label: "My Infrastructure" }, - position: { x: 0, y: 20 }, + position: { x: 0, y: 0 }, style: { background: "#ffffff", color: "#0f0f0f", @@ -72,6 +79,7 @@ export async function GET() { }, }; + // Server Nodes const serverNodes: Node[] = servers.map((server, index) => { const xPos = index * HORIZONTAL_SPACING - @@ -100,11 +108,12 @@ export async function GET() { }; }); + // Application Nodes const appNodes: Node[] = []; servers.forEach((server) => { - const serverX = - serverNodes.find((n) => n.id === `server-${server.id}`)?.position.x || 0; - const serverY = START_Y; + const serverNode = serverNodes.find((n) => n.id === `server-${server.id}`); + const serverX = serverNode?.position.x || 0; + const xOffset = (NODE_WIDTH - APP_NODE_WIDTH) / 2; applications .filter((app) => app.serverId === server.id) @@ -117,25 +126,26 @@ export async function GET() { ...app, }, position: { - x: serverX, - y: serverY + NODE_HEIGHT + 40 + appIndex * VERTICAL_SPACING, + x: serverX + xOffset, + y: START_Y + NODE_HEIGHT + 30 + appIndex * VERTICAL_SPACING, }, style: { - background: "#ffffff", + background: "#f5f5f5", color: "#0f0f0f", border: "2px solid #e6e4e1", borderRadius: "4px", - padding: "8px", - width: NODE_WIDTH, - height: NODE_HEIGHT, - fontSize: "0.9rem", - lineHeight: "1.2", + padding: "6px", + width: APP_NODE_WIDTH, + height: APP_NODE_HEIGHT, + fontSize: "0.8rem", + lineHeight: "1.1", whiteSpace: "pre-wrap", }, }); }); }); + // Connections const connections: Edge[] = [ ...servers.map((server) => ({ id: `conn-root-${server.id}`, @@ -159,8 +169,46 @@ export async function GET() { })), ]; + // Container Box + const allNodes = [rootNode, ...serverNodes, ...appNodes]; + let minX = Infinity; + let maxX = -Infinity; + let minY = Infinity; + let maxY = -Infinity; + + allNodes.forEach((node) => { + const width = parseInt(node.style.width?.toString() || "0", 10); + const height = parseInt(node.style.height?.toString() || "0", 10); + + minX = Math.min(minX, node.position.x); + maxX = Math.max(maxX, node.position.x + width); + minY = Math.min(minY, node.position.y); + maxY = Math.max(maxY, node.position.y + height); + }); + + const containerNode: Node = { + id: 'container', + type: 'container', + data: { label: '' }, + position: { + x: minX - CONTAINER_PADDING, + y: minY - CONTAINER_PADDING + }, + style: { + width: maxX - minX + 2 * CONTAINER_PADDING, + height: maxY - minY + 2 * CONTAINER_PADDING, + background: 'transparent', + border: '2px dashed #e2e8f0', + borderRadius: '8px', + zIndex: 0, + }, + draggable: false, + selectable: false, + zIndex: -1, + }; + return NextResponse.json({ - nodes: [rootNode, ...serverNodes, ...appNodes], + nodes: [containerNode, ...allNodes], edges: connections, }); } catch (error: unknown) {