1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-19 01:17:18 +02:00

feat: multi-project api access tokens (#857)

* fix: general select component typings

* custom multi-select for projects

* autocomplete element for token projects

* project multi-select with error handling

* projects in tokens list update

* multi-project tokens - select all button

* fix conflicting typescript changes

* improve multi-projects tokens form after review

* refactor multi-project select code structure

* test api token list projects column element

* simplify test renderer
This commit is contained in:
Tymoteusz Czech 2022-04-08 12:26:44 +02:00 committed by GitHub
parent 4b9271637d
commit b23226370a
18 changed files with 494 additions and 200 deletions

View File

@ -42,7 +42,7 @@
"@material-ui/lab": "4.0.0-alpha.61",
"@testing-library/dom": "8.12.0",
"@testing-library/jest-dom": "5.16.3",
"@testing-library/react": "13.0.0",
"@testing-library/react": "^12.1.4",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "14.0.4",
"@types/debounce": "1.2.1",

View File

@ -43,4 +43,10 @@ export const useStyles = makeStyles(theme => ({
position: 'absolute',
top: '-8px',
},
selectOptionsLink: {
cursor: 'pointer',
},
selectOptionCheckbox: {
marginRight: '0.2rem',
},
}));

View File

@ -6,54 +6,53 @@ import useProjects from 'hooks/api/getters/useProjects/useProjects';
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
import Input from 'component/common/Input/Input';
import { useStyles } from './ApiTokenForm.styles';
import { SelectProjectInput } from './SelectProjectInput/SelectProjectInput';
import { ApiTokenFormErrorType } from '../hooks/useApiTokenForm';
interface IApiTokenFormProps {
username: string;
type: string;
project: string;
projects: string[];
environment?: string;
setTokenType: (value: string) => void;
setUsername: React.Dispatch<React.SetStateAction<string>>;
setProject: React.Dispatch<React.SetStateAction<string>>;
setProjects: React.Dispatch<React.SetStateAction<string[]>>;
setEnvironment: React.Dispatch<React.SetStateAction<string | undefined>>;
handleSubmit: (e: any) => void;
handleCancel: () => void;
errors: { [key: string]: string };
mode: 'Create' | 'Edit';
clearErrors: () => void;
clearErrors: (error?: ApiTokenFormErrorType) => void;
}
const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
children,
username,
type,
project,
projects,
environment,
setUsername,
setTokenType,
setProject,
setProjects,
setEnvironment,
handleSubmit,
handleCancel,
errors,
clearErrors,
mode,
}) => {
const TYPE_ADMIN = 'ADMIN';
const styles = useStyles();
const { environments } = useEnvironments();
const { projects } = useProjects();
const { projects: availableProjects } = useProjects();
const selectableTypes = [
{ key: 'CLIENT', label: 'Client', title: 'Client SDK token' },
{ key: 'ADMIN', label: 'Admin', title: 'Admin API token' },
];
const selectableProjects = [{ id: '*', name: 'ALL' }, ...projects].map(
i => ({
key: i.id,
label: i.name,
title: i.name,
})
);
const selectableProjects = availableProjects.map(i => ({
value: i.id,
label: i.name,
}));
const selectableEnvs =
type === TYPE_ADMIN
@ -79,7 +78,7 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
label="Username"
error={errors.username !== undefined}
errorText={errors.username}
onFocus={() => clearErrors()}
onFocus={() => clearErrors('username')}
autoFocus
/>
<p className={styles.inputDescription}>
@ -93,21 +92,19 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
id="api_key_type"
name="type"
IconComponent={KeyboardArrowDownOutlined}
fullWidth
className={styles.selectInput}
/>
<p className={styles.inputDescription}>
Which project do you want to give access to?
</p>
<GeneralSelect
<SelectProjectInput
disabled={type === TYPE_ADMIN}
value={project}
options={selectableProjects}
onChange={e => setProject(e.target.value as string)}
label="Project"
id="api_key_project"
name="project"
IconComponent={KeyboardArrowDownOutlined}
className={styles.selectInput}
defaultValue={projects}
onChange={setProjects}
error={errors?.projects}
onFocus={() => clearErrors('projects')}
/>
<p className={styles.inputDescription}>
Which environment should the token have access to?
@ -121,6 +118,7 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
id="api_key_environment"
name="environment"
IconComponent={KeyboardArrowDownOutlined}
fullWidth
className={styles.selectInput}
/>
</div>

View File

@ -0,0 +1,7 @@
import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({
selectOptionsLink: {
cursor: 'pointer',
},
}));

