Create frames for network filters management
This commit is contained in:
		@@ -27,6 +27,11 @@ import { BaseLoginPage } from "./widgets/BaseLoginPage";
 | 
				
			|||||||
import { ViewNetworkRoute } from "./routes/ViewNetworkRoute";
 | 
					import { ViewNetworkRoute } from "./routes/ViewNetworkRoute";
 | 
				
			||||||
import { HomeRoute } from "./routes/HomeRoute";
 | 
					import { HomeRoute } from "./routes/HomeRoute";
 | 
				
			||||||
import { NetworkFiltersListRoute } from "./routes/NetworkFiltersListRoute";
 | 
					import { NetworkFiltersListRoute } from "./routes/NetworkFiltersListRoute";
 | 
				
			||||||
 | 
					import { ViewNWFilterRoute } from "./routes/ViewNWFilterRoute";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  CreateNWFilterRoute,
 | 
				
			||||||
 | 
					  EditNWFilterRoute,
 | 
				
			||||||
 | 
					} from "./routes/EditNWFilterRoute";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface AuthContext {
 | 
					interface AuthContext {
 | 
				
			||||||
  signedIn: boolean;
 | 
					  signedIn: boolean;
 | 
				
			||||||
@@ -63,6 +68,9 @@ export function App() {
 | 
				
			|||||||
          <Route path="net/:uuid/edit" element={<EditNetworkRoute />} />
 | 
					          <Route path="net/:uuid/edit" element={<EditNetworkRoute />} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <Route path="nwfilter" element={<NetworkFiltersListRoute />} />
 | 
					          <Route path="nwfilter" element={<NetworkFiltersListRoute />} />
 | 
				
			||||||
 | 
					          <Route path="nwfilter/new" element={<CreateNWFilterRoute />} />
 | 
				
			||||||
 | 
					          <Route path="nwfilter/:uuid" element={<ViewNWFilterRoute />} />
 | 
				
			||||||
 | 
					          <Route path="nwfilter/:uuid/edit" element={<EditNWFilterRoute />} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <Route path="sysinfo" element={<SysInfoRoute />} />
 | 
					          <Route path="sysinfo" element={<SysInfoRoute />} />
 | 
				
			||||||
          <Route path="*" element={<NotFoundRoute />} />
 | 
					          <Route path="*" element={<NotFoundRoute />} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import { APIClient } from "./ApiClient";
 | 
					import { APIClient } from "./ApiClient";
 | 
				
			||||||
 | 
					import { ServerApi } from "./ServerApi";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface NWFilterChain {
 | 
					export interface NWFilterChain {
 | 
				
			||||||
  protocol: string;
 | 
					  protocol: string;
 | 
				
			||||||
@@ -18,8 +19,91 @@ export interface NWFSMac {
 | 
				
			|||||||
  comment?: string;
 | 
					  comment?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO : complete
 | 
					export interface NWFSArpOrRARP {
 | 
				
			||||||
export type NWFSelector = NWFSAll | NWFSMac;
 | 
					  srcmacaddr?: string;
 | 
				
			||||||
 | 
					  srcmacmask?: string;
 | 
				
			||||||
 | 
					  dstmacaddr?: string;
 | 
				
			||||||
 | 
					  dstmacmask?: string;
 | 
				
			||||||
 | 
					  arpsrcipaddr?: string;
 | 
				
			||||||
 | 
					  arpsrcipmask?: number;
 | 
				
			||||||
 | 
					  arpdstipaddr?: string;
 | 
				
			||||||
 | 
					  arpdstipmask?: number;
 | 
				
			||||||
 | 
					  comment?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NWFSArp = NWFSArpOrRARP & {
 | 
				
			||||||
 | 
					  type: "arp";
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NWFSRArp = NWFSArpOrRARP & {
 | 
				
			||||||
 | 
					  type: "rarp";
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface NWFSIPBase {
 | 
				
			||||||
 | 
					  srcmacaddr?: string;
 | 
				
			||||||
 | 
					  srcmacmask?: string;
 | 
				
			||||||
 | 
					  dstmacaddr?: string;
 | 
				
			||||||
 | 
					  dstmacmask?: string;
 | 
				
			||||||
 | 
					  srcipaddr?: string;
 | 
				
			||||||
 | 
					  srcipmask?: number;
 | 
				
			||||||
 | 
					  dstipaddr?: string;
 | 
				
			||||||
 | 
					  dstipmask?: number;
 | 
				
			||||||
 | 
					  comment?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NFWSIPv4 = NWFSIPBase & { type: "ipv4" };
 | 
				
			||||||
 | 
					export type NFWSIPv6 = NWFSIPBase & { type: "ipv6" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Layer4State =
 | 
				
			||||||
 | 
					  | "NEW"
 | 
				
			||||||
 | 
					  | "ESTABLISHED"
 | 
				
			||||||
 | 
					  | "RELATED"
 | 
				
			||||||
 | 
					  | "INVALID"
 | 
				
			||||||
 | 
					  | "NONE";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface NWFSLayer4Base {
 | 
				
			||||||
 | 
					  srcmacaddr?: string;
 | 
				
			||||||
 | 
					  srcipaddr?: string;
 | 
				
			||||||
 | 
					  srcipmask?: number;
 | 
				
			||||||
 | 
					  dstipaddr?: string;
 | 
				
			||||||
 | 
					  dstipmask?: number;
 | 
				
			||||||
 | 
					  srcipfrom?: string;
 | 
				
			||||||
 | 
					  srcipto?: string;
 | 
				
			||||||
 | 
					  dstipfrom?: string;
 | 
				
			||||||
 | 
					  dstipto?: string;
 | 
				
			||||||
 | 
					  srcportstart?: number;
 | 
				
			||||||
 | 
					  srcportend?: number;
 | 
				
			||||||
 | 
					  dstportstart?: number;
 | 
				
			||||||
 | 
					  dstportend?: number;
 | 
				
			||||||
 | 
					  state?: Layer4State;
 | 
				
			||||||
 | 
					  comment?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NFWSTCPv4 = NWFSLayer4Base & { type: "tcp" };
 | 
				
			||||||
 | 
					export type NFWSUDPv4 = NWFSLayer4Base & { type: "udp" };
 | 
				
			||||||
 | 
					export type NFWSSCTPv4 = NWFSLayer4Base & { type: "sctp" };
 | 
				
			||||||
 | 
					export type NFWSICMPv4 = NWFSLayer4Base & { type: "icmp" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NFWSTCPv6 = NWFSLayer4Base & { type: "tcpipv6" };
 | 
				
			||||||
 | 
					export type NFWSUDPv6 = NWFSLayer4Base & { type: "udpipv6" };
 | 
				
			||||||
 | 
					export type NFWSSCTPv6 = NWFSLayer4Base & { type: "sctpipv6" };
 | 
				
			||||||
 | 
					export type NFWSICMPv6 = NWFSLayer4Base & { type: "icmpipv6" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NWFSelector =
 | 
				
			||||||
 | 
					  | NWFSAll
 | 
				
			||||||
 | 
					  | NWFSMac
 | 
				
			||||||
 | 
					  | NWFSArp
 | 
				
			||||||
 | 
					  | NWFSRArp
 | 
				
			||||||
 | 
					  | NFWSIPv4
 | 
				
			||||||
 | 
					  | NFWSIPv6
 | 
				
			||||||
 | 
					  | NFWSTCPv4
 | 
				
			||||||
 | 
					  | NFWSUDPv4
 | 
				
			||||||
 | 
					  | NFWSSCTPv4
 | 
				
			||||||
 | 
					  | NFWSICMPv4
 | 
				
			||||||
 | 
					  | NFWSTCPv6
 | 
				
			||||||
 | 
					  | NFWSUDPv6
 | 
				
			||||||
 | 
					  | NFWSSCTPv6
 | 
				
			||||||
 | 
					  | NFWSICMPv6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface NWFilterRule {
 | 
					export interface NWFilterRule {
 | 
				
			||||||
  action: "drop" | "reject" | "accept" | "return" | "continue";
 | 
					  action: "drop" | "reject" | "accept" | "return" | "continue";
 | 
				
			||||||
@@ -41,6 +125,10 @@ export function NWFilterURL(n: NWFilter, edit: boolean = false): string {
 | 
				
			|||||||
  return `/nwfilter/${n.uuid}${edit ? "/edit" : ""}`;
 | 
					  return `/nwfilter/${n.uuid}${edit ? "/edit" : ""}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function NWFilterIsBuiltin(n: NWFilter): boolean {
 | 
				
			||||||
 | 
					  return ServerApi.Config.builtin_nwfilter_rules.includes(n.name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class NWFilterApi {
 | 
					export class NWFilterApi {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Get the entire list of networks
 | 
					   * Get the entire list of networks
 | 
				
			||||||
@@ -57,4 +145,64 @@ export class NWFilterApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return list;
 | 
					    return list;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Get the information about a single network filter
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async GetSingle(uuid: string): Promise<NWFilter> {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      await APIClient.exec({
 | 
				
			||||||
 | 
					        method: "GET",
 | 
				
			||||||
 | 
					        uri: `/nwfilter/${uuid}`,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ).data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Get the source XML configuration of a network filter for debugging purposes
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async GetSingleXML(uuid: string): Promise<string> {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      await APIClient.exec({
 | 
				
			||||||
 | 
					        uri: `/nwfilter/${uuid}/src`,
 | 
				
			||||||
 | 
					        method: "GET",
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ).data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Create a new network filter
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async Create(n: NWFilter): Promise<{ uid: string }> {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      await APIClient.exec({
 | 
				
			||||||
 | 
					        method: "POST",
 | 
				
			||||||
 | 
					        uri: "/nwfilter/create",
 | 
				
			||||||
 | 
					        jsonData: n,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ).data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Update an existing network filter
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async Update(n: NWFilter): Promise<{ uid: string }> {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      await APIClient.exec({
 | 
				
			||||||
 | 
					        method: "PUT",
 | 
				
			||||||
 | 
					        uri: `/nwfilter/${n.uuid}`,
 | 
				
			||||||
 | 
					        jsonData: n,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    ).data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Delete a network filter
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static async Delete(n: NWFilter): Promise<void> {
 | 
				
			||||||
 | 
					    await APIClient.exec({
 | 
				
			||||||
 | 
					      method: "DELETE",
 | 
				
			||||||
 | 
					      uri: `/nwfilter/${n.uuid}`,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -160,12 +160,10 @@ export class NetworkApi {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Delete a network
 | 
					   * Delete a network
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  static async Delete(n: NetworkInfo): Promise<NetworkInfo[]> {
 | 
					  static async Delete(n: NetworkInfo): Promise<void> {
 | 
				
			||||||
    return (
 | 
					    await APIClient.exec({
 | 
				
			||||||
      await APIClient.exec({
 | 
					      method: "DELETE",
 | 
				
			||||||
        method: "DELETE",
 | 
					      uri: `/network/${n.uuid}`,
 | 
				
			||||||
        uri: `/network/${n.uuid}`,
 | 
					    });
 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    ).data;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										150
									
								
								virtweb_frontend/src/routes/EditNWFilterRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								virtweb_frontend/src/routes/EditNWFilterRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					import { Button } from "@mui/material";
 | 
				
			||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { useNavigate, useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					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 { NWFilter, NWFilterApi, NWFilterURL } from "../api/NWFilterApi";
 | 
				
			||||||
 | 
					import { NWFilterDetails } from "../widgets/nwfilter/NWFilterDetails";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CreateNWFilterRoute(): React.ReactElement {
 | 
				
			||||||
 | 
					  const alert = useAlert();
 | 
				
			||||||
 | 
					  const snackbar = useSnackbar();
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [nwfilter, setNWFilter] = React.useState<NWFilter>({
 | 
				
			||||||
 | 
					    name: "my-filter",
 | 
				
			||||||
 | 
					    join_filters: [],
 | 
				
			||||||
 | 
					    rules: [],
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const createNWFilter = async (n: NWFilter) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const res = await NWFilterApi.Create(n);
 | 
				
			||||||
 | 
					      snackbar("The network filter was successfully created!");
 | 
				
			||||||
 | 
					      navigate(`/nwfilter/${res.uid}`);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      console.error(e);
 | 
				
			||||||
 | 
					      alert(`Failed to create network filter!\n${e}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <EditNetworkFilterRouteInner
 | 
				
			||||||
 | 
					      nwfilter={nwfilter}
 | 
				
			||||||
 | 
					      creating={true}
 | 
				
			||||||
 | 
					      onCancel={() => navigate("/nwfilter")}
 | 
				
			||||||
 | 
					      onSave={createNWFilter}
 | 
				
			||||||
 | 
					      onReplace={setNWFilter}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function EditNWFilterRoute(): React.ReactElement {
 | 
				
			||||||
 | 
					  const alert = useAlert();
 | 
				
			||||||
 | 
					  const snackbar = useSnackbar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { uuid } = useParams();
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [nwfilter, setNWFilter] = React.useState<NWFilter | undefined>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const load = async () => {
 | 
				
			||||||
 | 
					    setNWFilter(await NWFilterApi.GetSingle(uuid!));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const updateNetworkFilter = async (n: NWFilter) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      await NWFilterApi.Update(n);
 | 
				
			||||||
 | 
					      snackbar("The network filter was successfully updated!");
 | 
				
			||||||
 | 
					      navigate(NWFilterURL(nwfilter!));
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      console.error(e);
 | 
				
			||||||
 | 
					      alert(`Failed to update network filter!\n${e}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <AsyncWidget
 | 
				
			||||||
 | 
					      loadKey={uuid}
 | 
				
			||||||
 | 
					      ready={nwfilter !== undefined}
 | 
				
			||||||
 | 
					      errMsg="Failed to fetch network filter information!"
 | 
				
			||||||
 | 
					      load={load}
 | 
				
			||||||
 | 
					      build={() => (
 | 
				
			||||||
 | 
					        <EditNetworkFilterRouteInner
 | 
				
			||||||
 | 
					          nwfilter={nwfilter!}
 | 
				
			||||||
 | 
					          creating={false}
 | 
				
			||||||
 | 
					          onCancel={() => navigate(`/nwfilter/${uuid}`)}
 | 
				
			||||||
 | 
					          onSave={updateNetworkFilter}
 | 
				
			||||||
 | 
					          onReplace={setNWFilter}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function EditNetworkFilterRouteInner(p: {
 | 
				
			||||||
 | 
					  nwfilter: NWFilter;
 | 
				
			||||||
 | 
					  creating: boolean;
 | 
				
			||||||
 | 
					  onCancel: () => void;
 | 
				
			||||||
 | 
					  onSave: (vm: NWFilter) => Promise<void>;
 | 
				
			||||||
 | 
					  onReplace: (vm: NWFilter) => 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 filter configuration...");
 | 
				
			||||||
 | 
					    await p.onSave(p.nwfilter);
 | 
				
			||||||
 | 
					    loadingMessage.hide();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <VirtWebRouteContainer
 | 
				
			||||||
 | 
					      label={p.creating ? "Create a Network Filter" : "Edit Network Filter"}
 | 
				
			||||||
 | 
					      actions={
 | 
				
			||||||
 | 
					        <span>
 | 
				
			||||||
 | 
					          <ConfigImportExportButtons
 | 
				
			||||||
 | 
					            currentConf={p.nwfilter}
 | 
				
			||||||
 | 
					            filename={`nwfilter-${p.nwfilter.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>
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <NWFilterDetails
 | 
				
			||||||
 | 
					        nwfilter={p.nwfilter}
 | 
				
			||||||
 | 
					        editable={true}
 | 
				
			||||||
 | 
					        onChange={valueChanged}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </VirtWebRouteContainer>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -15,7 +15,12 @@ import {
 | 
				
			|||||||
} from "@mui/material";
 | 
					} from "@mui/material";
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import { useNavigate } from "react-router-dom";
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
import { NWFilter, NWFilterApi, NWFilterURL } from "../api/NWFilterApi";
 | 
					import {
 | 
				
			||||||
 | 
					  NWFilter,
 | 
				
			||||||
 | 
					  NWFilterApi,
 | 
				
			||||||
 | 
					  NWFilterIsBuiltin,
 | 
				
			||||||
 | 
					  NWFilterURL,
 | 
				
			||||||
 | 
					} from "../api/NWFilterApi";
 | 
				
			||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
					import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
				
			||||||
import { RouterLink } from "../widgets/RouterLink";
 | 
					import { RouterLink } from "../widgets/RouterLink";
 | 
				
			||||||
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
					import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
				
			||||||
@@ -61,10 +66,7 @@ function NetworkFiltersListRouteInner(p: {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const onlyBuiltin = visibleFilters === VisibleFilters.Builtin;
 | 
					    const onlyBuiltin = visibleFilters === VisibleFilters.Builtin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return p.list.filter(
 | 
					    return p.list.filter((f) => NWFilterIsBuiltin(f) === onlyBuiltin);
 | 
				
			||||||
      (f) =>
 | 
					 | 
				
			||||||
        ServerApi.Config.builtin_nwfilter_rules.includes(f.name) === onlyBuiltin
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }, [visibleFilters]);
 | 
					  }, [visibleFilters]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										65
									
								
								virtweb_frontend/src/routes/ViewNWFilterRoute.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								virtweb_frontend/src/routes/ViewNWFilterRoute.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					import { Button } from "@mui/material";
 | 
				
			||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { useNavigate, useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  NWFilter,
 | 
				
			||||||
 | 
					  NWFilterApi,
 | 
				
			||||||
 | 
					  NWFilterIsBuiltin,
 | 
				
			||||||
 | 
					  NWFilterURL,
 | 
				
			||||||
 | 
					} from "../api/NWFilterApi";
 | 
				
			||||||
 | 
					import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
				
			||||||
 | 
					import { ConfigImportExportButtons } from "../widgets/ConfigImportExportButtons";
 | 
				
			||||||
 | 
					import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
				
			||||||
 | 
					import { NWFilterDetails } from "../widgets/nwfilter/NWFilterDetails";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ViewNWFilterRoute() {
 | 
				
			||||||
 | 
					  const { uuid } = useParams();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [nwfilter, setNWFilter] = React.useState<NWFilter | undefined>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const load = async () => {
 | 
				
			||||||
 | 
					    setNWFilter(await NWFilterApi.GetSingle(uuid!));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <AsyncWidget
 | 
				
			||||||
 | 
					      loadKey={uuid}
 | 
				
			||||||
 | 
					      ready={nwfilter !== undefined}
 | 
				
			||||||
 | 
					      errMsg="Failed to fetch network filter information!"
 | 
				
			||||||
 | 
					      load={load}
 | 
				
			||||||
 | 
					      build={() => <ViewNetworkFilterRouteInner nwfilter={nwfilter!} />}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ViewNetworkFilterRouteInner(p: {
 | 
				
			||||||
 | 
					  nwfilter: NWFilter;
 | 
				
			||||||
 | 
					}): React.ReactElement {
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <VirtWebRouteContainer
 | 
				
			||||||
 | 
					      label={`Network filter ${p.nwfilter.name}`}
 | 
				
			||||||
 | 
					      actions={
 | 
				
			||||||
 | 
					        <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					          <ConfigImportExportButtons
 | 
				
			||||||
 | 
					            filename={`nwfilter-${p.nwfilter.name}.json`}
 | 
				
			||||||
 | 
					            currentConf={p.nwfilter}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          {!NWFilterIsBuiltin(p.nwfilter) && (
 | 
				
			||||||
 | 
					            <Button
 | 
				
			||||||
 | 
					              variant="contained"
 | 
				
			||||||
 | 
					              style={{ marginLeft: "15px" }}
 | 
				
			||||||
 | 
					              onClick={() => navigate(NWFilterURL(p.nwfilter, true))}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Edit
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <NWFilterDetails nwfilter={p.nwfilter} editable={false} />
 | 
				
			||||||
 | 
					    </VirtWebRouteContainer>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import { ReactElement } from "react";
 | 
				
			||||||
 | 
					import { NWFilter } from "../../api/NWFilterApi";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DetailsProps {
 | 
				
			||||||
 | 
					  nwfilter: NWFilter;
 | 
				
			||||||
 | 
					  editable: boolean;
 | 
				
			||||||
 | 
					  onChange?: () => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function NWFilterDetails(p: DetailsProps): ReactElement {
 | 
				
			||||||
 | 
					  return <>todo</>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user