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.
This commit is contained in:
2026-04-20 23:52:00 -04:00
parent c4be1c721d
commit 167582b887
4 changed files with 121 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import api from '../../utils/api';
import { ARCHETYPES as DEFAULT_ARCHETYPES, DEFAULT_SERVICES } from './data';
import type { Archetype, ServiceDef } from './data';
import type { Net, MazeNode, Edge, DeckyNode } from './types';
import { applyLayout, loadLayout } from './useMazeLayoutStore';
export interface LANRow {
id: string;
@@ -214,7 +215,10 @@ export function useMazeApi(): MazeApi {
const getTopology = useCallback(async (id: string) => {
const { data } = await api.get<TopologyDetail>(`/topologies/${id}`);
return adaptTopology(data);
const hydrated = adaptTopology(data);
const layout = loadLayout(id);
const { nets, nodes } = applyLayout(hydrated.nets, hydrated.nodes, layout);
return { ...hydrated, nets, nodes };
}, []);
const getServices = useCallback(async () => {