mirror of
				https://github.com/checktheroads/hyperglass
				synced 2024-05-11 05:55:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			255 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import * as React from "react";
 | |
| import { useState, useEffect } from "react";
 | |
| import { Box, Flex } from "@chakra-ui/core";
 | |
| import { useForm } from "react-hook-form";
 | |
| import lodash from "lodash";
 | |
| import * as yup from "yup";
 | |
| import format from "string-format";
 | |
| import FormField from "~/components/FormField";
 | |
| import HelpModal from "~/components/HelpModal";
 | |
| import QueryLocation from "~/components/QueryLocation";
 | |
| import QueryType from "~/components/QueryType";
 | |
| import QueryTarget from "~/components/QueryTarget";
 | |
| import CommunitySelect from "~/components/CommunitySelect";
 | |
| import QueryVrf from "~/components/QueryVrf";
 | |
| import ResolvedTarget from "~/components/ResolvedTarget";
 | |
| import SubmitButton from "~/components/SubmitButton";
 | |
| import useConfig from "~/components/HyperglassProvider";
 | |
| 
 | |
| format.extend(String.prototype, {});
 | |
| 
 | |
| const formSchema = (config) =>
 | |
|     yup.object().shape({
 | |
|         query_location: yup
 | |
|             .array()
 | |
|             .of(yup.string())
 | |
|             .required(config.messages.no_input.format({ field: config.web.text.query_location })),
 | |
|         query_type: yup
 | |
|             .string()
 | |
|             .required(config.messages.no_input.format({ field: config.web.text.query_type })),
 | |
|         query_vrf: yup.string(),
 | |
|         query_target: yup
 | |
|             .string()
 | |
|             .required(config.messages.no_input.format({ field: config.web.text.query_target })),
 | |
|     });
 | |
| 
 | |
| const FormRow = ({ children, ...props }) => (
 | |
|     <Flex
 | |
|         flexDirection="row"
 | |
|         flexWrap="wrap"
 | |
|         w="100%"
 | |
|         justifyContent={["center", "center", "space-between", "space-between"]}
 | |
|         {...props}
 | |
|     >
 | |
|         {children}
 | |
|     </Flex>
 | |
| );
 | |
| 
 | |
