Reorganize network tab
This commit is contained in:
		@@ -2,23 +2,27 @@ import { Grid, Paper, Typography } from "@mui/material";
 | 
			
		||||
import React, { PropsWithChildren } from "react";
 | 
			
		||||
 | 
			
		||||
export function EditSection(
 | 
			
		||||
  p: { title: string; actions?: React.ReactElement } & PropsWithChildren
 | 
			
		||||
  p: { title?: string; actions?: React.ReactElement } & PropsWithChildren
 | 
			
		||||
): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <Grid item sm={12} md={6}>
 | 
			
		||||
      <Paper style={{ margin: "10px", padding: "10px" }}>
 | 
			
		||||
        <span
 | 
			
		||||
          style={{
 | 
			
		||||
            display: "flex",
 | 
			
		||||
            justifyContent: "space-between",
 | 
			
		||||
            alignItems: "center",
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Typography variant="h5" style={{ marginBottom: "15px" }}>
 | 
			
		||||
            {p.title}
 | 
			
		||||
          </Typography>
 | 
			
		||||
          {p.actions}
 | 
			
		||||
        </span>
 | 
			
		||||
        {(p.title || p.actions) && (
 | 
			
		||||
          <span
 | 
			
		||||
            style={{
 | 
			
		||||
              display: "flex",
 | 
			
		||||
              justifyContent: "space-between",
 | 
			
		||||
              alignItems: "center",
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            {p.title && (
 | 
			
		||||
              <Typography variant="h5" style={{ marginBottom: "15px" }}>
 | 
			
		||||
                {p.title}
 | 
			
		||||
              </Typography>
 | 
			
		||||
            )}
 | 
			
		||||
            {p.actions}
 | 
			
		||||
          </span>
 | 
			
		||||
        )}
 | 
			
		||||
        {p.children}
 | 
			
		||||
      </Paper>
 | 
			
		||||
    </Grid>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import DeleteIcon from "@mui/icons-material/Delete";
 | 
			
		||||
import {
 | 
			
		||||
  Avatar,
 | 
			
		||||
  Button,
 | 
			
		||||
  Grid,
 | 
			
		||||
  IconButton,
 | 
			
		||||
  ListItem,
 | 
			
		||||
  ListItemAvatar,
 | 
			
		||||
@@ -19,6 +20,7 @@ import { randomMacAddress } from "../../utils/RandUtils";
 | 
			
		||||
import { MACInput } from "./MACInput";
 | 
			
		||||
import { SelectInput } from "./SelectInput";
 | 
			
		||||
import { VMNetworkFilterParameters } from "./VMNetworkFilterParameters";
 | 
			
		||||
import { EditSection } from "./EditSection";
 | 
			
		||||
 | 
			
		||||
export function VMNetworksList(p: {
 | 
			
		||||
  vm: VMInfo;
 | 
			
		||||
@@ -37,22 +39,28 @@ export function VMNetworksList(p: {
 | 
			
		||||
 | 
			
		||||
  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 && (
 | 
			
		||||
        <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" && (
 | 
			
		||||
          <SelectInput
 | 
			
		||||
            editable={p.editable}
 | 
			
		||||
            label="Defined network"
 | 
			
		||||
            options={p.networksList.map((n) => {
 | 
			
		||||
              const chars = [n.forward_mode.toString()];
 | 
			
		||||
              if (n.ip_v4) chars.push("IPv4");
 | 
			
		||||
              if (n.ip_v6) chars.push("IPv6");
 | 
			
		||||
              if (n.description) chars.push(n.description);
 | 
			
		||||
          <>
 | 
			
		||||
            <SelectInput
 | 
			
		||||
              editable={p.editable}
 | 
			
		||||
              label="Defined network"
 | 
			
		||||
              options={p.networksList.map((n) => {
 | 
			
		||||
                const chars = [n.forward_mode.toString()];
 | 
			
		||||
                if (n.ip_v4) chars.push("IPv4");
 | 
			
		||||
                if (n.ip_v6) chars.push("IPv6");
 | 
			
		||||
                if (n.description) chars.push(n.description);
 | 
			
		||||
 | 
			
		||||
              return {
 | 
			
		||||
                label: n.name,
 | 
			
		||||
                value: n.name,
 | 
			
		||||
                description: chars.join(" - "),
 | 
			
		||||
              };
 | 
			
		||||
            })}
 | 
			
		||||
            value={p.network.network}
 | 
			
		||||
            onValueChange={(v) => {
 | 
			
		||||
              if (p.network.type === "DefinedNetwork")
 | 
			
		||||
                p.network.network = v as any;
 | 
			
		||||
              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}
 | 
			
		||||
                return {
 | 
			
		||||
                  label: n.name,
 | 
			
		||||
                  value: n.name,
 | 
			
		||||
                  description: chars.join(" - "),
 | 
			
		||||
                };
 | 
			
		||||
              })}
 | 
			
		||||
              value={p.network.network}
 | 
			
		||||
              onValueChange={(v) => {
 | 
			
		||||
                if (p.network.type === "DefinedNetwork")
 | 
			
		||||
                  p.network.network = v as any;
 | 
			
		||||
                p.onChange?.();
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
          </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>
 | 
			
		||||
    </>
 | 
			
		||||
 
 | 
			
		||||
@@ -288,14 +288,7 @@ function VMDetailsTabStorage(p: DetailsInnerProps): React.ReactElement {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function VMDetailsTabNetwork(p: DetailsInnerProps): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <Grid container spacing={2}>
 | 
			
		||||
      {/* Networks section */}
 | 
			
		||||
      <EditSection title="Networks">
 | 
			
		||||
        <VMNetworksList {...p} />
 | 
			
		||||
      </EditSection>
 | 
			
		||||
    </Grid>
 | 
			
		||||
  );
 | 
			
		||||
  return <VMNetworksList {...p} />;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function VMDetailsTabDanger(p: DetailsInnerProps): React.ReactElement {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user