Reorganize network tab

This commit is contained in:
Pierre HUBERT 2024-01-02 20:09:42 +01:00
parent 0175726696
commit 085deff4f7
3 changed files with 98 additions and 91 deletions

View File

@ -2,23 +2,27 @@ import { Grid, Paper, Typography } from "@mui/material";
import React, { PropsWithChildren } from "react"; import React, { PropsWithChildren } from "react";
export function EditSection( export function EditSection(
p: { title: string; actions?: React.ReactElement } & 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 {(p.title || p.actions) && (
style={{ <span
display: "flex", style={{
justifyContent: "space-between", display: "flex",
alignItems: "center", justifyContent: "space-between",
}} alignItems: "center",
> }}
<Typography variant="h5" style={{ marginBottom: "15px" }}> >
{p.title} {p.title && (
</Typography> <Typography variant="h5" style={{ marginBottom: "15px" }}>
{p.actions} {p.title}
</span> </Typography>
)}
{p.actions}
</span>
)}
{p.children} {p.children}
</Paper> </Paper>
</Grid> </Grid>

View File

@ -4,6 +4,7 @@ import DeleteIcon from "@mui/icons-material/Delete";
import { import {
Avatar, Avatar,
Button, Button,
Grid,
IconButton, IconButton,
ListItem, ListItem,
ListItemAvatar, ListItemAvatar,
@ -19,6 +20,7 @@ import { randomMacAddress } from "../../utils/RandUtils";
import { MACInput } from "./MACInput"; import { MACInput } from "./MACInput";
import { SelectInput } from "./SelectInput"; import { SelectInput } from "./SelectInput";
import { VMNetworkFilterParameters } from "./VMNetworkFilterParameters"; import { VMNetworkFilterParameters } from "./VMNetworkFilterParameters";
import { EditSection } from "./EditSection";
export function VMNetworksList(p: { export function VMNetworksList(p: {
vm: VMInfo; vm: VMInfo;
@ -37,22 +39,28 @@ export function VMNetworksList(p: {
return ( return (
<> <>
{/* networks list */}
{p.vm.networks.map((n, num) => (
<NetworkInfoWidget
key={num}
network={n}
removeFromList={() => {
p.vm.networks.splice(num, 1);
p.onChange?.();
}}
{...p}
/>
))}
{p.editable && ( {p.editable && (
<Button onClick={addNew}>Add a new network interface</Button> <div style={{ textAlign: "right", marginTop: "5px" }}>
<Button onClick={addNew}>Add a new network interface</Button>
</div>
)} )}
<Grid container spacing={2}>
{/* networks list */}
{p.vm.networks.map((n, num) => (
<EditSection key={num}>
<NetworkInfoWidget
key={num}
network={n}
removeFromList={() => {
p.vm.networks.splice(num, 1);
p.onChange?.();
}}
{...p}
/>
</EditSection>
))}
</Grid>
</> </>
); );
} }
@ -141,64 +149,66 @@ function NetworkInfoWidget(p: {
/> />
{p.network.type === "DefinedNetwork" && ( {p.network.type === "DefinedNetwork" && (
<SelectInput <>
editable={p.editable} <SelectInput
label="Defined network" editable={p.editable}
options={p.networksList.map((n) => { label="Defined network"
const chars = [n.forward_mode.toString()]; options={p.networksList.map((n) => {
if (n.ip_v4) chars.push("IPv4"); const chars = [n.forward_mode.toString()];
if (n.ip_v6) chars.push("IPv6"); if (n.ip_v4) chars.push("IPv4");
if (n.description) chars.push(n.description); if (n.ip_v6) chars.push("IPv6");
if (n.description) chars.push(n.description);
return { return {
label: n.name, label: n.name,
value: n.name, value: n.name,
description: chars.join(" - "), description: chars.join(" - "),
}; };
})} })}
value={p.network.network} value={p.network.network}
onValueChange={(v) => { onValueChange={(v) => {
if (p.network.type === "DefinedNetwork") if (p.network.type === "DefinedNetwork")
p.network.network = v as any; p.network.network = v as any;
p.onChange?.(); p.onChange?.();
}} }}
/>
)}
{/* Network Filter */}
<SelectInput
editable={p.editable}
label="Network filter"
value={p.network.nwfilterref?.name}
onValueChange={(v) => {
if (v && !p.network.nwfilterref) {
p.network.nwfilterref = { name: v, parameters: [] };
} else if (v) {
p.network.nwfilterref!.name = v;
} else {
p.network.nwfilterref = undefined;
}
p.onChange?.();
}}
options={[
{ label: "No network filer", value: undefined },
...p.networkFiltersList.map((v) => {
return {
value: v.name,
label: `${v.name} (${v.chain?.protocol ?? "unspecified"})`,
description: `${v.rules.length} rules - ${v.join_filters.length} joint filters`,
};
}),
]}
/>
{p.network.nwfilterref && (
<div style={{ margin: "10px" }}>
<VMNetworkFilterParameters
filterref={p.network.nwfilterref}
{...p}
/> />
</div>
{/* Network Filter */}
<SelectInput
editable={p.editable}
label="Network filter"
value={p.network.nwfilterref?.name}
onValueChange={(v) => {
if (v && !p.network.nwfilterref) {
p.network.nwfilterref = { name: v, parameters: [] };
} else if (v) {
p.network.nwfilterref!.name = v;
} else {
p.network.nwfilterref = undefined;
}
p.onChange?.();
}}
options={[
{ label: "No network filer", value: undefined },
...p.networkFiltersList.map((v) => {
return {
value: v.name,
label: `${v.name} (${v.chain?.protocol ?? "unspecified"})`,
description: `${v.rules.length} rules - ${v.join_filters.length} joint filters`,
};
}),
]}
/>
{p.network.nwfilterref && (
<div style={{ margin: "10px" }}>
<VMNetworkFilterParameters
filterref={p.network.nwfilterref}
{...p}
/>
</div>
)}
</>
)} )}
</div> </div>
</> </>

View File

@ -288,14 +288,7 @@ function VMDetailsTabStorage(p: DetailsInnerProps): React.ReactElement {
} }
function VMDetailsTabNetwork(p: DetailsInnerProps): React.ReactElement { function VMDetailsTabNetwork(p: DetailsInnerProps): React.ReactElement {
return ( return <VMNetworksList {...p} />;
<Grid container spacing={2}>
{/* Networks section */}
<EditSection title="Networks">
<VMNetworksList {...p} />
</EditSection>
</Grid>
);
} }
function VMDetailsTabDanger(p: DetailsInnerProps): React.ReactElement { function VMDetailsTabDanger(p: DetailsInnerProps): React.ReactElement {