Commit Graph

32 Commits

Author SHA1 Message Date
9d64d8a046 style(web/mazenet): tint palette chip with user accent color for contrast 2026-04-22 18:29:19 -04:00
c804d3111a style(web/mazenet): enlarge palette port/proto chip for legibility 2026-04-22 18:26:29 -04:00
602a0e1efc feat(web/mazenet): add Mail, Comms, Observability, Containers groups + remaining services 2026-04-22 18:23:24 -04:00
9c38a3f11a feat(web/mazenet): group Service Fleet items by category (Remote Access, Web, Databases, etc.) 2026-04-22 18:19:21 -04:00
1674316788 feat(web/mazenet): glide transitions for service fleet + inspector panels 2026-04-22 18:16:17 -04:00
e0231bf990 style(web/mazenet): rename PALETTE toggle to SERVICE FLEET 2026-04-22 18:14:17 -04:00
e35358afd1 feat(web/mazenet): fullscreen button also triggers browser fullscreen API 2026-04-22 18:12:38 -04:00
ef34df4a7d feat(web/mazenet): fullscreen canvas mode (hides topbar + sidebar, Esc to exit) 2026-04-22 18:11:37 -04:00
31d02a9726 feat(web/mazenet): toggleable palette (deployer) panel 2026-04-22 18:10:18 -04:00
8985c28fab fix(web/mazenet): stop canvas from overflowing viewport (flex-size shell instead of fixed calc) 2026-04-22 18:08:44 -04:00
3f460bab84 feat(web): show MazeNET decky running count + roll into dashboard
MazeNET header now reports '{running}/{total} DECKIES RUNNING' so
operators can see per-topology runtime status at a glance.

Dashboard ACTIVE DECKIES counters used to reflect only the fleet state
file; TopologyDecky rows (MazeNET deployments) are now added in —
deployed_deckies = fleet + all topology rows, active_deckies = fleet
(no runtime field) + topology rows whose state is 'running'.
2026-04-22 17:48:04 -04:00
6f537f52c2 fix(topology): remove DMZ gateway auto-attach on LAN create
POST /topologies/{id}/lans previously called _auto_attach_gateway()
whenever a non-DMZ LAN was created, which wired the DMZ gateway decky
to every new subnet. That's why a deployed gateway ended up with
eth0..ethN on every LAN regardless of what the user drew in MazeNET.

Drop the auto-attach helper entirely. The DMZ_ORPHAN deploy-time
validator (decnet/topology/validate.py:65-110) stays strict — users
must explicitly wire the gateway to each subnet they want bridged,
which is the whole point of having a topology editor.

useMazeApi.ts: drop stale auto-bridge reference from comment.
2026-04-22 17:14:09 -04:00
73ccf12678 fix(web): allow MazeNET canvas pan from inside net-box body
Pan drag previously required mousedown on the bare canvas (target ===
currentTarget). When zoomed in, net-boxes cover most of the viewport
so there was no bare grid to grab. Drop the guard — node/header/port/
resize handlers all call stopPropagation() already, so only net-box
body mousedowns bubble up to start the pan, which is exactly what
we want.
2026-04-22 16:43:38 -04:00
ef60b086ba feat(web): MazeNET canvas pan + zoom (0.25×–2.5×)
Wheel-to-zoom anchored at the cursor, ZOOM IN/OUT toolbar buttons, and
a live zoom% in the status bar. Pan layer gets transform-origin 0 0 and
a scale(zoom) factor; grid pattern tile scales with zoom; edge SVG is
overflow:visible so long edges don't clip at high zoom. World-space
hit-testing, resize deltas, and palette drops all divide by zoom.
Reset View zeroes pan AND zoom.
2026-04-22 16:40:47 -04:00
1f429cd00e feat(web): MazeNET 7b — service-level selection + inspector panel
Clicking a service tag selects it (stops node drag), extends Selection
discriminant with {type:'service',id,nodeId}, and renders an inspector
panel showing proto/port/subnet/risk chip + REMOVE SERVICE button
(gated off for observed nodes and degraded topologies). Service-tag
styling now pulls `risk` from DEFAULT_SERVICES metadata instead of
node.status alone.
2026-04-22 15:56:55 -04:00
6fbac5d057 feat(web): MazeNET 7a — canvas chrome + node-head visuals
Toolbar (RESET VIEW / AUTO-LAYOUT), status bar (GRAPH LIVE + pan + as-of
timestamp), 4-row legend, and archetype icon + status dot in each node
head.
2026-04-22 15:54:11 -04:00
9ea0abc321 fix(web): correct MazeApi type import in useTopologyEditor
useTopologyEditor imported 'UseMazeApi' but the actual exported type
is 'MazeApi'. tsc --noEmit missed it because the file isn't in the
default tsconfig include path; tsc -b (project references, used by
'npm run build') catches it.
2026-04-21 20:15:24 -04:00
c266d1b6e3 feat(mutator,web): add_decky op — create-and-attach in one mutation
apply_attach_decky requires an existing decky, so the MazeNET editor
had no way to grow a live topology: creating a new decky on active
topologies 409'd on the direct-CRUD createDecky call.

