Created first disk

This commit is contained in:
2023-10-26 11:43:05 +02:00
parent 081b0f7784
commit bdb2f6427d
14 changed files with 393 additions and 25 deletions

View File

@ -13,6 +13,8 @@ export interface ServerConstraints {
name_size: LenConstraint;
title_size: LenConstraint;
memory_size: LenConstraint;
disk_name_size: LenConstraint;
disk_size: LenConstraint;
}
export interface LenConstraint {

View File

@ -17,6 +17,18 @@ export type VMState =
| "PowerManagementSuspended"
| "Other";
export type DiskAllocType = "Sparse" | "Fixed";
export interface VMDisk {
size: number;
name: string;
alloc_type: DiskAllocType;
delete: boolean;
// application attribute
new?: boolean;
}
interface VMInfoInterface {
name: string;
uuid?: string;
@ -28,6 +40,7 @@ interface VMInfoInterface {
memory: number;
vnc_access: boolean;
iso_file?: string;
disks: VMDisk[];
}
export class VMInfo implements VMInfoInterface {
@ -41,6 +54,7 @@ export class VMInfo implements VMInfoInterface {
memory: number;
vnc_access: boolean;
iso_file?: string;
disks: VMDisk[];
constructor(int: VMInfoInterface) {
this.name = int.name;
@ -53,6 +67,7 @@ export class VMInfo implements VMInfoInterface {
this.memory = int.memory;
this.vnc_access = int.vnc_access;
this.iso_file = int.iso_file;
this.disks = int.disks;
}
static NewEmpty(): VMInfo {
@ -62,6 +77,7 @@ export class VMInfo implements VMInfoInterface {
architecture: "x86_64",
memory: 1024,
vnc_access: true,
disks: [],
});
}

View File

@ -18,6 +18,19 @@ export function TextInput(p: {
}): React.ReactElement {
if (((!p.editable && p.value) ?? "") === "") return <></>;
let valueError = undefined;
if (p.value && p.value.length > 0) {
if (p.size?.min && p.type !== "number" && p.value.length < p.size.min)
valueError = "Invalid value size";
if (p.checkValue && !p.checkValue(p.value)) valueError = "Invalid value!";
if (
p.type === "number" &&
p.size &&
(Number(p.value) > p.size.max || Number(p.value) < p.size.min)
)
valueError = "Invalide size range!";
}
return (
<TextField
label={p.label}
@ -39,13 +52,8 @@ export function TextInput(p: {
multiline={p.multiline}
minRows={p.minRows}
maxRows={p.maxRows}
error={
(p.checkValue &&
p.value &&
p.value.length > 0 &&
!p.checkValue(p.value)) ||
false
}
error={valueError !== undefined}
helperText={valueError}
/>
);
}

View File

@ -0,0 +1,114 @@
import {
Avatar,
Button,
ListItem,
ListItemAvatar,
ListItemText,
Paper,
} from "@mui/material";
import { VMDisk, VMInfo } from "../../api/VMApi";
import { filesize } from "filesize";
import Icon from "@mdi/react";
import { mdiHarddisk } from "@mdi/js";
import { TextInput } from "./TextInput";
import { ServerApi } from "../../api/ServerApi";
import { SelectInput } from "./SelectInput";
export function VMDisksList(p: {
vm: VMInfo;
onChange?: () => void;
editable: boolean;
}): React.ReactElement {
const addNewDisk = () => {
p.vm.disks.push({
alloc_type: "Sparse",
size: 10000,
delete: false,
name: `disk${p.vm.disks.length}`,
new: true,
});
p.onChange?.();
};
return (
<>
{/* disks list */}
{p.vm.disks.map((d, num) => (
<DiskInfo
key={num}
editable={p.editable}
disk={d}
onChange={p.onChange}
/>
))}
{p.editable && <Button onClick={addNewDisk}>Add new disk</Button>}
</>
);
}
function DiskInfo(p: {
editable: boolean;
disk: VMDisk;
onChange?: () => void;
}): React.ReactElement {
if (!p.editable || !p.disk.new)
return (
<ListItem>
<ListItemAvatar>
<Avatar>
<Icon path={mdiHarddisk} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={p.disk.name}
secondary={`${filesize(p.disk.size * 1000 * 1000)} - ${
p.disk.alloc_type
}`}
/>
{/* TODO delete disk if editable */}
</ListItem>
);
return (
<Paper elevation={3} style={{ margin: "10px", padding: "10px" }}>
<TextInput
editable={true}
label="Disk name"
size={ServerApi.Config.constraints.disk_name_size}
checkValue={(v) => /^[a-zA-Z0-9]+$/.test(v)}
value={p.disk.name}
onValueChange={(v) => {
p.disk.name = v ?? "";
p.onChange?.();
}}
/>
<TextInput
editable={true}
label="Disk size (MB)"
size={ServerApi.Config.constraints.disk_size}
value={p.disk.size.toString()}
onValueChange={(v) => {
p.disk.size = Number(v ?? "0");
p.onChange?.();
}}
type="number"
/>
<SelectInput
editable={true}
label="File allocation type"
options={[
{ label: "Sparse allocation", value: "Sparse" },
{ label: "Fixed allocation", value: "Fixed" },
]}
value={p.disk.alloc_type}
onValueChange={(v) => {
p.disk.alloc_type = v as any;
p.onChange?.();
}}
/>
</Paper>
);
}

View File

@ -11,6 +11,7 @@ import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
import { AsyncWidget } from "../AsyncWidget";
import React from "react";
import { filesize } from "filesize";
import { VMDisksList } from "../forms/VMDisksList";
interface DetailsProps {
vm: VMInfo;
@ -174,6 +175,7 @@ function VMDetailsInner(
}),
]}
/>
<VMDisksList vm={p.vm} editable={p.editable} onChange={p.onChange} />
</EditSection>
</Grid>
);