Can list and delete networks
This commit is contained in:
		@@ -19,6 +19,7 @@ import { VMListRoute } from "./routes/VMListRoute";
 | 
			
		||||
import { CreateVMRoute, EditVMRoute } from "./routes/EditVMRoute";
 | 
			
		||||
import { VMRoute } from "./routes/VMRoute";
 | 
			
		||||
import { VNCRoute } from "./routes/VNCRoute";
 | 
			
		||||
import { NetworksListRoute } from "./routes/NetworksListRoute";
 | 
			
		||||
 | 
			
		||||
interface AuthContext {
 | 
			
		||||
  signedIn: boolean;
 | 
			
		||||
@@ -47,6 +48,8 @@ export function App() {
 | 
			
		||||
          <Route path="vm/:uuid/edit" element={<EditVMRoute />} />
 | 
			
		||||
          <Route path="vm/:uuid/vnc" element={<VNCRoute />} />
 | 
			
		||||
 | 
			
		||||
          <Route path="net" element={<NetworksListRoute />} />
 | 
			
		||||
 | 
			
		||||
          <Route path="sysinfo" element={<SysInfoRoute />} />
 | 
			
		||||
          <Route path="*" element={<NotFoundRoute />} />
 | 
			
		||||
        </Route>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								virtweb_frontend/src/api/NetworksApi.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								virtweb_frontend/src/api/NetworksApi.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
import { APIClient } from "./ApiClient";
 | 
			
		||||
 | 
			
		||||
export interface IpConfig {
 | 
			
		||||
  bridge_address: string;
 | 
			
		||||
  prefix: number;
 | 
			
		||||
  dhcp_range?: [string, string];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NetworkInfo {
 | 
			
		||||
  name: string;
 | 
			
		||||
  uuid: string;
 | 
			
		||||
  title?: string;
 | 
			
		||||
  description?: string;
 | 
			
		||||
  forward_mode: "NAT" | "Isolated";
 | 
			
		||||
  device?: string;
 | 
			
		||||
  dns_server?: string;
 | 
			
		||||
  domain?: string;
 | 
			
		||||
  ip_v4?: IpConfig;
 | 
			
		||||
  ip_v6?: IpConfig;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function NetworkURL(n: NetworkInfo, edit: boolean = false): string {
 | 
			
		||||
  return `/net/${n.uuid}${edit ? "/edit" : ""}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class NetworkApi {
 | 
			
		||||
  /**
 | 
			
		||||
   * Get the entire list of networks
 | 
			
		||||
   */
 | 
			
		||||
  static async GetList(): Promise<NetworkInfo[]> {
 | 
			
		||||
    return (
 | 
			
		||||
      await APIClient.exec({
 | 
			
		||||
        method: "GET",
 | 
			
		||||
        uri: "/network/list",
 | 
			
		||||
      })
 | 
			
		||||
    ).data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Delete a network
 | 
			
		||||
   */
 | 
			
		||||
  static async Delete(n: NetworkInfo): Promise<NetworkInfo[]> {
 | 
			
		||||
    return (
 | 
			
		||||
      await APIClient.exec({
 | 
			
		||||
        method: "DELETE",
 | 
			
		||||
        uri: `/network/${n.uuid}`,
 | 
			
		||||
      })
 | 
			
		||||
    ).data;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										133
									
								
								virtweb_frontend/src/routes/NetworksListRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								virtweb_frontend/src/routes/NetworksListRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
import DeleteIcon from "@mui/icons-material/Delete";
 | 
			
		||||
import VisibilityIcon from "@mui/icons-material/Visibility";
 | 
			
		||||
import {
 | 
			
		||||
  Button,
 | 
			
		||||
  IconButton,
 | 
			
		||||
  Paper,
 | 
			
		||||
  Table,
 | 
			
		||||
  TableBody,
 | 
			
		||||
  TableCell,
 | 
			
		||||
  TableContainer,
 | 
			
		||||
  TableHead,
 | 
			
		||||
  TableRow,
 | 
			
		||||
  Typography,
 | 
			
		||||
} from "@mui/material";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { NetworkApi, NetworkInfo, NetworkURL } from "../api/NetworksApi";
 | 
			
		||||
import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
			
		||||
import { RouterLink } from "../widgets/RouterLink";
 | 
			
		||||
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
			
		||||
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
 | 
			
		||||
import { useSnackbar } from "../hooks/providers/SnackbarProvider";
 | 
			
		||||
import { useAlert } from "../hooks/providers/AlertDialogProvider";
 | 
			
		||||
 | 
			
		||||
export function NetworksListRoute(): React.ReactElement {
 | 
			
		||||
  const confirm = useConfirm();
 | 
			
		||||
  const snackbar = useSnackbar();
 | 
			
		||||
  const alert = useAlert();
 | 
			
		||||
 | 
			
		||||
  const [list, setList] = React.useState<NetworkInfo[] | undefined>();
 | 
			
		||||
 | 
			
		||||
  const [count, setCount] = React.useState(1);
 | 
			
		||||
 | 
			
		||||
  const load = async () => {
 | 
			
		||||
    setList(await NetworkApi.GetList());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const reload = () => {
 | 
			
		||||
    setList(undefined);
 | 
			
		||||
    setCount(count + 1);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const requestDelete = async (n: NetworkInfo) => {
 | 
			
		||||
    try {
 | 
			
		||||
      if (
 | 
			
		||||
        !(await confirm(
 | 
			
		||||
          "Do you really want to delete this network?",
 | 
			
		||||
          `Delete network ${n.name}`,
 | 
			
		||||
          "Delete"
 | 
			
		||||
        ))
 | 
			
		||||
      )
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
      await NetworkApi.Delete(n);
 | 
			
		||||
      reload();
 | 
			
		||||
      snackbar("The network was successfully deleted!");
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error(e);
 | 
			
		||||
      alert("Failed to delete the network!");
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <AsyncWidget
 | 
			
		||||
      loadKey={count}
 | 
			
		||||
      load={load}
 | 
			
		||||
      ready={list !== undefined}
 | 
			
		||||
      errMsg="Failed to load the list of networks!"
 | 
			
		||||
      build={() => (
 | 
			
		||||
        <NetworksListRouteInner list={list!} onRequestDelete={requestDelete} />
 | 
			
		||||
      )}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function NetworksListRouteInner(p: {
 | 
			
		||||
  list: NetworkInfo[];
 | 
			
		||||
  onRequestDelete: (n: NetworkInfo) => void;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <VirtWebRouteContainer
 | 
			
		||||
      label="Networks"
 | 
			
		||||
      actions={
 | 
			
		||||
        <RouterLink to="/net/new">
 | 
			
		||||
          <Button>New</Button>
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      <TableContainer component={Paper}>
 | 
			
		||||
        <Table>
 | 
			
		||||
          <TableHead>
 | 
			
		||||
            <TableRow>
 | 
			
		||||
              <TableCell>Name</TableCell>
 | 
			
		||||
              <TableCell>Description</TableCell>
 | 
			
		||||
              <TableCell>Network type</TableCell>
 | 
			
		||||
              <TableCell>IP</TableCell>
 | 
			
		||||
              <TableCell>Actions</TableCell>
 | 
			
		||||
            </TableRow>
 | 
			
		||||
          </TableHead>
 | 
			
		||||
          <TableBody>
 | 
			
		||||
            {p.list.map((t) => {
 | 
			
		||||
              return (
 | 
			
		||||
                <TableRow key={t.uuid} hover>
 | 
			
		||||
                  <TableCell>{t.name}</TableCell>
 | 
			
		||||
                  <TableCell>
 | 
			
		||||
                    {t.description ?? (
 | 
			
		||||
                      <Typography style={{ fontStyle: "italic" }}>
 | 
			
		||||
                        None
 | 
			
		||||
                      </Typography>
 | 
			
		||||
                    )}
 | 
			
		||||
                  </TableCell>
 | 
			
		||||
                  <TableCell>{t.forward_mode}</TableCell>
 | 
			
		||||
                  <TableCell>
 | 
			
		||||
                    {t.ip_v4 && "IPv4"} {t.ip_v6 && "IPv6"}
 | 
			
		||||
                  </TableCell>
 | 
			
		||||
                  <TableCell>
 | 
			
		||||
                    <RouterLink to={NetworkURL(t)}>
 | 
			
		||||
                      <IconButton>
 | 
			
		||||
                        <VisibilityIcon />
 | 
			
		||||
                      </IconButton>
 | 
			
		||||
                    </RouterLink>
 | 
			
		||||
                    <IconButton onClick={() => p.onRequestDelete(t)}>
 | 
			
		||||
                      <DeleteIcon />
 | 
			
		||||
                    </IconButton>
 | 
			
		||||
                  </TableCell>
 | 
			
		||||
                </TableRow>
 | 
			
		||||
              );
 | 
			
		||||
            })}
 | 
			
		||||
          </TableBody>
 | 
			
		||||
        </Table>
 | 
			
		||||
      </TableContainer>
 | 
			
		||||
    </VirtWebRouteContainer>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,11 @@
 | 
			
		||||
import { mdiBoxShadow, mdiDisc, mdiHome, mdiInformation } from "@mdi/js";
 | 
			
		||||
import {
 | 
			
		||||
  mdiBoxShadow,
 | 
			
		||||
  mdiDisc,
 | 
			
		||||
  mdiHome,
 | 
			
		||||
  mdiInformation,
 | 
			
		||||
  mdiLan,
 | 
			
		||||
  mdiNetwork,
 | 
			
		||||
} from "@mdi/js";
 | 
			
		||||
import Icon from "@mdi/react";
 | 
			
		||||
import {
 | 
			
		||||
  Box,
 | 
			
		||||
@@ -49,6 +56,11 @@ export function BaseAuthenticatedPage(): React.ReactElement {
 | 
			
		||||
            uri="/vms"
 | 
			
		||||
            icon={<Icon path={mdiBoxShadow} size={1} />}
 | 
			
		||||
          />
 | 
			
		||||
          <NavLink
 | 
			
		||||
            label="Networks"
 | 
			
		||||
            uri="/net"
 | 
			
		||||
            icon={<Icon path={mdiLan} size={1} />}
 | 
			
		||||
          />
 | 
			
		||||
          <NavLink
 | 
			
		||||
            label="ISO files"
 | 
			
		||||
            uri="/iso"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user