import { useEffect, useMemo, useState } from 'react'; import { Flex } from '@chakra-ui/react'; import { useForm } from 'react-hook-form'; import { uniqWith } from 'lodash'; import * as yup from 'yup'; import { AnimatedForm, FormRow, QueryVrf, FormField, HelpModal, QueryType, QueryTarget, SubmitButton, QueryLocation, ResolvedTarget, CommunitySelect, } from '~/components'; import { useConfig, useGlobalState } from '~/context'; import { useStrf, useGreeting } from '~/hooks'; import type { Families, TFormData, TDeviceVrf, TQueryTypes, OnChangeArgs } from '~/types'; function isString(a: any): a is string { return typeof a === 'string'; } function isQueryType(q: any): q is TQueryTypes { let result = false; if ( typeof q === 'string' && ['bgp_route', 'bgp_community', 'bgp_aspath', 'ping', 'traceroute'].includes(q) ) { result = true; } return result; } export const HyperglassForm = () => { const { web, content, devices, messages, networks, queries } = useConfig(); const { formData, isSubmitting } = useGlobalState(); const [greetingAck, setGreetingAck] = useGreeting(); const noQueryType = useStrf(messages.no_input, { field: web.text.query_type }); const noQueryLoc = useStrf(messages.no_input, { field: web.text.query_location }); const noQueryTarget = useStrf(messages.no_input, { field: web.text.query_target }); const formSchema = yup.object().shape({ query_location: yup.array().of(yup.string()).required(noQueryLoc), query_type: yup.string().required(noQueryType), query_vrf: yup.string(), query_target: yup.string().required(noQueryTarget), }); const { handleSubmit, register, unregister, setValue, errors } = useForm({ validationSchema: formSchema, 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([]); function onSubmit(values: TFormData): void { if (!greetingAck && web.greeting.required) { window.location.reload(false); setGreetingAck(false); } else { formData.set(values); isSubmitting.set(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); }); 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++; }); */ // function handleLocChange(locObj: TSelectOption) { // const allVrfs = [] as TDeviceVrf[][]; // const deviceVrfs = [] as TDeviceVrf[][]; // if (Array.isArray(locObj.value)) { // setQueryLocation(locObj.value); // for (const loc of locObj.value) { // const locVrfs = [] as TDeviceVrf[]; // for (const vrf of devices.filter(dev => dev.name === loc)[0].vrfs) { // locVrfs.push(vrf); // deviceVrfs.push([vrf]); // } // allVrfs.push(locVrfs); // } // } // // Use _.intersectionWith to create an array of VRFs common to all selected locations. // const intersecting: TDeviceVrf[] = intersectionWith(...allVrfs, isEqual); // setAvailVrfs(intersecting); // // If there are no intersecting VRFs, use the default VRF. // if (intersecting.filter(i => i.id === queryVrf).length === 0 && queryVrf !== 'default') { // setQueryVrf('default'); // } // let ipv4 = 0; // let ipv6 = 0; // if (deviceVrfs.length !== 0 && intersecting.length !== 0) { // const matching = deviceVrfs // // Select intersecting VRFs // .filter(v => intersecting.every(i => i.id === v.id)) // .reduce((a, b) => a.concat(b)) // .filter(v => v.id === 'default'); // for (const match of matching) { // if (match.ipv4) { // ipv4++; // } // if (match.ipv6) { // ipv6++; // } // } // } // if (ipv4 !== 0 && ipv4 === ipv6) { // setFamilies([4, 6]); // } else if (ipv4 > ipv6) { // setFamilies([4]); // } else if (ipv4 < ipv6) { // setFamilies([6]); // } else { // setFamilies([]); // } // } function handleLocChange(locations: string | string[]): void { const allVrfs = [] as TDeviceVrf[]; if (Array.isArray(locations)) { setQueryLocation(locations); for (const loc of locations) { for (const vrf of devices.filter(dev => dev.name === loc)[0].vrfs) { allVrfs.push(vrf); } } } // Use _.intersectionWith to create an array of VRFs common to all selected locations. const intersecting = uniqWith(allVrfs, (a, b) => a.id === b.id); setAvailVrfs(intersecting); // If there are no intersecting VRFs, use the default VRF. if (intersecting.filter(i => i.id === queryVrf).length === 0 && queryVrf !== 'default') { setQueryVrf('default'); } let ipv4 = 0; let ipv6 = 0; if (intersecting.length !== 0) { for (const intersection of intersecting) { if (intersection.ipv4) { ipv4++; } if (intersection.ipv6) { ipv6++; } } } if (ipv4 !== 0 && ipv4 === ipv6) { setFamilies([4, 6]); } else if (ipv4 > ipv6) { setFamilies([4]); } else if (ipv4 < ipv6) { setFamilies([6]); } else { setFamilies([]); } } function handleChange(e: OnChangeArgs): void { setValue(e.field, e.value); if (e.field === 'query_location') { handleLocChange(e.value); } else if (e.field === 'query_type' && isQueryType(e.value)) { setQueryType(e.value); } else if (e.field === 'query_vrf' && isString(e.value)) { setQueryVrf(e.value); } else if (e.field === 'query_target' && isString(e.value)) { setQueryTarget(e.value); } } const vrfContent = useMemo(() => { if (Object.keys(content.vrf).includes(queryVrf) && queryType !== '') { return content.vrf[queryVrf][queryType]; } }, [queryVrf]); const isFqdnQuery = useMemo(() => { return ['bgp_route', 'ping', 'traceroute'].includes(queryType); }, [queryType]); const fqdnQuery = useMemo(() => { let result = null; if (fqdnTarget && queryVrf === 'default' && fqdnTarget) { result = fqdnTarget; } return result; }, [queryVrf, queryType]); useEffect(() => { register({ name: 'query_location' }); register({ name: 'query_type' }); register({ name: 'query_vrf' }); }, [register]); Object.keys(errors).length >= 1 && console.error(errors); return ( }> {availVrfs.length > 1 && ( )} ) }> {queryType === 'bgp_community' && queries.bgp_community.mode === 'select' ? ( ) : ( )} ); };