-
- ({ key: t.name, label: t.name, title: t.name }));
-
- return ;
- }
-}
-
-TagTypeSelectComponent.propTypes = {
- value: PropTypes.string,
- types: PropTypes.array.isRequired,
- fetchTagTypes: PropTypes.func,
- onChange: PropTypes.func.isRequired,
-};
-
-export default TagTypeSelectComponent;
diff --git a/frontend/src/component/feature/tag-type-select-container.jsx b/frontend/src/component/feature/tag-type-select-container.jsx
deleted file mode 100644
index e1748dee7c..0000000000
--- a/frontend/src/component/feature/tag-type-select-container.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { connect } from 'react-redux';
-import TagTypeSelectComponent from './tag-type-select-component';
-import { fetchTagTypes } from '../../store/tag-type/actions';
-
-const mapStateToProps = (state, ownProps) => ({
- types: state.tagTypes.toJS(),
- ...ownProps,
-});
-
-const FormAddContainer = connect(mapStateToProps, { fetchTagTypes })(TagTypeSelectComponent);
-
-export default FormAddContainer;
diff --git a/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx b/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx
index 90d210aff8..e7b70c7ccc 100644
--- a/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx
+++ b/frontend/src/component/feature/variant/AddVariant/AddVariant.jsx
@@ -12,12 +12,13 @@ import {
} from '@material-ui/core';
import { Info } from '@material-ui/icons';
import Dialog from '../../../common/Dialogue';
-import MySelect from '../../../common/select';
+
import { modalStyles, trim } from '../../../common/util';
import { weightTypes } from '../enums';
import OverrideConfig from './OverrideConfig/OverrideConfig';
import { useCommonStyles } from '../../../../common.styles';
import ConditionallyRender from '../../../common/ConditionallyRender';
+import GeneralSelect from '../../../common/GeneralSelect/GeneralSelect';
const payloadOptions = [
{ key: 'string', label: 'string' },
@@ -264,7 +265,7 @@ const AddVariant = ({
-
-
-
Read more
diff --git a/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap b/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap
index c3fb5e087c..b9afd05668 100644
--- a/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap
+++ b/frontend/src/component/feature/view/__tests__/__snapshots__/view-component-test.jsx.snap
@@ -86,12 +86,64 @@ exports[`renders correctly with one feature 1`] = `
-
+
+
+ Feature type
+
+
+
+ Release
+
+
+
+
+
+
+
+
+ Feature type
+
+
+
+
+
({
__esModule: true,
default: 'UpdateStrategiesComponent',
}));
-jest.mock('../../feature-type-select-container', () => 'FeatureTypeSelect');
+jest.mock(
+ '../../../feature/FeatureView2/FeatureSettings/FeatureSettingsMetadata/FeatureTypeSelect/FeatureTypeSelect',
+ () => 'FeatureTypeSelect'
+);
jest.mock('../../../common/ProjectSelect', () => 'ProjectSelect');
-jest.mock('../../tag-type-select-container', () => 'TagTypeSelect');
+jest.mock('../../../common/TagSelect/TagSelect', () => 'TagSelect');
jest.mock('../../feature-tag-component', () => 'FeatureTagComponent');
jest.mock('../../add-tag-dialog-container', () => 'AddTagDialog');
+jest.spyOn(console, 'error').mockImplementation();
test('renders correctly with one feature', () => {
const feature = {
@@ -60,6 +64,7 @@ test('renders correctly with one feature', () => {
},
}),
},
+ featureTypes: { toJS: () => [{ id: 'release', name: 'Release' }] },
};
const mockReducer = state => state;
diff --git a/frontend/src/component/menu/Footer/Footer.jsx b/frontend/src/component/menu/Footer/Footer.jsx
index b4c3017f57..e0eecc33dc 100644
--- a/frontend/src/component/menu/Footer/Footer.jsx
+++ b/frontend/src/component/menu/Footer/Footer.jsx
@@ -11,7 +11,7 @@ export const Footer = () => {
return (
-
+
diff --git a/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap
index ffd6e7d91c..809f748a3a 100644
--- a/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap
+++ b/frontend/src/component/menu/__tests__/__snapshots__/footer-test.jsx.snap
@@ -5,7 +5,7 @@ exports[`should render DrawerMenu 1`] = `
className="makeStyles-footer-1"
>
{
/* eslint-disable-next-line */
}, []);
+ const goToTabWithName = (name: string) => {
+ const index = tabData.findIndex(t => t.name === name);
+ if(index >= 0) {
+ const tab = tabData[index];
+ history.push(tab.path);
+ setActiveTab(index);
+ }
+ }
+
const tabData = [
{
title: 'Overview',
@@ -127,8 +137,11 @@ const Project = () => {
-
+
Project: {project?.name}{' '}
+ goToTabWithName('settings')}>
+
+
{project?.description}
diff --git a/frontend/src/component/project/ProjectCard/ProjectCard.styles.ts b/frontend/src/component/project/ProjectCard/ProjectCard.styles.ts
index d4b523a582..87b5348246 100644
--- a/frontend/src/component/project/ProjectCard/ProjectCard.styles.ts
+++ b/frontend/src/component/project/ProjectCard/ProjectCard.styles.ts
@@ -24,6 +24,7 @@ export const useStyles = makeStyles(theme => ({
fontWeight: 'normal',
fontSize: '1rem',
},
+
projectIcon: {
margin: '1rem auto',
width: '80px',
diff --git a/frontend/src/component/project/ProjectEnvironment/ProjectEnvironment.tsx b/frontend/src/component/project/ProjectEnvironment/ProjectEnvironment.tsx
index 146f5ec2a6..4b0d58a18d 100644
--- a/frontend/src/component/project/ProjectEnvironment/ProjectEnvironment.tsx
+++ b/frontend/src/component/project/ProjectEnvironment/ProjectEnvironment.tsx
@@ -29,16 +29,24 @@ interface ProjectEnvironmentListProps {
projectId: string;
}
-const ProjectEnvironmentList = ({projectId}: ProjectEnvironmentListProps) => {
+const ProjectEnvironmentList = ({ projectId }: ProjectEnvironmentListProps) => {
const { hasAccess } = useContext(AccessContext);
// api state
const { toast, setToastData } = useToast();
const { uiConfig } = useUiConfig();
- const { environments, loading, error, refetch: refetchEnvs } = useEnvironments();
+ const {
+ environments,
+ loading,
+ error,
+ refetch: refetchEnvs,
+ } = useEnvironments();
const { project, refetch: refetchProject } = useProject(projectId);
- const { removeEnvironmentFromProject, addEnvironmentToProject } = useProjectApi();
-
+ const { removeEnvironmentFromProject, addEnvironmentToProject } =
+ useProjectApi();
+
+ console.log(project);
+
// local state
const [selectedEnv, setSelectedEnv] = useState
();
const [confirmName, setConfirmName] = useState('');
@@ -49,7 +57,7 @@ const ProjectEnvironmentList = ({projectId}: ProjectEnvironmentListProps) => {
const refetch = () => {
refetchEnvs();
refetchProject();
- }
+ };
const renderError = () => {
return (
@@ -62,74 +70,100 @@ const ProjectEnvironmentList = ({projectId}: ProjectEnvironmentListProps) => {
};
const errorMsg = (enable: boolean): string => {
- return `Got an API error when trying to ${enable ? 'enable' : 'disable'} the environment.`
- }
+ return `Got an API error when trying to ${
+ enable ? 'enable' : 'disable'
+ } the environment.`;
+ };
const toggleEnv = async (env: ProjectEnvironment) => {
- if(env.enabled) {
+ if (env.enabled) {
setSelectedEnv(env);
} else {
try {
await addEnvironmentToProject(projectId, env.name);
- setToastData({ text: 'Environment successfully enabled.', type: 'success', show: true});
+ setToastData({
+ text: 'Environment successfully enabled.',
+ type: 'success',
+ show: true,
+ });
} catch (error) {
- setToastData({text: errorMsg(true), type: 'error', show: true});
+ setToastData({
+ text: errorMsg(true),
+ type: 'error',
+ show: true,
+ });
}
}
refetch();
- }
+ };
const handleDisableEnvironment = async () => {
- if(selectedEnv && confirmName===selectedEnv.name) {
+ if (selectedEnv && confirmName === selectedEnv.name) {
try {
await removeEnvironmentFromProject(projectId, selectedEnv.name);
setSelectedEnv(undefined);
setConfirmName('');
- setToastData({ text: 'Environment successfully disabled.', type: 'success', show: true});
+ setToastData({
+ text: 'Environment successfully disabled.',
+ type: 'success',
+ show: true,
+ });
} catch (e) {
- setToastData({ text: errorMsg(false), type: 'error', show: true});
+ setToastData({
+ text: errorMsg(false),
+ type: 'error',
+ show: true,
+ });
}
-
+
refetch();
- }
- }
+ }
+ };
const handleCancelDisableEnvironment = () => {
setSelectedEnv(undefined);
setConfirmName('');
- }
+ };
const envs = environments.map(e => ({
name: e.name,
- enabled: (project?.environments).includes(e.name),
+ enabled: project?.environments.includes(e.name),
}));
const hasPermission = hasAccess(UPDATE_PROJECT, projectId);
const genLabel = (env: ProjectEnvironment) => (
<>
- {env.name}
environment is {env.enabled ? 'enabled' : 'disabled'}
+ {env.name}
environment is{' '}
+ {env.enabled ? 'enabled' : 'disabled'}
>
);
const renderEnvironments = () => {
- if(!uiConfig.flags.E) {
- return Feature not enabled.
+ if (!uiConfig.flags.E) {
+ return Feature not enabled.
;
}
return (
{envs.map(env => (
-
- }
+
+ }
/>
))}
);
};
-
return (
{
env={selectedEnv}
open={!!selectedEnv}
handleDisableEnvironment={handleDisableEnvironment}
- handleCancelDisableEnvironment={handleCancelDisableEnvironment}
+ handleCancelDisableEnvironment={
+ handleCancelDisableEnvironment
+ }
confirmName={confirmName}
setConfirmName={setConfirmName}
/>
diff --git a/frontend/src/component/strategies/CreateStrategy/StrategyParameters/StrategyParameter/StrategyParameter.jsx b/frontend/src/component/strategies/CreateStrategy/StrategyParameters/StrategyParameter/StrategyParameter.jsx
index f4637202a4..e27d0b3135 100644
--- a/frontend/src/component/strategies/CreateStrategy/StrategyParameters/StrategyParameter/StrategyParameter.jsx
+++ b/frontend/src/component/strategies/CreateStrategy/StrategyParameters/StrategyParameter/StrategyParameter.jsx
@@ -1,7 +1,8 @@
import { TextField, Checkbox, FormControlLabel } from '@material-ui/core';
import PropTypes from 'prop-types';
-import MySelect from '../../../../common/select';
+
import { styles as commonStyles } from '../../../../common';
+import GeneralSelect from '../../../../common/GeneralSelect/GeneralSelect';
const paramTypesOptions = [
{ key: 'string', label: 'string' },
@@ -26,7 +27,7 @@ const StrategyParameter = ({ set, input = {}, index }) => {
variant="outlined"
size="small"
/>
-
diff --git a/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts b/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts
index f76c95ca3e..87fa316087 100644
--- a/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts
+++ b/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts
@@ -68,7 +68,7 @@ const useFeatureApi = () => {
}
};
- const addTag = async (featureId: string, tag: ITag) => {
+ const addTagToFeature = async (featureId: string, tag: ITag) => {
// TODO: Change this path to the new API when moved.
const path = `api/admin/features/${featureId}/tags`;
const req = createRequest(path, {
@@ -85,7 +85,7 @@ const useFeatureApi = () => {
}
};
- const deleteTag = async (
+ const deleteTagFromFeature = async (
featureId: string,
type: string,
value: string
@@ -105,13 +105,74 @@ const useFeatureApi = () => {
}
};
+ const archiveFeatureToggle = async (
+ projectId: string,
+ featureId: string
+ ) => {
+ const path = `api/admin/projects/${projectId}/features/${featureId}`;
+ const req = createRequest(path, {
+ method: 'DELETE',
+ });
+
+ try {
+ const res = await makeRequest(req.caller, req.id);
+
+ return res;
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ const patchFeatureToggle = async (
+ projectId: string,
+ featureId: string,
+ patchPayload: any
+ ) => {
+ const path = `api/admin/projects/${projectId}/features/${featureId}`;
+ const req = createRequest(path, {
+ method: 'PATCH',
+ body: JSON.stringify(patchPayload),
+ });
+
+ try {
+ const res = await makeRequest(req.caller, req.id);
+
+ return res;
+ } catch (e) {
+ throw e;
+ }
+ };
+
+ const cloneFeatureToggle = async (
+ projectId: string,
+ featureId: string,
+ payload: {name: string, replaceGroupId: boolean}
+ ) => {
+ const path = `api/admin/projects/${projectId}/features/${featureId}/clone`;
+ const req = createRequest(
+ path,
+ { method: 'POST', body: JSON.stringify(payload) },
+ );
+
+ try {
+ const res = await makeRequest(req.caller, req.id);
+
+ return res;
+ } catch (e) {
+ throw e;
+ }
+ };
+
return {
changeFeatureProject,
errors,
toggleFeatureEnvironmentOn,
toggleFeatureEnvironmentOff,
- addTag,
- deleteTag,
+ addTagToFeature,
+ deleteTagFromFeature,
+ archiveFeatureToggle,
+ patchFeatureToggle,
+ cloneFeatureToggle
};
};
diff --git a/frontend/src/hooks/api/getters/useFeature/useFeature.ts b/frontend/src/hooks/api/getters/useFeature/useFeature.ts
index de83e101f8..8c96c83938 100644
--- a/frontend/src/hooks/api/getters/useFeature/useFeature.ts
+++ b/frontend/src/hooks/api/getters/useFeature/useFeature.ts
@@ -17,13 +17,29 @@ const useFeature = (
id: string,
options: IUseFeatureOptions = {}
) => {
- const fetcher = () => {
+ const fetcher = async () => {
const path = formatApiPath(
`api/admin/projects/${projectId}/features/${id}`
);
- return fetch(path, {
+
+ const res = await fetch(path, {
method: 'GET',
- }).then(res => res.json());
+ });
+
+
+ // If the status code is not in the range 200-299,
+ // we still try to parse and throw it.
+ if (!res.ok) {
+ const error = new Error('An error occurred while fetching the data.')
+ // Attach extra info to the error object.
+ // @ts-ignore
+ error.info = await res.json();
+ // @ts-ignore
+ error.status = res.status;
+ throw error;
+ }
+
+ return res.json()
};
const FEATURE_CACHE_KEY = `api/admin/projects/${projectId}/features/${id}`;
diff --git a/frontend/src/hooks/api/getters/useFeatureTypes/useFeatureTypes.ts b/frontend/src/hooks/api/getters/useFeatureTypes/useFeatureTypes.ts
new file mode 100644
index 0000000000..2962450a8a
--- /dev/null
+++ b/frontend/src/hooks/api/getters/useFeatureTypes/useFeatureTypes.ts
@@ -0,0 +1,36 @@
+import useSWR, { mutate } from 'swr';
+import { useState, useEffect } from 'react';
+import { formatApiPath } from '../../../../utils/format-path';
+import { IFeatureType } from '../../../../interfaces/featureTypes';
+
+const useFeatureTypes = () => {
+ const fetcher = async () => {
+ const path = formatApiPath(`api/admin/feature-types`);
+ const res = await fetch(path, {
+ method: 'GET',
+ });
+ return res.json();
+ };
+
+ const KEY = `api/admin/feature-types`;
+
+ const { data, error } = useSWR(KEY, fetcher);
+ const [loading, setLoading] = useState(!error && !data);
+
+ const refetch = () => {
+ mutate(KEY);
+ };
+
+ useEffect(() => {
+ setLoading(!error && !data);
+ }, [data, error]);
+
+ return {
+ featureTypes: (data?.types as IFeatureType[]) || [],
+ error,
+ loading,
+ refetch,
+ };
+};
+
+export default useFeatureTypes;
diff --git a/frontend/src/interfaces/environments.ts b/frontend/src/interfaces/environments.ts
index 3d24546654..6abd9b49e8 100644
--- a/frontend/src/interfaces/environments.ts
+++ b/frontend/src/interfaces/environments.ts
@@ -24,3 +24,10 @@ export interface IEnvironmentResponse {
export interface ISortOrderPayload {
[index: string]: number;
}
+
+export interface IEnvironmentMetrics {
+ name: string;
+ yes: number;
+ no: number;
+ timestamp: string;
+}
diff --git a/frontend/src/interfaces/featureTypes.ts b/frontend/src/interfaces/featureTypes.ts
new file mode 100644
index 0000000000..ef247545c7
--- /dev/null
+++ b/frontend/src/interfaces/featureTypes.ts
@@ -0,0 +1,6 @@
+export interface IFeatureType {
+ id: string;
+ name: string;
+ description: string;
+ lifetimeDays: number;
+}
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 6911685392..cc8e256b79 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1581,15 +1581,15 @@
"@types/yargs" "^16.0.0"
chalk "^4.0.0"
-"@material-ui/core@4.11.3":
- version "4.11.3"
- resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.11.3.tgz#f22e41775b0bd075e36a7a093d43951bf7f63850"
- integrity sha512-Adt40rGW6Uds+cAyk3pVgcErpzU/qxc7KBR94jFHBYretU4AtWZltYcNsbeMn9tXL86jjVL1kuGcIHsgLgFGRw==
+"@material-ui/core@4.12.3":
+ version "4.12.3"
+ resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca"
+ integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==
dependencies:
"@babel/runtime" "^7.4.4"
- "@material-ui/styles" "^4.11.3"
- "@material-ui/system" "^4.11.3"
- "@material-ui/types" "^5.1.0"
+ "@material-ui/styles" "^4.11.4"
+ "@material-ui/system" "^4.12.1"
+ "@material-ui/types" "5.1.0"
"@material-ui/utils" "^4.11.2"
"@types/react-transition-group" "^4.2.0"
clsx "^1.0.4"
@@ -1606,10 +1606,10 @@
dependencies:
"@babel/runtime" "^7.4.4"
-"@material-ui/lab@4.0.0-alpha.57":
- version "4.0.0-alpha.57"
- resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.57.tgz#e8961bcf6449e8a8dabe84f2700daacfcafbf83a"
- integrity sha512-qo/IuIQOmEKtzmRD2E4Aa6DB4A87kmY6h0uYhjUmrrgmEAgbbw9etXpWPVXuRK6AGIQCjFzV6WO2i21m1R4FCw==
+"@material-ui/lab@4.0.0-alpha.60":
+ version "4.0.0-alpha.60"
+ resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.60.tgz#5ad203aed5a8569b0f1753945a21a05efa2234d2"
+ integrity sha512-fadlYsPJF+0fx2lRuyqAuJj7hAS1tLDdIEEdov5jlrpb5pp4b+mRDUqQTUxi4inRZHS1bEXpU8QWUhO6xX88aA==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.11.2"
@@ -1617,14 +1617,14 @@
prop-types "^15.7.2"
react-is "^16.8.0 || ^17.0.0"
-"@material-ui/styles@^4.11.3":
- version "4.11.3"
- resolved "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.3.tgz"
- integrity sha512-HzVzCG+PpgUGMUYEJ2rTEmQYeonGh41BYfILNFb/1ueqma+p1meSdu4RX6NjxYBMhf7k+jgfHFTTz+L1SXL/Zg==
+"@material-ui/styles@^4.11.4":
+ version "4.11.4"
+ resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.4.tgz#eb9dfccfcc2d208243d986457dff025497afa00d"
+ integrity sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==
dependencies:
"@babel/runtime" "^7.4.4"
"@emotion/hash" "^0.8.0"
- "@material-ui/types" "^5.1.0"
+ "@material-ui/types" "5.1.0"
"@material-ui/utils" "^4.11.2"
clsx "^1.0.4"
csstype "^2.5.2"
@@ -1639,19 +1639,19 @@
jss-plugin-vendor-prefixer "^10.5.1"
prop-types "^15.7.2"
-"@material-ui/system@^4.11.3":
- version "4.11.3"
- resolved "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz"
- integrity sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==
+"@material-ui/system@^4.12.1":
+ version "4.12.1"
+ resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.1.tgz#2dd96c243f8c0a331b2bb6d46efd7771a399707c"
+ integrity sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.11.2"
csstype "^2.5.2"
prop-types "^15.7.2"
-"@material-ui/types@^5.1.0":
+"@material-ui/types@5.1.0":
version "5.1.0"
- resolved "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2"
integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==
"@material-ui/utils@^4.11.2":
@@ -2107,10 +2107,10 @@
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz"
integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
-"@types/node@14.17.20":
- version "14.17.20"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.20.tgz#74cc80438fd0467dc4377ee5bbad89a886df3c10"
- integrity sha512-gI5Sl30tmhXsqkNvopFydP7ASc4c2cLfGNQrVKN3X90ADFWFsPEsotm/8JHSUJQKTHbwowAHtcJPeyVhtKv0TQ==
+"@types/node@14.17.21":
+ version "14.17.21"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.21.tgz#6359d8cf73481e312a43886fa50afc70ce5592c6"
+ integrity sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA==
"@types/node@^14.14.31":
version "14.17.19"
@@ -2159,10 +2159,10 @@
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
-"@types/react-router-dom@5.3.0":
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.0.tgz#8c4e0aa0ccaf638ba965829ad29a10ac3cbe2212"
- integrity sha512-svUzpEpKDwK8nmfV2vpZNSsiijFNKY8+gUqGqvGGOVrXvX58k1JIJubZa5igkwacbq/0umphO5SsQn/BQsnKpw==
+"@types/react-router-dom@5.3.1":
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.1.tgz#76700ccce6529413ec723024b71f01fc77a4a980"
+ integrity sha512-UvyRy73318QI83haXlaMwmklHHzV9hjl3u71MmM6wYNu0hOVk9NLTa0vGukf8zXUqnwz4O06ig876YSPpeK28A==
dependencies:
"@types/history" "*"
"@types/react" "*"
@@ -4631,10 +4631,10 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
-date-fns@2.24.0:
- version "2.24.0"
- resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.24.0.tgz#7d86dc0d93c87b76b63d213b4413337cfd1c105d"
- integrity sha512-6ujwvwgPID6zbI0o7UbURi2vlLDR9uP26+tW6Lg+Ji3w7dd0i3DOcjcClLjLPranT60SSEFBwdSyYwn/ZkPIuw==
+date-fns@2.25.0:
+ version "2.25.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680"
+ integrity sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==
dayjs@^1.10.4:
version "1.10.7"
@@ -5787,6 +5787,11 @@ fast-glob@^3.1.1:
micromatch "^4.0.2"
picomatch "^2.2.1"
+fast-json-patch@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.1.0.tgz#ec8cd9b9c4c564250ec8b9140ef7a55f70acaee6"
+ integrity sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==
+
fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
@@ -6706,10 +6711,10 @@ immer@8.0.1:
resolved "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz"
integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==
-immutable@4.0.0-rc.15:
- version "4.0.0-rc.15"
- resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.15.tgz#c30056f05eaaf5650fd15230586688fdd15c54bc"
- integrity sha512-v8+A3sNyaieoP9dHegl3tEYnIZa7vqNiSv0U6D7YddiZi34VjKy4GsIxrRHj2d8+CS3MeiVja5QyNe4JO/aEXA==
+immutable@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
+ integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
import-cwd@^2.0.0:
version "2.1.0"
@@ -12742,10 +12747,10 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies:
minimalistic-assert "^1.0.0"
-web-vitals@2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-2.1.0.tgz#ebf5428875ab5bfc1056c2e80cd177001287de7b"
- integrity sha512-npEyJP8jHf3J71t1tRTEtz9FeKp8H2udWJUUq5ykfPhhstr//TUxiYhIEzLNwk4zv2ybAilMn7v7N6Mxmuitmg==
+web-vitals@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-2.1.1.tgz#9ae64fa9054b8865a3fa093cd8db302676822c2a"
+ integrity sha512-6i/cE+7l095Etvjo2kbtVC8OXzLc9D8XMIWBPWAt2CME/7qmIMZWQwVoKDD277poVHNdPcLgW5Jruhbi8+8Vcw==
webidl-conversions@^3.0.0:
version "3.0.1"