Can configure all network settings
This commit is contained in:
parent
b7d44f3091
commit
23f2029deb
@ -371,6 +371,12 @@ impl NetworkInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(domain) = &self.domain {
|
||||||
|
if !regex!("^[a-zA-Z0-9.]+$").is_match(domain) {
|
||||||
|
return Err(StructureExtraction("Domain name is invalid!").into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut ips = Vec::with_capacity(2);
|
let mut ips = Vec::with_capacity(2);
|
||||||
|
|
||||||
if let Some(ipv4) = self.ip_v4 {
|
if let Some(ipv4) = self.ip_v4 {
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
import { Grid, Paper, Typography } from "@mui/material";
|
import { Grid, Paper, Typography } from "@mui/material";
|
||||||
import { PropsWithChildren } from "react";
|
import React, { PropsWithChildren } from "react";
|
||||||
|
|
||||||
export function EditSection(
|
export function EditSection(
|
||||||
p: { title: string } & PropsWithChildren
|
p: { title: string; actions?: React.ReactElement } & PropsWithChildren
|
||||||
): React.ReactElement {
|
): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<Grid item sm={12} md={6}>
|
<Grid item sm={12} md={6}>
|
||||||
<Paper style={{ margin: "10px", padding: "10px" }}>
|
<Paper style={{ margin: "10px", padding: "10px" }}>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography variant="h5" style={{ marginBottom: "15px" }}>
|
<Typography variant="h5" style={{ marginBottom: "15px" }}>
|
||||||
{p.title}
|
{p.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{p.actions}
|
||||||
|
</span>
|
||||||
{p.children}
|
{p.children}
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
60
virtweb_frontend/src/widgets/forms/TextMaskInput.tsx
Normal file
60
virtweb_frontend/src/widgets/forms/TextMaskInput.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { FormControl, Input, InputLabel } from "@mui/material";
|
||||||
|
import { TextInput } from "./TextInput";
|
||||||
|
import { IMaskInput } from "react-imask";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface CustomProps {
|
||||||
|
onChange: (event: { target: { name: string; value: string } }) => void;
|
||||||
|
name: string;
|
||||||
|
placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TextMaskCustom = React.forwardRef<HTMLInputElement, CustomProps>(
|
||||||
|
function TextMaskCustom(props, ref) {
|
||||||
|
const { onChange, placeholder, ...other } = props;
|
||||||
|
return (
|
||||||
|
<IMaskInput
|
||||||
|
{...other}
|
||||||
|
mask={placeholder}
|
||||||
|
definitions={{
|
||||||
|
"#": /[1-9]/,
|
||||||
|
}}
|
||||||
|
inputRef={ref}
|
||||||
|
onAccept={(value: any) =>
|
||||||
|
onChange({ target: { name: props.name, value } })
|
||||||
|
}
|
||||||
|
overwrite
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export function TextMaskInput(p: {
|
||||||
|
label: string;
|
||||||
|
editable: boolean;
|
||||||
|
value?: string;
|
||||||
|
onValueChange?: (newVal: string | undefined) => void;
|
||||||
|
mask: string;
|
||||||
|
}): React.ReactElement {
|
||||||
|
const id = React.useRef(Math.random());
|
||||||
|
|
||||||
|
if (!p.editable) return <TextInput {...p} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl variant="standard" fullWidth>
|
||||||
|
<InputLabel htmlFor={`mi-${id.current}`}>{p.label}</InputLabel>
|
||||||
|
<Input
|
||||||
|
fullWidth
|
||||||
|
value={p.value ?? ""}
|
||||||
|
onChange={(c) =>
|
||||||
|
p.onValueChange?.(
|
||||||
|
c.target.value.length === 0 ? undefined : c.target.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
id={`mi-${id.current}`}
|
||||||
|
inputComponent={TextMaskCustom as any}
|
||||||
|
placeholder={p.mask}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -1,12 +1,14 @@
|
|||||||
import { Grid } from "@mui/material";
|
import { Checkbox, Grid } from "@mui/material";
|
||||||
import { NetworkInfo } from "../../api/NetworksApi";
|
|
||||||
import { ServerApi } from "../../api/ServerApi";
|
|
||||||
import { EditSection } from "../forms/EditSection";
|
|
||||||
import { TextInput } from "../forms/TextInput";
|
|
||||||
import { SelectInput } from "../forms/SelectInput";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { IpConfig, NetworkInfo } from "../../api/NetworksApi";
|
||||||
|
import { ServerApi } from "../../api/ServerApi";
|
||||||
import { AsyncWidget } from "../AsyncWidget";
|
import { AsyncWidget } from "../AsyncWidget";
|
||||||
import { IPv4Input } from "../forms/IPv4Input";
|
import { EditSection } from "../forms/EditSection";
|
||||||
|
import { IPInput } from "../forms/IPInput";
|
||||||
|
import { SelectInput } from "../forms/SelectInput";
|
||||||
|
import { TextInput } from "../forms/TextInput";
|
||||||
|
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||||
|
import { CheckboxInput } from "../forms/CheckboxInput";
|
||||||
|
|
||||||
interface DetailsProps {
|
interface DetailsProps {
|
||||||
net: NetworkInfo;
|
net: NetworkInfo;
|
||||||
@ -116,7 +118,7 @@ function NetworkDetailsInner(
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<IPv4Input
|
<IPInput
|
||||||
editable={p.editable}
|
editable={p.editable}
|
||||||
label="DNS server to use"
|
label="DNS server to use"
|
||||||
value={p.net.dns_server}
|
value={p.net.dns_server}
|
||||||
@ -124,8 +126,150 @@ function NetworkDetailsInner(
|
|||||||
p.net.dns_server = v;
|
p.net.dns_server = v;
|
||||||
p.onChange?.();
|
p.onChange?.();
|
||||||
}}
|
}}
|
||||||
|
version={4}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Domain"
|
||||||
|
editable={p.editable}
|
||||||
|
value={p.net.domain}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.net.domain = v;
|
||||||
|
p.onChange?.();
|
||||||
|
}}
|
||||||
|
multiline={true}
|
||||||
/>
|
/>
|
||||||
</EditSection>
|
</EditSection>
|
||||||
|
|
||||||
|
<IPSection
|
||||||
|
editable={p.editable}
|
||||||
|
config={p.net.ip_v4}
|
||||||
|
onChange={(c) => {
|
||||||
|
p.net.ip_v4 = c;
|
||||||
|
p.onChange?.();
|
||||||
|
}}
|
||||||
|
version={4}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IPSection
|
||||||
|
editable={p.editable}
|
||||||
|
config={p.net.ip_v6}
|
||||||
|
onChange={(c) => {
|
||||||
|
p.net.ip_v6 = c;
|
||||||
|
p.onChange?.();
|
||||||
|
}}
|
||||||
|
version={6}
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function IPSection(p: {
|
||||||
|
editable: boolean;
|
||||||
|
config?: IpConfig;
|
||||||
|
onChange: (c: IpConfig | undefined) => void;
|
||||||
|
version: 4 | 6;
|
||||||
|
}): React.ReactElement {
|
||||||
|
const confirm = useConfirm();
|
||||||
|
|
||||||
|
const toggleNetwork = async () => {
|
||||||
|
if (!!p.config) {
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
`Do you really want to disable IPv${p.version} on this network?`
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p.onChange?.(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.onChange?.({
|
||||||
|
bridge_address: p.version === 4 ? "192.168.1.1" : "fd00::1",
|
||||||
|
prefix: p.version === 4 ? 24 : 8,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!p.config && !p.editable) return <></>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EditSection
|
||||||
|
title={`IPv${p.version} network`}
|
||||||
|
actions={
|
||||||
|
<Checkbox
|
||||||
|
disabled={!p.editable}
|
||||||
|
checked={!!p.config}
|
||||||
|
onChange={toggleNetwork}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{p.config && (
|
||||||
|
<>
|
||||||
|
<IPInput
|
||||||
|
editable={p.editable}
|
||||||
|
label="Bridge address"
|
||||||
|
version={p.version}
|
||||||
|
value={p.config?.bridge_address}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.config!.bridge_address = v ?? "";
|
||||||
|
p.onChange?.(p.config);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Prefix"
|
||||||
|
editable={p.editable}
|
||||||
|
value={p.config.prefix.toString()}
|
||||||
|
type="number"
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.config!.prefix = Number(v);
|
||||||
|
p.onChange?.(p.config);
|
||||||
|
}}
|
||||||
|
size={p.version === 4 ? { min: 0, max: 32 } : { min: 0, max: 128 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CheckboxInput
|
||||||
|
checked={!!p.config.dhcp_range}
|
||||||
|
editable={p.editable}
|
||||||
|
label="Enable DHCP"
|
||||||
|
onValueChange={(v) => {
|
||||||
|
if (v)
|
||||||
|
p.config!.dhcp_range =
|
||||||
|
p.version === 4
|
||||||
|
? ["192.168.1.100", "192.168.1.200"]
|
||||||
|
: ["fd00::100", "fd00::f00"];
|
||||||
|
else p.config!.dhcp_range = undefined;
|
||||||
|
p.onChange?.(p.config);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{p.config?.dhcp_range && (
|
||||||
|
<>
|
||||||
|
<IPInput
|
||||||
|
label="DHCP allocation start"
|
||||||
|
editable={p.editable}
|
||||||
|
version={p.version}
|
||||||
|
value={p.config.dhcp_range[0]}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.config!.dhcp_range![0] = v!;
|
||||||
|
p.onChange(p.config);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<IPInput
|
||||||
|
label="DHCP allocation end"
|
||||||
|
editable={p.editable}
|
||||||
|
version={p.version}
|
||||||
|
value={p.config.dhcp_range[1]}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
p.config!.dhcp_range![1] = v!;
|
||||||
|
p.onChange(p.config);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</EditSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user