- Backend: new apply_add_decky that creates the decky row + its
  home-LAN edge atomically, auto-allocating an IP if none pinned.
  Post-apply validation still runs. Added to DISPATCH + _MUTATION_OPS
  Literal + CLI help text.
- Tests: 3 new ops tests (happy path, duplicate-name rejection,
  missing-LAN rejection) plus dispatch coverage update.
- Frontend: useTopologyEditor gains addDeckyToLan() composite. Pending
  routes through createDecky + attachEdge as before; active routes
  through a single add_decky enqueue. MazeNET.tsx drag-archetype,
  duplicate, DMZ-gateway, and ctx-menu add-decky paths all use the
  composite so active topologies stop 409'ing on new-decky drops.
2026-04-21 20:13:39 -04:00
8fd166470f feat(web): route editor actions through mutation queue on active topologies
useTopologyEditor now branches on topoStatus: pending keeps direct CRUD,
active/degraded routes through enqueueMutation with expected_version.
Every primitive returns a tagged PrimitiveResult; callers skip local
state updates on enqueued and wait for the SSE mutation.applied refetch
to reflect DB truth.

- remove_lan/remove_decky/detach_decky: direct name-keyed enqueues.
- update_decky/update_lan: services/x/y lifted to top-level payload keys,
  remainder placed under patch (matches apply_update_* contract).
- attach_decky: enqueued with decky+lan names; requires the decky to
  already exist (Phase B step 3 adds the create+attach composite).
- createDecky stays direct-CRUD this pass — no add_decky op yet, so
  new-decky drag will 409 on active until a follow-up commit.
- MazeNET surfaces mutation.failed payload.reason/error into actionErr
  so the status bar tells the user WHY a queue op was rejected.
2026-04-21 19:58:29 -04:00
aa848d5260 feat(web): useTopologyEditor skeleton + explicit streamLive gate
Phase B step 1 of DEBT-030: introduce a status-aware editor hook that
wraps useMazeApi. Every primitive currently pass-throughs to direct
CRUD and returns {kind: 'applied', data} — behavior is unchanged.
Follow-up commits route active/degraded topologies through
enqueueMutation when status != pending.

Also tighten the SSE LIVE indicator: flip setStreamLive(true) only on
snapshot, mutation.*, or status events, not on any incidental frame.
2026-04-21 19:54:55 -04:00
8ecb9e6c2d feat(web/mazenet): subscribe to topology SSE stream in editor
Wire the MazeNET editor to the new /topologies/{id}/events SSE route
so live (active|degraded) topologies reflect mutator state transitions
without reload:

- useTopologyStream hook opens an EventSource against
  /topologies/{id}/events?token=<jwt>, with 3s reconnect matching the
  dashboard's /stream consumer. Callback refs avoid tearing down the
  connection on consumer rerenders.