View File

@ -0,0 +1,23 @@
import React, { FC } from 'react';
import { Box, Link } from '@material-ui/core';
import { useStyles } from './SelectAllButton.styles';
type SelectAllButtonProps = {
isAllSelected: boolean;
onClick: () => void;
};
export const SelectAllButton: FC<SelectAllButtonProps> = ({
isAllSelected,
onClick,
}) => {
const styles = useStyles();
return (
<Box sx={{ ml: 3.5, my: 0.5 }}>
<Link onClick={onClick} className={styles.selectOptionsLink}>
{isAllSelected ? 'Deselect all' : 'Select all'}
</Link>
</Box>
);
};

View File

@ -0,0 +1,7 @@
import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({
selectOptionCheckbox: {
marginRight: '0.2rem',
},
}));

View File

@ -0,0 +1,148 @@
import React, { Fragment, useState, ChangeEvent, VFC } from 'react';
import {
Checkbox,
FormControlLabel,
TextField,
Box,
Paper,
} from '@material-ui/core';
import {
Autocomplete,
AutocompleteRenderGroupParams,
AutocompleteRenderInputParams,
AutocompleteRenderOptionState,
} from '@material-ui/lab';
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '@material-ui/icons/CheckBox';
import { IAutocompleteBoxOption } from 'component/common/AutocompleteBox/AutocompleteBox';
import { useStyles } from '../ApiTokenForm.styles';
import { SelectAllButton } from './SelectAllButton/SelectAllButton';
const ALL_PROJECTS = '*';
// Fix for shadow under Autocomplete - match with Select input
const CustomPaper = ({ ...props }) => <Paper elevation={8} {...props} />;
interface ISelectProjectInputProps {
disabled?: boolean;
options: IAutocompleteBoxOption[];
defaultValue: string[];
onChange: (value: string[]) => void;
onFocus?: () => void;
error?: string;
}
export const SelectProjectInput: VFC<ISelectProjectInputProps> = ({
options,
defaultValue = [ALL_PROJECTS],
onChange,
disabled,
error,
onFocus,
}) => {
const styles = useStyles();
const [projects, setProjects] = useState<string[]>(
typeof defaultValue === 'string' ? [defaultValue] : defaultValue
);
const [isWildcardSelected, selectWildcard] = useState(
typeof defaultValue === 'string' || defaultValue.includes(ALL_PROJECTS)
);
const isAllSelected = projects.length === options.length;
const onAllProjectsChange = (
e: ChangeEvent<HTMLInputElement>,
checked: boolean
) => {
if (checked) {
selectWildcard(true);
onChange([ALL_PROJECTS]);
} else {
selectWildcard(false);
onChange(projects.includes(ALL_PROJECTS) ? [] : projects);
}
};
const renderOption = (
option: IAutocompleteBoxOption,
{ selected }: AutocompleteRenderOptionState
) => (
<>
<Checkbox
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
checkedIcon={<CheckBoxIcon fontSize="small" />}
checked={selected}
className={styles.selectOptionCheckbox}
/>
{option.label}
</>
);
const renderGroup = ({ key, children }: AutocompleteRenderGroupParams) => (
<Fragment key={key}>
<SelectAllButton
isAllSelected={isAllSelected}
onClick={() => {
setProjects(
isAllSelected ? [] : options.map(({ value }) => value)
);
}}
/>
{children}
</Fragment>
);
const renderInput = (params: AutocompleteRenderInputParams) => (
<TextField
{...params}
error={!!error}
helperText={error}
variant="outlined"
label="Projects"
placeholder="Select one or more projects"
onFocus={onFocus}
/>
);
return (
<Box sx={{ mt: -1, mb: 3 }}>
<Box sx={{ mt: 1, mb: 0.25, ml: 1.5 }}>
<FormControlLabel
disabled={disabled}
control={
<Checkbox
checked={disabled || isWildcardSelected}
onChange={onAllProjectsChange}
/>
}
label="ALL current and future projects"
/>
</Box>
<Autocomplete
disabled={disabled || isWildcardSelected}
multiple
limitTags={2}
options={options}
disableCloseOnSelect
getOptionLabel={({ label }) => label}
groupBy={() => 'Select/Deselect all'}
renderGroup={renderGroup}
fullWidth
PaperComponent={CustomPaper}
renderOption={renderOption}
renderInput={renderInput}
value={
isWildcardSelected || disabled
? options
: options.filter(option =>
projects.includes(option.value)
)
}
onChange={(_, input) => {
const state = input.map(({ value }) => value);
setProjects(state);
onChange(state);
}}
/>
</Box>
);
};

