Start to build VM page
This commit is contained in:
@ -6,15 +6,16 @@ export function CheckboxInput(p: {
|
||||
checked: boolean | undefined;
|
||||
onValueChange: (v: boolean) => void;
|
||||
}): React.ReactElement {
|
||||
if (!p.editable && p.checked)
|
||||
return <Typography variant="body2">{p.label}</Typography>;
|
||||
//if (!p.editable && p.checked)
|
||||
// return <Typography variant="body2">{p.label}</Typography>;
|
||||
|
||||
if (!p.editable) return <></>;
|
||||
//if (!p.editable) return <></>;
|
||||
|
||||
return (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
disabled={!p.editable}
|
||||
checked={p.checked}
|
||||
onChange={(e) => p.onValueChange(e.target.checked)}
|
||||
/>
|
||||
|
@ -8,16 +8,16 @@ export interface SelectOption {
|
||||
|
||||
export function SelectInput(p: {
|
||||
value?: string;
|
||||
editing: boolean;
|
||||
editable: boolean;
|
||||
label: string;
|
||||
options: SelectOption[];
|
||||
onValueChange: (o?: string) => void;
|
||||
}): React.ReactElement {
|
||||
if (!p.editing && !p.value) return <></>;
|
||||
if (!p.editable && !p.value) return <></>;
|
||||
|
||||
if (!p.editing) {
|
||||
if (!p.editable) {
|
||||
const value = p.options.find((o) => o.value === p.value)?.label;
|
||||
return <TextInput label={p.label} editable={p.editing} value={value} />;
|
||||
return <TextInput label={p.label} editable={p.editable} value={value} />;
|
||||
}
|
||||
return (
|
||||
<FormControl fullWidth variant="standard" style={{ marginBottom: "15px" }}>
|
||||
|
138
virtweb_frontend/src/widgets/vms/VMDetails.tsx
Normal file
138
virtweb_frontend/src/widgets/vms/VMDetails.tsx
Normal file
@ -0,0 +1,138 @@
|
||||
import { Grid, Paper, Typography } from "@mui/material";
|
||||
import { PropsWithChildren } from "react";
|
||||
import { validate as validateUUID } from "uuid";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import { VMInfo } from "../../api/VMApi";
|
||||
import { CheckboxInput } from "../forms/CheckboxInput";
|
||||
import { SelectInput } from "../forms/SelectInput";
|
||||
import { TextInput } from "../forms/TextInput";
|
||||
|
||||
export function VMDetails(p: {
|
||||
vm: VMInfo;
|
||||
editable: boolean;
|
||||
onChange?: () => void;
|
||||
}): React.ReactElement {
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
{/* Metadata section */}
|
||||
<EditSection title="Metadata">
|
||||
<TextInput
|
||||
label="Name"
|
||||
editable={p.editable}
|
||||
value={p.vm.name}
|
||||
onValueChange={(v) => {
|
||||
p.vm.name = v ?? "";
|
||||
p.onChange?.();
|
||||
}}
|
||||
size={ServerApi.Config.constraints.name_size}
|
||||
/>
|
||||
|
||||
<TextInput label="UUID" editable={false} value={p.vm.uuid} />
|
||||
|
||||
<TextInput
|
||||
label="VM genid"
|
||||
editable={p.editable}
|
||||
value={p.vm.genid}
|
||||
onValueChange={(v) => {
|
||||
p.vm.genid = v;
|
||||
p.onChange?.();
|
||||
}}
|
||||
checkValue={(v) => validateUUID(v)}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Title"
|
||||
editable={p.editable}
|
||||
value={p.vm.title}
|
||||
onValueChange={(v) => {
|
||||
p.vm.title = v;
|
||||
p.onChange?.();
|
||||
}}
|
||||
size={ServerApi.Config.constraints.title_size}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Description"
|
||||
editable={p.editable}
|
||||
value={p.vm.description}
|
||||
onValueChange={(v) => {
|
||||
p.vm.description = v;
|
||||
p.onChange?.();
|
||||
}}
|
||||
multiline={true}
|
||||
/>
|
||||
</EditSection>
|
||||
|
||||
{/* General section */}
|
||||
<EditSection title="General">
|
||||
<SelectInput
|
||||
editable={p.editable}
|
||||
label="CPU Architecture"
|
||||
onValueChange={(v) => {
|
||||
p.vm.architecture = v! as any;
|
||||
p.onChange?.();
|
||||
}}
|
||||
value={p.vm.architecture}
|
||||
options={[
|
||||
{ label: "i686", value: "i686" },
|
||||
{ label: "x86_64", value: "x86_64" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
editable={p.editable}
|
||||
label="Boot type"
|
||||
onValueChange={(v) => {
|
||||
p.vm.boot_type = v! as any;
|
||||
p.onChange?.();
|
||||
}}
|
||||
value={p.vm.boot_type}
|
||||
options={[
|
||||
{ label: "UEFI with Secure Boot", value: "UEFISecureBoot" },
|
||||
{ label: "UEFI", value: "UEFI" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
label="Memory (MB)"
|
||||
editable={p.editable}
|
||||
type="number"
|
||||
value={p.vm.memory.toString()}
|
||||
onValueChange={(v) => {
|
||||
p.vm.memory = Number(v ?? "0");
|
||||
p.onChange?.();
|
||||
}}
|
||||
checkValue={(v) =>
|
||||
Number(v) > ServerApi.Config.constraints.memory_size.min &&
|
||||
Number(v) < ServerApi.Config.constraints.memory_size.max
|
||||
}
|
||||
/>
|
||||
|
||||
<CheckboxInput
|
||||
editable={p.editable}
|
||||
label="Enable VNC access"
|
||||
checked={p.vm.vnc_access}
|
||||
onValueChange={(v) => {
|
||||
p.vm.vnc_access = v;
|
||||
p.onChange?.();
|
||||
}}
|
||||
/>
|
||||
</EditSection>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
function EditSection(
|
||||
p: { title: string } & PropsWithChildren
|
||||
): React.ReactElement {
|
||||
return (
|
||||
<Grid item sm={12} md={6}>
|
||||
<Paper style={{ margin: "10px", padding: "10px" }}>
|
||||
<Typography variant="h5" style={{ marginBottom: "15px" }}>
|
||||
{p.title}
|
||||
</Typography>
|
||||
{p.children}
|
||||
</Paper>
|
||||
</Grid>
|
||||
);
|
||||
}
|
@ -11,7 +11,7 @@ import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||
import { useSnackbar } from "../../hooks/providers/SnackbarProvider";
|
||||
|
||||
export function VMStatusWidget(p: {
|
||||
d: VMInfo;
|
||||
vm: VMInfo;
|
||||
onChange?: (s: VMState) => void;
|
||||
}): React.ReactElement {
|
||||
const snackbar = useSnackbar();
|
||||
@ -20,7 +20,7 @@ export function VMStatusWidget(p: {
|
||||
|
||||
const refresh = async () => {
|
||||
try {
|
||||
const s = await VMApi.GetState(p.d);
|
||||
const s = await VMApi.GetState(p.vm);
|
||||
if (s !== state) p.onChange?.(s);
|
||||
setState(s);
|
||||
} catch (e) {
|
||||
@ -32,6 +32,7 @@ export function VMStatusWidget(p: {
|
||||
const changedAction = () => setState(undefined);
|
||||
|
||||
React.useEffect(() => {
|
||||
refresh();
|
||||
const i = setInterval(() => refresh(), 3000);
|
||||
|
||||
return () => clearInterval(i);
|
||||
@ -54,7 +55,7 @@ export function VMStatusWidget(p: {
|
||||
cond={["Shutdown", "Shutoff", "Crashed"]}
|
||||
icon={<PlayArrowIcon />}
|
||||
tooltip="Start the Virtual Machine"
|
||||
performAction={() => VMApi.StartVM(p.d)}
|
||||
performAction={() => VMApi.StartVM(p.vm)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
@ -64,7 +65,7 @@ export function VMStatusWidget(p: {
|
||||
cond={["Paused", "PowerManagementSuspended"]}
|
||||
icon={<PlayArrowIcon />}
|
||||
tooltip="Resume the Virtual Machine"
|
||||
performAction={() => VMApi.ResumeVM(p.d)}
|
||||
performAction={() => VMApi.ResumeVM(p.vm)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
@ -75,7 +76,7 @@ export function VMStatusWidget(p: {
|
||||
icon={<PauseIcon />}
|
||||
tooltip="Suspend the Virtual Machine"
|
||||
confirmMessage="Do you really want to supsend this VM?"
|
||||
performAction={() => VMApi.SuspendVM(p.d)}
|
||||
performAction={() => VMApi.SuspendVM(p.vm)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
@ -86,7 +87,7 @@ export function VMStatusWidget(p: {
|
||||
icon={<PowerSettingsNewIcon />}
|
||||
tooltip="Shutdown the Virtual Machine"
|
||||
confirmMessage="Do you really want to shutdown this VM?"
|
||||
performAction={() => VMApi.ShutdownVM(p.d)}
|
||||
performAction={() => VMApi.ShutdownVM(p.vm)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
@ -97,7 +98,7 @@ export function VMStatusWidget(p: {
|
||||
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)}
|
||||
performAction={() => VMApi.KillVM(p.vm)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
|
||||
@ -108,7 +109,7 @@ export function VMStatusWidget(p: {
|
||||
icon={<ReplayIcon />}
|
||||
tooltip="Reset the Virtual Machine"
|
||||
confirmMessage="Do you really want to reset this VM?"
|
||||
performAction={() => VMApi.ResetVM(p.d)}
|
||||
performAction={() => VMApi.ResetVM(p.vm)}
|
||||
onExecuted={changedAction}
|
||||
/>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user