feat(web/mazenet): polish editor UX

Canvas grew a deployed prop so nodes can visually distinguish "live in
docker" from "planned". ContextMenu learned nested submenus with
ChevronRight affordance; NetBox renders a ShieldAlert for DMZ LANs;
Palette got additional lucide icons. Dead PendingChange union pulled
out of types.ts — Phase-3 mutation ops are driven by the API layer now,
not a frontend type.
This commit is contained in:
2026-04-21 10:24:32 -04:00
parent 59d618d25f
commit 4727ea0af2
7 changed files with 115 additions and 74 deletions

View File

@@ -89,8 +89,22 @@ export function adaptTopology(detail: TopologyDetail): HydratedTopology {
// Home LAN = first edge; a multi-homed gateway is drawn inside its
// home LAN, membership in others is expressed via the edge list.
// Gateways (forwards_l3) MUST render inside a DMZ — auto-bridge adds
// subnet edges after the original DMZ edge, but edge ordering from the
// backend is not guaranteed, so we pick DMZ explicitly for gateways.
const dmzIds = new Set(detail.lans.filter((l) => l.is_dmz).map((l) => l.id));
const gatewayUuids = new Set(
detail.edges.filter((e) => e.forwards_l3).map((e) => e.decky_uuid),
);
const firstLanFor = new Map<string, string>();
for (const e of detail.edges) {
if (gatewayUuids.has(e.decky_uuid)) {
// Only accept a DMZ edge as home for a gateway.
if (dmzIds.has(e.lan_id) && !firstLanFor.has(e.decky_uuid)) {
firstLanFor.set(e.decky_uuid, e.lan_id);
}
continue;
}
if (!firstLanFor.has(e.decky_uuid)) firstLanFor.set(e.decky_uuid, e.lan_id);
}