diff --git a/.eslintrc.js b/.eslintrc.js index 062675e75c..6fd243d54e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,7 +28,8 @@ module.exports = { "src/**/*.ts", "integration/**/*.ts", "src/extensions/**/*.ts*", - "extensions/**/*.ts*" + "extensions/**/*.ts*", + "__mocks__/*.ts", ], parser: "@typescript-eslint/parser", extends: [ diff --git a/__mocks__/@linguiMacro.ts b/__mocks__/@linguiMacro.ts new file mode 100644 index 0000000000..5a0c157331 --- /dev/null +++ b/__mocks__/@linguiMacro.ts @@ -0,0 +1,3 @@ +module.exports = { + Trans: ({ children }: { children: React.ReactNode }) => children, +}; diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 889a09c914..08c94f0f8c 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -13,5 +13,8 @@ module.exports = { getPath: jest.fn() } }, - dialog: jest.fn() + dialog: jest.fn(), + ipcRenderer: { + on: jest.fn() + } }; diff --git a/extensions/pod-menu/src/logs-menu.tsx b/extensions/pod-menu/src/logs-menu.tsx index f80c55cc01..a1a6dba834 100644 --- a/extensions/pod-menu/src/logs-menu.tsx +++ b/extensions/pod-menu/src/logs-menu.tsx @@ -22,7 +22,7 @@ export class PodLogsMenu extends React.Component { const { object: pod, toolbar } = this.props const containers = pod.getAllContainers(); const statuses = pod.getContainerStatuses(); - if (!containers.length) return; + if (!containers.length) return null; return ( this.showLogs(containers[0]))}> diff --git a/extensions/pod-menu/src/shell-menu.tsx b/extensions/pod-menu/src/shell-menu.tsx index 772d17a894..02e248810b 100644 --- a/extensions/pod-menu/src/shell-menu.tsx +++ b/extensions/pod-menu/src/shell-menu.tsx @@ -34,7 +34,7 @@ export class PodShellMenu extends React.Component { render() { const { object, toolbar } = this.props const containers = object.getRunningContainers(); - if (!containers.length) return; + if (!containers.length) return null; return ( this.execShell(containers[0].name))}> diff --git a/extensions/telemetry/package-lock.json b/extensions/telemetry/package-lock.json index 57e74dc08b..bff56fc715 100644 --- a/extensions/telemetry/package-lock.json +++ b/extensions/telemetry/package-lock.json @@ -8,6 +8,12 @@ "version": "file:../../src/extensions/npm/extensions", "dev": true }, + "@types/analytics-node": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/analytics-node/-/analytics-node-3.1.3.tgz", + "integrity": "sha512-Yk299LUqnyJ6fNYQkLFd0yTfUwIvgfxH3f5WEX3ib0PC5T+mZgqcOPMDhNZ4AOD/A9tXKJQeBIb6KvgzuXflaQ==", + "dev": true + }, "@segment/loosely-validate-event": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", diff --git a/extensions/telemetry/package.json b/extensions/telemetry/package.json index 3b6137b3ac..cfb2bd6fa3 100644 --- a/extensions/telemetry/package.json +++ b/extensions/telemetry/package.json @@ -15,6 +15,7 @@ "dependencies": {}, "devDependencies": { "@k8slens/extensions": "file:../../src/extensions/npm/extensions", + "@types/analytics-node": "^3.1.3", "ts-loader": "^8.0.4", "typescript": "^4.0.3", "webpack": "^4.44.2", diff --git a/package.json b/package.json index 0d830908f1..d110e0ed78 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "kontena-lens", "productName": "Lens", "description": "Lens - The Kubernetes IDE", - "version": "4.0.0-alpha.2", + "version": "4.0.0-alpha.3", "main": "static/build/main.js", "copyright": "© 2020, Mirantis, Inc.", "license": "MIT", @@ -71,10 +71,14 @@ "^.+\\.tsx?$": "ts-jest" }, "moduleNameMapper": { - "\\.(css|scss)$": "/__mocks__/styleMock.ts" + "\\.(css|scss)$": "/__mocks__/styleMock.ts", + "^@lingui/macro$": "/__mocks__/@linguiMacro.ts" }, "modulePathIgnorePatterns": [ "/dist" + ], + "setupFiles": [ + "/src/jest.setup.ts" ] }, "build": { @@ -264,6 +268,8 @@ "@lingui/react": "^3.0.0-13", "@material-ui/core": "^4.10.1", "@rollup/plugin-json": "^4.1.0", + "@testing-library/jest-dom": "^5.11.5", + "@testing-library/react": "^11.1.0", "@types/chart.js": "^2.9.21", "@types/circular-dependency-plugin": "^5.0.1", "@types/color": "^3.0.1", @@ -337,6 +343,7 @@ "identity-obj-proxy": "^3.0.0", "include-media": "^1.4.9", "jest": "^26.0.1", + "jest-fetch-mock": "^3.0.3", "jest-mock-extended": "^1.0.10", "make-plural": "^6.2.1", "mini-css-extract-plugin": "^0.9.0", diff --git a/src/extensions/extension-manager.ts b/src/extensions/extension-manager.ts index 89879be602..332b0e5691 100644 --- a/src/extensions/extension-manager.ts +++ b/src/extensions/extension-manager.ts @@ -144,8 +144,12 @@ export class ExtensionManager { continue } const absPath = path.resolve(folderPath, fileName); - if (!fs.existsSync(absPath) || !fs.lstatSync(absPath).isDirectory()) { // skip non-directories - continue; + if (!fs.existsSync(absPath)) { + continue + } + const lstat = await fs.lstat(absPath) + if (!lstat.isDirectory() && !lstat.isSymbolicLink()) { // skip non-directories + continue } const manifestPath = path.resolve(absPath, "package.json"); const ext = await this.getExtensionByManifest(manifestPath).catch(() => null) diff --git a/src/jest.setup.ts b/src/jest.setup.ts new file mode 100644 index 0000000000..08727bc910 --- /dev/null +++ b/src/jest.setup.ts @@ -0,0 +1,4 @@ + +import fetchMock from "jest-fetch-mock" +// rewire global.fetch to call 'fetchMock' +fetchMock.enableMocks(); diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/renderer/api/endpoints/deployment.api.ts index 0b6230ab99..25164e10f9 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/renderer/api/endpoints/deployment.api.ts @@ -10,7 +10,7 @@ export class DeploymentApi extends KubeApi { getReplicas(params: { namespace: string; name: string }): Promise { return this.request .get(this.getScaleApiUrl(params)) - .then(({ status }: any) => status.replicas) + .then(({ status }: any) => status?.replicas) } scale(params: { namespace: string; name: string }, replicas: number) { diff --git a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx index 4ae8995f11..a5531affa3 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx @@ -3,7 +3,7 @@ import "./helm-chart-details.scss"; import React, { Component } from "react"; import { HelmChart, helmChartsApi } from "../../api/endpoints/helm-charts.api"; import { t, Trans } from "@lingui/macro"; -import { observable, toJS } from "mobx"; +import { observable, autorun } from "mobx"; import { observer } from "mobx-react"; import { Drawer, DrawerItem } from "../drawer"; import { autobind, stopPropagation } from "../../utils"; @@ -30,23 +30,23 @@ export class HelmChartDetails extends Component { private chartPromise: CancelablePromise<{ readme: string; versions: HelmChart[] }>; - async componentDidMount() { - const { chart: { name, repo, version } } = this.props - - try { - const { readme, versions } = await (this.chartPromise = helmChartsApi.get(repo, name, version)) - this.readme = readme - this.chartVersions = versions - this.selectedChart = versions[0] - } catch (error) { - this.error = error - } - } - componentWillUnmount() { this.chartPromise?.cancel(); } + chartUpdater = autorun(() => { + this.selectedChart = null + const { chart: { name, repo, version } } = this.props + helmChartsApi.get(repo, name, version).then(result => { + this.readme = result.readme + this.chartVersions = result.versions + this.selectedChart = result.versions[0] + }, + error => { + this.error = error; + }) + }); + @autobind() async onVersionChange({ value: version }: SelectOption) { this.selectedChart = this.chartVersions.find(chart => chart.version === version); diff --git a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.scss b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.scss index e36ad9583e..6d14dc29ae 100644 --- a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.scss +++ b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.scss @@ -20,11 +20,18 @@ } .desired-scale { - flex: 1 0; + flex: 1.1 0; } .slider-container { - flex: 1.3 0; + flex: 1 0; + } + + .plus-minus-container { + margin-left: $margin * 2; + .Icon { + --color-active: black; + } } .warning { @@ -39,4 +46,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx new file mode 100644 index 0000000000..4c01032377 --- /dev/null +++ b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.test.tsx @@ -0,0 +1,151 @@ +import React from 'react'; +import { render, waitFor, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect' + +import { DeploymentScaleDialog } from "./deployment-scale-dialog"; +jest.mock("../../api/endpoints"); +import { deploymentApi } from "../../api/endpoints"; + +const dummyDeployment = { + apiVersion: 'v1', + kind: 'dummy', + metadata: { + uid: 'dummy', + name: 'dummy', + creationTimestamp: 'dummy', + resourceVersion: 'dummy', + selfLink: 'link', + }, + selfLink: 'link', + spec: { + replicas: 1, + selector: { matchLabels: { dummy: 'label' } }, + template: { + metadata: { + labels: { dummy: 'label' }, + }, + spec: { + containers: [{ + name: 'dummy', + image: 'dummy', + resources: { + requests: { + cpu: '1', + memory: '10Mi', + }, + }, + terminationMessagePath: 'dummy', + terminationMessagePolicy: 'dummy', + imagePullPolicy: 'dummy', + }], + restartPolicy: 'dummy', + terminationGracePeriodSeconds: 10, + dnsPolicy: 'dummy', + serviceAccountName: 'dummy', + serviceAccount: 'dummy', + securityContext: {}, + schedulerName: 'dummy', + }, + }, + strategy: { + type: 'dummy', + rollingUpdate: { + maxUnavailable: 1, + maxSurge: 10, + }, + }, + }, + status: { + observedGeneration: 1, + replicas: 1, + updatedReplicas: 1, + readyReplicas: 1, + conditions: [{ + type: 'dummy', + status: 'dummy', + lastUpdateTime: 'dummy', + lastTransitionTime: 'dummy', + reason: 'dummy', + message: 'dummy', + }], + }, + getConditions: jest.fn(), + getConditionsText: jest.fn(), + getReplicas: jest.fn(), + getSelectors: jest.fn(), + getTemplateLabels: jest.fn(), + getAffinity: jest.fn(), + getTolerations: jest.fn(), + getNodeSelectors: jest.fn(), + getAffinityNumber: jest.fn(), + getId: jest.fn(), + getResourceVersion: jest.fn(), + getName: jest.fn(), + getNs: jest.fn(), + getAge: jest.fn(), + getFinalizers: jest.fn(), + getLabels: jest.fn(), + getAnnotations: jest.fn(), + getOwnerRefs: jest.fn(), + getSearchFields: jest.fn(), + toPlainObject: jest.fn(), + update: jest.fn(), + delete: jest.fn(), +} + +describe('', () => { + + it('renders w/o errors', () => { + const { container } = render(); + expect(container).toBeInstanceOf(HTMLElement); + }); + + it('inits with a dummy deployment with mocked current/desired scale', async () => { + // mock deploymentApi.getReplicas() which will be called + // when rendered. + const initReplicas = 3 + deploymentApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); + const { getByTestId } = render(); + DeploymentScaleDialog.open(dummyDeployment); + // we need to wait for the DeploymentScaleDialog to show up + // because there is an in which renders null at start. + await waitFor(async () => { + const [currentScale, desiredScale] = await Promise.all([ + getByTestId('current-scale'), + getByTestId('desired-scale'), + ]) + expect(currentScale).toHaveTextContent(`${initReplicas}`); + expect(desiredScale).toHaveTextContent(`${initReplicas}`); + }); + + }); + + it('changes the desired scale when clicking the icon buttons +/-', async () => { + const initReplicas = 1 + deploymentApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas); + const { getByTestId } = render(); + DeploymentScaleDialog.open(dummyDeployment); + await waitFor(async () => { + const desiredScale = await getByTestId('desired-scale'); + expect(desiredScale).toHaveTextContent(`${initReplicas}`); + }); + const up = await getByTestId('desired-replicas-up'); + const down = await getByTestId('desired-replicas-down') + fireEvent.click(up); + expect(await getByTestId('desired-scale')).toHaveTextContent(`${initReplicas + 1}`); + fireEvent.click(down); + expect(await getByTestId('desired-scale')).toHaveTextContent('1'); + // edge case, desiredScale must > 0 + fireEvent.click(down); + fireEvent.click(down); + expect(await getByTestId('desired-scale')).toHaveTextContent('1'); + const times = 120; + // edge case, desiredScale must < scaleMax (100) + for (let i = 0; i < times; i++) { + fireEvent.click(up); + } + expect(await getByTestId('desired-scale')).toHaveTextContent('100'); + }); + +}); + diff --git a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx index d421f4692e..e270729562 100644 --- a/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-scale-dialog.tsx @@ -83,21 +83,41 @@ export class DeploymentScaleDialog extends Component { } } + desiredReplicasUp = () => { + this.desiredReplicas < this.scaleMax && this.desiredReplicas++ + } + + desiredReplicasDown = () => { + this.desiredReplicas > 1 && this.desiredReplicas-- + }; + renderContents() { const { currentReplicas, desiredReplicas, onChange, scaleMax } = this; const warning = currentReplicas < 10 && desiredReplicas > 90; return ( <> -
+
Current replica scale: {currentReplicas}
-
+
Desired number of replicas: {desiredReplicas}
-
+
+
+ + +
{warning &&
@@ -139,4 +159,4 @@ export class DeploymentScaleDialog extends Component {
); } -} \ No newline at end of file +} diff --git a/src/renderer/components/+workloads-pods/pod-details.tsx b/src/renderer/components/+workloads-pods/pod-details.tsx index 6c20fd1326..a029591bbd 100644 --- a/src/renderer/components/+workloads-pods/pod-details.tsx +++ b/src/renderer/components/+workloads-pods/pod-details.tsx @@ -65,7 +65,6 @@ export class PodDetails extends React.Component { const { nodeName } = spec; const nodeSelector = pod.getNodeSelectors(); const volumes = pod.getVolumes(); - const labels = pod.getLabels(); const metrics = podsStore.metrics; return (
diff --git a/static/RELEASE_NOTES.md b/static/RELEASE_NOTES.md index dd168092a4..a797d716b8 100644 --- a/static/RELEASE_NOTES.md +++ b/static/RELEASE_NOTES.md @@ -2,7 +2,7 @@ Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights! -## 4.0.0-alpha.2 (current version) +## 4.0.0-alpha.3 (current version) - Extension API - Improved pod logs @@ -11,6 +11,9 @@ Here you can find description of changes we've built into each release. While we - Add LoadBalancer information to Ingress view - Move tracker to an extension - Add support page (as an extension) +- Status bar visual fixes +- Fix proxy upgrade socket timeouts +- Fix UI staleness after network issues ## 3.6.6 - Fix labels' word boundary to cover only drawer badges diff --git a/yarn.lock b/yarn.lock index 23721721b1..d981af5d90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -910,6 +910,14 @@ "@babel/helper-plugin-utils" "^7.10.1" "@babel/plugin-transform-typescript" "^7.10.1" +"@babel/runtime-corejs3@^7.10.2": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.1.tgz#51b9092befbeeed938335a109dbe0df51451e9dc" + integrity sha512-umhPIcMrlBZ2aTWlWjUseW9LjQKxi1dpFlQS8DzsxB//5K+u6GLTC/JliPKHsd5kJVPIU6X/Hy0YvWOYPcMxBw== + dependencies: + core-js-pure "^3.0.0" + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.6": version "7.10.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839" @@ -917,6 +925,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.9.2": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" + integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.1", "@babel/template@^7.3.3": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" @@ -1391,6 +1406,17 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^26.6.1": + version "26.6.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.1.tgz#2638890e8031c0bc8b4681e0357ed986e2f866c5" + integrity sha512-ywHavIKNpAVrStiRY5wiyehvcktpijpItvGiK72RAn5ctqmzvPk8OvKnvHeBqa1XdQr959CTWAJMqxI8BTibyg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + "@kubernetes/client-node@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@kubernetes/client-node/-/client-node-0.12.0.tgz#79120311bced206ac8fa36435fb4cc2c1828fff2" @@ -1666,6 +1692,42 @@ dependencies: defer-to-connect "^1.0.1" +"@testing-library/dom@^7.26.0": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.26.3.tgz#5554ee985f712d621bd676104b879f85d9a7a0ef" + integrity sha512-/1P6taENE/H12TofJaS3L1J28HnXx8ZFhc338+XPR5y1E3g5ttOgu86DsGnV9/n2iPrfJQVUZ8eiGYZGSxculw== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.10.3" + "@types/aria-query" "^4.2.0" + aria-query "^4.2.2" + chalk "^4.1.0" + dom-accessibility-api "^0.5.1" + lz-string "^1.4.4" + pretty-format "^26.4.2" + +"@testing-library/jest-dom@^5.11.5": + version "5.11.5" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.5.tgz#44010f37f4b1e15f9d433963b515db0b05182fc8" + integrity sha512-XI+ClHR864i6p2kRCEyhvpVejuer+ObVUF4cjCvRSF88eOMIfqw7RoS9+qoRhyigGswMfT64L6Nt0Ufotxbwtg== + dependencies: + "@babel/runtime" "^7.9.2" + "@types/testing-library__jest-dom" "^5.9.1" + aria-query "^4.2.2" + chalk "^3.0.0" + css "^3.0.0" + css.escape "^1.5.1" + lodash "^4.17.15" + redent "^3.0.0" + +"@testing-library/react@^11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.1.0.tgz#dfb4b3177d05a8ccf156b5fd14a5550e91d7ebe4" + integrity sha512-Nfz58jGzW0tgg3irmTB7sa02JLkLnCk+QN3XG6WiaGQYb0Qc4Ok00aujgjdxlIQWZHbb4Zj5ZOIeE9yKFSs4sA== + dependencies: + "@babel/runtime" "^7.11.2" + "@testing-library/dom" "^7.26.0" + "@tokenizer/token@^0.1.0", "@tokenizer/token@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.1.1.tgz#f0d92c12f87079ddfd1b29f614758b9696bc29e3" @@ -1676,6 +1738,11 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/aria-query@^4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" + integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== + "@types/babel__core@^7.1.7": version "7.1.8" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.8.tgz#057f725aca3641f49fc11c7a87a9de5ec588a5d7" @@ -1915,6 +1982,14 @@ dependencies: "@types/istanbul-lib-report" "*" +"@types/jest@*": + version "26.0.15" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.15.tgz#12e02c0372ad0548e07b9f4e19132b834cb1effe" + integrity sha512-s2VMReFXRg9XXxV+CW9e5Nz8fH2K1aEhwgjUqPPbQd7g95T0laAcvLv032EhFHIa5GHsZ8W7iJEQVaJq6k3Gog== + dependencies: + jest-diff "^26.0.0" + pretty-format "^26.0.0" + "@types/jest@26.x": version "26.0.13" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.13.tgz#5a7b9d5312f5dd521a38329c38ee9d3802a0b85e" @@ -2285,6 +2360,13 @@ "@types/webpack" "*" terser "^4.6.13" +"@types/testing-library__jest-dom@^5.9.1": + version "5.9.5" + resolved "https://registry.yarnpkg.com/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz#5bf25c91ad2d7b38f264b12275e5c92a66d849b0" + integrity sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ== + dependencies: + "@types/jest" "*" + "@types/tough-cookie@*": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" @@ -2927,6 +3009,14 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" + integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== + dependencies: + "@babel/runtime" "^7.10.2" + "@babel/runtime-corejs3" "^7.10.2" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -4317,6 +4407,11 @@ core-js-compat@^3.6.2: browserslist "^4.8.5" semver "7.0.0" +core-js-pure@^3.0.0: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813" + integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA== + core-js@^2.4.0: version "2.6.11" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" @@ -4396,6 +4491,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-fetch@^3.0.4: + version "3.0.6" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" + integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== + dependencies: + node-fetch "2.6.1" + cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -4531,6 +4633,11 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= + css@^2.0.0: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" @@ -4541,6 +4648,15 @@ css@^2.0.0: source-map-resolve "^0.5.2" urix "^0.1.0" +css@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" + integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== + dependencies: + inherits "^2.0.4" + source-map "^0.6.1" + source-map-resolve "^0.6.0" + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -4837,6 +4953,11 @@ diff-sequences@^26.0.0: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== +diff-sequences@^26.5.0: + version "26.5.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.5.0.tgz#ef766cf09d43ed40406611f11c6d8d9dd8b2fefd" + integrity sha512-ZXx86srb/iYy6jG71k++wBN9P9J05UNQ5hQHQd9MtMPvcqXPx/vKU69jfHV637D00Q2gSgPk2D+jSx3l1lDW/Q== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -4877,6 +4998,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-accessibility-api@^0.5.1: + version "0.5.4" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz#b06d059cdd4a4ad9a79275f9d414a5c126241166" + integrity sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ== + dom-converter@^0.2: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -7522,6 +7648,16 @@ jest-diff@^25.2.1: jest-get-type "^25.2.6" pretty-format "^25.5.0" +jest-diff@^26.0.0: + version "26.6.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.1.tgz#38aa194979f454619bb39bdee299fb64ede5300c" + integrity sha512-BBNy/zin2m4kG5In126O8chOBxLLS/XMTuuM2+YhgyHk87ewPzKTuTJcqj3lOWOi03NNgrl+DkMeV/exdvG9gg== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.5.0" + jest-get-type "^26.3.0" + pretty-format "^26.6.1" + jest-diff@^26.0.1: version "26.0.1" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.0.1.tgz#c44ab3cdd5977d466de69c46929e0e57f89aa1de" @@ -7573,6 +7709,14 @@ jest-environment-node@^26.0.1: jest-mock "^26.0.1" jest-util "^26.0.1" +jest-fetch-mock@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b" + integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw== + dependencies: + cross-fetch "^3.0.4" + promise-polyfill "^8.1.3" + jest-get-type@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" @@ -7583,6 +7727,11 @@ jest-get-type@^26.0.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + jest-haste-map@^26.0.1: version "26.0.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.0.1.tgz#40dcc03c43ac94d25b8618075804d09cd5d49de7" @@ -8631,6 +8780,11 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lz-string@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" + integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= + mac-ca@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mac-ca/-/mac-ca-1.0.4.tgz#4c8ae50f003dec4bc63f4688791f9321ff84e5f5" @@ -8906,6 +9060,11 @@ mimic-response@^3.1.0: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + mini-create-react-context@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" @@ -9187,6 +9346,11 @@ node-fetch-npm@^2.0.2: json-parse-better-errors "^1.0.0" safe-buffer "^5.1.1" +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-forge@^0.7.5: version "0.7.6" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" @@ -10553,6 +10717,16 @@ pretty-format@^25.2.1, pretty-format@^25.5.0: ansi-styles "^4.0.0" react-is "^16.12.0" +pretty-format@^26.0.0, pretty-format@^26.4.2, pretty-format@^26.6.1: + version "26.6.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.1.tgz#af9a2f63493a856acddeeb11ba6bcf61989660a8" + integrity sha512-MeqqsP5PYcRBbGMvwzsyBdmAJ4EFX7pWFyl7x4+dMVg5pE0ZDdBIvEH2ergvIO+Gvwv1wh64YuOY9y5LuyY/GA== + dependencies: + "@jest/types" "^26.6.1" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + pretty-format@^26.0.1: version "26.0.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.0.1.tgz#a4fe54fe428ad2fd3413ca6bbd1ec8c2e277e197" @@ -10596,6 +10770,11 @@ promise-inflight@^1.0.1, promise-inflight@~1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise-polyfill@^8.1.3: + version "8.2.0" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.2.0.tgz#367394726da7561457aba2133c9ceefbd6267da0" + integrity sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g== + promise-retry@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" @@ -10869,6 +11048,11 @@ react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-i resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" + integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== + react-redux@^7.1.1: version "7.2.1" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985" @@ -11162,6 +11346,14 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + redux@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" @@ -12022,6 +12214,14 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" +source-map-resolve@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" + integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.12: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" @@ -12438,6 +12638,13 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + strip-json-comments@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180"