| const HyperglassForm = React.forwardRef(
 | |
|     ({ isSubmitting, setSubmitting, setFormData, greetingAck, setGreetingAck, ...props }, ref) => {
 | |
|         const config = useConfig();
 | |
|         const { handleSubmit, register, unregister, setValue, errors } = useForm({
 | |
|             validationSchema: formSchema(config),
 | |
|             defaultValues: { query_vrf: "default", query_target: "" },
 | |
|         });
 | |
| 
 | |
|         const [queryLocation, setQueryLocation] = useState([]);
 | |
|         const [queryType, setQueryType] = useState("");
 | |
|         const [queryVrf, setQueryVrf] = useState("");
 | |
|         const [queryTarget, setQueryTarget] = useState("");
 | |
|         const [availVrfs, setAvailVrfs] = useState([]);
 | |
|         const [fqdnTarget, setFqdnTarget] = useState("");
 | |
|         const [displayTarget, setDisplayTarget] = useState("");
 | |
|         const [families, setFamilies] = useState([]);
 | |
|         const onSubmit = (values) => {
 | |
|             if (!greetingAck && config.web.greeting.required) {
 | |
|                 window.location.reload(false);
 | |
|                 setGreetingAck(false);
 | |
|             } else {
 | |
|                 setFormData(values);
 | |
|                 setSubmitting(true);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         const handleLocChange = (locObj) => {
 | |
|             setQueryLocation(locObj.value);
 | |
|             const allVrfs = [];
 | |
|             const deviceVrfs = [];
 | |
|             locObj.value.map((loc) => {
 | |
|                 const locVrfs = [];
 | |
|                 config.devices[loc].vrfs.map((vrf) => {
 | |
|                     locVrfs.push({
 | |
|                         label: vrf.display_name,
 | |
|                         value: vrf.id,
 | |
|                     });
 | |
|                     deviceVrfs.push([{ id: vrf.id, ipv4: vrf.ipv4, ipv6: vrf.ipv6 }]);
 | |
|                 });
 | |
|                 allVrfs.push(locVrfs);
 | |
|             });
 | |
| 
 | |
|             const intersecting = lodash.intersectionWith(...allVrfs, lodash.isEqual);
 | |
|             setAvailVrfs(intersecting);
 | |
|             !intersecting.includes(queryVrf) && queryVrf !== "default" && setQueryVrf("default");
 | |
| 
 | |
|             let ipv4 = 0;
 | |
|             let ipv6 = 0;
 | |
|             deviceVrfs.length !== 0 &&
 | |
|                 intersecting.length !== 0 &&
 | |
|                 deviceVrfs
 | |
|                     .filter((v) => intersecting.every((i) => i.id === v.id))
 | |
|                     .reduce((a, b) => a.concat(b))
 | |
|                     .filter((v) => v.id === "default")
 | |
|                     .map((v) => {
 | |
|                         v.ipv4 === true && ipv4++;
 | |
|                         v.ipv6 === true && ipv6++;
 | |
|                     });
 | |
|             if (ipv4 !== 0 && ipv4 === ipv6) {
 | |
|                 setFamilies([4, 6]);
 | |
|             } else if (ipv4 > ipv6) {
 | |
|                 setFamilies([4]);
 | |
|             } else if (ipv4 < ipv6) {
 | |
|                 setFamilies([6]);
 | |
|             } else {
 | |
|                 setFamilies([]);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         const handleChange = (e) => {
 | |
|             setValue(e.field, e.value);
 | |
|             e.field === "query_location"
 | |
|                 ? handleLocChange(e)
 | |
|                 : e.field === "query_type"
 | |
|                 ? setQueryType(e.value)
 | |
|                 : e.field === "query_vrf"
 | |
|                 ? setQueryVrf(e.value)
 | |
|                 : e.field === "query_target"
 | |
|                 ? setQueryTarget(e.value)
 | |
|                 : null;
 | |
|         };
 | |
| 
 | |
|         const vrfContent = config.content.vrf[queryVrf]?.[queryType];
 | |
| 
 | |
|         const validFqdnQueryType =
 | |
|             ["ping", "traceroute", "bgp_route"].includes(queryType) &&
 | |
|             fqdnTarget &&
 | |
|             queryVrf === "default"
 | |
|                 ? fqdnTarget
 | |
|                 : null;
 | |
| 
 | |
|         useEffect(() => {
 | |
|             register({ name: "query_location" });
 | |
|             register({ name: "query_type" });
 | |
|             register({ name: "query_vrf" });
 | |
|         }, [register]);
 | |
|         Object.keys(errors).length >= 1 && console.error(errors);
 | |
|         return (
 | |
|             <Box
 | |
|                 maxW={["100%", "100%", "75%", "75%"]}
 | |
|                 w="100%"
 | |
|                 p={0}
 | |
|                 mx="auto"
 | |
|                 my={4}
 | |
|                 textAlign="left"
 | |
|                 ref={ref}
 | |
|                 {...props}
 | |
|             >
 | |
|                 <form onSubmit={handleSubmit(onSubmit)}>
 | |
|                     <FormRow>
 | |
|                         <FormField
 | |
|                             label={config.web.text.query_location}
 | |
|                             name="query_location"
 | |
|                             error={errors.query_location}
 | |
|                         >
 | |
|                             <QueryLocation onChange={handleChange} locations={config.networks} />
 | |
|                         </FormField>
 | |
|                         <FormField
 | |
|                             label={config.web.text.query_type}
 | |
|                             name="query_type"
 | |
|                             error={errors.query_type}
 | |
|                             labelAddOn={
 | |
|                                 vrfContent && <HelpModal item={vrfContent} name="query_type" />
 | |
|                             }
 | |
|                         >
 | |
|                             <QueryType onChange={handleChange} queryTypes={config.queries.list} />
 | |
|                         </FormField>
 | |
|                     </FormRow>
 | |
|                     <FormRow>
 | |
|                         {availVrfs.length > 1 && (
 | |
|                             <FormField
 | |
|                                 label={config.web.text.query_vrf}
 | |
|                                 name="query_vrf"
 | |
|                                 error={errors.query_vrf}
 | |
|                             >
 | |
|                                 <QueryVrf
 | |
|                                     placeholder={config.web.text.query_vrf}
 | |
|                                     vrfs={availVrfs}
 | |
|                                     onChange={handleChange}
 | |
|                                 />
 | |
|                             </FormField>
 | |
|                         )}
 | |
|                         <FormField
 | |
|                             label={config.web.text.query_target}
 | |
|                             name="query_target"
 | |
|                             error={errors.query_target}
 | |
|                             fieldAddOn={
 | |
|                                 queryLocation.length !== 0 &&
 | |
|                                 validFqdnQueryType && (
 | |
|                                     <ResolvedTarget
 | |
|                                         queryTarget={queryTarget}
 | |
|                                         fqdnTarget={validFqdnQueryType}
 | |
|                                         setTarget={handleChange}
 | |
|                                         families={families}
 | |
|                                         availVrfs={availVrfs}
 | |
|                                     />
 | |
|                                 )
 | |
|                             }
 | |
|                         >
 | |
|                             {queryType === "bgp_community" &&
 | |
|                             config.queries.bgp_community.mode === "select" ? (
 | |
|                                 <CommunitySelect
 | |
|                                     name="query_target"
 | |
|                                     register={register}
 | |
|                                     unregister={unregister}
 | |
|                                     onChange={handleChange}
 | |
|                                     communities={config.queries.bgp_community.communities}
 | |
|                                 />
 | |
|                             ) : (
 | |
|                                 <QueryTarget
 | |
|                                     name="query_target"
 | |
|                                     placeholder={config.web.text.query_target}
 | |
|                                     register={register}
 | |
|                                     unregister={unregister}
 | |
|                                     resolveTarget={["ping", "traceroute", "bgp_route"].includes(
 | |
|                                         queryType
 | |
|                                     )}
 | |
|                                     value={queryTarget}
 | |
|                                     setFqdn={setFqdnTarget}
 | |
|                                     setTarget={handleChange}
 | |
|                                     displayValue={displayTarget}
 | |
|                                     setDisplayValue={setDisplayTarget}
 | |
|                                 />
 | |
|                             )}
 | |
|                         </FormField>
 | |
|                     </FormRow>
 | |
|                     <FormRow mt={0} justifyContent="flex-end">
 | |
|                         <Flex
 | |
|                             w="100%"
 | |
|                             maxW="100%"
 | |
|                             ml="auto"
 | |
|                             my={2}
 | |
|                             mr={[0, 0, 2, 2]}
 | |
|                             flexDirection="column"
 | |
|                             flex="0 0 0"
 | |
|                         >
 | |
|                             <SubmitButton isLoading={isSubmitting} />
 | |
|                         </Flex>
 | |
|                     </FormRow>
 | |
|                 </form>
 | |
|             </Box>
 | |
|         );
 | |
|     }
 | |
| );
 | |
| 
 | |
| HyperglassForm.displayName = "HyperglassForm";
 | |
| export default HyperglassForm;
 |