feat(ui): forwards_l3 toggle in Inspector with destructive-recreate confirm
W5's apply_update_decky now accepts a forwards_l3 flip on a live
topology only when payload['force'] is true (the unforced flip raises
MutationError to keep half-thinking operators from killing
in-container state). Until this commit there was no UI surface that
could even submit such a flip.
Inspector grows a 'PROMOTE TO GATEWAY' / 'DEMOTE GATEWAY' button when
a (non-observed) decky is selected. The handler:
* On pending topologies → submits via editor.updateDecky immediately.
No confirm dialog; no live containers to disturb.
* On active/degraded topologies → window.confirm() explaining the
destructive base recreate ('In-container state is lost; active
sessions to it drop'), then submits with extras.force=true.
useTopologyEditor.updateDecky grows an optional extras arg that
threads force: true into the queued mutation payload. The pending
CRUD path ignores it (no force needed when no containers exist).
MazeNET.tsx wires a toggleGateway callback that handles the
optimistic local state update, surfaces an enqueue toast on the
active path, and lets the SSE forwarder reconcile when
mutation.applied lands.
This commit is contained in:
@@ -68,6 +68,11 @@ export interface UseTopologyEditor {
|
||||
uuid: string,
|
||||
deckyName: string,
|
||||
patch: Partial<DeckyRow>,
|
||||
/** Extra top-level flags for the queued mutation payload — currently
|
||||
* only ``force`` (opts in to destructive recreates like the
|
||||
* forwards_l3 flip on a live topology). Ignored on the pending
|
||||
* CRUD path since pending edits never need force. */
|
||||
extras?: { force?: boolean },
|
||||
): Promise<PrimitiveResult<DeckyRow>>;
|
||||
deleteDecky(
|
||||
topologyId: string,
|
||||
@@ -169,7 +174,7 @@ export function useTopologyEditor(
|
||||
const res = await api.enqueueMutation(topologyId, 'add_decky', payload, topoVersion);
|
||||
return { kind: 'enqueued', mutationId: res.mutation_id };
|
||||
},
|
||||
async updateDecky(topologyId, uuid, deckyName, patch) {
|
||||
async updateDecky(topologyId, uuid, deckyName, patch, extras) {
|
||||
if (!live) {
|
||||
const data = await api.updateDecky(topologyId, uuid, patch);
|
||||
return { kind: 'applied', data };
|
||||
@@ -181,6 +186,7 @@ export function useTopologyEditor(
|
||||
else patchFields[k] = v;
|
||||
}
|
||||
if (Object.keys(patchFields).length > 0) payload.patch = patchFields;
|
||||
if (extras?.force) payload.force = true;
|
||||
const res = await api.enqueueMutation(topologyId, 'update_decky', payload, topoVersion);
|
||||
return { kind: 'enqueued', mutationId: res.mutation_id };
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user