- useMazeApi gains enqueueMutation(topologyId, op, payload,
  expectedVersion?) — thin wrapper over POST /mutations.
- MazeNET.tsx opens the stream only when topoStatus is active|degraded
  (pending editors have nothing to stream) and refetches on
  mutation.applied|failed|status events. Header shows a LIVE /
  CONNECTING… indicator.

Phase A slice — Apply (N changes) with an optimistic staged buffer
lands in a follow-up; the hooks + API method it'll need are already
here.
2026-04-21 14:38:58 -04:00
4727ea0af2 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.
2026-04-21 10:24:32 -04:00
167582b887 feat(mazenet): persist canvas layout per topology to localStorage
Dragging a LAN or decky, or resizing a NetBox, updates React state
but previously vanished on reload because the grid-layout adapter
rewrote everything from the graph. Add a per-topology localStorage
snapshot (key: mazenet.layout.<topologyId>) that captures net
x/y/w/h and decky x/y; useLayoutPersistor writes it debounced, and
getTopology merges it over adaptTopology's grid so entities without
a stored entry still fall back to a clean auto-layout. Deleting a
topology calls clearLayout to drop its snapshot.
2026-04-20 23:52:00 -04:00
c4be1c721d fix(mazenet): auto-layout nets + deckies in a deterministic grid
Dropping more than one LAN near the same spot stacked the NetBox
rectangles on top of each other, and multiple deckies in a LAN
landed on identical per-LAN coordinates. Since canvas position
persistence is deferred (localStorage pass), the stored x/y are
not load-bearing — compute layout from the topology graph instead.

adaptTopology now lays LANs out in a 3-col grid with the DMZ first
and stacks deckies 2-wide inside their home LAN. New LAN palette
drops append to the same grid, ignoring the raw drop point.
2026-04-20 23:47:29 -04:00
d701df24c8 feat(mazenet): upgrade inspector to design-handoff layout
Rebuild the inspector panel to match the handoff mock: crosshair-titled
header with dim type label and close X, status-dot + archetype-chip
head rows, connection list with directional arrows, member list with
click-to-select, and a pending-diff block at the foot.  Carry the
gateway/observed disable titles over from the ctx menu so the 'remove'
action stays honest.

Also prefix the subtitle with 'NETWORK OF NETWORKS' so the purpose of
this editor reads at a glance.
2026-04-20 23:28:02 -04:00
d770eaa9cd fix(mazenet-ui): detect gateway via forwards_l3, drop host-mode
Gateway detection in the editor previously matched
archetype === 'host-gateway' (a fictional archetype that never
existed in decnet/archetypes.py). Switch to
decky_config.forwards_l3 — the real runtime marker the composer
already reads — so deletion guards, drag-pinning, context menu
locking, and NodeCard DMZ-gateway styling all line up with what
actually ships at deploy time.

On DMZ palette drop, create the gateway with archetype=deaddeck,
services=['ssh'], forwards_l3=true, and mark the edge
is_bridge=true, forwards_l3=true. attachEdge now accepts those
flags so callers can seed a real bridge attachment.
2026-04-20 23:07:52 -04:00
6db5842a28 feat(web/mazenet): port-drag edges, context menus, delete actions 2026-04-20 19:26:49 -04:00
0401cccd1d feat(web/mazenet): interaction layer — pan, drag, resize, reparent 2026-04-20 19:22:25 -04:00
b928f5d932 feat(web/mazenet): render canvas — net boxes, node cards, bezier edges, topology loader 2026-04-20 19:16:34 -04:00
65290e13c7 feat(web/mazenet): visual shell — palette, canvas chrome, inspector, toolbar 2026-04-20 19:14:58 -04:00
4b881cb3ff feat(web/mazenet): types, demo seed, API hook with topology adapter 2026-04-20 19:12:11 -04:00
53db53792e feat(web): MazeNET scaffold — tokens, route, nav, stub page 2026-04-20 19:10:09 -04:00