import { Body1, Button, Caption1, Card, CardFooter, CardHeader, CardPreview, Spinner, Tooltip, makeStyles, typographyStyles, } from "@fluentui/react-components"; import { ArrowResetRegular, DesktopRegular, PauseRegular, Play16Regular, PowerRegular, StopRegular, } from "@fluentui/react-icons"; import { filesize } from "filesize"; import React from "react"; import { Rights } from "../api/ServerApi"; import { VMApi, VMInfo, VMInfoAndCaps, VMState } from "../api/VMApi"; import { useConfirm } from "../hooks/providers/ConfirmDialogProvider"; import { useToast } from "../hooks/providers/ToastProvider"; import { SectionContainer } from "./SectionContainer"; import { VMLiveScreenshot } from "./VMLiveScreenshot"; const useStyles = makeStyles({ body1Stronger: typographyStyles.body1Stronger, caption1: typographyStyles.caption1, }); export function VirtualMachinesWidget(p: { rights: Rights; }): React.ReactElement { return (
{p.rights.vms.map((v, n) => ( ))}
); } function VMWidget(p: { vm: VMInfoAndCaps }): React.ReactElement { const toast = useToast(); const [state, setState] = React.useState(); const styles = useStyles(); const load = async () => { const newState = await VMApi.State(p.vm); if (state !== newState) setState(newState); }; React.useEffect(() => { const interval = setInterval(async () => { try { if (p.vm.can_get_state) await load(); } catch (e) { console.error(e); toast("Error", `Failed to refresh ${p.vm.name} status!`, "error"); } }, 1000); return () => clearInterval(interval); }); return ( } header={ {p.vm.name} } description={ {p.vm.can_get_state ? state ?? "..." : "Unavailable"} } />

{p.vm.architecture} • RAM : {filesize(p.vm.memory * 1000 * 1000)}{" "} • {p.vm.number_vcpu} vCPU

{p.vm.description}

} enabled={p.vm.can_start} currState={state} possibleStates={["Shutdown", "Shutoff", "Crashed"]} onClick={VMApi.StartVM} /> } enabled={p.vm.can_resume} currState={state} possibleStates={["Paused", "PowerManagementSuspended"]} onClick={VMApi.ResumeVM} /> } enabled={p.vm.can_suspend} currState={state} possibleStates={["Running"]} onClick={VMApi.SuspendVM} /> } enabled={p.vm.can_shutdown} currState={state} possibleStates={["Running"]} onClick={VMApi.ShutdownVM} /> } enabled={p.vm.can_kill} currState={state} possibleStates={[ "Running", "Paused", "PowerManagementSuspended", "Blocked", ]} onClick={VMApi.KillVM} /> } enabled={p.vm.can_reset} currState={state} possibleStates={[ "Running", "Paused", "PowerManagementSuspended", "Blocked", ]} onClick={VMApi.ResetVM} />
); } function VMPreview(p: { vm: VMInfoAndCaps; state?: VMState; }): React.ReactElement { const styles = useStyles(); if (!p.vm.can_screenshot || p.state !== "Running") { return (
{p.vm.name}
); } return ; } function VMAction(p: { confirmAction?: boolean; vm: VMInfo; label: string; primary?: boolean; icon: React.ReactElement; enabled: boolean; currState?: VMState; possibleStates: VMState[]; onClick: (vm: VMInfo) => Promise; }): React.ReactElement { const toast = useToast(); const confirm = useConfirm(); const [loading, setLoading] = React.useState(false); const onClick = async () => { try { if ( p.confirmAction && !(await confirm( `Do you really want to ${p.label} the VM '${p.vm.name}'?` )) ) return; setLoading(true); await p.onClick(p.vm); toast(p.label, `Action successfully executed!`, "success"); } catch (e) { console.error(e); toast(p.label, `Failed to perform action: ${e}`, "error"); } finally { setLoading(false); } }; if (!p.currState || !p.possibleStates.includes(p.currState)) { return <>; } if (!p.enabled) return ( ); return ( ); }