Created first disk
This commit is contained in:
@ -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 {
|
||||
|
@ -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: [],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
114
virtweb_frontend/src/widgets/forms/VMDisksList.tsx
Normal file
114
virtweb_frontend/src/widgets/forms/VMDisksList.tsx
Normal 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>
|
||||
);
|
||||
}
|
@ -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>
|
||||
);
|
||||
|
Reference in New Issue
Block a user