diff --git a/package.json b/package.json
index 40d20c20..0743367e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@boomerang-io/carbon-addons-boomerang-react",
"description": "Carbon Addons for Boomerang apps",
- "version": "2.0.12",
+ "version": "2.0.14",
"author": {
"name": "Tim Bula",
"email": "timrbula@gmail.com"
@@ -65,12 +65,13 @@
"match-sorter": "6.3.1",
"react-autosuggest": "10.1.0",
"react-modal": "3.15.1",
+ "react-query": "3.34.12",
"react-toastify": "9.0.7",
"window-or-global": "1.0.1"
},
"peerDependencies": {
"@carbon/icons-react": "^10.38.0",
- "axios": ">=0.26.0",
+ "axios": ">= 0.26.0 < 1"
"carbon-components": "^10.25.0",
"carbon-components-react": "^7.25.0",
"carbon-icons": "^7.0.7",
@@ -78,6 +79,7 @@
"prop-types": "^15.7.2",
"react": "^17.0.0 || ^16.14.0",
"react-dom": "^17.0.0 || ^16.14.0",
+ "react-query": "3.34.12",
"react-router-dom": "^5.3.0",
"yup": ">=0.32.11"
},
@@ -112,7 +114,7 @@
"@testing-library/dom": "^8.11.2",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "12.1.2",
- "axios": "0.26.0",
+ "axios": "0.27.2"
"axios-mock-adapter": "^1.20.0",
"babel-plugin-dev-expression": "^0.2.3",
"browserslist-config-carbon": "^10.6.1",
diff --git a/src/components/PrivacyStatement/PrivacyStatement.js b/src/components/PrivacyStatement/PrivacyStatement.js
index ca0d2080..7ce89a12 100644
--- a/src/components/PrivacyStatement/PrivacyStatement.js
+++ b/src/components/PrivacyStatement/PrivacyStatement.js
@@ -1,10 +1,11 @@
-import React, { useState, useEffect } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
-import axios from 'axios';
+import { useQuery, useMutation } from 'react-query';
import dompurify from 'dompurify';
import { Accordion, AccordionItem, Button } from 'carbon-components-react';
import { ModalHeader, ModalBody, ModalFooter } from 'carbon-components-react';
import { settings } from 'carbon-components';
+import { serviceUrl, resolver } from '../../config/servicesConfig';
import window from 'window-or-global';
import HeaderMenuModalWrapper from '../../internal/HeaderMenuModalWrapper';
@@ -39,44 +40,41 @@ PrivacyStatement.defaultProps = {
};
function PrivacyStatement({ baseServiceUrl, platformName, platformEmail }) {
- const [statement, setStatement] = useState();
- const [error, setError] = useState();
- const [alertError, setAlertError] = useState();
+ const statementUrl = serviceUrl.getStatement({ baseServiceUrl });
- useEffect(() => {
- axios(`${baseServiceUrl}/users/consents`)
- .then((response) => setStatement(response.data))
- .catch((err) => setError(err));
- }, [baseServiceUrl]);
+ const { data: statement, error: statementError } = useQuery({
+ queryKey: statementUrl,
+ queryFn: resolver.query(statementUrl),
+ });
- function handleSubmit({ closeAlertModal, closeModal }) {
- axios
- .put(`${baseServiceUrl}/users/consent`, {
- version: statement.version,
- hasConsented: false,
- })
- .then(() => {
- notify(
- ,
- { containerId: `${prefix}--bmrg-header-notifications` }
- );
- // want to clear out any error state
- setError(false);
- setAlertError(false);
- closeAlertModal();
- closeModal();
- if (window.location) {
- window.location.reload(true);
- }
- })
- .catch((err) => {
- setAlertError(err);
- closeAlertModal();
- });
+ const { mutateAsync: mutateUserConsent, error: mutateUserConsentError } = useMutation(resolver.putUserConsent);
+
+ const error = statementError || mutateUserConsentError;
+
+ async function handleSubmit({ closeAlertModal, closeModal }) {
+ const body = {
+ hasConsented: false,
+ version: statement.version,
+ }
+
+ try {
+ await mutateUserConsent({ baseServiceUrl, body });
+ notify(
+ ,
+ { containerId: `${prefix}--bmrg-header-notifications` }
+ );
+ closeAlertModal();
+ closeModal();
+ if (window.location) {
+ window.location.reload(true);
+ }
+ } catch {
+ closeAlertModal();
+ }
}
// TOOD: decide to do something if there is an error or not
@@ -94,13 +92,8 @@ function PrivacyStatement({ baseServiceUrl, platformName, platformEmail }) {
return (
<>
{
- closeModal();
- setError('');
- setAlertError('');
- }}
- label={`Effective as of ${statement ? formatDateTimestamp(statement.effectiveDate) : ''
- }`}
+ closeModal={closeModal}
+ label={`Effective as of ${statement ? formatDateTimestamp(statement.effectiveDate) : ''}`}
title="Privacy Statement"
/>
@@ -130,9 +123,9 @@ function PrivacyStatement({ baseServiceUrl, platformName, platformEmail }) {
.
- {alertError && (
+ {mutateUserConsentError && (
- Failed to recieve deletion request. Please try again.
+ Failed to receive deletion request. Please try again.
)}
diff --git a/src/components/PrivacyStatement/PrivacyStatement.spec.js b/src/components/PrivacyStatement/PrivacyStatement.spec.js
index 8d8a2332..cf2ae2a4 100644
--- a/src/components/PrivacyStatement/PrivacyStatement.spec.js
+++ b/src/components/PrivacyStatement/PrivacyStatement.spec.js
@@ -1,4 +1,5 @@
import React from 'react';
+import { QueryClient, QueryClientProvider } from "react-query";
import { render, fireEvent, waitFor } from '@testing-library/react';
import PrivacyStatement from './PrivacyStatement.js';
@@ -10,6 +11,10 @@ import { PRIVACY_DATA } from './constants';
const baseServiceUrl = 'http://boomerang.com';
+const queryClient = new QueryClient({
+ defaultOptions: { queries: { refetchOnWindowFocus: false }, mutations: { throwOnError: true } },
+});
+
test('Privacy Statement error', async () => {
/**
* Simulate deleting account
@@ -29,7 +34,9 @@ test('Privacy Statement error', async () => {
mock.onPut(`${baseServiceUrl}/users/consent`).networkError();
const { getByText, getByRole, findByRole } = render(
-
+
+
+
);
const btn = getByRole('button', { name: /Privacy Statement/i });
@@ -42,7 +49,7 @@ test('Privacy Statement error', async () => {
fireEvent.click(confirmButton);
await waitFor(() =>
- expect(getByText(/Failed to recieve deletion request. Please try again./i)).toBeInTheDocument()
+ expect(getByText(/Failed to receive deletion request. Please try again./i)).toBeInTheDocument()
);
});
@@ -55,7 +62,11 @@ test('Privacy Statement success', async () => {
mock.onGet(`${baseServiceUrl}/users/consents`).reply(200, PRIVACY_DATA);
mock.onPut(`${baseServiceUrl}/users/consent`).reply(200);
- const { getByRole, findByRole } = render();
+ const { getByRole, findByRole } = render(
+
+
+
+ );
const btn = getByRole('button', { name: /Privacy Statement/i });
fireEvent.click(btn);
diff --git a/src/components/PrivacyStatement/PrivacyStatement.stories.js b/src/components/PrivacyStatement/PrivacyStatement.stories.js
index bd4201d5..bf6f1493 100644
--- a/src/components/PrivacyStatement/PrivacyStatement.stories.js
+++ b/src/components/PrivacyStatement/PrivacyStatement.stories.js
@@ -8,6 +8,7 @@
// /* eslint-disable no-console */
import React from 'react';
+import { QueryClient, QueryClientProvider } from "react-query";
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
@@ -16,6 +17,10 @@ import { PRIVACY_DATA } from './constants';
const mock = new MockAdapter(axios);
+const queryClient = new QueryClient({
+ defaultOptions: { queries: { refetchOnWindowFocus: false }, mutations: { throwOnError: true } },
+});
+
const props = () => ({
baseServiceUrl: 'http://ibm.com',
});
@@ -26,7 +31,11 @@ export default {
export const Default = () => {
mock.onGet('http://ibm.com/users/consents').reply(200, PRIVACY_DATA);
- return ;
+ return (
+
+
+
+ );
};
Default.story = {
diff --git a/src/components/ProfileSettings/ProfileSettings.js b/src/components/ProfileSettings/ProfileSettings.js
index 842acda9..378aa643 100644
--- a/src/components/ProfileSettings/ProfileSettings.js
+++ b/src/components/ProfileSettings/ProfileSettings.js
@@ -1,6 +1,6 @@
-import React, { useCallback, useState, useEffect } from 'react';
+import React , { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
-import axios from 'axios';
+import { useQuery, useMutation, useQueryClient } from 'react-query';
import {
Button,
Checkbox,
@@ -18,6 +18,7 @@ import ErrorMessage from '../ErrorMessage';
import HeaderMenuUser from '../HeaderMenuUser';
import notify from '../Notifications/notify';
import ToastNotification from '../Notifications/ToastNotification';
+import { serviceUrl, resolver } from '../../config/servicesConfig';
import { settings } from 'carbon-components';
import sortBy from 'lodash.sortby';
@@ -30,68 +31,55 @@ ProfileSettings.propTypes = {
};
function ProfileSettings({ baseServiceUrl, src, userName }) {
+ const queryClient = useQueryClient();
+
const [initialTeams, setInitialTeams] = useState([]);
const [teams, setTeams] = useState([]);
- const [disableModal, setDisableModal] = useState([]);
- const [isLoading, setIsLoading] = useState();
- const [isSubmitting, setIsSubmitting] = useState();
- const [isLoadingError, setIsLoadingError] = useState();
- const [isSubmitError, setIsSubmitError] = useState();
-
- const fetchTeams = useCallback(
- ({ showLoading }) => {
- if (showLoading) {
- setIsLoading(true);
- }
- axios(`${baseServiceUrl}/launchpad/user`)
- .then((response) => {
- const teams = response.data.lowerLevelGroups;
- setTeams(teams);
- setDisableModal(response.data.lowerLevelGroups === undefined);
- setInitialTeams(teams);
- })
- .catch((err) => setIsLoadingError(err))
- .then(() => {
- setIsLoading(false);
- });
- },
- [baseServiceUrl]
+
+ const userUrl = serviceUrl.getLaunchpadUser({ baseServiceUrl });
+ const profileUrl = serviceUrl.resourceUserProfile({ baseServiceUrl });
+
+ const { data: user, isLoading: userIsLoading, error: userError } = useQuery({
+ queryKey: userUrl,
+ queryFn: resolver.query(userUrl),
+ });
+
+ const { mutateAsync: mutateUserProfile, isLoading: mutateUserProfileIsLoading, error: mutateUserProfileError } = useMutation(resolver.patchUserProfile,
+ {
+ onSuccess: () => {
+ queryClient.invalidateQueries(userUrl);
+ queryClient.invalidateQueries(profileUrl);
+ },
+ }
);
+
+ const disableModal = user?.lowerLevelGroups === undefined;
useEffect(() => {
- fetchTeams({ showLoading: true });
- }, [fetchTeams]);
-
- function handleCloseModal({ closeModal }) {
- setIsLoadingError(false);
- setIsSubmitError(false);
- closeModal();
- fetchTeams({ showLoading: false });
- }
+ const teams = user?.lowerLevelGroups ?? [];
+ setInitialTeams(teams);
+ setTeams(teams);
+ }, [user]);
- function handleSubmit({ closeModal }) {
- setIsSubmitting(true);
- setIsSubmitError(false);
- axios
- .patch(`${baseServiceUrl}/users/profile`, {
- lowerLevelGroups: teams,
- })
- .then(() => {
- setIsSubmitting(false);
- notify(
- ,
- { containerId: `${prefix}--bmrg-header-notifications` }
- );
- handleCloseModal({ closeModal });
- })
- .catch((err) => {
- setIsSubmitting(false);
- setIsSubmitError(true);
- });
+ async function handleSubmit({ closeModal }) {
+ const body = {
+ lowerLevelGroups: teams,
+ }
+
+ try {
+ await mutateUserProfile({ baseServiceUrl, body });
+ notify(
+ ,
+ { containerId: `${prefix}--bmrg-header-notifications` }
+ );
+ closeModal();
+ } catch {
+ // noop
+ }
}
const visibleTeamCount = teams?.filter((team) => team?.visible)?.length ?? 0;
@@ -127,13 +115,14 @@ function ProfileSettings({ baseServiceUrl, src, userName }) {
setTeams(updatedTeams);
}
- if (disableModal)
+ if (disableModal) {
return (
{userName ? userName : ''}
);
+ }
return (
handleCloseModal({ closeModal })}
+ closeModal={closeModal}
title={`User profile - ${userName}`}
/>
@@ -161,9 +150,9 @@ function ProfileSettings({ baseServiceUrl, src, userName }) {
sensitive demos). You will not be able to access or view unchecked Teams from the
sidebar, and cannot add items to them from Catalog.
- {isLoading ? (
+ {userIsLoading ? (
- ) : isLoadingError ? (
+ ) : userError ? (
) : teams?.length > 0 ? (
@@ -209,7 +198,7 @@ function ProfileSettings({ baseServiceUrl, src, userName }) {
)}
- {isSubmitError && (
+ {mutateUserProfileError && (
)}
-
>
diff --git a/src/components/ProfileSettings/ProfileSettings.spec.js b/src/components/ProfileSettings/ProfileSettings.spec.js
index 974d78c2..3d93a0bb 100644
--- a/src/components/ProfileSettings/ProfileSettings.spec.js
+++ b/src/components/ProfileSettings/ProfileSettings.spec.js
@@ -1,5 +1,6 @@
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
+import { QueryClient, QueryClientProvider } from "react-query";
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { axe } from 'jest-axe';
@@ -8,13 +9,19 @@ import { PROFILE_SETTINGS_DATA } from './constants';
const baseServiceUrl = 'http://boomerang.com';
+const queryClient = new QueryClient({
+ defaultOptions: { queries: { refetchOnWindowFocus: false }, mutations: { throwOnError: true } },
+});
+
test('Profile Settings success', async () => {
const mock = new MockAdapter(axios);
mock.onGet(`${baseServiceUrl}/launchpad/user`).reply(200, PROFILE_SETTINGS_DATA);
mock.onPatch(`${baseServiceUrl}/users/profile`).networkError();
const { findByText, getByLabelText, getByText, queryByText } = render(
-
+
+
+
);
const userBtn = getByText('Boomerang Joe');
@@ -46,7 +53,9 @@ mock.onPatch(`${baseServiceUrl}/users/profile`).reply(500);
test('Profile Settings error', async () => {
const { findByText, findByLabelText, getByText } = render(
-
+
+
+
);
const userBtn = getByText('Boomerang Joe');
@@ -63,7 +72,9 @@ test('Profile Settings error', async () => {
test('Profile Settings accessibility', async () => {
const { container } = render(
-
+
+
+
);
const results = await axe(container);
expect(results).toHaveNoViolations();
diff --git a/src/components/ProfileSettings/ProfileSettings.stories.js b/src/components/ProfileSettings/ProfileSettings.stories.js
index 69e116e6..c41cd699 100644
--- a/src/components/ProfileSettings/ProfileSettings.stories.js
+++ b/src/components/ProfileSettings/ProfileSettings.stories.js
@@ -1,26 +1,32 @@
import React from 'react';
+import { QueryClient, QueryClientProvider } from "react-query";
import axios from 'axios';
import ProfileSettings from './ProfileSettings';
import MockAdapter from 'axios-mock-adapter';
import { PROFILE_SETTINGS_DATA } from './constants';
-const mock = new MockAdapter(axios);
-mock.onGet('https://ibm.com/launchpad/user').reply(200, PROFILE_SETTINGS_DATA);
-mock.onPatch('https://ibm.com/users/profile').reply(200);
+const queryClient = new QueryClient({
+ defaultOptions: { queries: { refetchOnWindowFocus: false }, mutations: { throwOnError: true } },
+});
export default {
title: 'ProfileSettings',
};
export const Default = () => {
+ const mock = new MockAdapter(axios);
+ mock.onGet('https://ibm.com/launchpad/user').reply(200, PROFILE_SETTINGS_DATA);
+ mock.onPatch('https://ibm.com/users/profile').reply(200);
return (
-
+
+
+
);
};
diff --git a/src/components/UIShell/UIShell.js b/src/components/UIShell/UIShell.js
index 1cb18a96..fc2dfd87 100644
--- a/src/components/UIShell/UIShell.js
+++ b/src/components/UIShell/UIShell.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-
+import { QueryClientProvider } from "react-query";
import Header from '../Header'; // Using default export
import HeaderMenuButton from '../HeaderMenuButton';
import HeaderMenuLink from '../HeaderMenuLink';
@@ -10,6 +10,7 @@ import Feedback from '../Feedback';
import PrivacyStatement from '../PrivacyStatement';
import SignOut from '../SignOut';
import GdprRedirectModal from '../GdprRedirectModal';
+import { queryClient } from "../../config/servicesConfig";
UIShell.propTypes = {
/**
@@ -214,7 +215,7 @@ function UIShell({
renderPrivacyStatement === false || features?.['consent.enabled'] === false;
return (
- <>
+
) : null}
- >
+
);
}
diff --git a/src/config/servicesConfig.js b/src/config/servicesConfig.js
new file mode 100644
index 00000000..d43e447f
--- /dev/null
+++ b/src/config/servicesConfig.js
@@ -0,0 +1,19 @@
+import axios from "axios";
+import { QueryClient } from "react-query";
+
+export const queryClient = new QueryClient({
+ defaultOptions: { queries: { refetchOnWindowFocus: false }, mutations: { throwOnError: true } },
+});
+
+export const serviceUrl = {
+ getStatement: ({ baseServiceUrl }) => `${baseServiceUrl}/users/consents`,
+ getLaunchpadUser: ({ baseServiceUrl }) => `${baseServiceUrl}/launchpad/user`,
+ resourceUserConsent: ({ baseServiceUrl }) => `${baseServiceUrl}/users/consent`,
+ resourceUserProfile: ({ baseServiceUrl }) => `${baseServiceUrl}/users/profile`,
+}
+
+export const resolver = {
+ query: (url, config) => () => axios.get(url, config).then((response) => response.data),
+ patchUserProfile: ({ baseServiceUrl, body }) => axios.patch(serviceUrl.resourceUserProfile({ baseServiceUrl }), body),
+ putUserConsent: ({ baseServiceUrl, body }) => axios.put(serviceUrl.resourceUserConsent({ baseServiceUrl }), body),
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index fc844b07..122727bf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1154,6 +1154,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.6.2":
+ version "7.19.0"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
+ integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/standalone@^7.4.5":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.18.9.tgz#27d9bccac590df9e2d34b632e5d600f68b3fe581"
@@ -5373,7 +5380,7 @@ bfj@^7.0.2:
hoopy "^0.1.4"
tryer "^1.0.1"
-big-integer@^1.6.7:
+big-integer@^1.6.16, big-integer@^1.6.7:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
@@ -5533,6 +5540,20 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
+broadcast-channel@^3.4.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
+ integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ detect-node "^2.1.0"
+ js-sha3 "0.8.0"
+ microseconds "0.2.0"
+ nano-time "1.0.0"
+ oblivious-set "1.0.0"
+ rimraf "3.0.2"
+ unload "2.2.0"
+
brorand@^1.0.1, brorand@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -7310,7 +7331,7 @@ detect-node-es@^1.1.0:
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
-detect-node@^2.0.4:
+detect-node@^2.0.4, detect-node@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
@@ -11190,6 +11211,11 @@ js-file-download@0.4.12:
resolved "https://registry.yarnpkg.com/js-file-download/-/js-file-download-0.4.12.tgz#10c70ef362559a5b23cdbdc3bd6f399c3d91d821"
integrity sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==
+js-sha3@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+ integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
js-string-escape@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
@@ -12047,7 +12073,7 @@ marksy@^8.0.0:
he "^1.2.0"
marked "^0.3.12"
-match-sorter@6.3.1:
+match-sorter@6.3.1, match-sorter@^6.0.2:
version "6.3.1"
resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda"
integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==
@@ -12268,6 +12294,11 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
braces "^3.0.2"
picomatch "^2.3.1"
+microseconds@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
+ integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
+
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -12569,6 +12600,13 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916"
integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==
+nano-time@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
+ integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==
+ dependencies:
+ big-integer "^1.6.16"
+
nanoclone@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
@@ -13175,6 +13213,11 @@ objectorarray@^1.0.5:
resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5"
integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==
+oblivious-set@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
+ integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
+
obuf@^1.0.0, obuf@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
@@ -15151,6 +15194,15 @@ react-popper@^1.3.7:
typed-styles "^0.0.7"
warning "^4.0.2"
+react-query@3.34.12:
+ version "3.34.12"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.34.12.tgz#dcaaf7b629f0868aae8afef9fb7692f6ea7643bf"
+ integrity sha512-flDdudQVH4CqE+kNYYYyo4g2Yjek3H/36G3b9bK5oe26jD5gFnx+PPwnq0gayq5z2dcSfr2z4+drvuyeZ3A5QQ==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ broadcast-channel "^3.4.1"
+ match-sorter "^6.0.2"
+
react-refresh@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
@@ -15891,6 +15943,13 @@ rfdc@^1.3.0:
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
+rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
rimraf@^2.5.4, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -15898,13 +15957,6 @@ rimraf@^2.5.4, rimraf@^2.6.3:
dependencies:
glob "^7.1.3"
-rimraf@^3.0.0, rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -17946,6 +17998,14 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+unload@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
+ integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
+ dependencies:
+ "@babel/runtime" "^7.6.2"
+ detect-node "^2.0.4"
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"