virtweb_backend/src
virtweb_frontend/src
40
virtweb_frontend/src/widgets/forms/DiskImageSelect.tsx
Normal file
40
virtweb_frontend/src/widgets/forms/DiskImageSelect.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
import { DiskImage } from "../../api/DiskImageApi";
|
||||
import {
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
MenuItem,
|
||||
SelectChangeEvent,
|
||||
} from "@mui/material";
|
||||
import { FileDiskImageWidget } from "../FileDiskImageWidget";
|
||||
|
||||
/**
|
||||
* Select a disk image
|
||||
*/
|
||||
export function DiskImageSelect(p: {
|
||||
label: string;
|
||||
value?: string;
|
||||
onValueChange: (image: string | undefined) => void;
|
||||
list: DiskImage[];
|
||||
}): React.ReactElement {
|
||||
const handleChange = (event: SelectChangeEvent) => {
|
||||
p.onValueChange(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl fullWidth variant="standard">
|
||||
<InputLabel>{p.label}</InputLabel>
|
||||
<Select value={p.value} label={p.label} onChange={handleChange}>
|
||||
<MenuItem value={undefined}>
|
||||
<i>None</i>
|
||||
</MenuItem>
|
||||
{p.list.map((d) => (
|
||||
<MenuItem value={d.file_name}>
|
||||
<FileDiskImageWidget image={d} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
@ -17,6 +17,7 @@ export function TextInput(p: {
|
||||
type?: React.HTMLInputTypeAttribute;
|
||||
style?: React.CSSProperties;
|
||||
helperText?: string;
|
||||
disabled?: boolean;
|
||||
}): React.ReactElement {
|
||||
if (!p.editable && (p.value ?? "") === "") return <></>;
|
||||
|
||||
@ -35,6 +36,7 @@ export function TextInput(p: {
|
||||
|
||||
return (
|
||||
<TextField
|
||||
disabled={p.disabled}
|
||||
label={p.label}
|
||||
value={p.value ?? ""}
|
||||
onChange={(e) =>
|
||||
|
@ -21,12 +21,15 @@ import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||
import { CheckboxInput } from "./CheckboxInput";
|
||||
import { SelectInput } from "./SelectInput";
|
||||
import { TextInput } from "./TextInput";
|
||||
import { DiskImageSelect } from "./DiskImageSelect";
|
||||
import { DiskImage } from "../../api/DiskImageApi";
|
||||
|
||||
export function VMDisksList(p: {
|
||||
vm: VMInfo;
|
||||
state?: VMState;
|
||||
onChange?: () => void;
|
||||
editable: boolean;
|
||||
diskImagesList: DiskImage[];
|
||||
}): React.ReactElement {
|
||||
const [currBackupRequest, setCurrBackupRequest] = React.useState<
|
||||
VMFileDisk | undefined
|
||||
@ -67,6 +70,7 @@ export function VMDisksList(p: {
|
||||
p.onChange?.();
|
||||
}}
|
||||
onRequestBackup={handleBackupRequest}
|
||||
diskImagesList={p.diskImagesList}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -93,6 +97,7 @@ function DiskInfo(p: {
|
||||
onChange?: () => void;
|
||||
removeFromList: () => void;
|
||||
onRequestBackup: (disk: VMFileDisk) => void;
|
||||
diskImagesList: DiskImage[];
|
||||
}): React.ReactElement {
|
||||
const confirm = useConfirm();
|
||||
const deleteDisk = async () => {
|
||||
@ -198,23 +203,6 @@ function DiskInfo(p: {
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<TextInput
|
||||
editable={true}
|
||||
label="Disk size (GB)"
|
||||
size={{
|
||||
min:
|
||||
ServerApi.Config.constraints.disk_size.min / (1000 * 1000 * 1000),
|
||||
max:
|
||||
ServerApi.Config.constraints.disk_size.max / (1000 * 1000 * 1000),
|
||||
}}
|
||||
value={(p.disk.size / (1000 * 1000 * 1000)).toString()}
|
||||
onValueChange={(v) => {
|
||||
p.disk.size = Number(v ?? "0") * 1000 * 1000 * 1000;
|
||||
p.onChange?.();
|
||||
}}
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
editable={true}
|
||||
label="Disk format"
|
||||
@ -243,6 +231,34 @@ function DiskInfo(p: {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TextInput
|
||||
editable={true}
|
||||
label="Disk size (GB)"
|
||||
size={{
|
||||
min:
|
||||
ServerApi.Config.constraints.disk_size.min / (1000 * 1000 * 1000),
|
||||
max:
|
||||
ServerApi.Config.constraints.disk_size.max / (1000 * 1000 * 1000),
|
||||
}}
|
||||
value={(p.disk.size / (1000 * 1000 * 1000)).toString()}
|
||||
onValueChange={(v) => {
|
||||
p.disk.size = Number(v ?? "0") * 1000 * 1000 * 1000;
|
||||
p.onChange?.();
|
||||
}}
|
||||
type="number"
|
||||
disabled={!!p.disk.from_image}
|
||||
/>
|
||||
|
||||
<DiskImageSelect
|
||||
label="Use disk image as template"
|
||||
list={p.diskImagesList}
|
||||
value={p.disk.from_image}
|
||||
onValueChange={(v) => {
|
||||
p.disk.from_image = v;
|
||||
p.onChange?.();
|
||||
}}
|
||||
/>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user