146 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Button } from "@mui/material";
 | |
| import React from "react";
 | |
| import { useNavigate, useParams } from "react-router-dom";
 | |
| import { NetworkApi, NetworkInfo, NetworkURL } from "../api/NetworksApi";
 | |
| import { useAlert } from "../hooks/providers/AlertDialogProvider";
 | |
| import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider";
 | |
| import { useSnackbar } from "../hooks/providers/SnackbarProvider";
 | |
| import { AsyncWidget } from "../widgets/AsyncWidget";
 | |
| import { ConfigImportExportButtons } from "../widgets/ConfigImportExportButtons";
 | |
| import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | |
| import { NetworkDetails } from "../widgets/net/NetworkDetails";
 | |
| 
 | |
| export function CreateNetworkRoute(): React.ReactElement {
 | |
|   const alert = useAlert();
 | |
|   const snackbar = useSnackbar();
 | |
|   const navigate = useNavigate();
 | |
| 
 | |
|   const [network, setNetwork] = React.useState<NetworkInfo>({
 | |
|     name: "NewNetwork",
 | |
|     forward_mode: "Isolated",
 | |
|   });
 | |
| 
 | |
|   const createNetwork = async (n: NetworkInfo) => {
 | |
|     try {
 | |
|       const res = await NetworkApi.Create(n);
 | |
|       snackbar("The network was successfully created!");
 | |
|       navigate(`/net/${res.uid}`);
 | |
|     } catch (e) {
 | |
|       console.error(e);
 | |
|       alert(`Failed to create network!\n${e}`);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   return (
 | |
|     <EditNetworkRouteInner
 | |
|       network={network}
 | |
|       creating={true}
 | |
|       onCancel={() => navigate("/net")}
 | |
|       onSave={createNetwork}
 | |
|       onReplace={setNetwork}
 | |
|     />
 | |
|   );
 | |
| }
 | |
| 
 | |
| export function EditNetworkRoute(): React.ReactElement {
 | |
|   const alert = useAlert();
 | |
|   const snackbar = useSnackbar();
 | |
| 
 | |
|   const { uuid } = useParams();
 | |
|   const navigate = useNavigate();
 | |
| 
 | |
|   const [network, setNetwork] = React.useState<NetworkInfo | undefined>();
 | |
| 
 | |
|   const load = async () => {
 | |
|     setNetwork(await NetworkApi.GetSingle(uuid!));
 | |
|   };
 | |
| 
 | |
|   const updateNetwork = async (n: NetworkInfo) => {
 | |
|     try {
 | |
|       await NetworkApi.Update(n);
 | |
|       snackbar("The network was successfully updated!");
 | |
|       navigate(NetworkURL(network!));
 | |
|     } catch (e) {
 | |
|       console.error(e);
 | |
|       alert(`Failed to update network!\n${e}`);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   return (
 | |
|     <AsyncWidget
 | |
|       loadKey={uuid}
 | |
|       ready={network !== undefined}
 | |
|       errMsg="Failed to fetch network information!"
 | |
|       load={load}
 | |
|       build={() => (
 | |
|         <EditNetworkRouteInner
 | |
|           network={network!}
 | |
|           creating={false}
 | |
|           onCancel={() => navigate(`/net/${uuid}`)}
 | |
|           onSave={updateNetwork}
 | |
|           onReplace={setNetwork}
 | |
|         />
 | |
|       )}
 | |
|     />
 | |
|   );
 | |
| }
 | |
| 
 | |
| function EditNetworkRouteInner(p: {
 | |
|   network: NetworkInfo;
 | |
|   creating: boolean;
 | |
|   onCancel: () => void;
 | |
|   onSave: (vm: NetworkInfo) => Promise<void>;
 | |
|   onReplace: (vm: NetworkInfo) => void;
 | |
| }): React.ReactElement {
 | |
|   const loadingMessage = useLoadingMessage();
 | |
| 
 | |
|   const [changed, setChanged] = React.useState(false);
 | |
| 
 | |
|   const [, updateState] = React.useState<any>();
 | |
|   const forceUpdate = React.useCallback(() => { updateState({}); }, []);
 | |
| 
 | |
|   const valueChanged = () => {
 | |
|     setChanged(true);
 | |
|     forceUpdate();
 | |
|   };
 | |
| 
 | |
|   const save = async () => {
 | |
|     loadingMessage.show("Saving network configuration...");
 | |
|     await p.onSave(p.network);
 | |
|     loadingMessage.hide();
 | |
|   };
 | |
| 
 | |
|   return (
 | |
|     <VirtWebRouteContainer
 | |
|       label={p.creating ? "Create a Network" : "Edit Network"}
 | |
|       actions={
 | |
|         <span>
 | |
|           <ConfigImportExportButtons
 | |
|             currentConf={p.network}
 | |
|             filename={`net-${p.network.name}.json`}
 | |
|             importConf={(c) => {
 | |
|               p.onReplace(c);
 | |
|               valueChanged();
 | |
|             }}
 | |
|           />
 | |
| 
 | |
|           {changed && (
 | |
|             <Button
 | |
|               variant="contained"
 | |
|               onClick={save}
 | |
|               style={{ marginRight: "10px" }}
 | |
|             >
 | |
|               {p.creating ? "Create" : "Save"}
 | |
|             </Button>
 | |
|           )}
 | |
|           <Button onClick={p.onCancel} variant="outlined">
 | |
|             Cancel
 | |
|           </Button>
 | |
|         </span>
 | |
|       }
 | |
|     >
 | |
|       <NetworkDetails net={p.network} editable={true} onChange={valueChanged} />
 | |
|     </VirtWebRouteContainer>
 | |
|   );
 | |
| }
 |