forked from mirrors/thatmattlove-hyperglass
continue typescript & chakra v1 migrations [skip ci]
This commit is contained in:
parent
59e767e501
commit
8c454cf0ae
20 changed files with 119 additions and 157 deletions
|
|
@ -19,7 +19,7 @@ export const ResetButton = forwardRef<HTMLButtonElement, ButtonProps>((props, re
|
|||
aria-label="Reset Form"
|
||||
opacity={isSubmitting.value ? 1 : 0}
|
||||
{...props}>
|
||||
<Icon as={ChevronLeft} boxSize={24} />
|
||||
<Icon as={ChevronLeft} boxSize={8} />
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|||
import { Select } from '~/components';
|
||||
import { useConfig } from '~/context';
|
||||
|
||||
import type { TNetwork, TSelectOption } from '~/types';
|
||||
import type { TNetwork, TSelectOptionMulti } from '~/types';
|
||||
import type { TQuerySelectField } from './types';
|
||||
|
||||
function buildOptions(networks: TNetwork[]) {
|
||||
|
|
@ -23,11 +23,12 @@ export const QueryLocation = (props: TQuerySelectField) => {
|
|||
const { networks } = useConfig();
|
||||
const options = useMemo(() => buildOptions(networks), [networks.length]);
|
||||
|
||||
function handleChange(e: TSelectOption): void {
|
||||
if (Array.isArray(e?.value) && e !== null) {
|
||||
const value = e.value.map(sel => sel);
|
||||
onChange({ field: 'query_location', value });
|
||||
function handleChange(e: TSelectOptionMulti): void {
|
||||
if (e === null) {
|
||||
e = [];
|
||||
}
|
||||
const value = e.map(sel => sel.value);
|
||||
onChange({ field: 'query_location', value });
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ export const Frame = (props: TFrame) => {
|
|||
{...props}
|
||||
/>
|
||||
<Footer />
|
||||
{/* <If c={developer_mode}>
|
||||
<If c={developer_mode}>
|
||||
<Debugger />
|
||||
</If> */}
|
||||
</If>
|
||||
</Flex>
|
||||
<If c={web.greeting.enable && !greetingAck}>
|
||||
<Greeting onClickThrough={setGreetingAck} />
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { uniqWith } from 'lodash';
|
||||
import { intersectionWith } from 'lodash';
|
||||
import * as yup from 'yup';
|
||||
import {
|
||||
If,
|
||||
AnimatedForm,
|
||||
FormRow,
|
||||
QueryVrf,
|
||||
|
|
@ -17,30 +18,17 @@ import {
|
|||
CommunitySelect,
|
||||
} from '~/components';
|
||||
import { useConfig, useGlobalState } from '~/context';
|
||||
import { useStrf, useGreeting } from '~/hooks';
|
||||
import { useStrf, useGreeting, useDevice } from '~/hooks';
|
||||
import { isQueryType, isString } from '~/types';
|
||||
|
||||
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 { web, content, messages, queries } = useConfig();
|
||||
|
||||
const { formData, isSubmitting } = useGlobalState();
|
||||
const [greetingAck, setGreetingAck] = useGreeting();
|
||||
const getDevice = useDevice();
|
||||
|
||||
const noQueryType = useStrf(messages.no_input, { field: web.text.query_type });
|
||||
const noQueryLoc = useStrf(messages.no_input, { field: web.text.query_location });
|
||||
|
|
@ -77,105 +65,23 @@ export const HyperglassForm = () => {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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);
|
||||
});
|
||||
function handleLocChange(locations: string[]): void {
|
||||
const allVrfs = [] as TDeviceVrf[][];
|
||||
|
||||
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++;
|
||||
});
|
||||
*/
|
||||
setQueryLocation(locations);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
// Create an array of each device's VRFs.
|
||||
for (const loc of locations) {
|
||||
const device = getDevice(loc);
|
||||
allVrfs.push(device.vrfs);
|
||||
}
|
||||
|
||||
// Use _.intersectionWith to create an array of VRFs common to all selected locations.
|
||||
const intersecting = uniqWith<TDeviceVrf>(allVrfs, (a, b) => a.id === b.id);
|
||||
const intersecting = intersectionWith(
|
||||
...allVrfs,
|
||||
(a: TDeviceVrf, b: TDeviceVrf) => a.id === b.id,
|
||||
);
|
||||
|
||||
setAvailVrfs(intersecting);
|
||||
|
||||
// If there are no intersecting VRFs, use the default VRF.
|
||||
|
|
@ -211,7 +117,7 @@ export const HyperglassForm = () => {
|
|||
function handleChange(e: OnChangeArgs): void {
|
||||
setValue(e.field, e.value);
|
||||
|
||||
if (e.field === 'query_location') {
|
||||
if (e.field === 'query_location' && Array.isArray(e.value)) {
|
||||
handleLocChange(e.value);
|
||||
} else if (e.field === 'query_type' && isQueryType(e.value)) {
|
||||
setQueryType(e.value);
|
||||
|
|
@ -277,11 +183,11 @@ export const HyperglassForm = () => {
|
|||
</FormField>
|
||||
</FormRow>
|
||||
<FormRow>
|
||||
{availVrfs.length > 1 && (
|
||||
<If c={availVrfs.length > 1}>
|
||||
<FormField label={web.text.query_vrf} name="query_vrf" errors={errors.query_vrf}>
|
||||
<QueryVrf label={web.text.query_vrf} vrfs={availVrfs} onChange={handleChange} />
|
||||
</FormField>
|
||||
)}
|
||||
</If>
|
||||
<FormField
|
||||
name="query_target"
|
||||
errors={errors.query_target}
|
||||
|
|
@ -298,7 +204,7 @@ export const HyperglassForm = () => {
|
|||
/>
|
||||
)
|
||||
}>
|
||||
{queryType === 'bgp_community' && queries.bgp_community.mode === 'select' ? (
|
||||
<If c={queryType === 'bgp_community' && queries.bgp_community.mode === 'select'}>
|
||||
<CommunitySelect
|
||||
name="query_target"
|
||||
register={register}
|
||||
|
|
@ -306,7 +212,8 @@ export const HyperglassForm = () => {
|
|||
onChange={handleChange}
|
||||
communities={queries.bgp_community.communities}
|
||||
/>
|
||||
) : (
|
||||
</If>
|
||||
<If c={!(queryType === 'bgp_community' && queries.bgp_community.mode === 'select')}>
|
||||
<QueryTarget
|
||||
name="query_target"
|
||||
register={register}
|
||||
|
|
@ -319,7 +226,7 @@ export const HyperglassForm = () => {
|
|||
setDisplayValue={setDisplayTarget}
|
||||
placeholder={web.text.query_target}
|
||||
/>
|
||||
)}
|
||||
</If>
|
||||
</FormField>
|
||||
</FormRow>
|
||||
<FormRow mt={0} justifyContent="flex-end">
|
||||
|
|
|
|||
|
|
@ -32,7 +32,11 @@ export interface TCommunities {
|
|||
}
|
||||
|
||||
export interface TRPKIState {
|
||||
state: 0 | 1 | 2 | 3;
|
||||
state:
|
||||
| 0 // Invalid
|
||||
| 1 // Valid
|
||||
| 2 // Unknown
|
||||
| 3; // Unverified
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@ import { Accordion, Box, Stack, useToken } from '@chakra-ui/react';
|
|||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { AnimatedDiv, Label } from '~/components';
|
||||
import { useConfig, useBreakpointValue } from '~/context';
|
||||
import { useDevice } from '~/hooks';
|
||||
import { isQueryType } from '~/types';
|
||||
import { Result } from './individual';
|
||||
|
||||
import type { TResults } from './types';
|
||||
|
||||
export const Results = (props: TResults) => {
|
||||
const { queryLocation, queryType, queryVrf, queryTarget, ...rest } = props;
|
||||
const { request_timeout, devices, queries, vrfs, web } = useConfig();
|
||||
const { request_timeout, queries, vrfs, web } = useConfig();
|
||||
const getDevice = useDevice();
|
||||
const targetBg = useToken('colors', 'teal.600');
|
||||
const queryBg = useToken('colors', 'cyan.500');
|
||||
const vrfBg = useToken('colors', 'blue.500');
|
||||
|
|
@ -61,6 +64,11 @@ export const Results = (props: TResults) => {
|
|||
const matchedVrf =
|
||||
vrfs.filter(v => v.id === queryVrf)[0] ?? vrfs.filter(v => v.id === 'default')[0];
|
||||
|
||||
let queryTypeLabel = '';
|
||||
if (isQueryType(queryType)) {
|
||||
queryTypeLabel = queries[queryType].display_name;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
|
|
@ -84,7 +92,7 @@ export const Results = (props: TResults) => {
|
|||
bg={queryBg}
|
||||
label={web.text.query_type}
|
||||
fontSize={{ base: 'xs', md: 'sm' }}
|
||||
value={queries[queryType].display_name}
|
||||
value={queryTypeLabel}
|
||||
/>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
|
|
@ -134,7 +142,7 @@ export const Results = (props: TResults) => {
|
|||
<AnimatePresence>
|
||||
{queryLocation &&
|
||||
queryLocation.map((loc, i) => {
|
||||
const device = devices.filter(d => d.name === loc)[0];
|
||||
const device = getDevice(loc);
|
||||
return (
|
||||
<motion.div
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import dynamic from 'next/dynamic';
|
||||
import { forwardRef, useMemo } from 'react';
|
||||
import { AccordionIcon, Icon, Spinner, Stack, Text, Tooltip } from '@chakra-ui/react';
|
||||
import { AccordionIcon, Box, Spinner, Stack, Text, Tooltip } from '@chakra-ui/react';
|
||||
import { BisError as Warning } from '@meronex/icons/bi';
|
||||
import { FaCheckCircle as Check } from '@meronex/icons/fa';
|
||||
import { useConfig, useColorValue } from '~/context';
|
||||
import { useStrf } from '~/hooks';
|
||||
|
||||
import type { TResultHeader } from './types';
|
||||
|
||||
const Check = dynamic<MeronexIcon>(() => import('@meronex/icons/fa').then(i => i.FaCheckCircle));
|
||||
const Warning = dynamic<MeronexIcon>(() => import('@meronex/icons/bi').then(i => i.BisError));
|
||||
|
||||
const runtimeText = (runtime: number, text: string): string => {
|
||||
let unit = 'seconds';
|
||||
if (runtime === 1) {
|
||||
|
|
@ -34,11 +32,11 @@ export const ResultHeader = forwardRef<HTMLDivElement, TResultHeader>((props, re
|
|||
<Spinner size="sm" mr={4} color={status} />
|
||||
) : error ? (
|
||||
<Tooltip hasArrow label={errorMsg} placement="top">
|
||||
<Icon as={Warning} color={warning} mr={4} boxSize={6} />
|
||||
<Box as={Warning} color={warning} mr={4} boxSize={6} />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip hasArrow label={label} placement="top">
|
||||
<Icon as={Check} color={defaultStatus} mr={4} boxSize={6} />
|
||||
<Box as={Check} color={defaultStatus} mr={4} boxSize={6} />
|
||||
</Tooltip>
|
||||
)}
|
||||
<Text fontSize="lg">{title}</Text>
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ export const Result = forwardRef<HTMLDivElement, TResult>((props, ref) => {
|
|||
|
||||
let copyValue = data?.output;
|
||||
|
||||
const formatData = useTableToString(queryTarget, data, [data.format]);
|
||||
const formatData = useTableToString(queryTarget, data, [data?.format]);
|
||||
|
||||
if (data?.format === 'application/json') {
|
||||
copyValue = formatData();
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ import {
|
|||
} from './styles';
|
||||
|
||||
import type { TSelectOption } from '~/types';
|
||||
import type { TSelect, TSelectContext, TBoxAsReactSelect } from './types';
|
||||
import type { TSelectBase, TSelectContext, TBoxAsReactSelect } from './types';
|
||||
|
||||
const SelectContext = createContext<TSelectContext>(Object());
|
||||
export const useSelectContext = () => useContext(SelectContext);
|
||||
|
||||
const ReactSelectAsBox = (props: TBoxAsReactSelect) => <Box as={ReactSelect} {...props} />;
|
||||
|
||||
export const Select = (props: TSelect) => {
|
||||
export const Select = (props: TSelectBase) => {
|
||||
const { ctl, options, multi, onSelect, ...rest } = props;
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export interface TSelectBase extends TBoxAsReactSelect {
|
|||
multi?: boolean;
|
||||
options: TOptions;
|
||||
required?: boolean;
|
||||
onSelect?: (s: TSelectOption) => void;
|
||||
onSelect?: (s: TSelectOption[]) => void;
|
||||
onChange?: (c: TSelectOption) => void;
|
||||
colorScheme?: ColorNames;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export * from './useBooleanValue';
|
||||
export * from './useDevice';
|
||||
export * from './useGreeting';
|
||||
export * from './useOpposingColor';
|
||||
export * from './useSessionStorage';
|
||||
|
|
|
|||
15
hyperglass/ui/hooks/useDevice.ts
Normal file
15
hyperglass/ui/hooks/useDevice.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { useCallback, useMemo } from 'react';
|
||||
import { useConfig } from '~/context';
|
||||
import { flatten } from '~/util';
|
||||
|
||||
import type { TDevice } from '~/types';
|
||||
|
||||
export function useDevice(): (i: string) => TDevice {
|
||||
const { networks } = useConfig();
|
||||
const devices = useMemo(() => flatten<TDevice>(networks.map(n => n.locations)), []);
|
||||
|
||||
function getDevice(id: string): TDevice {
|
||||
return devices.filter(dev => dev.name === id)[0];
|
||||
}
|
||||
return useCallback(getDevice, []);
|
||||
}
|
||||
4
hyperglass/ui/package.json
vendored
4
hyperglass/ui/package.json
vendored
|
|
@ -37,7 +37,7 @@
|
|||
"react-hook-form": "^5.7",
|
||||
"react-markdown": "^4.3.1",
|
||||
"react-query": "^2.26.4",
|
||||
"react-select": "^3.0.8",
|
||||
"react-select": "^3.1.1",
|
||||
"react-string-replace": "^0.4.4",
|
||||
"react-table": "^7.6.2",
|
||||
"string-format": "^2.0.0",
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.11.10",
|
||||
"@types/react-select": "^3.0.22",
|
||||
"@types/react-select": "^3.0.28",
|
||||
"@types/react-table": "^7.0.25",
|
||||
"@types/string-format": "^2.0.0",
|
||||
"@types/yup": "^0.29.9",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
export type TSelectOption = {
|
||||
export type TSelectOptionBase = {
|
||||
label: string;
|
||||
value: string | string[];
|
||||
value: string;
|
||||
group?: string;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type TSelectOption = TSelectOptionBase | null;
|
||||
|
||||
export type TSelectOptionMulti = TSelectOptionBase[] | null;
|
||||
|
||||
export type TSelectOptionGroup = {
|
||||
label: string;
|
||||
|
|
|
|||
|
|
@ -121,12 +121,12 @@ export interface TDevice extends TDeviceBase {
|
|||
}
|
||||
|
||||
export interface TNetworkLocation extends TDeviceBase {
|
||||
vrfs: TDeviceVrfBase[];
|
||||
vrfs: TDeviceVrf[];
|
||||
}
|
||||
|
||||
export interface TNetwork {
|
||||
display_name: string;
|
||||
locations: TNetworkLocation[];
|
||||
locations: TDevice[];
|
||||
}
|
||||
|
||||
export type TParsedDataField = [string, keyof TRoute, 'left' | 'right' | 'center' | null];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export type TQueryTypes = '' | 'bgp_route' | 'bgp_community' | 'bgp_aspath' | 'ping' | 'traceroute';
|
||||
export type TQueryTypes = '' | TValidQueryTypes;
|
||||
export type TValidQueryTypes = 'bgp_route' | 'bgp_community' | 'bgp_aspath' | 'ping' | 'traceroute';
|
||||
|
||||
export interface TFormData {
|
||||
query_location: string[];
|
||||
|
|
|
|||
16
hyperglass/ui/types/guards.ts
Normal file
16
hyperglass/ui/types/guards.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { TValidQueryTypes } from './data';
|
||||
|
||||
export function isQueryType(q: any): q is TValidQueryTypes {
|
||||
let result = false;
|
||||
if (
|
||||
typeof q === 'string' &&
|
||||
['bgp_route', 'bgp_community', 'bgp_aspath', 'ping', 'traceroute'].includes(q)
|
||||
) {
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function isString(a: any): a is string {
|
||||
return typeof a === 'string';
|
||||
}
|
||||
|
|
@ -2,5 +2,6 @@ export * from './common';
|
|||
export * from './config';
|
||||
export * from './data';
|
||||
export * from './dns-over-https';
|
||||
export * from './guards';
|
||||
export * from './table';
|
||||
export * from './theme';
|
||||
|
|
|
|||
|
|
@ -6,3 +6,9 @@ export function all(...iter: any[]) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function flatten<T extends unknown>(arr: any[][]): T[] {
|
||||
return arr.reduce(function (flat, toFlatten) {
|
||||
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
|
||||
}, []);
|
||||
}
|
||||
|
|
|
|||
16
hyperglass/ui/yarn.lock
vendored
16
hyperglass/ui/yarn.lock
vendored
|
|
@ -1055,10 +1055,10 @@
|
|||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-select@^3.0.22":
|
||||
version "3.0.22"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-3.0.22.tgz#b88306365e99fa86809a5c0ce0f1b4e8d0b626bf"
|
||||
integrity sha512-fqgmC979JPr/6476Pau6QnmI9zVV664R7Q92Ld1rgTn+umtUXT5X3+PO/x6O4imCZnh7XCqZcouabWAlAQJNpQ==
|
||||
"@types/react-select@^3.0.28":
|
||||
version "3.0.28"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-3.0.28.tgz#b9adb98421926321b81c4cfe6a40121c96a421f0"
|
||||
integrity sha512-Gfg3a/EPLyUQkfezcCQkmLW1Vz6+ziclJhn8dpBUEYJF3IUoxS81ToAi3ky2xtnAyk2wJFMXLvE73KiUd56yTA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
"@types/react-dom" "*"
|
||||
|
|
@ -5549,10 +5549,10 @@ react-remove-scroll@2.4.0:
|
|||
use-callback-ref "^1.2.3"
|
||||
use-sidecar "^1.0.1"
|
||||
|
||||
react-select@^3.0.8:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27"
|
||||
integrity sha512-wBFVblBH1iuCBprtpyGtd1dGMadsG36W5/t2Aj8OE6WbByDg5jIFyT7X5gT+l0qmT5TqWhxX+VsKJvCEl2uL9g==
|
||||
react-select@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.1.tgz#156a5b4a6c22b1e3d62a919cb1fd827adb4060bc"
|
||||
integrity sha512-HjC6jT2BhUxbIbxMZWqVcDibrEpdUJCfGicN0MMV+BQyKtCaPTgFekKWiOizSCy4jdsLMGjLqcFGJMhVGWB0Dg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
"@emotion/cache" "^10.0.9"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue