QUERYING WORKER UPDATER FLEET...
;
+
+ if (!isAdmin) {
+ return (
+
+
+
+
+
REMOTE UPDATES — WORKER FLEET
+
+
setShowFleetModal(true)}
+ disabled={fleetBusy || hosts.length === 0}
+ style={{
+ display: 'flex', alignItems: 'center', gap: '8px',
+ border: '1px solid var(--accent-color)', color: 'var(--accent-color)',
+ }}
+ >
+ {fleetBusy ? : }
+ {fleetBusy ? 'PUSHING...' : 'PUSH TO ALL'}
+
+
+
+ {showFleetModal && (
+
+
Push current tree to every enrolled worker
+
+ A tarball of the master's working tree will be uploaded to each worker's updater,
+ installed, and the agent will be restarted. Failed probes auto-roll-back.
+
+
+ setIncludeSelf(e.target.checked)} />
+ Also upgrade the updater itself (--include-self)
+
+
+ setShowFleetModal(false)} style={{ border: '1px solid var(--border-color)', color: 'var(--dim-color)' }}>
+ CANCEL
+
+
+ CONFIRM FLEET PUSH
+
+
+
+ )}
+
+ {hosts.length === 0 ? (
+
+
+ No workers with an updater bundle are enrolled. Run{' '}
+ decnet swarm enroll --host <name> --updater to add one.
+
+ ) : (
+
+ {hosts.map((h) => {
+ const busy = busyRow === h.host_uuid;
+ return (
+
+
+
+ {h.reachable ?
+ : }
+ {h.host_name}
+ {h.address}
+
+
+
handlePush(h, 'agent')}
+ disabled={busy || !h.reachable}
+ style={{ display: 'flex', alignItems: 'center', gap: '6px', border: '1px solid var(--accent-color)', color: 'var(--accent-color)' }}
+ >
+ {busy ? : }
+ PUSH
+
+
handlePush(h, 'self')}
+ disabled={busy || !h.reachable}
+ style={{ display: 'flex', alignItems: 'center', gap: '6px', border: '1px solid var(--highlight-color)', color: 'var(--highlight-color)' }}
+ >
+ {busy ? : }
+ UPDATER
+
+
handleRollback(h)}
+ disabled={busy || !h.reachable || !h.previous_sha}
+ style={{ display: 'flex', alignItems: 'center', gap: '6px', border: '1px solid var(--border-color)', color: 'var(--dim-color)' }}
+ title={h.previous_sha ? 'Roll back to previous release' : 'No previous release on worker'}
+ >
+ ROLLBACK
+
+
+
+ {h.reachable ? (
+
+
+
+
+
+ ) : (
+
+ UNREACHABLE — {h.detail || 'no response'}
+
+ )}
+
+ );
+ })}
+
+ )}
+
+
+ {toasts.map((t) => (
+
+ {t.kind === 'success' ?
:
}
+ {t.text}
+
+ ))}
+
+
+ );
+};
+
+const Info: React.FC<{ label: string; value: string; tone: 'accent' | 'dim' }> = ({ label, value, tone }) => (
+