This commit is contained in:
parent
c908d00c62
commit
20e6d7931e
@ -40,6 +40,7 @@ struct ServerConstraints {
|
|||||||
vnc_token_duration: u64,
|
vnc_token_duration: u64,
|
||||||
vm_name_size: LenConstraints,
|
vm_name_size: LenConstraints,
|
||||||
vm_title_size: LenConstraints,
|
vm_title_size: LenConstraints,
|
||||||
|
group_id_size: LenConstraints,
|
||||||
memory_size: LenConstraints,
|
memory_size: LenConstraints,
|
||||||
disk_name_size: LenConstraints,
|
disk_name_size: LenConstraints,
|
||||||
disk_size: LenConstraints,
|
disk_size: LenConstraints,
|
||||||
@ -72,6 +73,7 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder {
|
|||||||
|
|
||||||
vm_name_size: LenConstraints { min: 2, max: 50 },
|
vm_name_size: LenConstraints { min: 2, max: 50 },
|
||||||
vm_title_size: LenConstraints { min: 0, max: 50 },
|
vm_title_size: LenConstraints { min: 0, max: 50 },
|
||||||
|
group_id_size: LenConstraints { min: 3, max: 50 },
|
||||||
memory_size: LenConstraints {
|
memory_size: LenConstraints {
|
||||||
min: constants::MIN_VM_MEMORY,
|
min: constants::MIN_VM_MEMORY,
|
||||||
max: constants::MAX_VM_MEMORY,
|
max: constants::MAX_VM_MEMORY,
|
||||||
|
@ -211,7 +211,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
)
|
)
|
||||||
.route("/api/vnc", web::get().to(vm_controller::vnc))
|
.route("/api/vnc", web::get().to(vm_controller::vnc))
|
||||||
// Groups controller
|
// Groups controller
|
||||||
.route("/api/groups/list", web::get().to(groups_controller::list))
|
.route("/api/group/list", web::get().to(groups_controller::list))
|
||||||
// Network controller
|
// Network controller
|
||||||
.route(
|
.route(
|
||||||
"/api/network/create",
|
"/api/network/create",
|
||||||
|
15
virtweb_frontend/src/api/GroupApi.ts
Normal file
15
virtweb_frontend/src/api/GroupApi.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { APIClient } from "./ApiClient";
|
||||||
|
|
||||||
|
export class GroupApi {
|
||||||
|
/**
|
||||||
|
* Get the entire list of networks
|
||||||
|
*/
|
||||||
|
static async GetList(): Promise<string[]> {
|
||||||
|
return (
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "GET",
|
||||||
|
uri: "/group/list",
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ export interface ServerConstraints {
|
|||||||
vnc_token_duration: number;
|
vnc_token_duration: number;
|
||||||
vm_name_size: LenConstraint;
|
vm_name_size: LenConstraint;
|
||||||
vm_title_size: LenConstraint;
|
vm_title_size: LenConstraint;
|
||||||
|
group_id_size: LenConstraint;
|
||||||
memory_size: LenConstraint;
|
memory_size: LenConstraint;
|
||||||
disk_name_size: LenConstraint;
|
disk_name_size: LenConstraint;
|
||||||
disk_size: LenConstraint;
|
disk_size: LenConstraint;
|
||||||
|
@ -63,6 +63,7 @@ interface VMInfoInterface {
|
|||||||
genid?: string;
|
genid?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
group?: string;
|
||||||
boot_type: "UEFI" | "UEFISecureBoot";
|
boot_type: "UEFI" | "UEFISecureBoot";
|
||||||
architecture: "i686" | "x86_64";
|
architecture: "i686" | "x86_64";
|
||||||
memory: number;
|
memory: number;
|
||||||
@ -80,6 +81,7 @@ export class VMInfo implements VMInfoInterface {
|
|||||||
genid?: string;
|
genid?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
group?: string;
|
||||||
boot_type: "UEFI" | "UEFISecureBoot";
|
boot_type: "UEFI" | "UEFISecureBoot";
|
||||||
architecture: "i686" | "x86_64";
|
architecture: "i686" | "x86_64";
|
||||||
number_vcpu: number;
|
number_vcpu: number;
|
||||||
@ -96,6 +98,7 @@ export class VMInfo implements VMInfoInterface {
|
|||||||
this.genid = int.genid;
|
this.genid = int.genid;
|
||||||
this.title = int.title;
|
this.title = int.title;
|
||||||
this.description = int.description;
|
this.description = int.description;
|
||||||
|
this.group = int.group;
|
||||||
this.boot_type = int.boot_type;
|
this.boot_type = int.boot_type;
|
||||||
this.architecture = int.architecture;
|
this.architecture = int.architecture;
|
||||||
this.number_vcpu = int.number_vcpu;
|
this.number_vcpu = int.number_vcpu;
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { Button } from "@mui/material";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
import ListIcon from "@mui/icons-material/List";
|
||||||
|
import { Button, IconButton, Tooltip } from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid2";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { validate as validateUUID } from "uuid";
|
import { validate as validateUUID } from "uuid";
|
||||||
|
import { GroupApi } from "../../api/GroupApi";
|
||||||
import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
|
import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
|
||||||
import { NWFilter, NWFilterApi } from "../../api/NWFilterApi";
|
import { NWFilter, NWFilterApi } from "../../api/NWFilterApi";
|
||||||
import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
|
import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
|
||||||
@ -32,6 +35,7 @@ interface DetailsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function VMDetails(p: DetailsProps): React.ReactElement {
|
export function VMDetails(p: DetailsProps): React.ReactElement {
|
||||||
|
const [groupsList, setGroupsList] = React.useState<string[] | any>();
|
||||||
const [isoList, setIsoList] = React.useState<IsoFile[] | any>();
|
const [isoList, setIsoList] = React.useState<IsoFile[] | any>();
|
||||||
const [vcpuCombinations, setVCPUCombinations] = React.useState<
|
const [vcpuCombinations, setVCPUCombinations] = React.useState<
|
||||||
number[] | any
|
number[] | any
|
||||||
@ -42,6 +46,7 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
|
|||||||
>();
|
>();
|
||||||
|
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
|
setGroupsList(await GroupApi.GetList());
|
||||||
setIsoList(await IsoFilesApi.GetList());
|
setIsoList(await IsoFilesApi.GetList());
|
||||||
setVCPUCombinations(await ServerApi.NumberVCPUs());
|
setVCPUCombinations(await ServerApi.NumberVCPUs());
|
||||||
setNetworksList(await NetworkApi.GetList());
|
setNetworksList(await NetworkApi.GetList());
|
||||||
@ -55,6 +60,7 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
|
|||||||
errMsg="Failed to load the list of ISO files"
|
errMsg="Failed to load the list of ISO files"
|
||||||
build={() => (
|
build={() => (
|
||||||
<VMDetailsInner
|
<VMDetailsInner
|
||||||
|
groupsList={groupsList}
|
||||||
isoList={isoList}
|
isoList={isoList}
|
||||||
vcpuCombinations={vcpuCombinations}
|
vcpuCombinations={vcpuCombinations}
|
||||||
networksList={networksList}
|
networksList={networksList}
|
||||||
@ -75,6 +81,7 @@ enum VMTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DetailsInnerProps = DetailsProps & {
|
type DetailsInnerProps = DetailsProps & {
|
||||||
|
groupsList: string[];
|
||||||
isoList: IsoFile[];
|
isoList: IsoFile[];
|
||||||
vcpuCombinations: number[];
|
vcpuCombinations: number[];
|
||||||
networksList: NetworkInfo[];
|
networksList: NetworkInfo[];
|
||||||
@ -117,6 +124,8 @@ function VMDetailsInner(p: DetailsInnerProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
|
function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
|
||||||
|
const [addGroup, setAddGroup] = React.useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{
|
{
|
||||||
@ -175,6 +184,50 @@ function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
|
|||||||
}}
|
}}
|
||||||
multiline={true}
|
multiline={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div style={{ display: "flex" }}>
|
||||||
|
{addGroup ? (
|
||||||
|
<TextInput
|
||||||
|
label="Group"
|
||||||
|
editable={p.editable}
|
||||||
|
value={p.vm.group}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.vm.group = v;
|
||||||
|
p.onChange?.();
|
||||||
|
}}
|
||||||
|
size={ServerApi.Config.constraints.group_id_size}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<SelectInput
|
||||||
|
editable={p.editable}
|
||||||
|
label="Group"
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.vm.group = v! as any;
|
||||||
|
p.onChange?.();
|
||||||
|
}}
|
||||||
|
value={p.vm.group}
|
||||||
|
options={[
|
||||||
|
{ label: "None" },
|
||||||
|
...p.groupsList.map((g) => {
|
||||||
|
return { value: g, label: g };
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{p.editable && (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
addGroup
|
||||||
|
? "Use an existing group"
|
||||||
|
: "Add a new group instead of using existing one"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IconButton onClick={() => setAddGroup(!addGroup)}>
|
||||||
|
{addGroup ? <ListIcon /> : <AddIcon />}
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</EditSection>
|
</EditSection>
|
||||||
|
|
||||||
{/* General section */}
|
{/* General section */}
|
||||||
|
Loading…
Reference in New Issue
Block a user