mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
server restart thingy yay
This commit is contained in:
@@ -25,6 +25,7 @@ export const restoreConfigurationRevision = (socket, payload) => emitAdminReques
|
||||
export const createAdministrator = (socket, payload) => emitAdminRequest(socket, 'adminConfig:createAdministrator', payload);
|
||||
export const updateAdministrator = (socket, payload) => emitAdminRequest(socket, 'adminConfig:updateAdministrator', payload);
|
||||
export const deleteAdministrator = (socket, id) => emitAdminRequest(socket, 'adminConfig:deleteAdministrator', { id });
|
||||
export const restartApplication = (socket) => emitAdminRequest(socket, 'server:restartApplication');
|
||||
|
||||
export const getSetupStatus = (socket) => emitAdminRequest(socket, 'setup:status');
|
||||
export const createFirstAdministrator = (socket, payload) => emitAdminRequest(socket, 'setup:createAdministrator', payload);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Administration Overview
|
||||
// Purpose: Summarizes configuration state, revision history, audit history, and links to existing health/report surfaces.
|
||||
// Scope: Presents persisted administration metadata without duplicating operational service implementations.
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import CardFrame from '../../components/CardFrame/index.jsx';
|
||||
import { restoreConfigurationRevision } from '../api.js';
|
||||
import { restartApplication, restoreConfigurationRevision } from '../api.js';
|
||||
|
||||
function formatDate(value) {
|
||||
return Number.isFinite(Number(value)) ? new Date(Number(value)).toLocaleString() : 'unknown';
|
||||
@@ -11,6 +12,16 @@ function formatDate(value) {
|
||||
|
||||
export default function AdminOverview({ snapshot, socket, runSensitive, onSnapshot }) {
|
||||
const config = snapshot.configuration;
|
||||
const [restartRequested, setRestartRequested] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!restartRequested) return undefined;
|
||||
// The socket reconnect is the simplest authoritative success signal: the
|
||||
// replacement process is accepting browser connections again.
|
||||
const handleReconnect = () => setRestartRequested(false);
|
||||
socket.once('connect', handleReconnect);
|
||||
return () => socket.off('connect', handleReconnect);
|
||||
}, [restartRequested, socket]);
|
||||
|
||||
async function restore(revision) {
|
||||
if (!window.confirm(`Restore configuration revision ${revision}? This creates and immediately applies a new active revision.`)) return;
|
||||
@@ -25,6 +36,17 @@ export default function AdminOverview({ snapshot, socket, runSensitive, onSnapsh
|
||||
}
|
||||
}
|
||||
|
||||
async function restart() {
|
||||
if (!window.confirm('Restart the MultiRover application now? Connected rovers and browsers will disconnect briefly; the server host will not reboot.')) return;
|
||||
setRestartRequested(true);
|
||||
try {
|
||||
await runSensitive(() => restartApplication(socket));
|
||||
} catch (error) {
|
||||
setRestartRequested(false);
|
||||
window.alert(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-0.5">
|
||||
<CardFrame title="Administration overview" meta={`revision ${config.revision}`} bodyClassName="grid gap-0.5 p-0.5 md:grid-cols-3">
|
||||
@@ -36,6 +58,12 @@ export default function AdminOverview({ snapshot, socket, runSensitive, onSnapsh
|
||||
<Link className="button-dark" to="/reports">Open fleet reports</Link>
|
||||
<Link className="button-dark" to="/">Open driver application</Link>
|
||||
</CardFrame>
|
||||
<CardFrame title="Application" bodyClassName="space-y-0.5 p-1 text-sm">
|
||||
<p className="text-slate-300">Restart only the MultiRover application. The process supervisor starts it again automatically without rebooting the host.</p>
|
||||
<button type="button" className="button-danger" disabled={restartRequested} onClick={restart}>
|
||||
{restartRequested ? 'Waiting for application…' : 'Restart application'}
|
||||
</button>
|
||||
</CardFrame>
|
||||
<CardFrame title="Configuration revisions" meta={snapshot.revisions.length} bodyClassName="max-h-64 overflow-y-auto p-0.5 text-xs">
|
||||
{snapshot.revisions.map((revision) => (
|
||||
<div key={revision.revision} className="surface mb-0.5 grid items-center gap-0.5 p-0.5 md:grid-cols-[5rem_1fr_1fr_1fr_auto]">
|
||||
|
||||
@@ -105,7 +105,6 @@ export default function AdminPanelContent() {
|
||||
rebootRover,
|
||||
updateRover,
|
||||
updateAllRovers,
|
||||
rebootServer,
|
||||
setAudioLevels,
|
||||
setPersonalAudioAdjustmentRange,
|
||||
setPrivateSafety,
|
||||
@@ -119,7 +118,6 @@ export default function AdminPanelContent() {
|
||||
const [lockStates, setLockStates] = useState({});
|
||||
const [rebootStates, setRebootStates] = useState({});
|
||||
const [updateStates, setUpdateStates] = useState({});
|
||||
const [serverRebooting, setServerRebooting] = useState(false);
|
||||
const [clearingLlmHistory, setClearingLlmHistory] = useState(false);
|
||||
const [clearingOverseerHistory, setClearingOverseerHistory] = useState(false);
|
||||
const health = session?.health || null;
|
||||
@@ -229,18 +227,6 @@ export default function AdminPanelContent() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleServerReboot = async () => {
|
||||
const ok = window.confirm('Reboot the server host now? This will disconnect all users.');
|
||||
if (!ok) return;
|
||||
setServerRebooting(true);
|
||||
try {
|
||||
await rebootServer();
|
||||
} catch (err) {
|
||||
alert(err.message);
|
||||
setServerRebooting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClearLlmHistory = async () => {
|
||||
const ok = window.confirm(
|
||||
'Clear LLM commentary history now? This resets chat context, bot memory, and rover activity metrics for narration.',
|
||||
@@ -421,14 +407,6 @@ export default function AdminPanelContent() {
|
||||
return (
|
||||
<CardFrame title="Admin controls" actions={actions} bodyClassName="space-y-0.5 text-base">
|
||||
<div className="flex gap-0.5 text-xs">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleServerReboot}
|
||||
disabled={serverRebooting}
|
||||
className="button-danger disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
{serverRebooting ? 'Server rebooting...' : 'Reboot Server'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleTestRewardOverlay}
|
||||
|
||||
@@ -392,7 +392,6 @@ export function SessionProvider({ children }) {
|
||||
// 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 }),
|
||||
stopUploadedAudio: (roverId) => emitWithAck('audio:uploadStop', { roverId }),
|
||||
|
||||
Reference in New Issue
Block a user