View File

@ -1,5 +1,5 @@
import { useContext, useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
import { Fragment, useContext, useState } from 'react';
import { useHistory } from 'react-router-dom';
import {
Button,
IconButton,
@ -32,13 +32,15 @@ import { Alert } from '@material-ui/lab';
import copy from 'copy-to-clipboard';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMD } from 'utils/formatDate';
import { ProjectsList } from './ProjectsList/ProjectsList';
interface IApiToken {
createdAt: Date;
username: string;
secret: string;
type: string;
project: string;
project?: string;
projects?: string | string[];
environment: string;
}
@ -89,14 +91,6 @@ export const ApiTokenList = () => {
});
};
const renderProject = (projectId: string) => {
if (!projectId || projectId === '*') {
return projectId;
} else {
return <Link to={`/projects/${projectId}`}>{projectId}</Link>;
}
};
const renderApiTokens = (tokens: IApiToken[]) => {
return (
<Table size="small">
@ -118,7 +112,7 @@ export const ApiTokenList = () => {
<TableCell
className={`${styles.center} ${styles.hideXS}`}
>
Project
Projects
</TableCell>
<TableCell
className={`${styles.center} ${styles.hideXS}`}
@ -169,7 +163,10 @@ export const ApiTokenList = () => {
<TableCell
className={`${styles.center} ${styles.hideXS}`}
>
{renderProject(item.project)}
<ProjectsList
project={item.project}
projects={item.projects}
/>
</TableCell>
<TableCell
className={`${styles.center} ${styles.hideXS}`}
@ -181,8 +178,11 @@ export const ApiTokenList = () => {
<br />
<b>Env:</b> {item.environment}
<br />
<b>Project:</b>{' '}
{renderProject(item.project)}
<b>Projects:</b>{' '}
<ProjectsList
project={item.project}
projects={item.projects}
/>
</TableCell>
</>
}

View File

@ -0,0 +1,48 @@
import React from 'react';
import { render } from 'utils/testRenderer';
import { screen } from '@testing-library/react';
import { ProjectsList } from './ProjectsList';
describe('ProjectsList', () => {
it('should prioritize new "projects" array over deprecated "project"', async () => {
render(
<ProjectsList
project="project"
projects={['project1', 'project2']}
/>
);
const links = await screen.findAllByRole('link');
expect(links).toHaveLength(2);
expect(links[0]).toHaveTextContent('project1');
expect(links[1]).toHaveTextContent('project2');
expect(links[0]).toHaveAttribute('href', '/projects/project1');
expect(links[1]).toHaveAttribute('href', '/projects/project2');
});
it('should render correctly with single "project"', async () => {
render(<ProjectsList project="project" />);
const links = await screen.findAllByRole('link');
expect(links).toHaveLength(1);
expect(links[0]).toHaveTextContent('project');
});
it('should have comma between project links', async () => {
const { container } = render(<ProjectsList projects={['a', 'b']} />);
expect(container.textContent).toContain(', ');
});
it('should render asterisk if no projects are passed', async () => {
const { container } = render(<ProjectsList />);
expect(container.textContent).toEqual('*');
});
it('should render asterisk if empty projects array is passed', async () => {
const { container } = render(<ProjectsList projects={[]} />);
expect(container.textContent).toEqual('*');
});
});

View File

@ -0,0 +1,33 @@
import React, { Fragment, VFC } from 'react';
import { Link } from 'react-router-dom';
interface IProjectsListProps {
project?: string;
projects?: string | string[];
}
export const ProjectsList: VFC<IProjectsListProps> = ({
projects,
project,
}) => {
let fields = projects && Array.isArray(projects) ? projects : [project];
if (fields.length === 0) {
return <>*</>;
}
return (
<>
{fields.map((item, index) => (
<Fragment key={item}>
{index > 0 && ', '}
{!item || item === '*' ? (
'*'
) : (
<Link to={`/projects/${item}`}>{item}</Link>
)}
</Fragment>
))}
</>
);
};

View File

@ -23,11 +23,11 @@ export const CreateApiToken = () => {
getApiTokenPayload,
username,
type,
project,
projects,
environment,
setUsername,
setTokenType,
setProject,
setProjects,
setEnvironment,
isValid,
errors,
@ -84,12 +84,12 @@ export const CreateApiToken = () => {
<ApiTokenForm
username={username}
type={type}
project={project}
projects={projects}
environment={environment}
setEnvironment={setEnvironment}
setTokenType={setTokenType}
setUsername={setUsername}
setProject={setProject}
setProjects={setProjects}
errors={errors}
handleSubmit={handleSubmit}
handleCancel={handleCancel}

View File

@ -1,5 +1,8 @@
import { useEffect, useState } from 'react';
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
import { IApiTokenCreate } from 'hooks/api/actions/useApiTokensApi/useApiTokensApi';
export type ApiTokenFormErrorType = 'username' | 'projects';
export const useApiTokenForm = () => {
const { environments } = useEnvironments();
@ -7,9 +10,11 @@ export const useApiTokenForm = () => {
const [username, setUsername] = useState('');
const [type, setType] = useState('CLIENT');
const [project, setProject] = useState('*');
const [projects, setProjects] = useState<string[]>(['*']);
const [environment, setEnvironment] = useState<string>();
const [errors, setErrors] = useState({});
const [errors, setErrors] = useState<
Partial<Record<ApiTokenFormErrorType, string>>
>({});
useEffect(() => {
setEnvironment(type === 'ADMIN' ? '*' : initialEnvironment);
@ -18,7 +23,7 @@ export const useApiTokenForm = () => {
const setTokenType = (value: string) => {
if (value === 'ADMIN') {
setType(value);
setProject('*');
setProjects(['*']);
setEnvironment('*');
} else {
setType(value);
@ -26,37 +31,44 @@ export const useApiTokenForm = () => {
}
};
const getApiTokenPayload = () => {
return {
username: username,
type: type,
project: project,
environment: environment,
};
};
const getApiTokenPayload = (): IApiTokenCreate => ({
username,
type,
environment,
projects,
});
const isValid = () => {
const newErrors: Partial<Record<ApiTokenFormErrorType, string>> = {};
if (!username) {
setErrors({ username: 'Username is required.' });
return false;
} else {
setErrors({});
return true;
newErrors['username'] = 'Username is required';
}
if (projects.length === 0) {
newErrors['projects'] = 'At least one project is required';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const clearErrors = () => {
setErrors({});
const clearErrors = (error?: ApiTokenFormErrorType) => {
if (error) {
const newErrors = { ...errors };
delete newErrors[error];
setErrors(newErrors);
} else {
setErrors({});
}
};
return {
username,
type,
project,
projects,
environment,
setUsername,
setTokenType,
setProject,
setProjects,
setEnvironment,
getApiTokenPayload,
isValid,

View File

@ -17,17 +17,13 @@ export interface ISelectOption {
}
export interface ISelectMenuProps extends SelectProps {
name: string;
id: string;
name?: string;
value?: string;
label?: string;
autoFocus?: boolean;
options: ISelectOption[];
style?: object;
onChange?: OnGeneralSelectChange;
disabled?: boolean;
fullWidth?: boolean;
className?: string;
classes?: any;
defaultValue?: string;
}
@ -43,10 +39,8 @@ const GeneralSelect: React.FC<ISelectMenuProps> = ({
label = '',
options,
onChange,
defaultValue,
id,
disabled = false,
autoFocus,
className,
classes,
fullWidth,
@ -74,13 +68,11 @@ const GeneralSelect: React.FC<ISelectMenuProps> = ({
>
<InputLabel htmlFor={id}>{label}</InputLabel>
<Select
defaultValue={defaultValue}
name={name}
disabled={disabled}
onChange={onChange}
className={className}
label={label}
autoFocus={autoFocus}
id={id}
value={value}
IconComponent={KeyboardArrowDownOutlined}

View File

@ -30,7 +30,6 @@ const FeatureTypeSelect = ({
return (
<>
{/* @ts-expect-error */}
<GeneralSelect
disabled={!editable}
options={options}

View File

@ -115,7 +115,6 @@ const FeatureOverviewVariants = () => {
return (
<section style={{ paddingTop: '16px' }}>
{/* @ts-expect-error */}
<GeneralSelect
label="Stickiness"
options={options}

View File

@ -3,8 +3,8 @@ import useAPI from '../useApi/useApi';
export interface IApiTokenCreate {
username: string;
type: string;
project: string;
environment?: string;
projects: string[];
}
const useApiTokensApi = () => {

View File

@ -0,0 +1,17 @@
import { BrowserRouter as Router } from 'react-router-dom';
import { render as rtlRender, RenderOptions } from '@testing-library/react';
export const render = (
ui: JSX.Element,
{
route = '/',
...renderOptions
}: { route?: string } & Omit<RenderOptions, 'queries'> = {}
) => {
window.history.pushState({}, 'Test page', route);
return rtlRender(ui, {
wrapper: Router,
...renderOptions,
});
};

View File

@ -31,24 +31,24 @@
integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==
"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a"
integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.9.tgz#6bae81a06d95f4d0dec5bb9d74bbc1f58babdcfe"
integrity sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==
dependencies:
"@ampproject/remapping" "^2.1.0"
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.17.7"
"@babel/generator" "^7.17.9"
"@babel/helper-compilation-targets" "^7.17.7"
"@babel/helper-module-transforms" "^7.17.7"
"@babel/helpers" "^7.17.8"
"@babel/parser" "^7.17.8"
"@babel/helpers" "^7.17.9"
"@babel/parser" "^7.17.9"
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.17.3"
"@babel/traverse" "^7.17.9"
"@babel/types" "^7.17.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.1.2"
json5 "^2.2.1"
semver "^6.3.0"
"@babel/eslint-parser@^7.16.3":
@ -60,10 +60,10 @@
eslint-visitor-keys "^2.1.0"
semver "^6.3.0"
"@babel/generator@^7.17.3", "@babel/generator@^7.17.7", "@babel/generator@^7.7.2":
version "7.17.7"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad"
integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==
"@babel/generator@^7.17.9", "@babel/generator@^7.7.2":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.9.tgz#f4af9fd38fa8de143c29fce3f71852406fc1e2fc"
integrity sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==
dependencies:
"@babel/types" "^7.17.0"
jsesc "^2.5.1"
@ -94,15 +94,15 @@
browserslist "^4.17.5"
semver "^6.3.0"
"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6":
version "7.17.6"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9"
integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==
"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6", "@babel/helper-create-class-features-plugin@^7.17.9":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz#71835d7fb9f38bd9f1378e40a4c0902fdc2ea49d"
integrity sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.7"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-member-expression-to-functions" "^7.16.7"
"@babel/helper-function-name" "^7.17.9"
"@babel/helper-member-expression-to-functions" "^7.17.7"
"@babel/helper-optimise-call-expression" "^7.16.7"
"@babel/helper-replace-supers" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
@ -143,21 +143,13 @@
dependencies:
"@babel/types" "^7.16.7"
"@babel/helper-function-name@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f"
integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==
"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.17.9":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12"
integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==
dependencies:
"@babel/helper-get-function-arity" "^7.16.7"
"@babel/template" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/helper-get-function-arity@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419"
integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==
dependencies:
"@babel/types" "^7.16.7"
"@babel/types" "^7.17.0"
"@babel/helper-hoist-variables@^7.16.7":
version "7.16.7"
@ -166,7 +158,7 @@
dependencies:
"@babel/types" "^7.16.7"
"@babel/helper-member-expression-to-functions@^7.16.7":
"@babel/helper-member-expression-to-functions@^7.16.7", "@babel/helper-member-expression-to-functions@^7.17.7":
version "7.17.7"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4"
integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==
@ -267,28 +259,28 @@
"@babel/traverse" "^7.16.8"
"@babel/types" "^7.16.8"
"@babel/helpers@^7.17.8":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106"
integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==
"@babel/helpers@^7.17.9":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a"
integrity sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==
dependencies:
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.17.3"
"@babel/traverse" "^7.17.9"
"@babel/types" "^7.17.0"
"@babel/highlight@^7.16.7":
version "7.16.10"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88"
integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3"
integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240"
integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.9":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef"
integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
version "7.16.7"
@ -333,13 +325,14 @@
"@babel/plugin-syntax-class-static-block" "^7.14.5"
"@babel/plugin-proposal-decorators@^7.16.4":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.8.tgz#4f0444e896bee85d35cf714a006fc5418f87ff00"
integrity sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz#67a1653be9c77ce5b6c318aa90c8287b87831619"
integrity sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==
dependencies:
"@babel/helper-create-class-features-plugin" "^7.17.6"
"@babel/helper-create-class-features-plugin" "^7.17.9"
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/helper-replace-supers" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/plugin-syntax-decorators" "^7.17.0"
charcodes "^0.2.0"
@ -714,9 +707,9 @@
babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-modules-commonjs@^7.16.8":
version "7.17.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19"
integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz#274be1a2087beec0254d4abd4d86e52442e1e5b6"
integrity sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==
dependencies:
"@babel/helper-module-transforms" "^7.17.7"
"@babel/helper-plugin-utils" "^7.16.7"
@ -819,11 +812,11 @@
"@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-transform-regenerator@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb"
integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz#0a33c3a61cf47f45ed3232903683a0afd2d3460c"
integrity sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==
dependencies:
regenerator-transform "^0.14.2"
regenerator-transform "^0.15.0"
"@babel/plugin-transform-reserved-words@^7.16.7":
version "7.16.7"
@ -1017,17 +1010,17 @@
"@babel/plugin-transform-typescript" "^7.16.7"
"@babel/runtime-corejs3@^7.10.2":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.8.tgz#d7dd49fb812f29c61c59126da3792d8740d4e284"
integrity sha512-ZbYSUvoSF6dXZmMl/CYTMOvzIFnbGfv4W3SEHYgMvNsFTeLaF2gkGAF4K2ddmtSK4Emej+0aYcnSC6N5dPCXUQ==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz#3d02d0161f0fbf3ada8e88159375af97690f4055"
integrity sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==
dependencies:
core-js-pure "^3.20.2"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.17.8"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2"
integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
dependencies:
regenerator-runtime "^0.13.4"
@ -1040,18 +1033,18 @@
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2":
version "7.17.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57"
integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.7.2":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d"
integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==
dependencies:
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.17.3"
"@babel/generator" "^7.17.9"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-function-name" "^7.17.9"
"@babel/helper-hoist-variables" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/parser" "^7.17.3"
"@babel/parser" "^7.17.9"
"@babel/types" "^7.17.0"
debug "^4.1.0"
globals "^11.1.0"
@ -1709,7 +1702,7 @@
"@svgr/plugin-svgo" "^5.5.0"
loader-utils "^2.0.0"
"@testing-library/dom@8.12.0", "@testing-library/dom@^8.5.0":
"@testing-library/dom@8.12.0":
version "8.12.0"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.12.0.tgz#fef5e545533fb084175dda6509ee71d7d2f72e23"
integrity sha512-rBrJk5WjI02X1edtiUcZhgyhgBhiut96r5Jp8J5qktKdcvLcZpKDW8i2hkGMMItxrghjXuQ5AM6aE0imnFawaw==
@ -1723,6 +1716,20 @@
lz-string "^1.4.4"
pretty-format "^27.0.2"
"@testing-library/dom@^8.0.0":
version "8.13.0"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.13.0.tgz#bc00bdd64c7d8b40841e27a70211399ad3af46f5"
integrity sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
"@types/aria-query" "^4.2.0"
aria-query "^5.0.0"
chalk "^4.1.0"
dom-accessibility-api "^0.5.9"
lz-string "^1.4.4"
pretty-format "^27.0.2"
"@testing-library/jest-dom@5.16.3":
version "5.16.3"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.3.tgz#b76851a909586113c20486f1679ffb4d8ec27bfa"
@ -1749,13 +1756,13 @@
"@types/react-test-renderer" ">=16.9.0"
react-error-boundary "^3.1.0"
"@testing-library/react@13.0.0":
version "13.0.0"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.0.0.tgz#8cdaf4667c6c2b082eb0513731551e9db784e8bc"
integrity sha512-p0lYA1M7uoEmk2LnCbZLGmHJHyH59sAaZVXChTXlyhV/PRW9LoIh4mdf7tiXsO8BoNG+vN8UnFJff1hbZeXv+w==
"@testing-library/react@^12.1.4":
version "12.1.4"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.4.tgz#09674b117e550af713db3f4ec4c0942aa8bbf2c0"
integrity sha512-jiPKOm7vyUw311Hn/HlNQ9P8/lHNtArAx0PisXyFixDDvfl8DbD6EUdbshK5eqauvBSvzZd19itqQ9j3nferJA==
dependencies:
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^8.5.0"
"@testing-library/dom" "^8.0.0"
"@types/react-dom" "*"
"@testing-library/user-event@14.0.4":
@ -4098,9 +4105,9 @@ ejs@^3.1.6:
jake "^10.6.1"
electron-to-chromium@^1.4.84:
version "1.4.103"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz#abfe376a4d70fa1e1b4b353b95df5d6dfd05da3a"
integrity sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==
version "1.4.105"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.105.tgz#30de5e4ba020140b698539b2d366cd9c3a337ec7"
integrity sha512-6w2bmoQBSUgCQjbSjiVv9IS1lXwW2aQABlUJ1vlE8Vci/sVXxUNQrHLQa5N1ioc82Py+a36DlUA5KvrAlHMMeA==
emittery@^0.8.1:
version "0.8.1"
@ -4273,7 +4280,7 @@ eslint-import-resolver-node@^0.3.6:
debug "^3.2.7"
resolve "^1.20.0"
eslint-module-utils@^2.7.2:
eslint-module-utils@^2.7.3:
version "2.7.3"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee"
integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==
@ -4290,23 +4297,23 @@ eslint-plugin-flowtype@^8.0.3:
string-natural-compare "^3.0.1"
eslint-plugin-import@^2.25.3:
version "2.25.4"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1"
integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==
version "2.26.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"
integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==
dependencies:
array-includes "^3.1.4"
array.prototype.flat "^1.2.5"
debug "^2.6.9"
doctrine "^2.1.0"
eslint-import-resolver-node "^0.3.6"
eslint-module-utils "^2.7.2"
eslint-module-utils "^2.7.3"
has "^1.0.3"
is-core-module "^2.8.0"
is-core-module "^2.8.1"
is-glob "^4.0.3"
minimatch "^3.0.4"
minimatch "^3.1.2"
object.values "^1.1.5"
resolve "^1.20.0"
tsconfig-paths "^3.12.0"
resolve "^1.22.0"
tsconfig-paths "^3.14.1"
eslint-plugin-jest@^25.3.0:
version "25.7.0"
@ -4808,9 +4815,9 @@ forever-agent@~0.6.1:
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
fork-ts-checker-webpack-plugin@^6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e"
integrity sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==
version "6.5.1"
resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.1.tgz#fd689e2d9de6ac76abb620909eea56438cd0f232"
integrity sha512-x1wumpHOEf4gDROmKTaB6i4/Q6H3LwmjVO7fIX47vBwlZbtPjU33hgoMuD/Q/y6SU8bnuYSoN6ZQOLshGp0T/g==
dependencies:
"@babel/code-frame" "^7.8.3"
"@types/json-schema" "^7.0.5"
@ -5445,7 +5452,7 @@ is-ci@^3.0.0:
dependencies:
ci-info "^3.2.0"
is-core-module@^2.2.0, is-core-module@^2.8.0, is-core-module@^2.8.1:
is-core-module@^2.2.0, is-core-module@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
@ -6218,7 +6225,7 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
json5@^2.1.2, json5@^2.2.0:
json5@^2.1.2, json5@^2.2.0, json5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
@ -6523,12 +6530,10 @@ lower-case@^2.0.2:
dependencies:
tslib "^2.0.3"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
lru-cache@^7.4.0:
version "7.7.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.7.3.tgz#98cd19eef89ce6a4a3c4502c17c833888677c252"
integrity sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==
lru-cache@^7.4.0:
version "7.7.3"
@ -7232,9 +7237,9 @@ postcss-custom-media@^8.0.0:
integrity sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==
postcss-custom-properties@^12.1.5:
version "12.1.5"
resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.5.tgz#e669cfff89b0ea6fc85c45864a32b450cb6b196f"
integrity sha512-FHbbB/hRo/7cxLGkc2NS7cDRIDN1oFqQnUKBiyh4b/gwk8DD8udvmRDpUhEK836kB8ggUCieHVOvZDnF9XhI3g==
version "12.1.6"
resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.6.tgz#345b5b64c9520bb66390393646e8d5fbb7f10b58"
integrity sha512-QEnQkDkb+J+j2bfJisJJpTAFL+lUFl66rUNvnjPBIvRbZACLG4Eu5bmBCIY4FJCqhwsfbBpmJUyb3FcR/31lAg==
dependencies:
postcss-value-parser "^4.2.0"
@ -7934,16 +7939,21 @@ react-hooks-global-state@1.0.2:
resolved "https://registry.yarnpkg.com/react-hooks-global-state/-/react-hooks-global-state-1.0.2.tgz#37bbc3203a0be9f3ac0658abfd28dd7ce7ee166c"
integrity sha512-UcWz+VjcUUCQ7bXGmOhanGII3j22zyPSjwJnQWeycxFYj/etBxIbz9xziEm4sv5+OqGuS7bzvpx24XkCxgJ7Bg==
"react-is@^16.12.0 || ^17.0.0", "react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0":
version "18.0.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.0.0.tgz#026f6c4a27dbe33bf4a35655b9e1327c4e55e3f5"
integrity sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==
react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
"react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-refresh@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
@ -8034,12 +8044,12 @@ react-scripts@5.0.0:
fsevents "^2.3.2"
react-shallow-renderer@^16.13.1:
version "16.14.1"
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124"
integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==
version "16.15.0"
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457"
integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==
dependencies:
object-assign "^4.1.1"
react-is "^16.12.0 || ^17.0.0"
react-is "^16.12.0 || ^17.0.0 || ^18.0.0"
react-test-renderer@17.0.2:
version "17.0.2"
@ -8142,10 +8152,10 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.9:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
regenerator-transform@^0.14.2:
version "0.14.5"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==
regenerator-transform@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==
dependencies:
"@babel/runtime" "^7.8.4"
@ -8469,11 +8479,11 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2, semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
version "7.3.6"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.6.tgz#5d73886fb9c0c6602e79440b97165c29581cbb2b"
integrity sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==
dependencies:
lru-cache "^6.0.0"
lru-cache "^7.4.0"
send@0.17.2:
version "0.17.2"
@ -9159,7 +9169,7 @@ tryer@^1.0.1:
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
tsconfig-paths@^3.12.0:
tsconfig-paths@^3.14.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==
@ -9455,9 +9465,9 @@ webpack-dev-middleware@^5.3.1:
schema-utils "^4.0.0"
webpack-dev-server@^4.6.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.8.0.tgz#022bb845946e31ca01527509a942869ecfc7e047"
integrity sha512-yZ7OWVP1nOtv8s10R/ZCsH6zf6QKkNusMRBE9DsQbOknRzKaFYYrbwVPCXp8ynUOTt3RlD9szM8H0pUlrJ6wcw==
version "4.8.1"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.8.1.tgz#58f9d797710d6e25fa17d6afab8708f958c11a29"
integrity sha512-dwld70gkgNJa33czmcj/PlKY/nOy/BimbrgZRaR9vDATBQAYgLzggR0nxDtPLJiLrMgZwbE6RRfJ5vnBBasTyg==
dependencies:
"@types/bonjour" "^3.5.9"
"@types/connect-history-api-fallback" "^1.3.5"
@ -9859,11 +9869,6 @@ y18n@^5.0.5:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"