From 79efb006f525d322aea046c282388a621e5870a0 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Mon, 6 Jul 2026 17:30:22 -0700 Subject: [PATCH] =?UTF-8?q?feat(app):=20mesh=20bands=20=E2=80=94=20kind-co?= =?UTF-8?q?lumns,=20draggable,=20shared=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remote machines' deployments now sit in the same kind-columns as local (so a cross-node edge runs straight down its column), are draggable with persisted positions, and the lane headers lift above the topmost band so they head every machine's columns. --- app/src/pages/SystemMap.tsx | 51 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/app/src/pages/SystemMap.tsx b/app/src/pages/SystemMap.tsx index 3579f12..e86e627 100644 --- a/app/src/pages/SystemMap.tsx +++ b/app/src/pages/SystemMap.tsx @@ -93,7 +93,6 @@ const PROTO_COLOR: Record = { system: "#6e7681", } const EXTERNAL_X = 1450 // external resources (references) — beyond Internet -const MESH_Y = -150 // band above the local lanes for other machines' deployments const HANDLE = { opacity: 0, width: 8, height: 8 } as const @@ -491,33 +490,35 @@ export function SystemMapPage() { }) }) - // Other machines (mesh-discovered) — a read-only band above the local lanes, - // one row per node, its deployments laid out horizontally. + // Other machines (mesh-discovered). Each is a band above the local lanes, with + // its deployments in the SAME kind-columns as local, draggable, and the shared + // lane headers lifted above the topmost band so they head every machine. const byMachine = new Map() for (const md of meshResp?.deployments ?? []) { const arr = byMachine.get(md.node) ?? [] arr.push(md) byMachine.set(md.node, arr) } - let mrow = 0 + let bandBaseline = TOP - 70 // first band sits just above local; bands stack upward + let headersY = TOP - 40 // rises above the bands when machines are present for (const [machine, deps] of byMachine) { - const y = MESH_Y - mrow * (ROW_H + 8) - nodes.push({ - id: `__machine_${machine}__`, - type: "lane", - position: { x: PROG_X, y: y - 4 }, - selectable: false, - draggable: false, - deletable: false, - data: { label: `⬡ ${machine}` }, - }) - deps.forEach((md, i) => { + const perLaneM: Record = {} + const laid = deps + .filter((md) => LANES[md.kind]) + .map((md) => { + const lane = LANES[md.kind] + const row = (perLaneM[md.kind] = (perLaneM[md.kind] ?? 0) + 1) - 1 + return { md, x: lane.x, row } + }) + const rows = Math.max(1, ...Object.values(perLaneM)) + const bandTop = bandBaseline - (rows - 1) * ROW_H + for (const { md, x, row } of laid) { nodes.push({ id: `__remote_${machine}_${md.name}__`, type: "remote", - position: { x: i * 150, y }, - selectable: false, - draggable: false, + position: { x, y: bandTop + row * ROW_H }, + selectable: true, + draggable: true, deletable: false, data: { label: md.name, @@ -525,8 +526,18 @@ export function SystemMapPage() { sub: md.endpoints[0] ? `:${md.endpoints[0].port}` : undefined, }, }) + } + nodes.push({ + id: `__machine_${machine}__`, + type: "lane", + position: { x: PROG_X, y: bandTop }, + selectable: false, + draggable: false, + deletable: false, + data: { label: `⬡ ${machine}` }, }) - mrow++ + headersY = Math.min(headersY, bandTop - 44) + bandBaseline = bandTop - (ROW_H + 44) // gap before the next machine (upward) } const maxRows = Math.max(1, ...Object.values(perLane)) @@ -557,7 +568,7 @@ export function SystemMapPage() { nodes.push({ id: `__lane_${title}__`, type: "lane", - position: { x, y: TOP - 40 }, + position: { x, y: headersY }, data: { label: title }, selectable: false, draggable: false,