update all rovers buttone

This commit is contained in:
legop3
2026-07-13 16:03:51 -04:00
parent c742fa1c81
commit 5d8cb48fd0
8 changed files with 237 additions and 150 deletions
@@ -69,6 +69,7 @@ export default function AdminPanelContent() {
setAdminReason,
rebootRover,
updateRover,
updateAllRovers,
rebootServer,
setAudioLevels,
setPrivateSafety,
@@ -181,6 +182,35 @@ export default function AdminPanelContent() {
}
};
const handleUpdateAll = async () => {
const roverCount = roster.filter((rover) => rover?.id).length;
if (roverCount === 0) return;
const ok = window.confirm(
`Update all ${roverCount} rover${roverCount === 1 ? '' : 's'} now? Each rover will run its self-update and reboot if the update starts successfully.`,
);
if (!ok) return;
trackAnalyticsEvent('rover_update_all_click', { roverCount });
try {
// The server owns the fan-out because it has the authoritative online
// rover map and can enforce admin privileges once before issuing the
// existing per-rover update command to every connected rover.
const result = await updateAllRovers();
trackAnalyticsEvent('rover_update_all_result', {
status: 'accepted',
updated: result?.updated?.length || 0,
failed: result?.failed?.length || 0,
});
if (result?.failed?.length) {
alert(`Update requested for ${result.updated?.length || 0} rover(s). ${result.failed.length} rover(s) failed to queue.`);
}
} catch (err) {
trackAnalyticsEvent('rover_update_all_result', { status: 'failed', reason: err?.message || 'unknown' });
alert(err.message);
}
};
const handleServerReboot = async () => {
const ok = window.confirm('Reboot the server host now? This will disconnect all users.');
if (!ok) return;
@@ -487,6 +517,17 @@ export default function AdminPanelContent() {
</div>
</div>
<div className="flex items-center justify-between gap-0.5 text-xs">
<span className="text-slate-400">Rovers</span>
<button
type="button"
onClick={handleUpdateAll}
disabled={roster.length === 0}
className="button-danger disabled:cursor-not-allowed disabled:opacity-60"
>
Update All
</button>
</div>
<RoverRoster
roster={roster}
renderActions={(rover) => (
+4
View File
@@ -410,6 +410,10 @@ export function SessionProvider({ children }) {
// maintenance without becoming a remote shell.
updateRover: (roverId) =>
emitWithAck('command', { roverId, type: 'update', data: { update: {} } }),
// Bulk rover updates stay server-owned so the admin browser sends one
// intent, then the server checks privileges and fans out the same fixed
// update command to every currently connected rover.
updateAllRovers: () => emitWithAck('command:updateAllRovers'),
rebootServer: () => emitWithAck('server:reboot'),
playUploadedAudio: ({ roverId, name, mime, dataBase64 }) =>
emitWithAck('audio:uploadPlay', { roverId, name, mime, dataBase64 }),