mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-11 11:16:55 +00:00
81858a0bb0
* feat(mesh): refine the Routing tab and add per-route removal
Tighten the Fleet > Routing tab so its node cards and diagnostics read
honestly for proxy-connected fleets, and remove a couple of dead ends.
- Node cards drop the "pilot connected/offline" line, which was meaningless
for nodes that connect over the HTTP API proxy. The compact card drops the
matching agent cell and now reads stacks / aliases / bridge.
- Enabling mesh on a proxy node shows a transient "Connecting" state and
settles to meshed on its own, instead of flashing "Degraded" with a manual
refresh while the bridge finishes dialing.
- The alias detail sheet gains a "Remove from mesh" action that opts the
alias's owning stack out (the confirmation says how many aliases that
drops), and a "Topology" tab. The standalone topology sheet and its
opt-in-sheet shortcut are removed in favor of the tab.
- The "Add stack" affordance stays reachable on a meshed node, so a node
that already has aliases is no longer a dead end.
- Diagnostics and the alias detail sheet show a transport-aware line
("local", "API proxy bridge", or "Pilot tunnel" with its state) instead of
a fixed "Pilot tunnel" label.
Adds unit coverage for the new state derivation, transport descriptor, the
enable auto-converge, and the admin-gated removal, and updates the mesh docs.
* fix(mesh): harden Routing tab toggle and alias sheet against async races
Independent review surfaced two narrow async races in the new code.
- RoutingNodeCard: cancel the converge re-poll batch at the start of any
toggle (so a slow disable can't let a prior enable's re-polls fire), and
guard the toast, refresh, timer scheduling, and setToggling behind a mounted
ref so nothing runs after the card unmounts while the enable POST is still
in flight.
- MeshRouteDetailSheet: re-check the cancelled flag after reading the
diagnostic body, not just before it. Reading the body is itself async, so a
superseded alias's diagnostic could otherwise call setDiag and expose Remove
for the wrong stack.
Adds tests for unmount-before-enable-resolves and the deferred-diagnostic
alias switch.
45 lines
1.8 KiB
TypeScript
45 lines
1.8 KiB
TypeScript
import type { MeshNodeStatus, MeshReverseCallbackStatus } from '@/types/mesh';
|
|
|
|
export function reverseBridgeLabel(status: MeshReverseCallbackStatus): string {
|
|
switch (status) {
|
|
case 'connected': return 'connected';
|
|
case 'connecting': return 'connecting';
|
|
case 'unavailable': return 'unavailable';
|
|
case 'not_applicable': return 'n/a';
|
|
default: {
|
|
const _exhaustive: never = status;
|
|
throw new Error(`Unhandled reverse callback status: ${String(_exhaustive)}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface TransportLine {
|
|
label: string;
|
|
value: string;
|
|
}
|
|
|
|
/**
|
|
* One-line transport descriptor for a mesh node, keyed off how the node
|
|
* actually participates in routing. "Pilot tunnel" is shown only for
|
|
* pilot-agent nodes; proxy peers report their API proxy bridge state, and the
|
|
* local node runs in-process. This keeps the Routing diagnostics honest for a
|
|
* fleet that connects its remotes over the HTTP API proxy rather than a pilot.
|
|
*/
|
|
export function describeTransport(node: MeshNodeStatus | undefined, pilotConnected: boolean): TransportLine {
|
|
if (!node) return { label: 'Transport', value: 'unknown' };
|
|
switch (node.reachableMode) {
|
|
case 'local':
|
|
return { label: 'Transport', value: 'local (in-process)' };
|
|
case 'pilot':
|
|
return { label: 'Pilot tunnel', value: pilotConnected ? 'connected' : 'disconnected' };
|
|
case 'proxy':
|
|
return { label: 'API proxy bridge', value: reverseBridgeLabel(node.reverseCallbackStatus) };
|
|
case 'unreachable':
|
|
return { label: 'Transport', value: 'unreachable' };
|
|
default: {
|
|
const _exhaustive: never = node.reachableMode;
|
|
throw new Error(`Unhandled reachable mode: ${String(_exhaustive)}`);
|
|
}
|
|
}
|
|
}
|