Can configure network autostart
This commit is contained in:
parent
23f2029deb
commit
8b53875349
@ -95,6 +95,29 @@ export class NetworkApi {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if autostart is enabled on a network
|
||||
*/
|
||||
static async IsAutostart(net: NetworkInfo): Promise<boolean> {
|
||||
return (
|
||||
await APIClient.exec({
|
||||
uri: `/network/${net.uuid}/autostart`,
|
||||
method: "GET",
|
||||
})
|
||||
).data.autostart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set autostart status of a network
|
||||
*/
|
||||
static async SetAutostart(net: NetworkInfo, enabled: boolean): Promise<void> {
|
||||
await APIClient.exec({
|
||||
uri: `/network/${net.uuid}/autostart`,
|
||||
method: "PUT",
|
||||
jsonData: { autostart: enabled },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing network
|
||||
*/
|
||||
|
@ -46,10 +46,10 @@ interface VMInfoInterface {
|
||||
|
||||
export class VMInfo implements VMInfoInterface {
|
||||
name: string;
|
||||
uuid?: string | undefined;
|
||||
genid?: string | undefined;
|
||||
title?: string | undefined;
|
||||
description?: string | undefined;
|
||||
uuid?: string;
|
||||
genid?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
boot_type: "UEFI" | "UEFISecureBoot";
|
||||
architecture: "i686" | "x86_64";
|
||||
memory: number;
|
||||
|
79
virtweb_frontend/src/widgets/forms/IPInput.tsx
Normal file
79
virtweb_frontend/src/widgets/forms/IPInput.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import { TextInput } from "./TextInput";
|
||||
|
||||
export function IPInput(p: {
|
||||
label: string;
|
||||
editable: boolean;
|
||||
value?: string;
|
||||
onValueChange?: (newVal: string | undefined) => void;
|
||||
version: 4 | 6;
|
||||
}): React.ReactElement {
|
||||
const { onValueChange, ...props } = p;
|
||||
return (
|
||||
<TextInput
|
||||
onValueChange={(v) => {
|
||||
onValueChange?.(p.version === 4 ? sanitizeIpV4(v) : sanitizeIpV6(v));
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function sanitizeIpV4(s: string | undefined): string | undefined {
|
||||
if (s === "" || s === undefined) return s;
|
||||
|
||||
let split = s.split(".");
|
||||
if (split.length > 4) split.splice(4);
|
||||
|
||||
let needAnotherIteration = false;
|
||||
|
||||
const res = split
|
||||
.map((v) => {
|
||||
if (v === "") return "";
|
||||
|
||||
const num = Number(v);
|
||||
if (isNaN(num) || num < 0) return "0";
|
||||
if (num > 255) {
|
||||
needAnotherIteration = true;
|
||||
return v.slice(0, 2) + "." + v.slice(2);
|
||||
}
|
||||
return num.toString();
|
||||
})
|
||||
.join(".");
|
||||
|
||||
return needAnotherIteration ? sanitizeIpV4(res) : res;
|
||||
}
|
||||
|
||||
function sanitizeIpV6(s: string | undefined): string | undefined {
|
||||
if (s === "" || s === undefined) return s;
|
||||
|
||||
const split = s.split(":");
|
||||
if (split.length > 8) split.splice(8);
|
||||
|
||||
let needAnotherIteration = false;
|
||||
|
||||
let res = split
|
||||
.map((e) => {
|
||||
if (e === "") return e;
|
||||
|
||||
const num = parseInt(e, 16);
|
||||
if (isNaN(num)) return "0";
|
||||
|
||||
let s = num.toString(16);
|
||||
if (num > 0xffff) {
|
||||
needAnotherIteration = true;
|
||||
return s.slice(0, 4) + ":" + s.slice(4);
|
||||
}
|
||||
|
||||
return s;
|
||||
})
|
||||
.join(":");
|
||||
|
||||
const firstIndex = res.indexOf("::");
|
||||
let nextIndex = res.lastIndexOf("::");
|
||||
while (nextIndex !== firstIndex) {
|
||||
res = res.slice(0, nextIndex) + res.slice(nextIndex + 1);
|
||||
nextIndex = res.lastIndexOf("::");
|
||||
}
|
||||
|
||||
return needAnotherIteration ? sanitizeIpV6(res) : res;
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
import { Alert, CircularProgress, Typography } from "@mui/material";
|
||||
import { VMApi, VMInfo } from "../../api/VMApi";
|
||||
import { AsyncWidget } from "../AsyncWidget";
|
||||
import React from "react";
|
||||
import { CheckboxInput } from "./CheckboxInput";
|
||||
import { useAlert } from "../../hooks/providers/AlertDialogProvider";
|
||||
import { useSnackbar } from "../../hooks/providers/SnackbarProvider";
|
||||
|
||||
export function VMAutostartInput(p: {
|
||||
export function ResAutostartInput(p: {
|
||||
editable: boolean;
|
||||
vm: VMInfo;
|
||||
checkAutotostart: () => Promise<boolean>;
|
||||
setAutotostart: (enable: boolean) => Promise<void>;
|
||||
ressourceName: string;
|
||||
}): React.ReactElement {
|
||||
const alert = useAlert();
|
||||
const snackbar = useSnackbar();
|
||||
@ -16,25 +17,25 @@ export function VMAutostartInput(p: {
|
||||
const [enabled, setEnabled] = React.useState<boolean | undefined>();
|
||||
|
||||
const load = async () => {
|
||||
setEnabled(await VMApi.IsAutostart(p.vm));
|
||||
setEnabled(await p.checkAutotostart());
|
||||
};
|
||||
|
||||
const update = async (enabled: boolean) => {
|
||||
try {
|
||||
await VMApi.SetAutostart(p.vm, enabled);
|
||||
snackbar("Autostart status successfully updated!");
|
||||
await p.setAutotostart(enabled);
|
||||
snackbar(`Autostart status of ${p.ressourceName} successfully updated!`);
|
||||
setEnabled(enabled);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
alert("Failed to update autostart status of the VM!");
|
||||
alert(`Failed to update autostart status of ${p.ressourceName}!`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AsyncWidget
|
||||
loadKey={p.vm.uuid}
|
||||
loadKey={p.ressourceName}
|
||||
load={load}
|
||||
errMsg="Failed to check autostart status of the VM!"
|
||||
errMsg={`Failed to check autostart status of ${p.ressourceName}!`}
|
||||
buildLoading={() => (
|
||||
<Typography>
|
||||
<CircularProgress size={"1rem"} /> Checking for autostart
|
||||
@ -42,27 +43,29 @@ export function VMAutostartInput(p: {
|
||||
)}
|
||||
buildError={(e: string) => <Alert severity="error">{e}</Alert>}
|
||||
build={() => (
|
||||
<VMAutostartInputInner
|
||||
<ResAutostartInputInner
|
||||
editable={p.editable}
|
||||
enabled={enabled!}
|
||||
setEnabled={update}
|
||||
resName={p.ressourceName}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function VMAutostartInputInner(p: {
|
||||
function ResAutostartInputInner(p: {
|
||||
editable: boolean;
|
||||
enabled: boolean;
|
||||
setEnabled: (b: boolean) => void;
|
||||
resName: string;
|
||||
}): React.ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<CheckboxInput
|
||||
editable={p.editable}
|
||||
checked={p.enabled}
|
||||
label="Autostart VM"
|
||||
label={`Autostart ${p.resName}`}
|
||||
onValueChange={p.setEnabled}
|
||||
/>
|
||||
</div>
|
@ -16,7 +16,7 @@ export function TextInput(p: {
|
||||
maxRows?: number;
|
||||
type?: React.HTMLInputTypeAttribute;
|
||||
}): React.ReactElement {
|
||||
if (((!p.editable && p.value) ?? "") === "") return <></>;
|
||||
if (!p.editable && (p.value ?? "") === "") return <></>;
|
||||
|
||||
let valueError = undefined;
|
||||
if (p.value && p.value.length > 0) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Checkbox, Grid } from "@mui/material";
|
||||
import React from "react";
|
||||
import { IpConfig, NetworkInfo } from "../../api/NetworksApi";
|
||||
import { IpConfig, NetworkApi, NetworkInfo } from "../../api/NetworksApi";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import { AsyncWidget } from "../AsyncWidget";
|
||||
import { EditSection } from "../forms/EditSection";
|
||||
@ -9,6 +9,7 @@ import { SelectInput } from "../forms/SelectInput";
|
||||
import { TextInput } from "../forms/TextInput";
|
||||
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||
import { CheckboxInput } from "../forms/CheckboxInput";
|
||||
import { ResAutostartInput } from "../forms/ResAutostartInput";
|
||||
|
||||
interface DetailsProps {
|
||||
net: NetworkInfo;
|
||||
@ -75,8 +76,16 @@ function NetworkDetailsInner(
|
||||
}}
|
||||
multiline={true}
|
||||
/>
|
||||
|
||||
{p.net.uuid && (
|
||||
<ResAutostartInput
|
||||
editable={p.editable}
|
||||
ressourceName="Network"
|
||||
checkAutotostart={() => NetworkApi.IsAutostart(p.net)}
|
||||
setAutotostart={(e) => NetworkApi.SetAutostart(p.net, e)}
|
||||
/>
|
||||
)}
|
||||
</EditSection>
|
||||
{/* TODO : autostart */}
|
||||
|
||||
<EditSection title="General settings">
|
||||
<SelectInput
|
||||
|
@ -3,16 +3,16 @@ import React from "react";
|
||||
import { validate as validateUUID } from "uuid";
|
||||
import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import { VMInfo } from "../../api/VMApi";
|
||||
import { VMApi, VMInfo } from "../../api/VMApi";
|
||||
import { AsyncWidget } from "../AsyncWidget";
|
||||
import { CheckboxInput } from "../forms/CheckboxInput";
|
||||
import { EditSection } from "../forms/EditSection";
|
||||
import { SelectInput } from "../forms/SelectInput";
|
||||
import { TextInput } from "../forms/TextInput";
|
||||
import { VMAutostartInput } from "../forms/VMAutostartInput";
|
||||
import { VMDisksList } from "../forms/VMDisksList";
|
||||
import { VMSelectIsoInput } from "../forms/VMSelectIsoInput";
|
||||
import { VMScreenshot } from "./VMScreenshot";
|
||||
import { ResAutostartInput } from "../forms/ResAutostartInput";
|
||||
|
||||
interface DetailsProps {
|
||||
vm: VMInfo;
|
||||
@ -156,7 +156,14 @@ function VMDetailsInner(
|
||||
}}
|
||||
/>
|
||||
|
||||
{p.vm.uuid && <VMAutostartInput editable={p.editable} vm={p.vm} />}
|
||||
{p.vm.uuid && (
|
||||
<ResAutostartInput
|
||||
editable={p.editable}
|
||||
ressourceName="VM"
|
||||
checkAutotostart={() => VMApi.IsAutostart(p.vm)}
|
||||
setAutotostart={(e) => VMApi.SetAutostart(p.vm, e)}
|
||||
/>
|
||||
)}
|
||||
</EditSection>
|
||||
|
||||
{/* Storage section */}
|
||||
|
Loading…
Reference in New Issue
Block a user