From cd3260af3e0950805a68c91789e496c2b31dfcf1 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Tue, 21 Jan 2020 10:22:20 +0800 Subject: [PATCH] rewrite plugins mgmt page with react --- .github/workflows/CI.yml | 1 + package.json | 21 +- resources/assets/src/components/Loading.tsx | 9 + resources/assets/src/{index.ts => index.tsx} | 14 ++ resources/assets/src/scripts/i18n.ts | 3 +- resources/assets/src/scripts/net.ts | 3 +- resources/assets/src/scripts/route.ts | 2 +- resources/assets/src/shims.d.ts | 9 +- .../admin/PluginsManagement/InfoBox.styl | 31 +++ .../views/admin/PluginsManagement/InfoBox.tsx | 88 ++++++++ .../views/admin/PluginsManagement/index.tsx | 103 +++++++++ .../views/admin/PluginsManagement/types.ts | 10 + resources/assets/src/webpack.d.ts | 9 + resources/assets/tests/tsconfig.json | 21 ++ .../assets/tests/{scripts => }/types.d.ts | 14 +- .../views/admin/PluginsManagement.test.tsx | 204 +++++++++++++++++ resources/assets/tests/webpack.d.ts | 6 +- tsconfig.json | 20 +- webpack.config.js | 29 ++- yarn.lock | 212 +++++++++++++++++- 20 files changed, 768 insertions(+), 41 deletions(-) create mode 100644 resources/assets/src/components/Loading.tsx rename resources/assets/src/{index.ts => index.tsx} (58%) create mode 100644 resources/assets/src/views/admin/PluginsManagement/InfoBox.styl create mode 100644 resources/assets/src/views/admin/PluginsManagement/InfoBox.tsx create mode 100644 resources/assets/src/views/admin/PluginsManagement/index.tsx create mode 100644 resources/assets/src/views/admin/PluginsManagement/types.ts create mode 100644 resources/assets/src/webpack.d.ts create mode 100644 resources/assets/tests/tsconfig.json rename resources/assets/tests/{scripts => }/types.d.ts (57%) create mode 100644 resources/assets/tests/views/admin/PluginsManagement.test.tsx diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ad3800eb..3a89eadf 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -88,6 +88,7 @@ jobs: run: | yarn lint yarn tsc -p . --noEmit + yarn tsc -p ./resources/assets/tests --noEmit jest: name: Frontend Tests runs-on: ubuntu-latest diff --git a/package.json b/package.json index dad98a42..b0ab853f 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,14 @@ "dependencies": { "@babel/runtime": "^7.8.0", "@fortawesome/fontawesome-free": "^5.12.0", + "@hot-loader/react-dom": "^16.11.0", "@tweenjs/tween.js": "^18.4.2", "admin-lte": "^3.0.1", "echarts": "^4.6.0", "jquery": "^3.4.1", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-hot-loader": "^4.12.18", "rxjs": "^6.5.3", "skinview3d": "^1.2.1", "vue": "^2.6.11", @@ -35,10 +39,13 @@ "@babel/plugin-transform-runtime": "^7.8.3", "@babel/preset-env": "^7.8.2", "@gplane/tsconfig": "^1.0.0", + "@testing-library/react": "^9.4.0", "@types/bootstrap": "^4.3.1", "@types/echarts": "^4.4.2", "@types/jest": "^24.0.25", "@types/jquery": "^3.3.29", + "@types/react": "^16.9.17", + "@types/react-dom": "^16.9.4", "@types/webpack": "^4.41.2", "@typescript-eslint/eslint-plugin": "^2.8.0", "@typescript-eslint/parser": "^2.8.0", @@ -188,12 +195,13 @@ "js", "vue", "ts", + "tsx", "json", "node" ], "moduleNameMapper": { "^@/(.*)$": "/resources/assets/src/$1", - "\\.css$": "/resources/assets/tests/__mocks__/style.ts", + "\\.(css|styl)$": "/resources/assets/tests/__mocks__/style.ts", "\\.(png|jpg)$": "/resources/assets/tests/__mocks__/file.ts" }, "setupFilesAfterEnv": [ @@ -204,6 +212,15 @@ "/resources/assets/tests/setup", "/resources/assets/tests/utils" ], - "testRegex": "resources/assets/tests/.*\\.(spec|test)\\.(t|j)s$" + "testMatch": [ + "/resources/assets/tests/**/*.test.ts", + "/resources/assets/tests/**/*.test.tsx" + ], + "globals": { + "ts-jest": { + "tsConfig": "/resources/assets/tests/tsconfig.json", + "isolatedModules": true + } + } } } diff --git a/resources/assets/src/components/Loading.tsx b/resources/assets/src/components/Loading.tsx new file mode 100644 index 00000000..980ba246 --- /dev/null +++ b/resources/assets/src/components/Loading.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +const Loading = () => ( +
+ +
+) + +export default Loading diff --git a/resources/assets/src/index.ts b/resources/assets/src/index.tsx similarity index 58% rename from resources/assets/src/index.ts rename to resources/assets/src/index.tsx index c3c5e8c1..75529c1f 100644 --- a/resources/assets/src/index.ts +++ b/resources/assets/src/index.tsx @@ -1,6 +1,9 @@ import Vue from 'vue' +import * as React from 'react' +import ReactDOM from 'react-dom' import './scripts/app' import routes from './scripts/route' +import Loading from './components/Loading' Vue.config.productionTip = false @@ -15,6 +18,17 @@ function loadModules() { if (route.module) { Promise.all(route.module.map(m => m())) } + if (route.react) { + const Component = React.lazy( + route.react as (() => Promise<{ default: React.ComponentType }>) + ) + const Root = () => ( + }> + + + ) + ReactDOM.render(, document.querySelector(route.el)) + } if (route.component) { Vue.prototype.$route = new RegExp(`^${route.path}$`, 'i').exec(blessing.route) // eslint-disable-next-line no-new diff --git a/resources/assets/src/scripts/i18n.ts b/resources/assets/src/scripts/i18n.ts index 47bfea27..8630e0d3 100644 --- a/resources/assets/src/scripts/i18n.ts +++ b/resources/assets/src/scripts/i18n.ts @@ -44,5 +44,4 @@ Vue.use(_Vue => { }) }) -// eslint-disable-next-line @typescript-eslint/unbound-method -window.trans = trans +Object.assign(window, { trans }) diff --git a/resources/assets/src/scripts/net.ts b/resources/assets/src/scripts/net.ts index 7ec61a58..c0af72f2 100644 --- a/resources/assets/src/scripts/net.ts +++ b/resources/assets/src/scripts/net.ts @@ -4,9 +4,10 @@ import { queryStringify } from './utils' import { showModal } from './notify' import { trans } from './i18n' -export interface ResponseBody { +export interface ResponseBody { code: number message: string + data: T extends null ? never : T } class HTTPError extends Error { diff --git a/resources/assets/src/scripts/route.ts b/resources/assets/src/scripts/route.ts index 2994ed15..f2dfad30 100644 --- a/resources/assets/src/scripts/route.ts +++ b/resources/assets/src/scripts/route.ts @@ -78,7 +78,7 @@ export default [ }, { path: 'admin/plugins/manage', - component: () => import('../views/admin/Plugins.vue'), + react: () => import('../views/admin/PluginsManagement'), el: '.content > .container-fluid', }, { diff --git a/resources/assets/src/shims.d.ts b/resources/assets/src/shims.d.ts index fca61508..707fd334 100644 --- a/resources/assets/src/shims.d.ts +++ b/resources/assets/src/shims.d.ts @@ -1,25 +1,22 @@ import Vue from 'vue' -import * as JQuery from 'jquery' +import JQuery from 'jquery' import { ModalOptions, ModalResult } from './scripts/modal' import { Toast } from './scripts/toast' -type I18n = 'en' | 'zh_CN' - declare global { // eslint-disable-next-line no-redeclare let blessing: { base_url: string debug: boolean env: string - fallback_locale: I18n - locale: I18n + fallback_locale: string + locale: string site_name: string timezone: string version: string route: string extra: any i18n: object - ui: object fetch: { get(url: string, params?: object): Promise diff --git a/resources/assets/src/views/admin/PluginsManagement/InfoBox.styl b/resources/assets/src/views/admin/PluginsManagement/InfoBox.styl new file mode 100644 index 00000000..5d11ef8d --- /dev/null +++ b/resources/assets/src/views/admin/PluginsManagement/InfoBox.styl @@ -0,0 +1,31 @@ +.box + cursor default + transition-property box-shadow + transition-duration 0.3s + width 32% + @media (max-width: 1280px) + width 47% + @media (max-width: 768px) + width 100% + &:hover + box-shadow 0 .5rem 1rem rgba(0,0,0,.15) + +.content + max-width 85% + +.actions + margin-top -7px + a + transition-property color + transition-duration 0.3s + color #000 + &:hover + color #999 + &:not(:last-child) + margin-right 9px + +.description + font-size 14px + white-space nowrap + overflow hidden + text-overflow ellipsis diff --git a/resources/assets/src/views/admin/PluginsManagement/InfoBox.tsx b/resources/assets/src/views/admin/PluginsManagement/InfoBox.tsx new file mode 100644 index 00000000..af87ac8a --- /dev/null +++ b/resources/assets/src/views/admin/PluginsManagement/InfoBox.tsx @@ -0,0 +1,88 @@ +import React, { useCallback } from 'react' +import { trans } from '../../../scripts/i18n' +import { Plugin } from './types' +import styles from './InfoBox.styl' + +interface Props { + plugin: Plugin + onEnable(plugin: Plugin): void + onDisable(plugin: Plugin): void + onDelete(plugin: Plugin): void + baseUrl: string +} + +const InfoBox: React.FC = props => { + const { plugin } = props + + const handleChange = useCallback( + (event: React.ChangeEvent) => { + event.preventDefault() + + if (event.target.checked) { + props.onEnable(plugin) + } else { + props.onDisable(plugin) + } + }, + [], + ) + + const handleDelete = useCallback(() => { + props.onDelete(plugin) + }, []) + + return ( +
+ + + +
+
+
+ + {plugin.title} + v{plugin.version} +
+
+ {plugin.readme && ( + + + + )} + {plugin.enabled && plugin.config && ( + + + + )} + + + +
+
+
{plugin.description}
+
+
+ ) +} + +export default React.memo(InfoBox) diff --git a/resources/assets/src/views/admin/PluginsManagement/index.tsx b/resources/assets/src/views/admin/PluginsManagement/index.tsx new file mode 100644 index 00000000..f09b1911 --- /dev/null +++ b/resources/assets/src/views/admin/PluginsManagement/index.tsx @@ -0,0 +1,103 @@ +import React, { useState, useEffect, useCallback } from 'react' +import { hot } from 'react-hot-loader/root' +import { trans } from '../../../scripts/i18n' +import * as fetch from '../../../scripts/net' +import { toast, showModal } from '../../../scripts/notify' +import Loading from '../../../components/Loading' +import alertUnresolved from '../../../components/mixins/alertUnresolvedPlugins' +import InfoBox from './InfoBox' +import { Plugin } from './types' + +const PluginsManagement: React.FC = () => { + const [loading, setLoading] = useState(false) + const [plugins, setPlugins] = useState([]) + useEffect(() => { + const getPlugins = async () => { + setLoading(true) + setPlugins(await fetch.get('/admin/plugins/data')) + setLoading(false) + } + getPlugins() + }, []) + + const handleEnable = useCallback(async (plugin: Plugin, i: number) => { + const { + code, + message, + data: { reason } = { reason: [] }, + }: fetch.ResponseBody<{ + reason: string[] + }> = await fetch.post('/admin/plugins/manage', { + action: 'enable', + name: plugin.name, + }) + if (code === 0) { + toast.success(message) + setPlugins(plugins => { + plugins.splice(i, 1, { ...plugin, enabled: true }) + return plugins.slice() + }) + } else { + alertUnresolved(message, reason) + } + }, []) + + const handleDisable = useCallback(async (plugin: Plugin, i: number) => { + const { code, message } = await fetch.post('/admin/plugins/manage', { + action: 'disable', + name: plugin.name, + }) + if (code === 0) { + toast.success(message) + setPlugins(plugins => { + plugins.splice(i, 1, { ...plugin, enabled: false }) + return plugins.slice() + }) + } else { + toast.error(message) + } + }, []) + + const handleDelete = useCallback(async (plugin: Plugin) => { + try { + await showModal({ + title: plugin.title, + text: trans('admin.confirmDeletion'), + okButtonType: 'danger', + }) + } catch { + return + } + + const { code, message } = await fetch.post('/admin/plugins/manage', { + action: 'delete', + name: plugin.name, + }) + if (code === 0) { + const { name } = plugin + setPlugins(plugins => plugins.filter(plugin => plugin.name !== name)) + toast.success(message) + } else { + toast.error(message) + } + }, []) + + return loading ? ( + + ) : ( +
+ {plugins.map((plugin, i) => ( + handleEnable(plugin, i)} + onDisable={plugin => handleDisable(plugin, i)} + onDelete={handleDelete} + baseUrl={blessing.base_url} + /> + ))} +
+ ) +} + +export default hot(PluginsManagement) diff --git a/resources/assets/src/views/admin/PluginsManagement/types.ts b/resources/assets/src/views/admin/PluginsManagement/types.ts new file mode 100644 index 00000000..3ebf9d04 --- /dev/null +++ b/resources/assets/src/views/admin/PluginsManagement/types.ts @@ -0,0 +1,10 @@ +export type Plugin = { + name: string + title: string + description: string + version: string + enabled: boolean + config: boolean + readme: boolean + icon: { fa: string; faType: 'fas' | 'fab'; bg: string } +} diff --git a/resources/assets/src/webpack.d.ts b/resources/assets/src/webpack.d.ts new file mode 100644 index 00000000..8c582452 --- /dev/null +++ b/resources/assets/src/webpack.d.ts @@ -0,0 +1,9 @@ +declare module '*.vue' { + import Vue from 'vue' + + export default Vue +} + +declare module '*.styl' { + export default {} as Record +} diff --git a/resources/assets/tests/tsconfig.json b/resources/assets/tests/tsconfig.json new file mode 100644 index 00000000..5da8e1c0 --- /dev/null +++ b/resources/assets/tests/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "baseUrl": "..", + "paths": { + "@/scripts/*": [ + "./tests/ts-shims/*", + "./src/scripts/*" + ], + "@/components/*": [ + "./src/components/*" + ], + "@/views/*": [ + "./src/views/*" + ] + } + }, + "include": [ + "." + ] +} diff --git a/resources/assets/tests/scripts/types.d.ts b/resources/assets/tests/types.d.ts similarity index 57% rename from resources/assets/tests/scripts/types.d.ts rename to resources/assets/tests/types.d.ts index 126a4ecd..38195e1b 100644 --- a/resources/assets/tests/scripts/types.d.ts +++ b/resources/assets/tests/types.d.ts @@ -1,4 +1,4 @@ -class Request { +declare class Request { url: string headers: Map @@ -19,3 +19,15 @@ interface Window { $: jest.Mock } + +declare let blessing: { + base_url: string + site_name: string + timezone: string + version: string + route: string + extra: any + i18n: object + fetch: any + event: any +} diff --git a/resources/assets/tests/views/admin/PluginsManagement.test.tsx b/resources/assets/tests/views/admin/PluginsManagement.test.tsx new file mode 100644 index 00000000..bebef074 --- /dev/null +++ b/resources/assets/tests/views/admin/PluginsManagement.test.tsx @@ -0,0 +1,204 @@ +import React from 'react' +import { render, wait, fireEvent } from '@testing-library/react' +import { trans } from '@/scripts/i18n' +import * as fetch from '@/scripts/net' +import { showModal, toast } from '@/scripts/notify' +import PluginsManagement from '@/views/admin/PluginsManagement' + +jest.mock('@/scripts/net') +jest.mock('@/scripts/notify') + +test('show loading indicator', () => { + fetch.get.mockResolvedValue([]) + const { queryByTitle } = render() + expect(queryByTitle('Loading...')).not.toBeNull() +}) + +test('plugin info box', async () => { + fetch.get.mockResolvedValue([ + { + name: 'a', + title: 'My Plugin', + version: '1.0.0', + description: 'desc', + config: true, + readme: true, + icon: {}, + enabled: true, + }, + ]) + + const { queryByTitle, queryByText } = render() + await wait() + + expect(queryByTitle(trans('admin.configurePlugin'))).not.toBeNull() + expect(queryByTitle(trans('admin.pluginReadme'))).not.toBeNull() + expect(queryByText('My Plugin')).not.toBeNull() + expect(queryByText('v1.0.0')).not.toBeNull() + expect(queryByText('desc')).not.toBeNull() +}) + +describe('enable plugin', () => { + beforeEach(() => { + fetch.get.mockResolvedValue([ + { + name: 'a', + icon: {}, + enabled: false, + }, + ]) + }) + + it('successfully', async () => { + fetch.get.mockResolvedValue([ + { + name: 'a', + icon: {}, + enabled: false, + }, + ]) + fetch.post.mockResolvedValue({ code: 0, message: '0' }) + + const { getByTitle } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.enablePlugin'))) + await wait() + + expect(fetch.post).toBeCalledWith('/admin/plugins/manage', { + action: 'enable', + name: 'a', + }) + expect(toast.success).toBeCalled() + }) + + it('failed', async () => { + fetch.post.mockResolvedValue({ + code: 1, + message: '1', + data: { reason: ['abc'] }, + }) + + const { getByTitle } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.enablePlugin'))) + await wait() + + expect(fetch.post).toBeCalledWith('/admin/plugins/manage', { + action: 'enable', + name: 'a', + }) + expect(showModal).toBeCalledWith({ + mode: 'alert', + dangerousHTML: expect.stringContaining('
  • abc
  • '), + }) + }) +}) + +describe('disable plugin', () => { + beforeEach(() => { + fetch.get.mockResolvedValue([ + { + name: 'a', + icon: {}, + enabled: true, + }, + ]) + }) + + it('successfully', async () => { + fetch.post.mockResolvedValue({ code: 0, message: '0' }) + + const { getByTitle } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.disablePlugin'))) + await wait() + + expect(fetch.post).toBeCalledWith('/admin/plugins/manage', { + action: 'disable', + name: 'a', + }) + expect(toast.success).toBeCalledWith('0') + }) + + it('failed', async () => { + fetch.post.mockResolvedValue({ code: 1, message: '1' }) + + const { getByTitle } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.disablePlugin'))) + await wait() + + expect(fetch.post).toBeCalledWith('/admin/plugins/manage', { + action: 'disable', + name: 'a', + }) + expect(toast.error).toBeCalledWith('1') + }) +}) + +describe('delete plugin', () => { + beforeEach(() => { + fetch.get.mockResolvedValue([ + { + name: 'a', + title: 'My Plugin', + icon: {}, + enabled: false, + }, + ]) + }) + + it('rejected by user', async () => { + showModal.mockRejectedValue({}) + + const { getByTitle } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.deletePlugin'))) + await wait() + expect(showModal).toBeCalledWith({ + title: 'My Plugin', + text: trans('admin.confirmDeletion'), + okButtonType: 'danger', + }) + expect(fetch.post).not.toBeCalled() + }) + + it('successfully', async () => { + showModal.mockResolvedValue({ value: '' }) + fetch.post.mockResolvedValue({ code: 0, message: '0' }) + + const { getByTitle, queryByText } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.deletePlugin'))) + await wait() + expect(fetch.post).toBeCalledWith('/admin/plugins/manage', { + action: 'delete', + name: 'a', + }) + expect(toast.success).toBeCalledWith('0') + expect(queryByText('My Plugin')).toBeNull() + }) + + it('failed', async () => { + showModal.mockResolvedValue({ value: '' }) + fetch.post.mockResolvedValue({ code: 1, message: '1' }) + + const { getByTitle, queryByText } = render() + await wait() + + fireEvent.click(getByTitle(trans('admin.deletePlugin'))) + await wait() + expect(fetch.post).toBeCalledWith('/admin/plugins/manage', { + action: 'delete', + name: 'a', + }) + expect(toast.error).toBeCalledWith('1') + expect(queryByText('My Plugin')).not.toBeNull() + }) +}) diff --git a/resources/assets/tests/webpack.d.ts b/resources/assets/tests/webpack.d.ts index 1a135a4b..8c582452 100644 --- a/resources/assets/tests/webpack.d.ts +++ b/resources/assets/tests/webpack.d.ts @@ -5,9 +5,5 @@ declare module '*.vue' { } declare module '*.styl' { - export default {} -} - -declare module '*.yml' { - export default {} + export default {} as Record } diff --git a/tsconfig.json b/tsconfig.json index a098af7f..6ee8f133 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,22 +5,10 @@ "module": "esnext", "moduleResolution": "node", "baseUrl": ".", - "paths": { - "@/scripts/*": [ - "./resources/assets/tests/ts-shims/*", - "./resources/assets/src/scripts/*" - ], - "@/components/*": [ - "./resources/assets/src/components/*" - ], - "@/views/*": [ - "./resources/assets/src/views/*" - ] - } + "incremental": true }, - "exclude": [ - "node_modules", - "plugins", - "vendor" + "include": [ + "resources/assets/src", + "resources/assets/webpack.d.ts" ] } diff --git a/webpack.config.js b/webpack.config.js index b80ea95f..48472f4c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -12,7 +12,7 @@ const devMode = !process.argv.includes('-p') const config = { mode: devMode ? 'development' : 'production', entry: { - app: './resources/assets/src/index.ts', + app: ['react-hot-loader/patch', './resources/assets/src/index.tsx'], 'language-chooser': './resources/assets/src/scripts/language-chooser.ts', style: [ 'bootstrap/dist/css/bootstrap.min.css', @@ -46,8 +46,7 @@ const config = { use: ['cache-loader', 'vue-loader'], }, { - test: /\.(css|styl(us)?)$/, - exclude: /node_modules/, + test: /\.vue.*\.stylus$/, use: [ 'vue-style-loader', { loader: 'css-loader', options: { importLoaders: 2 } }, @@ -55,6 +54,25 @@ const config = { 'stylus-loader', ], }, + { + test: /views.*\.styl$/, + use: [ + 'style-loader', + { + loader: 'css-loader', + options: { + importLoaders: 2, + modules: { + localIdentName: devMode ? '[name]__[local]' : '[hash:base64]', + }, + localsConvention: 'dashes', + esModule: true, + }, + }, + 'postcss-loader', + 'stylus-loader', + ], + }, { test: /(node_modules.*)\.css$/, use: [ @@ -93,7 +111,10 @@ const config = { }), ], resolve: { - extensions: ['.js', '.ts', '.vue', '.json'], + extensions: ['.js', '.ts', '.tsx', '.vue', '.json'], + alias: { + 'react-dom': '@hot-loader/react-dom', + }, }, optimization: { minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})], diff --git a/yarn.lock b/yarn.lock index 4a14fb23..6cbd0f92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -828,6 +828,13 @@ levenary "^1.1.0" semver "^5.5.0" +"@babel/runtime@^7.6.2", "@babel/runtime@^7.7.6": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1" + integrity sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/runtime@^7.8.0": version "7.8.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.0.tgz#8c81711517c56b3d00c6de706b0fb13dc3531549" @@ -960,6 +967,16 @@ resolved "https://registry.npmjs.org/@gplane/tsconfig/-/tsconfig-1.0.0.tgz#c7e6d56ece3d045abe46d00aece990d8412440f0" integrity sha512-x0Lxt+oBXGVK8qYYLQvohFYQZlt9KgeVfkGAEXWOq38Gxu5KdcsGzPvyWPMhz5Og/U2pWXbjw4+rN4Qa7CPiWQ== +"@hot-loader/react-dom@^16.11.0": + version "16.11.0" + resolved "https://registry.yarnpkg.com/@hot-loader/react-dom/-/react-dom-16.11.0.tgz#c0b483923b289db5431516f56ee2a69448ebf9bd" + integrity sha512-cIOVB8YgT4EVCNiXK+gGuYl6adW/TKlW3N7GvgY5QgpL2NTWagF/oJxVscHSdR3O7NjJsoxdseB5spqwCHNIhA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.17.0" + "@jest/console@^24.7.1": version "24.7.1" resolved "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545" @@ -1131,11 +1148,37 @@ resolved "https://registry.yarnpkg.com/@lgaitan/pace-progress/-/pace-progress-1.0.7.tgz#c96fbbd9fd4cf528feed34ea0c8f9d8b3e98f0dd" integrity sha1-yW+72f1M9Sj+7TTqDI+diz6Y8N0= +"@sheerun/mutationobserver-shim@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b" + integrity sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q== + "@sweetalert2/theme-bootstrap-4@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@sweetalert2/theme-bootstrap-4/-/theme-bootstrap-4-2.2.1.tgz#a0e3496f2d5aa2993f8fe1c59dcec0673941cddb" integrity sha512-EzAc/HFO16wuZCmawdv0mxRknXtQ5XYmms8gHCcRBqVJsolwl0xKanH8wC2tf4O6dFLou6ZndNqii8ArQO66pA== +"@testing-library/dom@^6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-6.11.0.tgz#962a38f1a721fdb7c9e35e7579e33ff13a00eda4" + integrity sha512-Pkx9LMIGshyNbfmecjt18rrAp/ayMqGH674jYER0SXj0iG9xZc+zWRjk2Pg9JgPBDvwI//xGrI/oOQkAi4YEew== + dependencies: + "@babel/runtime" "^7.6.2" + "@sheerun/mutationobserver-shim" "^0.3.2" + "@types/testing-library__dom" "^6.0.0" + aria-query "3.0.0" + pretty-format "^24.9.0" + wait-for-expect "^3.0.0" + +"@testing-library/react@^9.4.0": + version "9.4.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-9.4.0.tgz#b021ac8cb987c8dc54c6841875f745bf9b2e88e5" + integrity sha512-XdhDWkI4GktUPsz0AYyeQ8M9qS/JFie06kcSnUVcpgOwFjAu9vhwR83qBl+lw9yZWkbECjL8Hd+n5hH6C0oWqg== + dependencies: + "@babel/runtime" "^7.7.6" + "@testing-library/dom" "^6.11.0" + "@types/testing-library__react" "^9.1.2" + "@ttskch/select2-bootstrap4-theme@^1.3.2": version "1.3.2" resolved "https://registry.yarnpkg.com/@ttskch/select2-bootstrap4-theme/-/select2-bootstrap4-theme-1.3.2.tgz#c9e17e34fb2cfd9f41b8efe3584165ccbdd96969" @@ -1274,11 +1317,31 @@ resolved "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f" integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w== +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + "@types/q@^1.5.1": version "1.5.2" resolved "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/react-dom@*", "@types/react-dom@^16.9.4": + version "16.9.4" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df" + integrity sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^16.9.17": + version "16.9.17" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.17.tgz#58f0cc0e9ec2425d1441dd7b623421a867aa253e" + integrity sha512-UP27In4fp4sWF5JgyV6pwVPAQM83Fj76JOcg02X5BZcpSu5Wx+fP9RMqc2v0ssBoQIFvD5JdKY41gjJJKmw6Bg== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/sizzle@*": version "2.3.2" resolved "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" @@ -1299,6 +1362,21 @@ resolved "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== +"@types/testing-library__dom@*", "@types/testing-library__dom@^6.0.0": + version "6.11.1" + resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-6.11.1.tgz#6058a6ac391db679f7c60dbb27b81f0620de2dd9" + integrity sha512-ImChHtQqmjwraRLqBC2sgSQFtczeFvBmBcfhTYZn/3KwXbyD07LQykEQ0xJo7QHc1GbVvf7pRyGaIe6PkCdxEw== + dependencies: + pretty-format "^24.3.0" + +"@types/testing-library__react@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@types/testing-library__react/-/testing-library__react-9.1.2.tgz#e33af9124c60a010fc03a34eff8f8a34a75c4351" + integrity sha512-CYaMqrswQ+cJACy268jsLAw355DZtPZGt3Jwmmotlcu8O/tkoXBI6AeZ84oZBJsIsesozPKzWzmv/0TIU+1E9Q== + dependencies: + "@types/react-dom" "*" + "@types/testing-library__dom" "*" + "@types/uglify-js@*": version "3.0.4" resolved "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" @@ -1842,6 +1920,14 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -1937,6 +2023,11 @@ ast-transform@0.0.0: esprima "~1.0.4" through "~2.3.4" +ast-types-flow@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + ast-types@^0.7.0: version "0.7.8" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.7.8.tgz#902d2e0d60d071bdcd46dc115e1809ed11c138a9" @@ -2734,6 +2825,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^2.11.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^2.20.0, commander@~2.20.0: version "2.20.0" resolved "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" @@ -3171,6 +3267,11 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" +csstype@^2.2.0: + version "2.6.8" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.8.tgz#0fb6fc2417ffd2816a418c9336da74d7f07db431" + integrity sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA== + cyclist@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" @@ -3657,6 +3758,11 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= + domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" @@ -4358,7 +4464,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-levenshtein@~2.0.4, fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -4790,6 +4896,14 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" +global@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -4947,6 +5061,13 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#101685d3aff3b23ea213163f6e8e12f4f111e19f" + integrity sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw== + dependencies: + react-is "^16.7.0" + homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -6394,7 +6515,7 @@ loglevel@^1.6.6: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -6626,6 +6747,13 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + mini-css-extract-plugin@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" @@ -7938,7 +8066,7 @@ pretty-format@^22.4.3: ansi-regex "^3.0.0" ansi-styles "^3.2.0" -pretty-format@^24.9.0: +pretty-format@^24.3.0, pretty-format@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== @@ -7985,6 +8113,15 @@ prompts@^2.0.1: kleur "^3.0.2" sisteransi "^1.0.0" +prop-types@^15.6.1, prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + proxy-addr@~2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" @@ -8154,11 +8291,54 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-dom@^16.12.0: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11" + integrity sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.18.0" + +react-hot-loader@^4.12.18: + version "4.12.18" + resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.18.tgz#a9029e34af2690d76208f9a35189d73c2dfea6a7" + integrity sha512-qYD0Qi9lIbg9jLyfmodfqvAQqCBsoPKxAhca8Nxvy2/2pO5Q9r2kM28jN0bbbSnhwK8dJ7FjsfVtXKOxMW+bqw== + dependencies: + fast-levenshtein "^2.0.6" + global "^4.3.0" + hoist-non-react-statics "^3.3.0" + loader-utils "^1.1.0" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + shallowequal "^1.1.0" + source-map "^0.7.3" + +react-is@^16.7.0, react-is@^16.8.1: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" + integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== + react-is@^16.8.4: version "16.8.6" resolved "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react@^16.12.0: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.12.0.tgz#0c0a9c6a142429e3614834d5a778e18aa78a0b83" + integrity sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + read-pkg-up@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" @@ -8564,6 +8744,22 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +scheduler@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe" + integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +scheduler@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" + integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -8743,6 +8939,11 @@ shallow-copy@~0.0.1: resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" integrity sha1-QV9CcC1z2BAzApLMXuhurhoRoXA= +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -10019,6 +10220,11 @@ w3c-hr-time@^1.0.1: dependencies: browser-process-hrtime "^0.1.2" +wait-for-expect@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-3.0.1.tgz#ec204a76b0038f17711e575720aaf28505ac7185" + integrity sha512-3Ha7lu+zshEG/CeHdcpmQsZnnZpPj/UsG3DuKO8FskjuDbkx3jE3845H+CuwZjA2YWYDfKMU2KhnCaXMLd3wVw== + walker@^1.0.7, walker@~1.0.5: version "1.0.7" resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"