Show VM status
This commit is contained in:
@ -1,8 +1,154 @@
|
||||
import { VMInfo } from "../../api/VMApi";
|
||||
import PauseIcon from "@mui/icons-material/Pause";
|
||||
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||
import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew";
|
||||
import ReplayIcon from "@mui/icons-material/Replay";
|
||||
import StopIcon from "@mui/icons-material/Stop";
|
||||
import { CircularProgress, IconButton, Tooltip } from "@mui/material";
|
||||
import React from "react";
|
||||
import { VMApi, VMInfo, VMState } from "../../api/VMApi";
|
||||
import { useAlert } from "../../hooks/providers/AlertDialogProvider";
|
||||
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||
import { useSnackbar } from "../../hooks/providers/SnackbarProvider";
|
||||
|
||||
export function VMStatusWidget(p: {
|
||||
d: VMInfo;
|
||||
onChange?: () => void;
|
||||
onChange?: (s: VMState) => void;
|
||||
}): React.ReactElement {
|
||||
return <>TODO</>;
|
||||
const snackbar = useSnackbar();
|
||||
|
||||
const [state, setState] = React.useState<undefined | VMState>(undefined);
|
||||
|
||||
const refresh = async () => {
|
||||
try {
|
||||
const s = await VMApi.GetState(p.d);
|
||||
if (s !== state) p.onChange?.(s);
|
||||
setState(s);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snackbar("Failed to refresh VM status!");
|
||||
}
|
||||
};
|
||||
|
||||
const changedAction = () => setState(undefined);
|
||||
|
||||
React.useEffect(() => {
|
||||
const i = setInterval(() => refresh(), 3000);
|
||||
|
||||
return () => clearInterval(i);
|
||||
});
|
||||
|
||||
if (state === undefined)
|
||||
return (
|
||||
<>
|
||||
<CircularProgress size={"1rem"} />
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ display: "inline-flex" }}>
|
||||
{state}
|
||||
|
||||
{/* Start VM */}
|
||||
<ActionButton
|
||||
currState={state}
|
||||
cond={["Shutdown", "Shutoff", "Crashed"]}
|
||||
icon={<PlayArrowIcon />}
|
||||
tooltip="Start the Virtual Machine"
|
||||
performAction={() => VMApi.StartVM(p.d)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
{/* Resume VM */}
|
||||
<ActionButton
|
||||
currState={state}
|
||||
cond={["Paused", "PowerManagementSuspended"]}
|
||||
icon={<PlayArrowIcon />}
|
||||
tooltip="Resume the Virtual Machine"
|
||||
performAction={() => VMApi.ResumeVM(p.d)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
{/* Suspend VM */}
|
||||
<ActionButton
|
||||
currState={state}
|
||||
cond={["Running"]}
|
||||
icon={<PauseIcon />}
|
||||
tooltip="Suspend the Virtual Machine"
|
||||
confirmMessage="Do you really want to supsend this VM?"
|
||||
performAction={() => VMApi.SuspendVM(p.d)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
{/* Shutdown VM */}
|
||||
<ActionButton
|
||||
currState={state}
|
||||
cond={["Running"]}
|
||||
icon={<PowerSettingsNewIcon />}
|
||||
tooltip="Shutdown the Virtual Machine"
|
||||
confirmMessage="Do you really want to shutdown this VM?"
|
||||
performAction={() => VMApi.ShutdownVM(p.d)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
{/* Kill VM */}
|
||||
<ActionButton
|
||||
currState={state}
|
||||
cond={["Running", "Paused", "PowerManagementSuspended", "Blocked"]}
|
||||
icon={<StopIcon />}
|
||||
tooltip="Kill the Virtual Machine"
|
||||
confirmMessage="Do you really want to kill this VM? This could lead to data loss / corruption!"
|
||||
performAction={() => VMApi.KillVM(p.d)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
{/* Reset VM */}
|
||||
<ActionButton
|
||||
currState={state}
|
||||
cond={["Running", "Paused", "PowerManagementSuspended", "Blocked"]}
|
||||
icon={<ReplayIcon />}
|
||||
tooltip="Reset the Virtual Machine"
|
||||
confirmMessage="Do you really want to reset this VM?"
|
||||
performAction={() => VMApi.ResetVM(p.d)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ActionButton(p: {
|
||||
currState: VMState;
|
||||
cond: VMState[];
|
||||
icon: React.ReactElement;
|
||||
tooltip: string;
|
||||
confirmMessage?: string;
|
||||
performAction: () => Promise<void>;
|
||||
onExecuted: () => void;
|
||||
}): React.ReactElement {
|
||||
const confirm = useConfirm();
|
||||
const alert = useAlert();
|
||||
|
||||
if (!p.cond.includes(p.currState)) return <></>;
|
||||
|
||||
const performAction = async () => {
|
||||
try {
|
||||
if (p.confirmMessage && !(await confirm(p.confirmMessage))) return;
|
||||
await p.performAction();
|
||||
p.onExecuted();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert("Failed to perform action! " + e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip title={p.tooltip}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={performAction}
|
||||
style={{ paddingBottom: "0px", paddingTop: "0px" }}
|
||||
>
|
||||
{p.icon}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user