diff --git a/.env b/.env index 2874b4a976..5183e318c7 100644 --- a/.env +++ b/.env @@ -23,6 +23,7 @@ PUBLISHER_BASE_URL='' REFRESH_ACCESS_TOKEN_ENDPOINT='' SEGMENT_KEY='' SITE_NAME='' +STUDIO_SHORT_NAME='Studio' SUPPORT_EMAIL='' SUPPORT_URL='' USER_INFO_COOKIE_NAME='' @@ -30,16 +31,11 @@ ENABLE_ACCESSIBILITY_PAGE=false ENABLE_PROGRESS_GRAPH_SETTINGS=false ENABLE_TEAM_TYPE_SETTING=false ENABLE_NEW_EDITOR_PAGES=true -ENABLE_NEW_HOME_PAGE = false ENABLE_NEW_COURSE_OUTLINE_PAGE = false -ENABLE_NEW_UPDATES_PAGE = false ENABLE_NEW_VIDEO_UPLOAD_PAGE = false -ENABLE_NEW_GRADING_PAGE = false -ENABLE_NEW_COURSE_TEAM_PAGE = false -ENABLE_NEW_IMPORT_PAGE = false -ENABLE_NEW_EXPORT_PAGE = false ENABLE_UNIT_PAGE = false ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN = false +ENABLE_TAGGING_TAXONOMY_PAGES = false BBB_LEARN_MORE_URL='' HOTJAR_APP_ID='' HOTJAR_VERSION=6 diff --git a/.env.development b/.env.development index b17611fad3..4b98461d45 100644 --- a/.env.development +++ b/.env.development @@ -25,6 +25,7 @@ REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh' SEGMENT_KEY=null SITE_NAME='Your Plaform Name Here' STUDIO_BASE_URL='http://localhost:18010' +STUDIO_SHORT_NAME='Studio' SUPPORT_EMAIL= SUPPORT_URL='https://support.edx.org' USER_INFO_COOKIE_NAME='edx-user-info' @@ -32,16 +33,11 @@ ENABLE_ACCESSIBILITY_PAGE=false ENABLE_PROGRESS_GRAPH_SETTINGS=false ENABLE_TEAM_TYPE_SETTING=false ENABLE_NEW_EDITOR_PAGES=true -ENABLE_NEW_HOME_PAGE = false ENABLE_NEW_COURSE_OUTLINE_PAGE = false -ENABLE_NEW_UPDATES_PAGE = false ENABLE_NEW_VIDEO_UPLOAD_PAGE = false -ENABLE_NEW_GRADING_PAGE = false -ENABLE_NEW_COURSE_TEAM_PAGE = false -ENABLE_NEW_IMPORT_PAGE = false -ENABLE_NEW_EXPORT_PAGE = false ENABLE_UNIT_PAGE = false ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN = false +ENABLE_TAGGING_TAXONOMY_PAGES = true BBB_LEARN_MORE_URL='' HOTJAR_APP_ID='' HOTJAR_VERSION=6 diff --git a/.env.test b/.env.test index 8a57403943..8c810bb90b 100644 --- a/.env.test +++ b/.env.test @@ -22,21 +22,17 @@ REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh' SEGMENT_KEY=null SITE_NAME='edX' STUDIO_BASE_URL='http://localhost:18010' +STUDIO_SHORT_NAME='Studio' SUPPORT_EMAIL='support@example.com' SUPPORT_URL='https://support.edx.org' USER_INFO_COOKIE_NAME='edx-user-info' ENABLE_PROGRESS_GRAPH_SETTINGS=false ENABLE_TEAM_TYPE_SETTING=false ENABLE_NEW_EDITOR_PAGES=true -ENABLE_NEW_HOME_PAGE = false ENABLE_NEW_COURSE_OUTLINE_PAGE = true -ENABLE_NEW_UPDATES_PAGE = true ENABLE_NEW_VIDEO_UPLOAD_PAGE = true -ENABLE_NEW_GRADING_PAGE = true -ENABLE_NEW_COURSE_TEAM_PAGE = true -ENABLE_NEW_IMPORT_PAGE = true -ENABLE_NEW_EXPORT_PAGE = true ENABLE_UNIT_PAGE = true ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN = true +ENABLE_TAGGING_TAXONOMY_PAGES = true BBB_LEARN_MORE_URL='' INVITE_STUDENTS_EMAIL_TO="someone@domain.com" diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index fec11d6c25..23163aa640 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -1,10 +1,43 @@ # Run commitlint on the commit messages in a pull request. +# +# This is the same worflow of +# https://github.com/openedx/.github/blob/master/.github/workflows/commitlint.yml +# +# We are using typescript with react-query on this MFE, and it is necessary +# to add one more step to remove tsconfig.json due to an issue in commitlint. +# https://github.com/conventional-changelog/commitlint/issues/3256 +# +# We can return use the open edx workflow when the issue is fixed. name: Lint Commit Messages on: - pull_request +defaults: + run: + shell: bash + jobs: commitlint: - uses: openedx/.github/.github/workflows/commitlint.yml@master + runs-on: ubuntu-20.04 + steps: + - name: Check out the repo + uses: actions/checkout@v4 + with: + # Fetch 100 commits. Should be enough? + fetch-depth: 100 + + - name: Download a local configuration file if needed + run: | + if [[ ! -f commitlint.config.js ]]; then + echo "Downloading the default commitlint config from edx_lint" + wget --no-verbose -O commitlint.config.js https://raw.githubusercontent.com/openedx/edx-lint/HEAD/edx_lint/files/commitlint.config.js + fi + + - name: remove tsconfig.json # see issue https://github.com/conventional-changelog/commitlint/issues/3256 + run: | + rm -f tsconfig.json + + - name: Run commitlint + uses: wagoid/commitlint-github-action@v5 diff --git a/.stylelintrc.json b/.stylelintrc.json index 43148337a9..7c00badf8b 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -8,7 +8,7 @@ "ignoreUnits": ["\\.5"] }], "property-no-vendor-prefix": [true, { - "ignoreProperties": ["animation", "filter"] + "ignoreProperties": ["animation", "filter", "transform", "transition"] }], "value-no-vendor-prefix": [true, { "ignoreValues": ["fill-available"] diff --git a/Makefile b/Makefile index f576f0fee4..f7cf268afb 100644 --- a/Makefile +++ b/Makefile @@ -8,14 +8,14 @@ i18n = ./src/i18n transifex_input = $(i18n)/transifex_input.json # This directory must match .babelrc . -transifex_temp = ./temp/babel-plugin-react-intl +transifex_temp = ./temp/babel-plugin-formatjs precommit: npm run lint npm audit requirements: - npm install + npm ci i18n.extract: # Pulling display strings from .jsx files into .json files... @@ -72,6 +72,7 @@ validate: make validate-no-uncommitted-package-lock-changes npm run i18n_extract npm run lint -- --max-warnings 0 + npm run types npm run test npm run build diff --git a/README.rst b/README.rst index 0b2fcbc708..8959458aa7 100644 --- a/README.rst +++ b/README.rst @@ -1,20 +1,70 @@ -|Build Status| |Codecov| |license| - -############################# frontend-app-course-authoring ############################# -Please tag `@edx/teaching-and-learning `_ on any PRs or issues. Thanks. +|license-badge| |status-badge| |codecov-badge| -************ -Introduction -************ + +Purpose +******* This is the Course Authoring micro-frontend, currently under development by `2U `_. Its purpose is to provide both a framework and UI for new or replacement React-based authoring features outside ``edx-platform``. You can find the current set described below. -******** + +Getting Started +************ + +Prerequisites +============= + +The `devstack`_ is currently recommended as a development environment for your +new MFE. If you start it with ``make dev.up.lms`` that should give you +everything you need as a companion to this frontend. + +Note that it is also possible to use `Tutor`_ to develop an MFE. You can refer +to the `relevant tutor-mfe documentation`_ to get started using it. + +.. _Devstack: https://github.com/openedx/devstack + +.. _Tutor: https://github.com/overhangio/tutor + +.. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe#mfe-development + +Configuration +============= + +All features that integrate into the edx-platform CMS require that the ``COURSE_AUTHORING_MICROFRONTEND_URL`` Django setting is set in the CMS environment and points to this MFE's deployment URL. This should be done automatically if you are using devstack or tutor-mfe. + +Cloning and Startup +=================== + + +1. Clone the repo: + + ``git clone https://github.com/openedx/frontend-app-course-authoring.git`` + +2. Use node v18.x. + + The current version of the micro-frontend build scripts support node 18. + Using other major versions of node *may* work, but this is unsupported. For + convenience, this repository includes an .nvmrc file to help in setting the + correct node version via `nvm use`_. + +3. Install npm dependencies: + + ``cd frontend-app-course-authoring && npm install`` + + +4. Start the dev server: + + ``npm start`` + + +The dev server is running at `http://localhost:2001 `_. +or whatever port you setup. + + Features ******** @@ -23,14 +73,12 @@ Feature: Pages and Resources Studio Tab Enables a "Pages & Resources" menu item in Studio, under the "Content" menu. +.. image:: ./docs/readme-images/feature-pages-resources.png + Requirements ------------ -The following are external requirements for this feature to function correctly: - -* ``edx-platform`` Django settings: - - * ``COURSE_AUTHORING_MICROFRONTEND_URL``: must be set in the CMS environment and point to this MFE's deployment URL. +The following are requirements for this feature to function correctly: * ``edx-platform`` Waffle flags: @@ -79,15 +127,13 @@ For a particular course, this page allows one to: Feature: New React XBlock Editors ================================= +.. image:: ./docs/readme-images/feature-problem-editor.png + This allows an operator to enable the use of new React editors for the HTML, Video, and Problem XBlocks, all of which are provided here. Requirements ------------ -* ``edx-platform`` Django settings: - - * ``COURSE_AUTHORING_MICROFRONTEND_URL``: must be set in the CMS environment and point to this MFE's deployment URL. - * ``edx-platform`` Waffle flags: * ``new_core_editors.use_new_text_editor``: must be enabled for the new HTML Xblock editor to be used in Studio @@ -99,7 +145,7 @@ Configuration In additional to the standard settings, the following local configuration item is required: -* ``ENABLE_NEW_EDITOR_PAGES``: must be enabled in order to actually present the new XBlock editors +* ``ENABLE_NEW_EDITOR_PAGES``: must be enabled in order to actually present the new XBlock editors (on by default) Feature Description ------------------- @@ -113,12 +159,13 @@ When a corresponding waffle flag is set, upon editing a block in Studio, the vie Feature: New Proctoring Exams View ================================== +.. image:: ./docs/readme-images/feature-proctored-exams.png + Requirements ------------ * ``edx-platform`` Django settings: - * ``COURSE_AUTHORING_MICROFRONTEND_URL``: must be set in the CMS environment and point to this MFE's deployment URL. * ``ZENDESK_*``: necessary if automatic ZenDesk ticket creation is desired * ``edx-platform`` Feature flags: @@ -144,34 +191,94 @@ In Studio, a new item ("Proctored Exam Settings") is added to "Other Course Sett * Select a proctoring provider * Enable automatic creation of Zendesk tickets for "suspicious" proctored exam attempts +Feature: Advanced Settings +========================== -********** -Developing -********** +.. image:: ./docs/readme-images/feature-advanced-settings.png -`Devstack `_. If you start Devstack with ``make dev.up.studio`` that should give you everything you need as a companion to this frontend. +Requirements +------------ -Installation and Startup -======================== +* ``edx-platform`` Waffle flags: -1. Clone the repo: + * ``contentstore.new_studio_mfe.use_new_advanced_settings_page``: this feature flag must be enabled for the link to the settings view to be shown. It can be enabled on a per-course basis. - ``git clone https://github.com/openedx/frontend-app-course-authoring.git`` +Feature Description +------------------- -2. Install npm dependencies: +In Studio, the "Advanced Settings" page for each enabled course will now be served by this frontend, instead of the UI built into edx-platform. The advanced settings page holds many different settings for the course, such as what features or XBlocks are enabled. - ``cd frontend-app-course-authoring && npm install`` +Feature: Files & Uploads +========================== -3. Start the dev server: +.. image:: ./docs/readme-images/feature-files-uploads.png - ``npm start`` +Requirements +------------ + +* ``edx-platform`` Waffle flags: + + * ``contentstore.new_studio_mfe.use_new_files_uploads_page``: this feature flag must be enabled for the link to the Files & Uploads page to go to the MFE. It can be enabled on a per-course basis. + +Feature Description +------------------- + +In Studio, the "Files & Uploads" page for each enabled course will now be served by this frontend, instead of the UI built into edx-platform. This page allows managing static asset files like PDFs, images, etc. used for the course. + +Feature: Course Updates +========================== + +.. image:: ./docs/readme-images/feature-course-updates.png + +Requirements +------------ + +* ``edx-platform`` Waffle flags: + + * ``contentstore.new_studio_mfe.use_new_updates_page``: this feature flag must be enabled. + +Feature: Import/Export Pages +============================ + +.. image:: ./docs/readme-images/feature-export.png + +Requirements +------------ + +* ``edx-platform`` Waffle flags: + + * ``contentstore.new_studio_mfe.use_new_export_page``: this feature flag will change the CMS to link to the new export page. + * ``contentstore.new_studio_mfe.use_new_import_page``: this feature flag will change the CMS to link to the new import page. + +Feature: Tagging/Taxonomy Pages +================================ + +.. image:: ./docs/readme-images/feature-tagging-taxonomy-pages.png + +Requirements +------------ + +* ``edx-platform`` Waffle flags: + + * ``contentstore.new_studio_mfe.use_tagging_taxonomy_list_page``: this feature flag must be enabled. + +Configuration +------------- + +In additional to the standard settings, the following local configuration items are required: + +* ``ENABLE_TAGGING_TAXONOMY_PAGES``: must be enabled in order to actually present the new Tagging/Taxonomy pages. + + +Developing +********** + +`Devstack `_. If you start Devstack with ``make dev.up.studio`` that should give you everything you need as a companion to this frontend. -The dev server is running at `http://localhost:2001 `_. If your devstack includes the default Demo course, you can visit the following URLs to see content: -- `Proctored Exam Settings `_ -- `Pages and Resources `_ (work in progress) +- `Pages and Resources `_ Troubleshooting ======================== @@ -182,7 +289,7 @@ Troubleshooting If there is still an error, look for "no package [...] found" in the error message and install missing package via brew. (https://github.com/Automattic/node-canvas/issues/1733) -********* + Deploying ********* @@ -197,3 +304,92 @@ The production build is created with ``npm run build``. :target: https://codecov.io/gh/edx/frontend-app-course-authoring .. |license| image:: https://img.shields.io/npm/l/@edx/frontend-app-course-authoring.svg :target: @edx/frontend-app-course-authoring + +Internationalization +==================== + +Please see refer to the `frontend-platform i18n howto`_ for documentation on +internationalization. + +.. _frontend-platform i18n howto: https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst + + +Getting Help +************ + +If you're having trouble, we have discussion forums at +https://discuss.openedx.org where you can connect with others in the community. + +Our real-time conversations are on Slack. You can request a `Slack +invitation`_, then join our `community Slack workspace`_. Because this is a +frontend repository, the best place to discuss it would be in the `#wg-frontend +channel`_. + +For anything non-trivial, the best path is to open an issue in this repository +with as many details about the issue you are facing as you can provide. + +https://github.com/openedx/frontend-app-course-authoring/issues + +For more information about these options, see the `Getting Help`_ page. + +.. _Slack invitation: https://openedx.org/slack +.. _community Slack workspace: https://openedx.slack.com/ +.. _#wg-frontend channel: https://openedx.slack.com/archives/C04BM6YC7A6 +.. _Getting Help: https://openedx.org/community/connect + + +License +******* + +The code in this repository is licensed under the AGPLv3 unless otherwise +noted. + +Please see `LICENSE `_ for details. + + +Contributing +************ + +Contributions are very welcome. Please read `How To Contribute`_ for details. + +.. _How To Contribute: https://openedx.org/r/how-to-contribute + +This project is currently accepting all types of contributions, bug fixes, +security fixes, maintenance work, or new features. However, please make sure +to have a discussion about your new feature idea with the maintainers prior to +beginning development to maximize the chances of your change being accepted. +You can start a conversation by creating a new issue on this repo summarizing +your idea. + + +The Open edX Code of Conduct +**************************** + +All community members are expected to follow the `Open edX Code of Conduct`_. + +.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/ + +People +****** + +The assigned maintainers for this component and other project details may be +found in `Backstage`_. Backstage pulls this data from the ``catalog-info.yaml`` +file in this repo. + +.. _Backstage: https://open-edx-backstage.herokuapp.com/catalog/default/component/frontend-app-course-authoring + + +Reporting Security Issues +************************* + +Please do not report security issues in public, and email security@openedx.org instead. + +.. |license-badge| image:: https://img.shields.io/github/license/openedx/frontend-app-course-authoring.svg + :target: https://github.com/openedx/frontend-app-course-authoring/blob/master/LICENSE + :alt: License + +.. |status-badge| image:: https://img.shields.io/badge/Status-Maintained-brightgreen + +.. |codecov-badge| image:: https://codecov.io/github/openedx/frontend-app-course-authoring/coverage.svg?branch=master + :target: https://codecov.io/github/openedx/frontend-app-course-authoring?branch=master + :alt: Codecov diff --git a/codecov.yml b/codecov.yml index c41479bad7..64b8f80010 100644 --- a/codecov.yml +++ b/codecov.yml @@ -8,3 +8,6 @@ coverage: default: target: auto threshold: 0% +ignore: + - "src/grading-settings/grading-scale/react-ranger.js" + - "src/index.js" diff --git a/docs/readme-images/feature-advanced-settings.png b/docs/readme-images/feature-advanced-settings.png new file mode 100644 index 0000000000..73df080e17 Binary files /dev/null and b/docs/readme-images/feature-advanced-settings.png differ diff --git a/docs/readme-images/feature-course-updates.png b/docs/readme-images/feature-course-updates.png new file mode 100644 index 0000000000..2bc9620fd7 Binary files /dev/null and b/docs/readme-images/feature-course-updates.png differ diff --git a/docs/readme-images/feature-export.png b/docs/readme-images/feature-export.png new file mode 100644 index 0000000000..fbbec31d66 Binary files /dev/null and b/docs/readme-images/feature-export.png differ diff --git a/docs/readme-images/feature-files-uploads.png b/docs/readme-images/feature-files-uploads.png new file mode 100644 index 0000000000..a13132223b Binary files /dev/null and b/docs/readme-images/feature-files-uploads.png differ diff --git a/docs/readme-images/feature-pages-resources.png b/docs/readme-images/feature-pages-resources.png new file mode 100644 index 0000000000..8b2316f280 Binary files /dev/null and b/docs/readme-images/feature-pages-resources.png differ diff --git a/docs/readme-images/feature-problem-editor.png b/docs/readme-images/feature-problem-editor.png new file mode 100644 index 0000000000..75f3504e62 Binary files /dev/null and b/docs/readme-images/feature-problem-editor.png differ diff --git a/docs/readme-images/feature-proctored-exams.png b/docs/readme-images/feature-proctored-exams.png new file mode 100644 index 0000000000..e0b25d9f27 Binary files /dev/null and b/docs/readme-images/feature-proctored-exams.png differ diff --git a/docs/readme-images/feature-tagging-taxonomy-pages.png b/docs/readme-images/feature-tagging-taxonomy-pages.png new file mode 100644 index 0000000000..e27c469c51 Binary files /dev/null and b/docs/readme-images/feature-tagging-taxonomy-pages.png differ diff --git a/package-lock.json b/package-lock.json index ee028fa967..067c3894a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,63 +9,82 @@ "version": "0.1.0", "license": "AGPL-3.0", "dependencies": { - "@edx/brand": "npm:@edx/brand-openedx@1.1.0", - "@edx/frontend-component-footer": "12.0.0", - "@edx/frontend-enterprise-hotjar": "^1.2.1", - "@edx/frontend-lib-content-components": "^1.169.0", - "@edx/frontend-platform": "4.2.0", - "@edx/paragon": "^20.45.4", - "@fortawesome/fontawesome-svg-core": "1.2.28", - "@fortawesome/free-brands-svg-icons": "5.11.2", - "@fortawesome/free-regular-svg-icons": "5.11.2", - "@fortawesome/free-solid-svg-icons": "5.11.2", - "@fortawesome/react-fontawesome": "0.1.9", + "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", + "@edx/frontend-component-footer": "^12.3.0", + "@edx/frontend-component-header": "^4.7.0", + "@edx/frontend-enterprise-hotjar": "^2.0.0", + "@edx/frontend-lib-content-components": "1.175.1", + "@edx/frontend-platform": "5.6.1", + "@edx/paragon": "^21.5.6", + "@fortawesome/fontawesome-svg-core": "1.2.36", + "@fortawesome/free-brands-svg-icons": "5.15.4", + "@fortawesome/free-regular-svg-icons": "5.15.4", + "@fortawesome/free-solid-svg-icons": "5.15.4", + "@fortawesome/react-fontawesome": "0.2.0", "@reduxjs/toolkit": "1.5.0", + "@tanstack/react-query": "4.36.1", "classnames": "2.2.6", "core-js": "3.8.1", "email-validator": "2.0.4", + "file-saver": "^2.0.5", "formik": "2.2.6", "jszip": "^3.10.1", "lodash": "4.17.21", - "moment": "2.29.2", + "moment": "2.29.4", "prop-types": "15.7.2", - "react": "16.14.0", + "react": "17.0.2", "react-datepicker": "^4.13.0", - "react-dom": "16.14.0", + "react-dom": "17.0.2", "react-helmet": "^6.1.0", - "react-ranger": "^2.1.0", - "react-redux": "7.1.3", - "react-responsive": "8.1.0", - "react-router": "5.2.0", - "react-router-dom": "5.2.0", + "react-redux": "7.2.9", + "react-responsive": "9.0.2", + "react-router": "6.16.0", + "react-router-dom": "6.16.0", "react-textarea-autosize": "^8.4.1", - "react-transition-group": "4.4.1", + "react-transition-group": "4.4.5", "redux": "4.0.5", "regenerator-runtime": "0.13.7", + "universal-cookie": "^4.0.4", "uuid": "^3.4.0", "yup": "0.31.1" }, "devDependencies": { - "@edx/browserslist-config": "1.0.0", - "@edx/frontend-build": "12.8.6", + "@edx/browserslist-config": "1.2.0", + "@edx/frontend-build": "13.0.4", "@edx/reactifex": "^1.0.3", "@edx/stylelint-config-edx": "^2.3.0", - "@testing-library/jest-dom": "5.16.4", - "@testing-library/react": "12.1.1", + "@edx/typescript-config": "^1.0.1", + "@testing-library/jest-dom": "5.17.0", + "@testing-library/react": "12.1.5", "@testing-library/user-event": "^13.2.1", + "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "axios-mock-adapter": "1.20.0", "enzyme": "3.11.0", - "enzyme-adapter-react-16": "1.15.6", "enzyme-to-json": "^3.6.2", - "glob": "7.1.6", - "husky": "3.1.0", - "react-test-renderer": "16.9.0", - "reactifex": "1.1.1" + "glob": "7.2.3", + "husky": "7.0.4", + "jest-canvas-mock": "^2.5.2", + "react-test-renderer": "17.0.2", + "reactifex": "1.1.1", + "ts-loader": "^9.5.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "engines": { + "node": ">=0.10.0" } }, + "node_modules/@adobe/css-tools": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.1.tgz", + "integrity": "sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==", + "dev": true + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", @@ -76,9 +95,9 @@ } }, "node_modules/@babel/cli": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.5.tgz", + "integrity": "sha512-N5d7MjzwsQ2wppwjhrsicVDhJSqF9labEP/swYiHhio4Ca2XjEehpgPmerjnLQl7BPE59BLud0PTWGYwqFl/cQ==", "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "commander": "^4.0.1", @@ -103,59 +122,41 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/cli/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.0", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.0", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.0", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -171,13 +172,13 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.19.1", - "dev": true, - "license": "MIT", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.9.tgz", + "integrity": "sha512-xdMkt39/nviO/4vpVdrEYPwXCsYIXSSAr6mC7WQsNIlGnuxKyKE7GZjalcnbSWiC4OXGNNN3UQPeHfjSC6sTDA==", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || >=14.0.0" @@ -187,12 +188,20 @@ "eslint": "^7.5.0 || ^8.0.0" } }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", + "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", "dependencies": { - "@babel/types": "^7.21.4", + "@babel/types": "^7.22.15", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -203,7 +212,6 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -215,59 +223,64 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-member-expression-to-functions": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/helper-split-export-declaration": "^7.18.6" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -276,13 +289,22 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.3.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -291,132 +313,127 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "dev": true, - "license": "MIT", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.6" - }, + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", + "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", "dependencies": { - "@babel/types": "^7.21.0" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "dev": true, - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "dev": true, - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -426,112 +443,111 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.20.7", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dependencies": { - "@babel/types": "^7.20.2" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.20.0", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dependencies": { - "@babel/types": "^7.20.0" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "dev": true, - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.20.5", - "dev": true, - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", + "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -539,9 +555,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -550,11 +566,11 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", + "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -564,13 +580,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", + "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-proposal-optional-chaining": "^7.20.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -579,15 +595,14 @@ "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -596,13 +611,17 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -611,89 +630,69 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.12.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-dynamic-import": { + "node_modules/@babel/plugin-proposal-unicode-property-regex": { "version": "7.18.6", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "dev": true, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "dev": true, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "dev": true, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-plugin-utils": "^7.12.13" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -702,31 +701,34 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=6.9.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -735,159 +737,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.20.0", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -898,7 +753,6 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -909,7 +763,6 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -919,11 +772,11 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -934,7 +787,6 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -945,7 +797,6 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -956,7 +807,6 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -967,7 +817,6 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -978,7 +827,6 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -989,7 +837,6 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1000,8 +847,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1014,7 +861,6 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1027,11 +873,11 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1040,28 +886,27 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-remap-async-to-generator": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1070,12 +915,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", + "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { "node": ">=6.9.0" @@ -1084,12 +932,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1098,20 +948,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-replace-supers": "^7.20.7", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1120,13 +962,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz", + "integrity": "sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/template": "^7.20.7" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1135,12 +976,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.21.3", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1149,27 +991,36 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", + "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" @@ -1178,13 +1029,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1193,12 +1044,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz", + "integrity": "sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1207,14 +1058,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1223,12 +1073,12 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1237,12 +1087,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1251,13 +1102,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.20.11", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", "dependencies": { - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1266,14 +1117,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.21.2", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", "dependencies": { - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-simple-access": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1282,15 +1132,134 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.20.11", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", + "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-identifier": "^7.19.1" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz", + "integrity": "sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz", + "integrity": "sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz", + "integrity": "sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -1300,12 +1269,12 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1315,12 +1284,12 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.20.5", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.20.5", - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1330,11 +1299,59 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", + "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1344,12 +1361,43 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz", + "integrity": "sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1359,11 +1407,43 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.21.3", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", + "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1373,11 +1453,11 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1387,11 +1467,11 @@ } }, "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.21.3", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.22.5.tgz", + "integrity": "sha512-BF5SXoO+nX3h5OhlN78XbbDrBOffv+AxPP2ENaJOVqjWCgBDeOY3WcaUcddutGSfoap+5NEQ/q/4I3WZIvgkXA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1401,11 +1481,11 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", + "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1415,15 +1495,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.21.0", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz", + "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-jsx": "^7.18.6", - "@babel/types": "^7.21.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1433,11 +1513,11 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.18.6" + "@babel/plugin-transform-react-jsx": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1447,12 +1527,12 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz", + "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1462,12 +1542,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.20.5", - "dev": true, - "license": "MIT", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "regenerator-transform": "^0.15.1" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" @@ -1477,11 +1557,11 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1491,11 +1571,11 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1505,12 +1585,12 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1520,11 +1600,11 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1534,11 +1614,11 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1548,11 +1628,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1562,14 +1642,14 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.21.3", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.15.tgz", + "integrity": "sha512-1uirS0TnijxvQLnlv5wQBwOX3E1wCFX7ITv+9pBV2wKEk4K+M5tqDaoNXnTH8tjEIYHLO98MwiTWO04Ggz4XuA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-typescript": "^7.20.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1579,11 +1659,26 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "dev": true, - "license": "MIT", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1593,12 +1688,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1607,38 +1702,41 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.20.2", - "dev": true, - "license": "MIT", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", "dependencies": { - "@babel/compat-data": "^7.20.1", - "@babel/helper-compilation-targets": "^7.20.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.20.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.20.2", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.5.tgz", + "integrity": "sha512-fj06hw89dpiZzGZtxn+QybifF07nNiZjZ7sazs2aVDcysAZVGjW7+7iFYxg6GLNM47R/thYfLdrXc+2f11Vi9A==", + "dependencies": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -1648,44 +1746,61 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.20.2", - "@babel/plugin-transform-classes": "^7.20.2", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.20.2", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.19.6", - "@babel/plugin-transform-modules-commonjs": "^7.19.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.6", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.20.1", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.5", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.5", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.20.2", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.3", + "babel-plugin-polyfill-corejs3": "^0.8.1", + "babel-plugin-polyfill-regenerator": "^0.5.0", + "core-js-compat": "^3.30.2", "semver": "^6.3.0" }, "engines": { @@ -1696,9 +1811,9 @@ } }, "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "dev": true, - "license": "MIT", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -1707,20 +1822,20 @@ "esutils": "^2.0.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/preset-react": { - "version": "7.18.6", - "dev": true, - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.5.tgz", + "integrity": "sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-react-display-name": "^7.18.6", - "@babel/plugin-transform-react-jsx": "^7.18.6", - "@babel/plugin-transform-react-jsx-development": "^7.18.6", - "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-transform-react-display-name": "^7.22.5", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1730,15 +1845,15 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.0.tgz", + "integrity": "sha512-6P6VVa/NM/VlAYj5s2Aq/gdVg8FSENCg3wlZ6Qau9AcPaoF5LbN1nyGlR9DTRIw9PpxI94e+ReydsJHcjwAweg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-validator-option": "^7.21.0", - "@babel/plugin-syntax-jsx": "^7.21.4", - "@babel/plugin-transform-modules-commonjs": "^7.21.2", - "@babel/plugin-transform-typescript": "^7.21.3" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-typescript": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1749,8 +1864,8 @@ }, "node_modules/@babel/regjsgen": { "version": "0.8.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { "version": "7.21.0", @@ -1762,53 +1877,36 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3/node_modules/regenerator-runtime": { - "version": "0.13.11", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/runtime/node_modules/regenerator-runtime": { "version": "0.13.11", "license": "MIT" }, "node_modules/@babel/template": { - "version": "7.20.7", - "dev": true, - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.17.tgz", + "integrity": "sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.16", + "@babel/types": "^7.22.17", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1817,12 +1915,12 @@ } }, "node_modules/@babel/types": { - "version": "7.21.4", - "dev": true, - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1831,12 +1929,11 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" }, "node_modules/@cnakazawa/watch": { "version": "1.0.4", - "dev": true, "license": "Apache-2.0", "dependencies": { "exec-sh": "^0.3.2", @@ -1971,69 +2068,94 @@ } }, "node_modules/@cospired/i18n-iso-languages": { - "version": "2.2.0", - "license": "MIT", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cospired/i18n-iso-languages/-/i18n-iso-languages-4.1.0.tgz", + "integrity": "sha512-5+JK7YiO9r/FmwtlEPL1tQNt04/9AuN1t9GO/0C2yitqhKwFRa1r7VohNNUnFgB84MW5v4Lwq8ZAUZexuJh1nQ==", "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@csstools/cascade-layer-name-parser": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.5.tgz", + "integrity": "sha512-v/5ODKNBMfBl0us/WQjlfsvSlYxfZLhNMVIsuCPib2ulTwGKYbKJbwqw671+qH9Y4wvWVnu7LBChvml/wBKjFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.0.0", - "@csstools/css-tokenizer": "^2.0.0" + "@csstools/css-parser-algorithms": "^2.3.2", + "@csstools/css-tokenizer": "^2.2.1" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.1.0", - "dev": true, - "license": "MIT", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.2.tgz", + "integrity": "sha512-sLYGdAdEY2x7TSw9FtmdaTrh2wFtRJO5VMbBrA8tEqEod7GEggFmxTSK9XqExib3yMuYNcvcTdCZIP6ukdjAIA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.0.0" + "@csstools/css-tokenizer": "^2.2.1" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.1.0", - "dev": true, - "license": "MIT", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.1.tgz", + "integrity": "sha512-Zmsf2f/CaEPWEVgw29odOj+WEVoiJy9s9NOv5GgNY9mZ1CZ7394By6wONrONrTsnNDv6F9hR02nvFihrGVGHBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.0.2", - "dev": true, - "license": "MIT", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.5.tgz", + "integrity": "sha512-IxVBdYzR8pYe89JiyXQuYk4aVVoCPhMJkz6ElRwlVysjwURTsTk/bmY/z4FfeRE+CRBMlykPwXEVUg8lThv7AQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.0.0", - "@csstools/css-tokenizer": "^2.0.0" + "@csstools/css-parser-algorithms": "^2.3.2", + "@csstools/css-tokenizer": "^2.2.1" } }, "node_modules/@csstools/selector-specificity": { @@ -2054,8 +2176,8 @@ }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "engines": { "node": ">=10.0.0" } @@ -2110,19 +2232,20 @@ } }, "node_modules/@edx/brand": { - "name": "@edx/brand-openedx", - "version": "1.1.0", - "license": "GPL-3.0-or-later" + "name": "@openedx/brand-openedx", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@openedx/brand-openedx/-/brand-openedx-1.2.2.tgz", + "integrity": "sha512-mBvxR7aB9290j9+h3d/9G8VkG1b8ecLSmlxc0vskfm7DL/fKUzFmHAj3PI7Z4kkwCQOL4QT5mJHJKC0ZFf7qvQ==" }, "node_modules/@edx/browserslist-config": { - "version": "1.0.0", - "dev": true, - "license": "AGPL-3.0" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@edx/browserslist-config/-/browserslist-config-1.2.0.tgz", + "integrity": "sha512-T1+6P52Yx7SMkmoIr4O0Q3m/DyRdrLTJbv1xVijdRLFEq1hqdafEs+Ln1423U5LSkTePb9AOkEtL1G0RZLFl1w==" }, "node_modules/@edx/eslint-config": { - "version": "3.1.1", - "dev": true, - "license": "MIT", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@edx/eslint-config/-/eslint-config-3.2.0.tgz", + "integrity": "sha512-X2o34xr3KqmQSV/vJVv6k4FxUKYwbBATHTtTHLTYQvM9PVoM3WbKQP9tl6Z057pRErKzshJcks+4ENzDyhr11Q==", "peerDependencies": { "eslint": "^6.8.0 || ^7.0.0 || ^8.0.0", "eslint-config-airbnb": "^18.0.1 || ^19.0.0", @@ -2133,64 +2256,67 @@ } }, "node_modules/@edx/frontend-build": { - "version": "12.8.6", - "dev": true, - "license": "AGPL-3.0", + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/@edx/frontend-build/-/frontend-build-13.0.4.tgz", + "integrity": "sha512-c6i4h19as3vNMIgo+vLNhBk3cM4TOUtBrgYmLrzLtLcWsNZUojnrufrLOdtWmNNKylcBUI9Lvyv++/KrtfJo9w==", "dependencies": { - "@babel/cli": "7.21.0", - "@babel/core": "7.21.0", - "@babel/eslint-parser": "7.19.1", + "@babel/cli": "7.22.5", + "@babel/core": "7.22.5", + "@babel/eslint-parser": "7.22.9", "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-object-rest-spread": "7.20.7", "@babel/plugin-syntax-dynamic-import": "7.8.3", - "@babel/preset-env": "7.20.2", - "@babel/preset-react": "7.18.6", - "@edx/eslint-config": "3.1.1", - "@edx/new-relic-source-map-webpack-plugin": "1.0.2", - "@fullhuman/postcss-purgecss": "^5.0.0", - "@pmmmwh/react-refresh-webpack-plugin": "0.5.10", - "@svgr/webpack": "6.5.1", - "autoprefixer": "10.4.14", + "@babel/preset-env": "7.22.5", + "@babel/preset-react": "7.22.5", + "@edx/eslint-config": "3.2.0", + "@edx/new-relic-source-map-webpack-plugin": "2.1.0", + "@formatjs/cli": "^6.0.3", + "@fullhuman/postcss-purgecss": "5.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", + "@svgr/webpack": "8.1.0", + "autoprefixer": "10.4.16", "babel-jest": "26.6.3", - "babel-loader": "9.1.2", - "babel-plugin-react-intl": "7.9.4", + "babel-loader": "9.1.3", + "babel-plugin-formatjs": "^10.4.0", "babel-plugin-transform-imports": "2.0.0", "babel-polyfill": "6.26.0", - "clean-webpack-plugin": "3.0.0", + "chalk": "4.1.2", + "clean-webpack-plugin": "4.0.0", "css-loader": "5.2.7", - "cssnano": "5.1.15", + "cssnano": "6.0.1", "dotenv": "8.6.0", - "dotenv-webpack": "7.1.1", - "eslint": "8.29.0", + "dotenv-webpack": "8.0.1", + "eslint": "8.44.0", "eslint-config-airbnb": "19.0.4", - "eslint-plugin-import": "2.26.0", - "eslint-plugin-jsx-a11y": "6.6.1", - "eslint-plugin-react": "7.31.11", + "eslint-plugin-import": "2.27.5", + "eslint-plugin-jsx-a11y": "6.7.1", + "eslint-plugin-react": "7.32.2", "eslint-plugin-react-hooks": "4.6.0", + "express": "4.18.2", "file-loader": "6.2.0", - "html-webpack-plugin": "5.5.0", + "html-webpack-plugin": "5.5.3", "identity-obj-proxy": "3.0.0", - "image-minimizer-webpack-plugin": "3.3.0", + "image-minimizer-webpack-plugin": "3.8.3", "jest": "26.6.3", "mini-css-extract-plugin": "1.6.2", - "postcss": "8.4.21", - "postcss-custom-media": "^9.1.2", - "postcss-loader": "6.2.1", - "postcss-rtlcss": "3.7.2", + "postcss": "8.4.31", + "postcss-custom-media": "10.0.2", + "postcss-loader": "7.3.3", + "postcss-rtlcss": "4.0.8", "react-dev-utils": "12.0.1", "react-refresh": "0.14.0", "resolve-url-loader": "5.0.0", - "sass": "1.60.0", - "sass-loader": "12.6.0", - "sharp": "^0.31.0", - "source-map-loader": "^4.0.1", - "style-loader": "3.3.2", + "sass": "1.65.1", + "sass-loader": "13.3.2", + "sharp": "0.32.6", + "source-map-loader": "4.0.1", + "style-loader": "3.3.3", "url-loader": "4.1.1", - "webpack": "5.76.0", - "webpack-bundle-analyzer": "4.5.0", - "webpack-cli": "5.0.1", - "webpack-dev-server": "4.13.2", - "webpack-merge": "5.8.0" + "webpack": "5.88.2", + "webpack-bundle-analyzer": "4.9.1", + "webpack-cli": "5.1.4", + "webpack-dev-server": "4.15.1", + "webpack-merge": "5.9.0" }, "bin": { "fedx-scripts": "bin/fedx-scripts.js" @@ -2199,108 +2325,270 @@ "react": "^16.9.0 || ^17.0.0" } }, + "node_modules/@edx/frontend-build/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@edx/frontend-build/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@edx/frontend-build/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@edx/frontend-build/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@edx/frontend-build/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@edx/frontend-build/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@edx/frontend-component-footer": { - "version": "12.0.0", - "license": "AGPL-3.0", + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.5.1.tgz", + "integrity": "sha512-bLXfSDyyf8z+n4VXkraQ98qhkc+ZXuvRy65kXUE3s560oDv0qdiKU054W8uPY6wtsdu4WQ50C/Mluxzd60UKUg==", "dependencies": { - "@fortawesome/fontawesome-svg-core": "6.4.0", - "@fortawesome/free-brands-svg-icons": "6.4.0", - "@fortawesome/free-regular-svg-icons": "6.4.0", - "@fortawesome/free-solid-svg-icons": "6.4.0", - "@fortawesome/react-fontawesome": "0.2.0" + "@edx/paragon": "^21.3.1", + "@fortawesome/fontawesome-svg-core": "6.4.2", + "@fortawesome/free-brands-svg-icons": "6.4.2", + "@fortawesome/free-regular-svg-icons": "6.4.2", + "@fortawesome/free-solid-svg-icons": "6.4.2", + "@fortawesome/react-fontawesome": "0.2.0", + "lodash": "^4.17.21" }, "peerDependencies": { - "@edx/frontend-platform": "^4.0.0", + "@edx/frontend-platform": "^4.0.0 || ^5.0.0 || ^6.0.0", "prop-types": "^15.5.10", "react": "^16.9.0 || ^17.0.0", "react-dom": "^16.9.0 || ^17.0.0" } }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.4.0", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==", "hasInstallScript": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.4.0", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", "hasInstallScript": true, - "license": "MIT", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.4.0" + "@fortawesome/fontawesome-common-types": "6.4.2" }, "engines": { "node": ">=6" } }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-brands-svg-icons": { - "version": "6.4.0", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz", + "integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==", "hasInstallScript": true, - "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.4.0" + "@fortawesome/fontawesome-common-types": "6.4.2" }, "engines": { "node": ">=6" } }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-regular-svg-icons": { - "version": "6.4.0", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.2.tgz", + "integrity": "sha512-0+sIUWnkgTVVXVAPQmW4vxb9ZTHv0WstOa3rBx9iPxrrrDH6bNLsDYuwXF9b6fGm+iR7DKQvQshUH/FJm3ed9Q==", "hasInstallScript": true, - "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.4.0" + "@fortawesome/fontawesome-common-types": "6.4.2" }, "engines": { "node": ">=6" } }, "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.4.0", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz", + "integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==", "hasInstallScript": true, - "license": "(CC-BY-4.0 AND MIT)", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.4.0" + "@fortawesome/fontawesome-common-types": "6.4.2" }, "engines": { "node": ">=6" } }, - "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/react-fontawesome": { - "version": "0.2.0", - "license": "MIT", + "node_modules/@edx/frontend-component-header": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.9.3.tgz", + "integrity": "sha512-xm99J61OmeHjQpEIfadRiDGZGDO49ZOB00D42ZzKWRkWyuhCmqmc2XnlgYWj3hcfKjsKjcwUzhWms10Yu9HymQ==", "dependencies": { - "prop-types": "^15.8.1" + "@edx/paragon": "21.5.6", + "@fortawesome/fontawesome-svg-core": "6.4.2", + "@fortawesome/free-brands-svg-icons": "6.4.2", + "@fortawesome/free-regular-svg-icons": "6.4.2", + "@fortawesome/free-solid-svg-icons": "6.4.2", + "@fortawesome/react-fontawesome": "^0.2.0", + "axios-mock-adapter": "1.22.0", + "babel-polyfill": "6.26.0", + "react-responsive": "8.2.0", + "react-transition-group": "4.4.5" }, "peerDependencies": { - "@fortawesome/fontawesome-svg-core": "~1 || ~6", - "react": ">=16.3" + "@edx/frontend-platform": "^4.0.0 || ^5.0.0 || ^6.0.0", + "prop-types": "^15.5.10", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0" } }, - "node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/react-fontawesome/node_modules/prop-types": { - "version": "15.8.1", - "license": "MIT", + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", + "hasInstallScript": true, "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz", + "integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.2.tgz", + "integrity": "sha512-0+sIUWnkgTVVXVAPQmW4vxb9ZTHv0WstOa3rBx9iPxrrrDH6bNLsDYuwXF9b6fGm+iR7DKQvQshUH/FJm3ed9Q==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz", + "integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/axios-mock-adapter": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz", + "integrity": "sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, + "node_modules/@edx/frontend-component-header/node_modules/react-responsive": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", + "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==", + "dependencies": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.3.0", + "prop-types": "^15.6.1", + "shallow-equal": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + }, + "peerDependencies": { + "react": ">=16.8.0" } }, "node_modules/@edx/frontend-enterprise-hotjar": { - "version": "1.2.1", - "license": "AGPL-3.0", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@edx/frontend-enterprise-hotjar/-/frontend-enterprise-hotjar-2.0.0.tgz", + "integrity": "sha512-R9MIhysVKPaALKwhengYTZSG32gXka/AnOaSCw/lrV1tWeK4uLl6EP3PSFLXezU5YiFs1NnsDFh7NMlo2FlN7w==", "peerDependencies": { - "react": "^16.12.0", - "react-dom": "^16.12.0", - "react-router-dom": "^5.2.0" + "react": "^16.12.0 || ^17.0.0", + "react-dom": "^16.12.0 || ^17.0.0", + "react-router-dom": "^6.0.0" } }, "node_modules/@edx/frontend-lib-content-components": { - "version": "1.169.0", - "resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-1.169.0.tgz", - "integrity": "sha512-PNs7KntOdF/oyL82dG/GprdKwE6kfO5UnNPJVK2Dh4WBO/rUWuQUfTewxVI61Qyegg+SJKseBHYfxyp9COCN4Q==", + "version": "1.175.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-1.175.1.tgz", + "integrity": "sha512-V9yljFYDF2ttelsBr3uQcPQhgI/ejTBsydDjCTNvJtZ+zRypYdKaIsdYyR9if3T6WpdQ/LwYQ4/vQpDybhCAxA==", "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/lang-xml": "^6.0.0", @@ -2336,26 +2624,22 @@ "xmlchecker": "^0.1.0" }, "peerDependencies": { - "@edx/frontend-platform": "^4.0.0", - "@edx/paragon": "^20.27.0", + "@edx/frontend-platform": "^4.0.0 || ^5.0.0", + "@edx/paragon": "^21.5.6", "prop-types": "^15.5.10", "react": "^16.14.0 || ^17.0.0", "react-dom": "^16.14.0 || ^17.0.0" } }, - "node_modules/@edx/frontend-lib-content-components/node_modules/@edx/browserslist-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@edx/browserslist-config/-/browserslist-config-1.2.0.tgz", - "integrity": "sha512-T1+6P52Yx7SMkmoIr4O0Q3m/DyRdrLTJbv1xVijdRLFEq1hqdafEs+Ln1423U5LSkTePb9AOkEtL1G0RZLFl1w==" - }, "node_modules/@edx/frontend-lib-content-components/node_modules/@reduxjs/toolkit": { - "version": "1.8.5", - "license": "MIT", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz", + "integrity": "sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==", "dependencies": { - "immer": "^9.0.7", - "redux": "^4.1.2", - "redux-thunk": "^2.4.1", - "reselect": "^4.1.5" + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18", @@ -2370,65 +2654,27 @@ } } }, - "node_modules/@edx/frontend-lib-content-components/node_modules/fast-xml-parser": { - "version": "4.0.12", - "license": "MIT", + "node_modules/@edx/frontend-lib-content-components/node_modules/@reduxjs/toolkit/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" + "@babel/runtime": "^7.9.2" } }, "node_modules/@edx/frontend-lib-content-components/node_modules/immer": { - "version": "9.0.15", - "license": "MIT", + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" } }, - "node_modules/@edx/frontend-lib-content-components/node_modules/moment": { - "version": "2.29.4", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/@edx/frontend-lib-content-components/node_modules/react-is": { - "version": "17.0.2", - "license": "MIT" - }, - "node_modules/@edx/frontend-lib-content-components/node_modules/react-redux": { - "version": "7.2.8", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.15.4", - "@types/react-redux": "^7.1.20", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" - }, - "peerDependencies": { - "react": "^16.8.3 || ^17 || ^18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/@edx/frontend-lib-content-components/node_modules/react-responsive": { "version": "8.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", + "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==", "dependencies": { "hyphenate-style-name": "^1.0.0", "matchmediaquery": "^0.3.0", @@ -2444,7 +2690,8 @@ }, "node_modules/@edx/frontend-lib-content-components/node_modules/react-transition-group": { "version": "4.4.2", - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -2458,16 +2705,18 @@ }, "node_modules/@edx/frontend-lib-content-components/node_modules/redux": { "version": "4.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", + "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", "dependencies": { "@babel/runtime": "^7.9.2" } }, "node_modules/@edx/frontend-platform": { - "version": "4.2.0", - "license": "AGPL-3.0", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-5.6.1.tgz", + "integrity": "sha512-7MOIjGGYplVY7yHrSea90EkQ24UxKxRKU9FaihB41yUSL/Vin1txDuIn3059Xr+60QfIKRsym+LogXe9IZ47Dw==", "dependencies": { - "@cospired/i18n-iso-languages": "2.2.0", + "@cospired/i18n-iso-languages": "4.1.0", "@formatjs/intl-pluralrules": "4.3.3", "@formatjs/intl-relativetimeformat": "10.0.1", "axios": "0.27.2", @@ -2492,12 +2741,13 @@ "transifex-utils.js": "i18n/scripts/transifex-utils.js" }, "peerDependencies": { - "@edx/paragon": ">= 10.0.0 < 21.0.0", + "@edx/frontend-build": ">= 8.1.0 || ^12.9.0-alpha.1", + "@edx/paragon": ">= 10.0.0 < 22.0.0", "prop-types": "^15.7.2", "react": "^16.9.0 || ^17.0.0", "react-dom": "^16.9.0 || ^17.0.0", "react-redux": "^7.1.1", - "react-router-dom": "^5.0.1", + "react-router-dom": "^6.0.0", "redux": "^4.0.4" } }, @@ -2509,46 +2759,31 @@ "form-data": "^4.0.0" } }, - "node_modules/@edx/frontend-platform/node_modules/glob": { - "version": "7.2.3", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@edx/new-relic-source-map-webpack-plugin": { - "version": "1.0.2", - "dev": true, - "license": "AGPL-3.0", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@edx/new-relic-source-map-webpack-plugin/-/new-relic-source-map-webpack-plugin-2.1.0.tgz", + "integrity": "sha512-OrlvtdsPcWuOm6NBWfUxFE06qdPiu2bf9nU4I9t8Lu7WW6NsosAB5hxm5U+MBMZP2AuVl3FAt0k0lZsu3+ri8Q==", "dependencies": { "@newrelic/publish-sourcemap": "^5.0.1" } }, "node_modules/@edx/paragon": { - "version": "20.45.4", - "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.45.4.tgz", - "integrity": "sha512-ifkkBR4PRGlsFdMwuyYznUMrifyaO9Yy0PyTsP2iD99Pn5ZZMqYOmtvMm8Ek087ABbc/7MIwzxWXMhTvQpNVNw==", + "version": "21.5.6", + "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-21.5.6.tgz", + "integrity": "sha512-CWR9mFBQAnZ29GeP8igPk3dBLgIQmZJ6tZQiou6855TjHIXcvgmbIvtchKw9SgzhW+D5B0hQJet94zsm+GG/Rg==", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/react-fontawesome": "^0.1.18", "@popperjs/core": "^2.11.4", "bootstrap": "^4.6.2", + "chalk": "^4.1.2", + "child_process": "^1.0.2", "classnames": "^2.3.1", "email-prop-type": "^3.0.0", "file-selector": "^0.6.0", "font-awesome": "^4.7.0", "glob": "^8.0.3", + "inquirer": "^8.2.5", "lodash.uniqby": "^4.7.0", "mailto-link": "^2.0.0", "prop-types": "^15.8.1", @@ -2566,10 +2801,13 @@ "uncontrollable": "^7.2.1", "uuid": "^9.0.0" }, + "bin": { + "paragon": "bin/paragon-scripts.js" + }, "peerDependencies": { "react": "^16.8.6 || ^17.0.0", "react-dom": "^16.8.6 || ^17.0.0", - "react-intl": "^5.25.1" + "react-intl": "^5.25.1 || ^6.4.0" } }, "node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-common-types": { @@ -2602,6 +2840,20 @@ "react": ">=16.x" } }, + "node_modules/@edx/paragon/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/@edx/paragon/node_modules/brace-expansion": { "version": "2.0.1", "license": "MIT", @@ -2609,10 +2861,41 @@ "balanced-match": "^1.0.0" } }, + "node_modules/@edx/paragon/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@edx/paragon/node_modules/classnames": { "version": "2.3.1", "license": "MIT" }, + "node_modules/@edx/paragon/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@edx/paragon/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/@edx/paragon/node_modules/glob": { "version": "8.0.3", "license": "ISC", @@ -2630,6 +2913,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@edx/paragon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/@edx/paragon/node_modules/minimatch": { "version": "5.1.0", "license": "ISC", @@ -2665,18 +2956,15 @@ "react": ">=16.8.0" } }, - "node_modules/@edx/paragon/node_modules/react-transition-group": { - "version": "4.4.2", - "license": "BSD-3-Clause", + "node_modules/@edx/paragon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" + "has-flag": "^4.0.0" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "engines": { + "node": ">=8" } }, "node_modules/@edx/paragon/node_modules/uuid": { @@ -2710,14 +2998,56 @@ "stylelint-scss": "^4.1.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", + "node_modules/@edx/typescript-config": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@edx/typescript-config/-/typescript-config-1.0.1.tgz", + "integrity": "sha512-w0g3nIX9oEch8Rip8q8sb/nrurGEHA1BEjK/I1LAQwA44K4FPMWvyvabmZErrdTJ9sXcZL10aWD3bat1obV8Bg==", "dev": true, - "license": "MIT", + "peerDependencies": { + "typescript": "^4.9.4" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -2734,13 +3064,13 @@ }, "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", - "dev": true, - "license": "Python-2.0" + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "dev": true, - "license": "MIT", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dependencies": { "type-fest": "^0.20.2" }, @@ -2753,8 +3083,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "4.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { "argparse": "^2.0.1" }, @@ -2764,8 +3094,8 @@ }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "engines": { "node": ">=10" }, @@ -2773,6 +3103,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@formatjs/cli": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.0.tgz", + "integrity": "sha512-sP04UpocRHYwSovUnunAZHYvCTVbNcaLtWKnr1lETGRUnRRQqnXy/3d2Ce271ELXmNUSde2eHRdu4rv2XaVaiQ==", + "bin": { + "formatjs": "bin/formatjs" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "vue": "^3.3.4" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, "node_modules/@formatjs/ecma402-abstract": { "version": "1.11.4", "license": "MIT", @@ -2851,23 +3208,6 @@ "tslib": "^2.1.0" } }, - "node_modules/@formatjs/intl-numberformat": { - "version": "5.7.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@formatjs/ecma402-abstract": "1.4.0", - "tslib": "^2.0.1" - } - }, - "node_modules/@formatjs/intl-numberformat/node_modules/@formatjs/ecma402-abstract": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - } - }, "node_modules/@formatjs/intl-pluralrules": { "version": "4.3.3", "license": "MIT", @@ -2886,41 +3226,6 @@ "tslib": "^2.1.0" } }, - "node_modules/@formatjs/ts-transformer": { - "version": "2.13.0", - "dev": true, - "license": "MIT", - "dependencies": { - "intl-messageformat-parser": "6.1.2", - "tslib": "^2.0.1", - "typescript": "^4.0" - }, - "peerDependencies": { - "ts-jest": "^26.4.0" - }, - "peerDependenciesMeta": { - "ts-jest": { - "optional": true - } - } - }, - "node_modules/@formatjs/ts-transformer/node_modules/@formatjs/ecma402-abstract": { - "version": "1.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - } - }, - "node_modules/@formatjs/ts-transformer/node_modules/intl-messageformat-parser": { - "version": "6.1.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@formatjs/ecma402-abstract": "1.5.0", - "tslib": "^2.0.1" - } - }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "0.2.36", "hasInstallScript": true, @@ -2930,59 +3235,77 @@ } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "1.2.28", - "license": "MIT", + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "^0.2.28" + "@fortawesome/fontawesome-common-types": "^0.2.36" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-brands-svg-icons": { - "version": "5.11.2", - "license": "(CC-BY-4.0 AND MIT)", + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz", + "integrity": "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==", + "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "^0.2.25" + "@fortawesome/fontawesome-common-types": "^0.2.36" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-regular-svg-icons": { - "version": "5.11.2", - "license": "(CC-BY-4.0 AND MIT)", + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz", + "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==", + "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "^0.2.25" + "@fortawesome/fontawesome-common-types": "^0.2.36" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "5.11.2", - "license": "(CC-BY-4.0 AND MIT)", + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", + "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "^0.2.25" + "@fortawesome/fontawesome-common-types": "^0.2.36" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/react-fontawesome": { - "version": "0.1.9", - "license": "MIT", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", "dependencies": { - "prop-types": "^15.7.2" + "prop-types": "^15.8.1" }, "peerDependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.20", - "react": "16.x" + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, + "node_modules/@fortawesome/react-fontawesome/node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, "node_modules/@fullhuman/postcss-purgecss": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "purgecss": "^5.0.0" @@ -2992,9 +3315,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "dev": true, - "license": "Apache-2.0", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -3006,8 +3329,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "engines": { "node": ">=12.22" }, @@ -3018,12 +3341,11 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -3038,7 +3360,6 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { "version": "5.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3046,7 +3367,6 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -3058,7 +3378,6 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -3069,7 +3388,6 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { "version": "2.3.0", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -3083,7 +3401,6 @@ }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -3094,7 +3411,6 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3102,8 +3418,8 @@ }, "node_modules/@jest/console": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", "dependencies": { "@jest/types": "^26.6.2", "@types/node": "*", @@ -3118,8 +3434,8 @@ }, "node_modules/@jest/console/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -3132,8 +3448,8 @@ }, "node_modules/@jest/console/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3147,8 +3463,8 @@ }, "node_modules/@jest/console/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -3158,29 +3474,29 @@ }, "node_modules/@jest/console/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@jest/console/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/@jest/console/node_modules/slash": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { "node": ">=8" } }, "node_modules/@jest/console/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -3190,8 +3506,8 @@ }, "node_modules/@jest/core": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", "dependencies": { "@jest/console": "^26.6.2", "@jest/reporters": "^26.6.2", @@ -3228,8 +3544,8 @@ }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -3242,8 +3558,8 @@ }, "node_modules/@jest/core/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3257,8 +3573,8 @@ }, "node_modules/@jest/core/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -3268,21 +3584,21 @@ }, "node_modules/@jest/core/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@jest/core/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/@jest/core/node_modules/rimraf": { "version": "3.0.2", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dependencies": { "glob": "^7.1.3" }, @@ -3295,16 +3611,16 @@ }, "node_modules/@jest/core/node_modules/slash": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { "node": ">=8" } }, "node_modules/@jest/core/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -3314,8 +3630,8 @@ }, "node_modules/@jest/environment": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", "dependencies": { "@jest/fake-timers": "^26.6.2", "@jest/types": "^26.6.2", @@ -3326,76 +3642,124 @@ "node": ">= 10.14.2" } }, - "node_modules/@jest/fake-timers": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "optional": true, + "peer": true, "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "optional": true, + "peer": true, "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" + "jest-get-type": "^29.6.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect-utils/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "optional": true, + "peer": true, "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" + "write-file-atomic": "^4.0.2" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, - "optionalDependencies": { - "node-notifier": "^8.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { + "node_modules/@jest/expect/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "optional": true, + "peer": true + }, + "node_modules/@jest/expect/node_modules/@types/yargs": { + "version": "17.0.28", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", + "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "optional": true, + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/expect/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3406,10 +3770,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/reporters/node_modules/chalk": { + "node_modules/@jest/expect/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3421,10 +3787,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/reporters/node_modules/color-convert": { + "node_modules/@jest/expect/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/expect/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -3432,219 +3816,318 @@ "node": ">=7.0.0" } }, - "node_modules/@jest/reporters/node_modules/color-name": { + "node_modules/@jest/expect/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true, + "peer": true }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "optional": true, + "peer": true + }, + "node_modules/@jest/expect/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "optional": true, + "peer": true, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@jest/expect/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "optional": true, + "peer": true, "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, - "node_modules/@jest/reporters/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "optional": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "optional": true, + "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/@jest/schemas": { - "version": "28.0.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "optional": true, + "peer": true, "dependencies": { - "@sinclair/typebox": "^0.23.3" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/source-map": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "optional": true, + "peer": true, "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/source-map/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@jest/expect/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-result": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "optional": true, + "peer": true, "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "optional": true, + "peer": true, "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "optional": true, + "peer": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "peer": true, "dependencies": { - "color-convert": "^2.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "yallist": "^4.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "optional": true, + "peer": true, "dependencies": { - "color-name": "~1.1.4" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=7.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "optional": true, + "peer": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/transform/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/expect/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "optional": true, + "peer": true + }, + "node_modules/@jest/expect/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/@jest/transform/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@jest/expect/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/@jest/transform/node_modules/supports-color": { + "node_modules/@jest/expect/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -3652,25 +4135,97 @@ "node": ">=8" } }, - "node_modules/@jest/types": { + "node_modules/@jest/expect/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "optional": true, + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@jest/expect/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/@jest/fake-timers": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" }, "engines": { "node": ">= 10.14.2" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { + "node_modules/@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "node-notifier": "^8.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -3681,10 +4236,10 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/types/node_modules/chalk": { + "node_modules/@jest/reporters/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3696,10 +4251,10 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/types/node_modules/color-convert": { + "node_modules/@jest/reporters/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -3707,255 +4262,411 @@ "node": ">=7.0.0" } }, - "node_modules/@jest/types/node_modules/color-name": { + "node_modules/@jest/reporters/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/@jest/types/node_modules/has-flag": { + "node_modules/@jest/reporters/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dependencies": { - "has-flag": "^4.0.0" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, "engines": { "node": ">=8" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, + "node_modules/@jest/reporters/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "dev": true, - "license": "MIT", + "node_modules/@jest/reporters/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", + "node_modules/@jest/schemas": { + "version": "28.0.2", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@sinclair/typebox": "^0.23.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "dev": true, - "license": "MIT", + "node_modules/@jest/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" }, "engines": { - "node": ">=6.0.0" + "node": ">= 10.14.2" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "dev": true, - "license": "MIT" + "node_modules/@jest/source-map/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "dev": true, - "license": "MIT", + "node_modules/@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@lezer/common": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/@lezer/css": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.2.tgz", - "integrity": "sha512-5TKMAReXukfEmIiZprDlGfZVfOOCyEStFi1YLzxclm9H3G/HHI49/2wzlRT6bQw5r7PoZVEtjTItEkb/UuZQyg==", + "node_modules/@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@lezer/highlight": { - "version": "1.0.0", + "node_modules/@jest/transform": { + "version": "26.6.2", "license": "MIT", "dependencies": { - "@lezer/common": "^1.0.0" + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" } }, - "node_modules/@lezer/html": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.4.tgz", - "integrity": "sha512-HdJYMVZcT4YsMo7lW3ipL4NoyS2T67kMPuSVS5TgLGqmaCjEU/D6xv7zsa1ktvTK5lwk7zzF1e3eU6gBZIPm5g==", + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", "dependencies": { - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@lezer/javascript": { - "version": "1.0.2", + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", "license": "MIT", "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@lezer/lr": { - "version": "1.2.3", + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "@lezer/common": "^1.0.0" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@lezer/xml": { - "version": "1.0.1", + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", "license": "MIT", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.10", - "dev": true, + "node_modules/@jest/transform/node_modules/slash": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/source-map": { + "version": "0.6.1", "license": "BSD-3-Clause", - "optional": true, - "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" + "has-flag": "^4.0.0" }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" + "engines": { + "node": ">=8" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, + "node_modules/@jest/types": { + "version": "26.6.2", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">= 10.14.2" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { - "version": "3.1.0", - "dev": true, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "semver": "^6.0.0" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "color-name": "~1.1.4" }, "engines": { - "node": ">=10" + "node": ">=7.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@lezer/common": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/@lezer/css": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.2.tgz", + "integrity": "sha512-5TKMAReXukfEmIiZprDlGfZVfOOCyEStFi1YLzxclm9H3G/HHI49/2wzlRT6bQw5r7PoZVEtjTItEkb/UuZQyg==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.4.tgz", + "integrity": "sha512-HdJYMVZcT4YsMo7lW3ipL4NoyS2T67kMPuSVS5TgLGqmaCjEU/D6xv7zsa1ktvTK5lwk7zzF1e3eU6gBZIPm5g==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } }, "node_modules/@newrelic/publish-sourcemap": { "version": "5.1.0", - "dev": true, - "license": "New Relic proprietary", + "resolved": "https://registry.npmjs.org/@newrelic/publish-sourcemap/-/publish-sourcemap-5.1.0.tgz", + "integrity": "sha512-pOpW0InKZp/DXUmD3h6vaCGdtMDY5LyzzKvq3S3MBwTKm5Qc5ka3yZC73sLAMOXnjKZmdyG3d8A5LC+LawOEpA==", "dependencies": { "superagent": "^3.4.1", "yargs": "^16.0.3" @@ -3968,8 +4679,8 @@ }, "node_modules/@newrelic/publish-sourcemap/node_modules/yargs": { "version": "16.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -3985,29 +4696,28 @@ }, "node_modules/@newrelic/publish-sourcemap/node_modules/yargs-parser": { "version": "20.2.9", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "engines": { "node": ">=10" } }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", "optional": true }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dependencies": { "eslint-scope": "5.1.1" } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -4019,7 +4729,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -4027,7 +4736,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -4038,9 +4746,9 @@ } }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.10", - "dev": true, - "license": "MIT", + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz", + "integrity": "sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==", "dependencies": { "ansi-html-community": "^0.0.8", "common-path-prefix": "^3.0.0", @@ -4059,7 +4767,7 @@ "@types/webpack": "4.x || 5.x", "react-refresh": ">=0.10.0 <1.0.0", "sockjs-client": "^1.4.0", - "type-fest": ">=0.17.0 <4.0.0", + "type-fest": ">=0.17.0 <5.0.0", "webpack": ">=4.43.0 <6.0.0", "webpack-dev-server": "3.x || 4.x", "webpack-hot-middleware": "2.x", @@ -4087,9 +4795,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "dev": true, - "license": "MIT" + "version": "1.0.0-next.23", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", + "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==" }, "node_modules/@popperjs/core": { "version": "2.11.5", @@ -4109,6 +4817,14 @@ "reselect": "^4.0.0" } }, + "node_modules/@remix-run/router": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.9.0.tgz", + "integrity": "sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@restart/context": { "version": "2.1.4", "license": "MIT", @@ -4133,26 +4849,26 @@ }, "node_modules/@sinonjs/commons": { "version": "1.8.6", - "dev": true, - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { "version": "6.0.1", - "dev": true, - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", "dependencies": { "@sinonjs/commons": "^1.7.0" } }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4163,9 +4879,9 @@ } }, "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "7.0.0", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", "engines": { "node": ">=14" }, @@ -4178,9 +4894,9 @@ } }, "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "7.0.0", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", "engines": { "node": ">=14" }, @@ -4193,11 +4909,11 @@ } }, "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4208,11 +4924,11 @@ } }, "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4223,11 +4939,11 @@ } }, "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4238,11 +4954,11 @@ } }, "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4253,9 +4969,9 @@ } }, "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", "engines": { "node": ">=12" }, @@ -4268,21 +4984,21 @@ } }, "node_modules/@svgr/babel-preset": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", - "@svgr/babel-plugin-remove-jsx-attribute": "*", - "@svgr/babel-plugin-remove-jsx-empty-expression": "*", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", - "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", - "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", - "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", - "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4293,34 +5009,89 @@ } }, "node_modules/@svgr/core": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.1" + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@svgr/core/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@svgr/core/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@svgr/core/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@svgr/core/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", "dependencies": { - "@babel/types": "^7.20.0", + "@babel/types": "^7.21.3", "entities": "^4.4.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4328,37 +5099,37 @@ } }, "node_modules/@svgr/plugin-jsx": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/hast-util-to-babel-ast": "^6.5.1", + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", "svg-parser": "^2.0.4" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "@svgr/core": "^6.0.0" + "@svgr/core": "*" } }, "node_modules/@svgr/plugin-svgo": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", "dependencies": { - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "svgo": "^2.8.0" + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -4368,28 +5139,118 @@ "@svgr/core": "*" } }, + "node_modules/@svgr/plugin-svgo/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@svgr/plugin-svgo/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@svgr/webpack": { - "version": "6.5.1", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", "dependencies": { - "@babel/core": "^7.19.6", - "@babel/plugin-transform-react-constant-elements": "^7.18.12", - "@babel/preset-env": "^7.19.4", + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@svgr/core": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "@svgr/plugin-svgo": "^6.5.1" + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@tanstack/query-core": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", + "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.36.1.tgz", + "integrity": "sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==", + "dependencies": { + "@tanstack/query-core": "4.36.1", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/@testing-library/dom": { "version": "8.14.0", "dev": true, @@ -4473,15 +5334,16 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "5.16.4", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", + "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", "dev": true, - "license": "MIT", "dependencies": { + "@adobe/css-tools": "^4.0.1", "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", "aria-query": "^5.0.0", "chalk": "^3.0.0", - "css": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", @@ -4495,8 +5357,9 @@ }, "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -4509,8 +5372,9 @@ }, "node_modules/@testing-library/jest-dom/node_modules/chalk": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4521,8 +5385,9 @@ }, "node_modules/@testing-library/jest-dom/node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -4532,21 +5397,24 @@ }, "node_modules/@testing-library/jest-dom/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/@testing-library/jest-dom/node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@testing-library/jest-dom/node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -4555,19 +5423,21 @@ } }, "node_modules/@testing-library/react": { - "version": "12.1.1", + "version": "12.1.5", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", + "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0" + "@testing-library/dom": "^8.0.0", + "@types/react-dom": "<18.0.0" }, "engines": { "node": ">=12" }, "peerDependencies": { - "react": "*", - "react-dom": "*" + "react": "<18.0.0", + "react-dom": "<18.0.0" } }, "node_modules/@testing-library/user-event": { @@ -4599,16 +5469,16 @@ }, "node_modules/@tootallnate/once": { "version": "1.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "engines": { "node": ">= 6" } }, "node_modules/@trysound/sax": { "version": "0.2.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", "engines": { "node": ">=10.13.0" } @@ -4620,7 +5490,6 @@ }, "node_modules/@types/babel__core": { "version": "7.20.0", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -4632,15 +5501,21 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.4", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, + "node_modules/@types/babel__helper-plugin-utils": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@types/babel__helper-plugin-utils/-/babel__helper-plugin-utils-7.10.1.tgz", + "integrity": "sha512-6RaT7i6r2rT6ouIDZ2Cd6dPkq4wn1F8pLyDO+7wPVsL1dodvORiZORImaD6j9FBcHjPGuERE0hhtwkuPNXsO0A==", + "dependencies": { + "@types/babel__core": "*" + } + }, "node_modules/@types/babel__template": { "version": "7.4.1", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -4649,25 +5524,24 @@ }, "node_modules/@types/babel__traverse": { "version": "7.18.3", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.3.0" } }, "node_modules/@types/body-parser": { - "version": "1.19.2", - "dev": true, - "license": "MIT", + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", + "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "node_modules/@types/bonjour": { - "version": "3.5.10", - "dev": true, - "license": "MIT", + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.11.tgz", + "integrity": "sha512-isGhjmBtLIxdHBDl2xGwUzEM8AOyOvWsADWq7rqirdi/ZQoHnLWErHvsThcEzTX8juDRiZtzp2Qkv5bgNh6mAg==", "dependencies": { "@types/node": "*" } @@ -4681,17 +5555,17 @@ } }, "node_modules/@types/connect": { - "version": "3.4.35", - "dev": true, - "license": "MIT", + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "dev": true, - "license": "MIT", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz", + "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -4702,9 +5576,9 @@ "license": "MIT" }, "node_modules/@types/eslint": { - "version": "8.37.0", - "dev": true, - "license": "MIT", + "version": "8.44.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz", + "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -4712,22 +5586,22 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.4", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "node_modules/@types/estree": { - "version": "0.0.51", - "dev": true, - "license": "MIT" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" }, "node_modules/@types/express": { - "version": "4.17.17", - "dev": true, - "license": "MIT", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.19.tgz", + "integrity": "sha512-UtOfBtzN9OvpZPPbnnYunfjM7XCI4jyk1NvnFhTVz5krYAnW4o5DCoIekvms+8ApqhB4+9wSge1kBijdfTSmfg==", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -4736,27 +5610,20 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.33", - "dev": true, - "license": "MIT", + "version": "4.17.37", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", + "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/fs-extra": { - "version": "9.0.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, "node_modules/@types/glob": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dependencies": { "@types/minimatch": "*", "@types/node": "*" @@ -4764,7 +5631,6 @@ }, "node_modules/@types/graceful-fs": { "version": "4.1.6", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4780,13 +5646,18 @@ }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==" }, "node_modules/@types/http-proxy": { - "version": "1.17.10", - "dev": true, - "license": "MIT", + "version": "1.17.12", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.12.tgz", + "integrity": "sha512-kQtujO08dVtQ2wXAuSFfk9ASy3sug4+ogFR8Kd8UgP8PEuc1/G/8yjYRmp//PcDNJEUKOza/MrQu15bouEUCiw==", "dependencies": { "@types/node": "*" } @@ -4797,12 +5668,10 @@ }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", - "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -4810,7 +5679,6 @@ }, "node_modules/@types/istanbul-reports": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -4857,23 +5725,27 @@ }, "node_modules/@types/json-schema": { "version": "7.0.11", - "dev": true, "license": "MIT" }, + "node_modules/@types/json-stable-stringify": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.34.tgz", + "integrity": "sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw==" + }, "node_modules/@types/json5": { "version": "0.0.29", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, "node_modules/@types/mime": { - "version": "3.0.1", - "dev": true, - "license": "MIT" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==" }, "node_modules/@types/minimatch": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -4883,41 +5755,59 @@ }, "node_modules/@types/node": { "version": "18.0.0", - "dev": true, "license": "MIT" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", - "dev": true, "license": "MIT" }, "node_modules/@types/parse-json": { "version": "4.0.0", - "dev": true, "license": "MIT" }, "node_modules/@types/prettier": { - "version": "2.7.2", - "dev": true, - "license": "MIT" + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "node_modules/@types/prop-types": { "version": "15.7.5", "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.7", - "dev": true, - "license": "MIT" + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==" }, "node_modules/@types/range-parser": { - "version": "1.2.4", - "dev": true, - "license": "MIT" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==" }, "node_modules/@types/react": { - "version": "18.0.14", - "license": "MIT", + "version": "17.0.68", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.68.tgz", + "integrity": "sha512-y8heXejd/Gi43S28GOqIFmr6BzhLa3anMlPojRu4rHh3MtRrrpB+BtLEcqP3XPO1urXByzBdkOLU7sodYWnpkA==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "17.0.20", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.20.tgz", + "integrity": "sha512-4pzIjSxDueZZ90F52mU3aPoogkHIoSIDG+oQ+wQK7Cy2B9S+MvOqY0uEA/qawKz381qrEDkvpwyt8Bm31I8sbA==", + "dev": true, + "dependencies": { + "@types/react": "^17" + } + }, + "node_modules/@types/react-dom/node_modules/@types/react": { + "version": "17.0.65", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.65.tgz", + "integrity": "sha512-oxur785xZYHvnI7TRS61dXbkIhDPnGfsXKv0cNXR/0ml4SipRIFpSMzA7HMEfOywFwJ5AOnPrXYTEiTRUQeGlQ==", + "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4943,60 +5833,52 @@ }, "node_modules/@types/retry": { "version": "0.12.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "node_modules/@types/scheduler": { "version": "0.16.2", "license": "MIT" }, - "node_modules/@types/schema-utils": { - "version": "2.4.0", - "dev": true, - "license": "MIT", + "node_modules/@types/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", + "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", "dependencies": { - "schema-utils": "*" + "@types/mime": "^1", + "@types/node": "*" } }, "node_modules/@types/serve-index": { - "version": "1.9.1", - "dev": true, - "license": "MIT", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-asaEIoc6J+DbBKXtO7p2shWUpKacZOoMBEGBgPG91P8xhO53ohzHWGCs4ScZo5pQMf5ukQzVT9fhX1WzpHihig==", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.1", - "dev": true, - "license": "MIT", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", + "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", "dependencies": { + "@types/http-errors": "*", "@types/mime": "*", "@types/node": "*" } }, "node_modules/@types/sockjs": { - "version": "0.3.33", - "dev": true, - "license": "MIT", + "version": "0.3.34", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.34.tgz", + "integrity": "sha512-R+n7qBFnm/6jinlteC9DBL5dGiDGjWAvjo4viUanpnc/dG1y7uDoacXPIQ/PQEg1fI912SMHIa014ZjRpvDw4g==", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/source-list-map": { - "version": "0.1.2", - "dev": true, - "license": "MIT" - }, "node_modules/@types/stack-utils": { "version": "2.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/tapable": { - "version": "1.0.8", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.5", @@ -5006,68 +5888,20 @@ "@types/jest": "*" } }, - "node_modules/@types/uglify-js": { - "version": "3.17.1", - "dev": true, - "license": "MIT", - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/@types/uglify-js/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@types/warning": { "version": "3.0.0", "license": "MIT" }, - "node_modules/@types/webpack": { - "version": "4.41.33", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/tapable": "^1", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "anymatch": "^3.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/@types/webpack-sources": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.7.3" - } - }, - "node_modules/@types/webpack/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@types/ws": { - "version": "8.5.4", - "dev": true, - "license": "MIT", + "version": "8.5.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.7.tgz", + "integrity": "sha512-6UrLjiDUvn40CMrAubXuIVtj2PEfKDffJS7ychvnPU44j+KVeXmdHHTgqcM/dxLUTHxlXHiFM8Skmb8ozGdTnQ==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { "version": "15.0.15", - "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -5075,7 +5909,6 @@ }, "node_modules/@types/yargs-parser": { "version": "21.0.0", - "dev": true, "license": "MIT" }, "node_modules/@videojs/http-streaming": { @@ -5122,140 +5955,140 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "dev": true, - "license": "MIT" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "dev": true, - "license": "MIT" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "dev": true, - "license": "MIT" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "dev": true, - "license": "MIT" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "dev": true, - "license": "Apache-2.0", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "dev": true, - "license": "MIT" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "dev": true, - "license": "MIT", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webpack-cli/configtest": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "engines": { "node": ">=14.15.0" }, @@ -5265,9 +6098,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "engines": { "node": ">=14.15.0" }, @@ -5277,9 +6110,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "engines": { "node": ">=14.15.0" }, @@ -5293,6 +6126,52 @@ } } }, + "node_modules/@wojtekmaj/enzyme-adapter-react-17": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.8.0.tgz", + "integrity": "sha512-zeUGfQRziXW7R7skzNuJyi01ZwuKCH8WiBNnTgUJwdS/CURrJwAhWsfW7nG7E30ak8Pu3ZwD9PlK9skBfAoOBw==", + "dev": true, + "dependencies": { + "@wojtekmaj/enzyme-adapter-utils": "^0.2.0", + "enzyme-shallow-equal": "^1.0.0", + "has": "^1.0.0", + "prop-types": "^15.7.0", + "react-is": "^17.0.0", + "react-test-renderer": "^17.0.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/enzyme-adapter-react-17?sponsor=1" + }, + "peerDependencies": { + "enzyme": "^3.0.0", + "react": "^17.0.0-0", + "react-dom": "^17.0.0-0" + } + }, + "node_modules/@wojtekmaj/enzyme-adapter-react-17/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/@wojtekmaj/enzyme-adapter-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.2.0.tgz", + "integrity": "sha512-ZvZm9kZxZEKAbw+M1/Q3iDuqQndVoN8uLnxZ8bzxm7KgGTBejrGRoJAp8f1EN8eoO3iAjBNEQnTDW/H4Ekb0FQ==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.0", + "has": "^1.0.0", + "object.fromentries": "^2.0.0", + "prop-types": "^15.7.0" + }, + "funding": { + "url": "https://github.com/wojtekmaj/enzyme-adapter-utils?sponsor=1" + }, + "peerDependencies": { + "react": "^17.0.0-0" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.7.5", "license": "MIT", @@ -5302,30 +6181,22 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "dev": true, - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/abab": { "version": "2.0.6", - "dev": true, "license": "BSD-3-Clause" }, - "node_modules/abbrev": { - "version": "1.1.1", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, "node_modules/accepts": { "version": "1.3.8", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -5335,9 +6206,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "dev": true, - "license": "MIT", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "bin": { "acorn": "bin/acorn" }, @@ -5347,8 +6218,8 @@ }, "node_modules/acorn-globals": { "version": "6.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dependencies": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" @@ -5356,8 +6227,8 @@ }, "node_modules/acorn-globals/node_modules/acorn": { "version": "7.4.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "bin": { "acorn": "bin/acorn" }, @@ -5366,32 +6237,31 @@ } }, "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "dev": true, - "license": "MIT", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "peerDependencies": { "acorn": "^8" } }, "node_modules/acorn-jsx": { "version": "5.3.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "engines": { "node": ">=0.4.0" } }, "node_modules/address": { "version": "1.2.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -5399,7 +6269,6 @@ }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", @@ -5421,8 +6290,8 @@ }, "node_modules/agent-base": { "version": "6.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dependencies": { "debug": "4" }, @@ -5430,31 +6299,8 @@ "node": ">= 6.0.0" } }, - "node_modules/airbnb-prop-types": { - "version": "2.16.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array.prototype.find": "^2.1.1", - "function.prototype.name": "^1.1.2", - "is-regex": "^1.1.0", - "object-is": "^1.1.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2", - "prop-types": "^15.7.2", - "prop-types-exact": "^1.2.0", - "react-is": "^16.13.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "peerDependencies": { - "react": "^0.14 || ^15.0.0 || ^16.0.0-alpha" - } - }, "node_modules/ajv": { "version": "6.12.6", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5469,8 +6315,8 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dependencies": { "ajv": "^8.0.0" }, @@ -5485,8 +6331,8 @@ }, "node_modules/ajv-formats/node_modules/ajv": { "version": "8.12.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -5500,12 +6346,11 @@ }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/ajv-keywords": { "version": "3.5.2", - "dev": true, "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" @@ -5513,7 +6358,6 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -5527,18 +6371,17 @@ }, "node_modules/ansi-html-community": { "version": "0.0.8", - "dev": true, + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "engines": [ "node >= 0.8.0" ], - "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } }, "node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5546,8 +6389,8 @@ }, "node_modules/ansi-styles": { "version": "3.2.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dependencies": { "color-convert": "^1.9.0" }, @@ -5557,7 +6400,6 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -5567,45 +6409,8 @@ "node": ">= 8" } }, - "node_modules/aproba": { - "version": "2.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.0", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/argparse": { "version": "1.0.10", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -5626,16 +6431,15 @@ "license": "0BSD" }, "node_modules/aria-query": { - "version": "5.0.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=6.0" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" } }, "node_modules/arr-diff": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5643,7 +6447,6 @@ }, "node_modules/arr-flatten": { "version": "1.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5651,7 +6454,6 @@ }, "node_modules/arr-union": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5659,7 +6461,6 @@ }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -5670,19 +6471,19 @@ } }, "node_modules/array-flatten": { - "version": "2.1.2", - "dev": true, - "license": "MIT" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-includes": { - "version": "3.1.6", - "dev": true, - "license": "MIT", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "is-string": "^1.0.7" }, "engines": { @@ -5693,27 +6494,23 @@ } }, "node_modules/array-union": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" - }, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/array-uniq": { "version": "1.0.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "engines": { "node": ">=0.10.0" } }, "node_modules/array-unique": { "version": "0.3.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5737,28 +6534,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.find": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.4", - "es-shim-unscopables": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array.prototype.flat": { - "version": "1.3.0", - "dev": true, - "license": "MIT", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -5769,13 +6552,13 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "dev": true, - "license": "MIT", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -5786,15 +6569,35 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "dev": true, - "license": "MIT", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", + "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/arrify": { @@ -5812,7 +6615,6 @@ }, "node_modules/assign-symbols": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5820,8 +6622,8 @@ }, "node_modules/ast-types-flow": { "version": "0.0.7", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" }, "node_modules/astral-regex": { "version": "2.0.0", @@ -5838,7 +6640,6 @@ }, "node_modules/at-least-node": { "version": "1.0.0", - "dev": true, "license": "ISC", "engines": { "node": ">= 4.0.0" @@ -5846,7 +6647,6 @@ }, "node_modules/atob": { "version": "2.1.2", - "dev": true, "license": "(MIT OR Apache-2.0)", "bin": { "atob": "bin/atob.js" @@ -5863,8 +6663,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.14", - "dev": true, + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "funding": [ { "type": "opencollective", @@ -5873,13 +6674,16 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -5896,7 +6700,6 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5906,16 +6709,15 @@ } }, "node_modules/axe-core": { - "version": "4.6.3", - "dev": true, - "license": "MPL-2.0", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.1.tgz", + "integrity": "sha512-9l850jDDPnKq48nbad8SiEelCv4OrUWrKab/cPj0GScVg6cb6NbCCt/Ulk26QEq5jP9NnGr04Bit1BHyV6r5CQ==", "engines": { "node": ">=4" } }, "node_modules/axios": { "version": "0.21.4", - "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.14.0" @@ -5947,13 +6749,20 @@ } }, "node_modules/axobject-query": { - "version": "2.2.0", - "dev": true, - "license": "Apache-2.0" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" }, "node_modules/babel-jest": { "version": "26.6.3", - "dev": true, "license": "MIT", "dependencies": { "@jest/transform": "^26.6.2", @@ -5974,7 +6783,6 @@ }, "node_modules/babel-jest/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5988,7 +6796,6 @@ }, "node_modules/babel-jest/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -6003,7 +6810,6 @@ }, "node_modules/babel-jest/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -6014,12 +6820,10 @@ }, "node_modules/babel-jest/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/babel-jest/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6027,7 +6831,6 @@ }, "node_modules/babel-jest/node_modules/slash": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6035,7 +6838,6 @@ }, "node_modules/babel-jest/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -6045,11 +6847,11 @@ } }, "node_modules/babel-loader": { - "version": "9.1.2", - "dev": true, - "license": "MIT", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dependencies": { - "find-cache-dir": "^3.3.2", + "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" }, "engines": { @@ -6062,8 +6864,8 @@ }, "node_modules/babel-loader/node_modules/ajv": { "version": "8.12.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -6077,8 +6879,8 @@ }, "node_modules/babel-loader/node_modules/ajv-keywords": { "version": "5.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -6088,18 +6890,18 @@ }, "node_modules/babel-loader/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/babel-loader/node_modules/schema-utils": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dependencies": { "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", + "ajv": "^8.9.0", "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 12.13.0" @@ -6109,1150 +6911,1583 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/babel-plugin-formatjs": { + "version": "10.5.6", + "resolved": "https://registry.npmjs.org/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.6.tgz", + "integrity": "sha512-XlE8WHF/ZstS5K3ZCWb5nQ6e9u6KpNquTpHpjteGaMSguSjvbfNb7CsF4YHq1fTPBdHWNspA3qfAqMGgHBO4mw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" + "@babel/core": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-jsx": "7", + "@babel/traverse": "7", + "@babel/types": "^7.12.11", + "@formatjs/icu-messageformat-parser": "2.6.2", + "@formatjs/ts-transformer": "3.13.5", + "@types/babel__core": "^7.1.7", + "@types/babel__helper-plugin-utils": "^7.10.0", + "@types/babel__traverse": "^7.1.7", + "tslib": "^2.4.0" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@formatjs/ecma402-abstract": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.2.tgz", + "integrity": "sha512-k2mTh0m+IV1HRdU0xXM617tSQTi53tVR2muvYOsBeYcUgEAyxV1FOC7Qj279th3fBVQ+Dj6muvNJZcHSPNdbKg==", "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": ">= 10.14.2" + "@formatjs/intl-localematcher": "0.4.2", + "tslib": "^2.4.0" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.2.tgz", + "integrity": "sha512-nF/Iww7sc5h+1MBCDRm68qpHTCG4xvGzYs/x9HFcDETSGScaJ1Fcadk5U/NXjXeCtzD+DhN4BAwKFVclHfKMdA==", "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@formatjs/ecma402-abstract": "1.17.2", + "@formatjs/icu-skeleton-parser": "1.6.2", + "tslib": "^2.4.0" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.2.tgz", + "integrity": "sha512-VtB9Slo4ZL6QgtDFJ8Injvscf0xiDd4bIV93SOJTBjUF4xe2nAWOoSjLEtqIG+hlIs1sNrVKAaFo3nuTI4r5ZA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@formatjs/ecma402-abstract": "1.17.2", + "tslib": "^2.4.0" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@formatjs/intl-localematcher": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.2.tgz", + "integrity": "sha512-BGdtJFmaNJy5An/Zan4OId/yR9Ih1OojFjcduX/xOvq798OgWSyDtd6Qd5jqJXwJs1ipe4Fxu9+cshic5Ox2tA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/babel-plugin-formatjs/node_modules/@formatjs/ts-transformer": { + "version": "3.13.5", + "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.13.5.tgz", + "integrity": "sha512-dh2mmZqkId0UeM+FQtmwugpMGvyzTBmXj5LjwD4M5OeSm62tcgkScjqeO/1EetaNS/JkTUBbsFBnHzaDzh3yOw==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" + "@formatjs/icu-messageformat-parser": "2.6.2", + "@types/json-stable-stringify": "^1.0.32", + "@types/node": "14 || 16 || 17", + "chalk": "^4.0.0", + "json-stable-stringify": "^1.0.1", + "tslib": "^2.4.0", + "typescript": "^4.7 || 5" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "ts-jest": ">=27" + }, + "peerDependenciesMeta": { + "ts-jest": { + "optional": true + } } }, - "node_modules/babel-plugin-react-intl": { - "version": "7.9.4", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/babel-plugin-formatjs/node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "optional": true, + "peer": true, "dependencies": { - "@babel/core": "^7.9.0", - "@babel/helper-plugin-utils": "^7.8.3", - "@babel/types": "^7.9.5", - "@formatjs/ts-transformer": "^2.6.0", - "@types/babel__core": "^7.1.7", - "@types/fs-extra": "^9.0.1", - "@types/schema-utils": "^2.4.0", - "fs-extra": "^9.0.0", - "intl-messageformat-parser": "^5.3.7", - "schema-utils": "^2.6.6" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-plugin-react-intl/node_modules/schema-utils": { - "version": "2.7.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "optional": true, + "peer": true, "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 8.9.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/babel-plugin-transform-imports": { - "version": "2.0.0", - "dev": true, - "license": "ISC", + "node_modules/babel-plugin-formatjs/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "optional": true, + "peer": true, "dependencies": { - "@babel/types": "^7.4", - "is-valid-path": "^0.1.1" + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-polyfill": { - "version": "6.26.0", - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "optional": true, + "peer": true, "dependencies": { - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "regenerator-runtime": "^0.10.5" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-polyfill/node_modules/core-js": { - "version": "2.6.12", - "hasInstallScript": true, - "license": "MIT" - }, - "node_modules/babel-polyfill/node_modules/regenerator-runtime": { - "version": "0.10.5", - "license": "MIT" - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "optional": true, + "peer": true, "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-preset-jest": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "optional": true, + "peer": true, "dependencies": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/babel-runtime": { - "version": "6.26.0", - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "optional": true, + "peer": true, "dependencies": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/babel-runtime/node_modules/core-js": { - "version": "2.6.12", - "hasInstallScript": true, - "license": "MIT" - }, - "node_modules/babel-runtime/node_modules/regenerator-runtime": { - "version": "0.11.1", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/base": { - "version": "0.11.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "optional": true, + "peer": true, "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "optional": true, + "peer": true, "dependencies": { - "is-descriptor": "^1.0.0" + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/batch": { - "version": "0.6.1", - "dev": true, - "license": "MIT" + "node_modules/babel-plugin-formatjs/node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/big.js": { - "version": "5.2.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, "engines": { - "node": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/bl": { - "version": "4.1.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "optional": true, + "peer": true + }, + "node_modules/babel-plugin-formatjs/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "peer": true, "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "type-detect": "4.0.8" } }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "optional": true, + "peer": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/body-parser": { - "version": "1.20.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/babel-plugin-formatjs/node_modules/@types/yargs": { + "version": "17.0.28", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", + "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "optional": true, + "peer": true, "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "@types/yargs-parser": "*" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">= 0.8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "optional": true, + "peer": true, "dependencies": { - "ms": "2.0.0" + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "optional": true, + "peer": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/babel-plugin-formatjs/node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "optional": true, + "peer": true, "dependencies": { - "side-channel": "^1.0.4" + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": ">=0.6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/bonjour-service": { - "version": "1.1.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/bootstrap": { - "version": "4.6.2", + "node_modules/babel-plugin-formatjs/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" + "url": "https://github.com/sponsors/sibiraj-s" } ], - "license": "MIT", - "peerDependencies": { - "jquery": "1.9.1 - 3", - "popper.js": "^1.16.1" + "optional": true, + "peer": true, + "engines": { + "node": ">=8" } }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "optional": true, + "peer": true + }, + "node_modules/babel-plugin-formatjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/braces": { - "version": "3.0.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/babel-plugin-formatjs/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "optional": true, + "peer": true + }, + "node_modules/babel-plugin-formatjs/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "optional": true, + "peer": true, "dependencies": { - "fill-range": "^7.0.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "dev": true, - "license": "BSD-2-Clause" + "node_modules/babel-plugin-formatjs/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/browserslist": { - "version": "4.21.5", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "node_modules/babel-plugin-formatjs/node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" }, - "bin": { - "browserslist": "cli.js" + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/babel-plugin-formatjs/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "optional": true, + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/bser": { - "version": "2.1.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/babel-plugin-formatjs/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "optional": true, + "peer": true, "dependencies": { - "node-int64": "^0.4.0" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "node_modules/babel-plugin-formatjs/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT" + "node_modules/babel-plugin-formatjs/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } }, - "node_modules/bytes": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "optional": true, + "peer": true, "engines": { - "node": ">= 0.8" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cache-base": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "optional": true, + "peer": true, "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/cache-parser": { - "version": "1.2.4", - "license": "MIT" + "node_modules/babel-plugin-formatjs/node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } }, - "node_modules/call-bind": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "optional": true, + "peer": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "optional": true, + "peer": true, "dependencies": { - "callsites": "^2.0.0" + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/caller-path": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "optional": true, + "peer": true, "dependencies": { - "caller-callsite": "^2.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "optional": true, + "peer": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "optional": true, + "peer": true, "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "optional": true, + "peer": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, + "node_modules/babel-plugin-formatjs/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "optional": true, + "peer": true, "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/camelcase-keys/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, + "node_modules/babel-plugin-formatjs/node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "optional": true, + "peer": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "optional": true, + "peer": true, "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001474", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/canvas": { - "version": "2.11.2", - "dev": true, - "hasInstallScript": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "optional": true, "peer": true, "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/capture-exit": { - "version": "2.0.0", - "dev": true, - "license": "ISC", + "node_modules/babel-plugin-formatjs/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "optional": true, + "peer": true, "dependencies": { - "rsvp": "^4.8.4" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/cast-array": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "isarray": "0.0.1" + "node_modules/babel-plugin-formatjs/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "optional": true, + "peer": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "optional": true, + "peer": true, "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" }, "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/babel-plugin-formatjs/node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "optional": true, + "peer": true, "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-formatjs/node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "optional": true, + "peer": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" }, "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/chownr": { - "version": "2.0.0", - "dev": true, - "license": "ISC", + "node_modules/babel-plugin-formatjs/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "optional": true, "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=6.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/cjs-module-lexer": { - "version": "0.6.0", - "dev": true, - "license": "MIT" - }, - "node_modules/class-utils": { - "version": "0.3.6", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "optional": true, + "peer": true, "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "optional": true, + "peer": true, "dependencies": { - "is-descriptor": "^0.1.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "peer": true, "dependencies": { - "kind-of": "^3.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, "dependencies": { - "is-buffer": "^1.1.5" + "yallist": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/class-utils/node_modules/is-buffer": { - "version": "1.1.6", - "dev": true, - "license": "MIT" - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "optional": true, + "peer": true, "dependencies": { - "kind-of": "^3.0.2" + "path-key": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, + "node_modules/babel-plugin-formatjs/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "optional": true, + "peer": true, "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/class-utils/node_modules/kind-of": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/classnames": { - "version": "2.2.6", - "license": "MIT" + "node_modules/babel-plugin-formatjs/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "optional": true, + "peer": true }, - "node_modules/clean-css": { - "version": "5.3.2", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "peer": true, "dependencies": { - "source-map": "~0.6.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 10.0" + "node": ">=10" } }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-webpack-plugin": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "optional": true, + "peer": true, "dependencies": { - "@types/webpack": "^4.4.31", - "del": "^4.1.1" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=8.9.0" - }, - "peerDependencies": { - "webpack": "*" + "node": ">=8" } }, - "node_modules/cliui": { - "version": "7.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "node_modules/babel-plugin-formatjs/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, + "node_modules/babel-plugin-formatjs/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "optional": true, + "peer": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/co": { - "version": "4.6.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "peer": true, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=0.10.0" } }, - "node_modules/codemirror": { - "version": "6.0.1", - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "optional": true, + "peer": true, "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/color": { - "version": "4.2.3", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "optional": true, + "peer": true, "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" }, "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } } }, - "node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/color-string": { - "version": "1.9.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "optional": true, + "peer": true, "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" } }, - "node_modules/color-support": { - "version": "1.1.3", - "dev": true, - "license": "ISC", + "node_modules/babel-plugin-formatjs/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "optional": true, "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, "bin": { - "color-support": "bin.js" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/color/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-formatjs/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "optional": true, + "peer": true, "dependencies": { - "color-name": "~1.1.4" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": ">=7.0.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/colord": { - "version": "2.9.3", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.19", - "dev": true, - "license": "MIT" + "node_modules/babel-plugin-formatjs/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "license": "MIT", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "license": "BSD-3-Clause", "dependencies": { - "delayed-stream": "~1.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/commander": { - "version": "4.1.1", - "dev": true, + "node_modules/babel-plugin-jest-hoist": { + "version": "26.6.2", "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, "engines": { - "node": ">= 6" + "node": ">= 10.14.2" } }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/commondir": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/compressible": { - "version": "2.0.18", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.3", + "semver": "^6.3.1" }, - "engines": { - "node": ">= 0.6" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/compression": { - "version": "1.7.4", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz", + "integrity": "sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" + "@babel/helper-define-polyfill-provider": "^0.4.3", + "core-js-compat": "^3.32.2" }, - "engines": { - "node": ">= 0.8.0" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "dependencies": { - "ms": "2.0.0" + "@babel/helper-define-polyfill-provider": "^0.4.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/compression/node_modules/ms": { + "node_modules/babel-plugin-transform-imports": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "@babel/types": "^7.4", + "is-valid-path": "^0.1.1" + } }, - "node_modules/concat-map": { - "version": "0.0.1", + "node_modules/babel-polyfill": { + "version": "6.26.0", + "license": "MIT", + "dependencies": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + } + }, + "node_modules/babel-polyfill/node_modules/core-js": { + "version": "2.6.12", + "hasInstallScript": true, "license": "MIT" }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "dev": true, + "node_modules/babel-polyfill/node_modules/regenerator-runtime": { + "version": "0.10.5", "license": "MIT" }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "dev": true, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "26.6.2", + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, "engines": { - "node": ">=0.8" + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true + "node_modules/babel-runtime": { + "version": "6.26.0", + "license": "MIT", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "dev": true, + "node_modules/babel-runtime/node_modules/core-js": { + "version": "2.6.12", + "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/babel-runtime/node_modules/regenerator-runtime": { + "version": "0.11.1", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -7266,1456 +8501,3737 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" - }, - "node_modules/content-type": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } + ] }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "dev": true, - "license": "MIT" + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" }, - "node_modules/cookie": { - "version": "0.4.2", + "node_modules/big.js": { + "version": "5.2.2", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": "*" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/cookiejar": { - "version": "2.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "dev": true, + "node_modules/binary-extensions": { + "version": "2.2.0", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/core-js": { - "version": "3.8.1", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/core-js-compat": { - "version": "3.30.0", - "dev": true, - "license": "MIT", + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "browserslist": "^4.21.5" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-pure": { - "version": "3.30.0", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "engines": { + "node": ">= 6" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "dev": true, - "license": "MIT", + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">=10" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/crelt": { - "version": "1.0.5", - "license": "MIT" + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "dev": true, - "license": "MIT", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">=4.8" + "node": ">=0.10.0" } }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/css": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, - "node_modules/css-declaration-sorter": { - "version": "6.4.0", - "dev": true, - "license": "ISC", - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } + "node_modules/bonjour-service/node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, - "node_modules/css-functions-list": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", - "integrity": "sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==", - "dev": true, - "engines": { - "node": ">=12.22" - } + "node_modules/boolbase": { + "version": "1.0.0", + "license": "ISC" }, - "node_modules/css-loader": { - "version": "5.2.7", - "dev": true, + "node_modules/bootstrap": { + "version": "4.6.2", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], "license": "MIT", - "dependencies": { - "icss-utils": "^5.1.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, "peerDependencies": { - "webpack": "^4.27.0 || ^5.0.0" + "jquery": "1.9.1 - 3", + "popper.js": "^1.16.1" } }, - "node_modules/css-loader/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", + "node_modules/brace-expansion": { + "version": "1.1.11", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/css-loader/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", + "node_modules/braces": { + "version": "3.0.2", + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "fill-range": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/css-loader/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/css-mediaquery": { - "version": "0.1.2", - "license": "BSD" + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, - "node_modules/css-select": { - "version": "5.1.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/css-tree": { - "version": "1.1.3", - "dev": true, - "license": "MIT", + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "optional": true, + "peer": true, "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "fast-json-stable-stringify": "2.x" }, "engines": { - "node": ">=8.0.0" + "node": ">= 6" } }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "node_modules/bser": { + "version": "2.1.1", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" } }, - "node_modules/css-what": { - "version": "6.1.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "dev": true, + "node_modules/buffer-from": { + "version": "1.1.2", "license": "MIT" }, - "node_modules/css/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "dev": true, + "node_modules/cache-base": { + "version": "1.0.1", "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/cssnano": { - "version": "5.1.15", - "dev": true, + "node_modules/cache-parser": { + "version": "1.2.4", + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.2", "license": "MIT", "dependencies": { - "cssnano-preset-default": "^5.2.14", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cssnano-preset-default": { - "version": "5.2.14", - "dev": true, + "node_modules/callsites": { + "version": "3.1.0", "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^3.1.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.1", - "postcss-convert-values": "^5.1.3", - "postcss-discard-comments": "^5.1.2", - "postcss-discard-duplicates": "^5.1.0", - "postcss-discard-empty": "^5.1.1", - "postcss-discard-overridden": "^5.1.0", - "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.4", - "postcss-minify-font-values": "^5.1.0", - "postcss-minify-gradients": "^5.1.1", - "postcss-minify-params": "^5.1.4", - "postcss-minify-selectors": "^5.2.1", - "postcss-normalize-charset": "^5.1.0", - "postcss-normalize-display-values": "^5.1.0", - "postcss-normalize-positions": "^5.1.1", - "postcss-normalize-repeat-style": "^5.1.1", - "postcss-normalize-string": "^5.1.0", - "postcss-normalize-timing-functions": "^5.1.0", - "postcss-normalize-unicode": "^5.1.1", - "postcss-normalize-url": "^5.1.0", - "postcss-normalize-whitespace": "^5.1.1", - "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.2", - "postcss-reduce-transforms": "^5.1.0", - "postcss-svgo": "^5.1.0", - "postcss-unique-selectors": "^5.1.1" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "node_modules/cssnano-utils": { - "version": "3.1.0", - "dev": true, + "node_modules/camelcase": { + "version": "6.3.0", "license": "MIT", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": ">=10" }, - "peerDependencies": { - "postcss": "^8.2.15" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/csso": { - "version": "4.2.0", + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, - "license": "MIT", "dependencies": { - "css-tree": "^1.1.2" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cssom": { - "version": "0.4.4", - "dev": true, - "license": "MIT" - }, - "node_modules/cssstyle": { - "version": "2.3.0", + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "MIT", - "dependencies": { - "cssom": "~0.3.6" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "dev": true, - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.1.0", - "license": "MIT" + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "dev": true, - "license": "BSD-2-Clause" + "node_modules/caniuse-lite": { + "version": "1.0.30001547", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz", + "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] }, - "node_modules/data-urls": { + "node_modules/capture-exit": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "rsvp": "^4.8.4" }, "engines": { - "node": ">=10" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "node_modules/cast-array": { + "version": "1.0.1", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" + "isarray": "0.0.1" } }, - "node_modules/debug": { - "version": "4.3.4", - "dev": true, - "license": "MIT", + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dependencies": { - "ms": "2.1.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=4" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "dev": true, - "license": "MIT", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", "dev": true, + "license": "MIT", "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" } }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "node_modules/cheerio-select": { + "version": "2.1.0", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "dev": true, - "license": "MIT" - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">=0.10" - } + "node_modules/child_process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", + "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==" }, - "node_modules/decompress-response": { - "version": "6.0.0", - "dev": true, + "node_modules/chokidar": { + "version": "3.5.3", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "license": "MIT", "dependencies": { - "mimic-response": "^3.1.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=10" + "node": ">= 8.10.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/deep-diff": { - "version": "0.3.8", - "license": "MIT" + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, - "node_modules/deep-extend": { - "version": "0.6.0", - "dev": true, - "license": "MIT", + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "engines": { - "node": ">=4.0.0" + "node": ">=6.0" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, + "node_modules/ci-info": { + "version": "2.0.0", "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, + "node_modules/cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==" + }, + "node_modules/class-utils": { + "version": "0.3.6", "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/default-gateway": { - "version": "6.0.3", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "license": "MIT", "dependencies": { - "execa": "^5.0.0" + "is-descriptor": "^0.1.0" }, "engines": { - "node": ">= 10" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/execa": { - "version": "5.1.1", - "dev": true, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" + "is-buffer": "^1.1.5" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-gateway/node_modules/get-stream": { - "version": "6.0.1", - "dev": true, - "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/class-utils/node_modules/is-buffer": { + "version": "1.1.6", + "license": "MIT" }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "4.0.1", - "dev": true, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/path-key": { - "version": "3.1.1", - "dev": true, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/default-gateway/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", + "node_modules/classnames": { + "version": "2.2.6", + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "source-map": "~0.6.0" }, "engines": { - "node": ">= 8" + "node": ">= 10.0" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/define-properties": { - "version": "1.1.4", - "dev": true, - "license": "MIT", + "node_modules/clean-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "del": "^4.1.1" }, "engines": { - "node": ">= 0.4" + "node": ">=10.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "webpack": ">=4.0.0 <6.0.0" } }, - "node_modules/define-property": { - "version": "2.0.2", - "dev": true, - "license": "MIT", + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "restore-cursor": "^3.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/del": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, + "node_modules/cli-spinners": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "license": "MIT", + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "engines": { - "node": ">=0.4.0" + "node": ">= 10" } }, - "node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/depd": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + "node_modules/cliui": { + "version": "7.0.4", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/dequal": { - "version": "2.0.2", - "license": "MIT", + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "engines": { - "node": ">=6" + "node": ">=0.8" } }, - "node_modules/destroy": { - "version": "1.2.0", - "dev": true, - "license": "MIT", + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6" } }, - "node_modules/detect-libc": { - "version": "2.0.1", - "dev": true, - "license": "Apache-2.0", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "engines": { - "node": ">=8" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/detect-newline": { - "version": "3.1.0", - "dev": true, + "node_modules/codemirror": { + "version": "6.0.1", "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "license": "MIT" + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==" }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "dev": true, + "node_modules/collection-visit": { + "version": "1.0.0", "license": "MIT", "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" }, "engines": { - "node": ">= 4.2.1" + "node": ">=0.10.0" } }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dependencies": { - "ms": "2.0.0" + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" } }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } }, - "node_modules/diacritics": { - "version": "1.3.0", - "license": "MIT" + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, - "node_modules/diff-sequences": { - "version": "28.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "path-type": "^4.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/discontinuous-range": { - "version": "1.0.0", - "dev": true, - "license": "MIT" + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/dns-equal": { - "version": "1.0.0", - "dev": true, + "node_modules/colord": { + "version": "2.9.3", "license": "MIT" }, - "node_modules/dns-packet": { - "version": "5.5.0", - "dev": true, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", "license": "MIT", "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/doctrine": { + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", + "license": "ISC" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dependencies": { - "esutils": "^2.0.2" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": ">=6.0.0" + "node": ">= 0.6" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.14", - "dev": true, - "license": "MIT" - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "dev": true, - "license": "MIT", + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dependencies": { - "utila": "~0.4" + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "license": "MIT", + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" + "ms": "2.0.0" } }, - "node_modules/dom-serializer": { + "node_modules/compression/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "license": "MIT" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" + "safe-buffer": "5.2.1" }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "engines": { + "node": ">= 0.6" } }, - "node_modules/dom-walk": { - "version": "0.1.2" - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "dev": true, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } - ], - "license": "BSD-2-Clause" + ] }, - "node_modules/domexception": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "webidl-conversions": "^5.0.0" - }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/convert-source-map": { + "version": "1.9.0", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.4.2", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/domhandler": { - "version": "5.0.3", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "license": "MIT", "engines": { - "node": ">= 4" - }, + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "3.8.1", + "hasInstallScript": true, + "license": "MIT", "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/domutils": { - "version": "3.0.1", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/core-js-compat": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.0.tgz", + "integrity": "sha512-0w4LcLXsVEuNkIqwjjf9rjCoPhK8uqA4tMRh4Ge26vfLtUutshn+aRJU21I9LCJlh2QQHfisNToLjw1XEJLTWw==", "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "browserslist": "^4.22.1" }, "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "node_modules/core-js-pure": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.0.tgz", + "integrity": "sha512-FKSIDtJnds/YFIEaZ4HszRX7hkxGpNKM7FC9aJ9WLJbSd3lD4vOltFuVIBLR8asSx9frkTSqL0dw90SKQxgKrg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/dotenv": { - "version": "8.6.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=10" - } + "node_modules/core-util-is": { + "version": "1.0.3", + "license": "MIT" }, - "node_modules/dotenv-defaults": { - "version": "2.0.2", + "node_modules/cosmiconfig": { + "version": "7.1.0", "dev": true, "license": "MIT", "dependencies": { - "dotenv": "^8.2.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/dotenv-webpack": { - "version": "7.1.1", - "dev": true, - "license": "MIT", + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "optional": true, + "peer": true, "dependencies": { - "dotenv-defaults": "^2.0.2" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" }, - "engines": { - "node": ">=10" + "bin": { + "create-jest": "bin/create-jest.js" }, - "peerDependencies": { - "webpack": "^4 || ^5" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/duplexer": { - "version": "0.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.353", - "dev": true, - "license": "ISC" - }, - "node_modules/email-prop-type": { - "version": "3.0.1", - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "optional": true, + "peer": true, "dependencies": { - "email-validator": "^2.0.4" - } - }, - "node_modules/email-validator": { - "version": "2.0.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, "engines": { - "node": ">4.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/emittery": { - "version": "0.7.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node_modules/create-jest/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "license": "MIT" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, "engines": { - "node": ">= 4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/encodeurl": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, "engines": { - "node": ">= 0.8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "optional": true, + "peer": true, "dependencies": { - "once": "^1.4.0" + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/enhanced-resolve": { - "version": "5.12.0", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "optional": true, + "peer": true, "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">=10.13.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/entities": { - "version": "4.4.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" + "node_modules/create-jest/node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/envinfo": { - "version": "7.8.1", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" + "node_modules/create-jest/node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/enzyme": { - "version": "3.11.0", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "optional": true, + "peer": true, "dependencies": { - "array.prototype.flat": "^1.2.3", - "cheerio": "^1.0.0-rc.3", - "enzyme-shallow-equal": "^1.0.1", - "function.prototype.name": "^1.1.2", - "has": "^1.0.3", - "html-element-map": "^1.2.0", - "is-boolean-object": "^1.0.1", - "is-callable": "^1.1.5", - "is-number-object": "^1.0.4", - "is-regex": "^1.0.5", - "is-string": "^1.0.5", - "is-subset": "^0.1.1", - "lodash.escape": "^4.0.1", - "lodash.isequal": "^4.5.0", - "object-inspect": "^1.7.0", - "object-is": "^1.0.2", - "object.assign": "^4.1.0", - "object.entries": "^1.1.1", - "object.values": "^1.1.1", - "raf": "^3.4.1", - "rst-selector-parser": "^2.2.3", - "string.prototype.trim": "^1.2.1" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/enzyme-adapter-react-16": { - "version": "1.15.6", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "optional": true, + "peer": true, "dependencies": { - "enzyme-adapter-utils": "^1.14.0", - "enzyme-shallow-equal": "^1.0.4", - "has": "^1.0.3", - "object.assign": "^4.1.2", - "object.values": "^1.1.2", - "prop-types": "^15.7.2", - "react-is": "^16.13.1", - "react-test-renderer": "^16.0.0-0", - "semver": "^5.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, - "peerDependencies": { - "enzyme": "^3.0.0", - "react": "^16.0.0-0", - "react-dom": "^16.0.0-0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/enzyme-adapter-react-16/node_modules/semver": { - "version": "5.7.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "node_modules/create-jest/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "optional": true, + "peer": true + }, + "node_modules/create-jest/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "peer": true, + "dependencies": { + "type-detect": "4.0.8" } }, - "node_modules/enzyme-adapter-utils": { - "version": "1.14.0", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "optional": true, + "peer": true, "dependencies": { - "airbnb-prop-types": "^2.16.0", - "function.prototype.name": "^1.1.3", - "has": "^1.0.3", - "object.assign": "^4.1.2", - "object.fromentries": "^2.0.3", - "prop-types": "^15.7.2", - "semver": "^5.7.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "peerDependencies": { - "react": "0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/enzyme-adapter-utils/node_modules/semver": { - "version": "5.7.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "node_modules/create-jest/node_modules/@types/yargs": { + "version": "17.0.28", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", + "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "optional": true, + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" } }, - "node_modules/enzyme-shallow-equal": { - "version": "1.0.4", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "peer": true, "dependencies": { - "has": "^1.0.3", - "object-is": "^1.1.2" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/enzyme-to-json": { - "version": "3.6.2", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "optional": true, + "peer": true, "dependencies": { - "@types/cheerio": "^0.22.22", - "lodash": "^4.17.21", - "react-is": "^16.12.0" + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { - "node": ">=6.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "enzyme": "^3.4.0" + "@babel/core": "^7.8.0" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "dev": true, - "license": "MIT", + "node_modules/create-jest/node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "optional": true, + "peer": true, "dependencies": { - "is-arrayish": "^0.2.1" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", + "node_modules/create-jest/node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "optional": true, + "peer": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "optional": true, + "peer": true + }, + "node_modules/create-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/create-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true, + "peer": true + }, + "node_modules/create-jest/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "optional": true, + "peer": true + }, + "node_modules/create-jest/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/create-jest/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "optional": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "optional": true, + "peer": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/create-jest/node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "optional": true, + "peer": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "optional": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "optional": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/create-jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "optional": true, + "peer": true + }, + "node_modules/create-jest/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/create-jest/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/create-jest/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "optional": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/create-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "optional": true, + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/create-jest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, + "node_modules/crelt": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", + "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-functions-list": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.1.0.tgz", + "integrity": "sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==", + "dev": true, + "engines": { + "node": ">=12.22" + } + }, + "node_modules/css-loader": { + "version": "5.2.7", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.15", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^3.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.27.0 || ^5.0.0" + } + }, + "node_modules/css-loader/node_modules/lru-cache": { + "version": "6.0.0", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.3.8", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/css-mediaquery": { + "version": "0.1.2", + "license": "BSD" + }, + "node_modules/css-select": { + "version": "5.1.0", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssfontparser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", + "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==", + "dev": true + }, + "node_modules/cssnano": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", + "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", + "dependencies": { + "cssnano-preset-default": "^6.0.1", + "lilconfig": "^2.1.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", + "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^4.0.0", + "postcss-calc": "^9.0.0", + "postcss-colormin": "^6.0.0", + "postcss-convert-values": "^6.0.0", + "postcss-discard-comments": "^6.0.0", + "postcss-discard-duplicates": "^6.0.0", + "postcss-discard-empty": "^6.0.0", + "postcss-discard-overridden": "^6.0.0", + "postcss-merge-longhand": "^6.0.0", + "postcss-merge-rules": "^6.0.1", + "postcss-minify-font-values": "^6.0.0", + "postcss-minify-gradients": "^6.0.0", + "postcss-minify-params": "^6.0.0", + "postcss-minify-selectors": "^6.0.0", + "postcss-normalize-charset": "^6.0.0", + "postcss-normalize-display-values": "^6.0.0", + "postcss-normalize-positions": "^6.0.0", + "postcss-normalize-repeat-style": "^6.0.0", + "postcss-normalize-string": "^6.0.0", + "postcss-normalize-timing-functions": "^6.0.0", + "postcss-normalize-unicode": "^6.0.0", + "postcss-normalize-url": "^6.0.0", + "postcss-normalize-whitespace": "^6.0.0", + "postcss-ordered-values": "^6.0.0", + "postcss-reduce-initial": "^6.0.0", + "postcss-reduce-transforms": "^6.0.0", + "postcss-svgo": "^6.0.0", + "postcss-unique-selectors": "^6.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", + "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "node_modules/csstype": { + "version": "3.1.0", + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "optional": true, + "peer": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-diff": { + "version": "0.3.8", + "license": "MIT" + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/default-gateway/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/default-gateway/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-gateway/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/default-gateway/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/diacritics": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/diff-sequences": { + "version": "28.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.14", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2" + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "5.0.3", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-webpack": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.0.1.tgz", + "integrity": "sha512-CdrgfhZOnx4uB18SgaoP9XHRN2v48BbjuXQsZY5ixs5A8579NxQkmMxRtI7aTwSiSQcM2ao12Fdu+L3ZS3bG4w==", + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.549", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.549.tgz", + "integrity": "sha512-gpXfJslSi4hYDkA0mTLEpYKRv9siAgSUgZ+UWyk+J5Cttpd1ThCVwdclzIwQSclz3hYn049+M2fgrP1WpvF8xg==" + }, + "node_modules/email-prop-type": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "email-validator": "^2.0.4" + } + }, + "node_modules/email-validator": { + "version": "2.0.4", + "engines": { + "node": ">4.0" + } + }, + "node_modules/emittery": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.4.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/enzyme": { + "version": "3.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flat": "^1.2.3", + "cheerio": "^1.0.0-rc.3", + "enzyme-shallow-equal": "^1.0.1", + "function.prototype.name": "^1.1.2", + "has": "^1.0.3", + "html-element-map": "^1.2.0", + "is-boolean-object": "^1.0.1", + "is-callable": "^1.1.5", + "is-number-object": "^1.0.4", + "is-regex": "^1.0.5", + "is-string": "^1.0.5", + "is-subset": "^0.1.1", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.7.0", + "object-is": "^1.0.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.1", + "object.values": "^1.1.1", + "raf": "^3.4.1", + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.2.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/enzyme-shallow-equal": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3", + "object-is": "^1.1.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/enzyme-to-json": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cheerio": "^0.22.22", + "lodash": "^4.17.21", + "react-is": "^16.12.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "enzyme": "^3.4.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", "dev": true, + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==" + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb": { + "version": "19.0.4", + "license": "MIT", + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "engines": { + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", "license": "MIT", "dependencies": { - "stackframe": "^1.3.4" + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "node_modules/es-abstract": { - "version": "1.21.2", - "dev": true, - "license": "MIT", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=7.0.0" } }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "dev": true, - "license": "MIT" + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">= 8" } }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/escalade": { - "version": "3.1.1", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=0.8.0" + "node": ">=10.13.0" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/eslint/node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=6.0" + "node": ">=8" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "argparse": "^2.0.1" }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "dev": true, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "dev": true, - "license": "MIT", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": { - "prelude-ls": "~1.1.2" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 8" } }, - "node_modules/eslint": { - "version": "8.29.0", - "dev": true, - "license": "MIT", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, - "bin": { - "eslint": "bin/eslint.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -8723,299 +12239,247 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "dev": true, - "license": "MIT", + "node_modules/esprima": { + "version": "4.0.1", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" + "estraverse": "^5.1.0" }, "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, + "node_modules/esutils": { + "version": "2.0.3", + "license": "BSD-2-Clause", "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" + "node": ">=0.10.0" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "dev": true, + "node_modules/exec-sh": { + "version": "0.3.6", + "license": "MIT" + }, + "node_modules/execa": { + "version": "1.0.0", "license": "MIT", "dependencies": { - "debug": "^3.2.7" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "node": ">=6" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "dev": true, + "node_modules/expand-brackets": { + "version": "2.1.4", "license": "MIT", "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { + "node_modules/expand-brackets/node_modules/debug": { "version": "2.6.9", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "is-descriptor": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.6.1", - "dev": true, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.18.9", - "aria-query": "^4.2.2", - "array-includes": "^3.1.5", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.4.3", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.2", - "language-tags": "^1.0.5", - "minimatch": "^3.1.2", - "semver": "^6.3.0" + "is-extendable": "^0.1.0" }, "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": { - "version": "4.2.2", - "dev": true, - "license": "Apache-2.0", + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=6.0" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react": { - "version": "7.31.11", - "dev": true, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "dev": true, + "node_modules/expand-brackets/node_modules/is-buffer": { + "version": "1.1.6", + "license": "MIT" + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "kind-of": "^3.0.2" }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "is-buffer": "^1.1.5" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/prop-types": { - "version": "15.8.1", - "dev": true, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", "license": "MIT", "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "dev": true, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", "license": "MIT", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "license": "MIT", "engines": { - "node": ">=8.0.0" + "node": ">=0.10.0" } }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "engines": { - "node": ">=4.0" + "node": ">=6" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/expect": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": ">= 10.14.2" } }, - "node_modules/eslint/node_modules/ansi-styles": { + "node_modules/expect/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -9026,15 +12490,10 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/eslint/node_modules/chalk": { + "node_modules/expect/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9046,10 +12505,10 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint/node_modules/color-convert": { + "node_modules/expect/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -9057,3242 +12516,3550 @@ "node": ">=7.0.0" } }, - "node_modules/eslint/node_modules/color-name": { + "node_modules/expect/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/eslint/node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, + "node_modules/expect/node_modules/diff-sequences": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "engines": { - "node": ">= 8" + "node": ">= 10.14.2" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { + "node_modules/expect/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/expect/node_modules/jest-diff": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 10.14.2" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", + "node_modules/expect/node_modules/jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dependencies": { - "is-glob": "^4.0.3" + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" }, "engines": { - "node": ">=10.13.0" + "node": ">= 10.14.2" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "dev": true, - "license": "MIT", + "node_modules/expect/node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { - "type-fest": "^0.20.2" + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 10" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "node_modules/expect/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "dev": true, - "license": "MIT", + "node_modules/expect/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "argparse": "^2.0.1" + "has-flag": "^4.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/eslint/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { - "shebang-regex": "^3.0.0" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.10.0" } }, - "node_modules/eslint/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "ms": "2.0.0" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/eslint/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, - "node_modules/espree": { - "version": "9.5.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" }, "engines": { "node": ">=4" } }, - "node_modules/esquery": { - "version": "1.5.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { - "estraverse": "^5.1.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">=0.10" + "node": ">=0.10.0" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/extglob": { + "version": "2.0.4", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">=4.0" + "node": ">=0.10.0" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, "engines": { - "node": ">=4.0" + "node": ">=0.10.0" } }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "dev": true, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "dev": true, + "node_modules/fast-deep-equal": { + "version": "3.1.3", "license": "MIT" }, - "node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/exec-sh": { - "version": "0.3.6", - "dev": true, + "node_modules/fast-defer": { + "version": "1.1.7", "license": "MIT" }, - "node_modules/execa": { - "version": "1.0.0", - "dev": true, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", "license": "MIT", "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": ">=6" + "node": ">=8.6.0" } }, - "node_modules/exit": { - "version": "0.1.2", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "license": "MIT" }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "dev": true, - "license": "MIT", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/fast-xml-parser": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz", + "integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "strnum": "^1.0.5" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "fxparser": "src/cli/cli.js" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "dev": true, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "reusify": "^1.0.4" } }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "dev": true, - "license": "MIT", + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dependencies": { - "is-descriptor": "^0.1.0" + "websocket-driver": ">=0.5.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.8.0" } }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/fb-watchman": { + "version": "2.0.2", + "license": "Apache-2.0", "dependencies": { - "is-extendable": "^0.1.0" + "bser": "2.1.1" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "dev": true, + "node_modules/file-entry-cache": { + "version": "6.0.1", "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">=0.10.0" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "dev": true, + "node_modules/file-loader": { + "version": "6.2.0", "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/expand-brackets/node_modules/is-buffer": { - "version": "1.1.6", - "dev": true, - "license": "MIT" + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" }, - "node_modules/expand-brackets/node_modules/is-data-descriptor": { - "version": "0.1.4", - "dev": true, + "node_modules/file-selector": { + "version": "0.6.0", "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "tslib": "^2.4.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 12" } }, - "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, + "node_modules/filesize": { + "version": "8.0.7", + "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4.0" } }, - "node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "dev": true, + "node_modules/fill-range": { + "version": "7.0.1", "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/expand-brackets/node_modules/is-extendable": { - "version": "0.1.1", - "dev": true, + "node_modules/filter-obj": { + "version": "1.1.0", "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/expand-template": { - "version": "2.0.3", - "dev": true, - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/expect": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dependencies": { - "color-convert": "^2.0.1" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dependencies": { - "color-name": "~1.1.4" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=7.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/expect/node_modules/diff-sequences": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, "engines": { - "node": ">= 10.14.2" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/expect/node_modules/jest-diff": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "find-up": "^6.3.0" }, "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/expect/node_modules/jest-matcher-utils": { - "version": "26.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "node": ">=14.16" }, - "engines": { - "node": ">= 10.14.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/pretty-format": { - "version": "26.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, + "node_modules/find-cache-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "engines": { - "node": ">= 10" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expect/node_modules/react-is": { - "version": "17.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/expect/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, + "node_modules/find-up": { + "version": "5.0.0", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express": { - "version": "4.18.2", - "dev": true, + "node_modules/flat-cache": { + "version": "3.0.4", "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/express/node_modules/cookie": { - "version": "0.5.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "license": "ISC", "dependencies": { - "ms": "2.0.0" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/express/node_modules/path-to-regexp": { - "version": "0.1.7", - "dev": true, - "license": "MIT" + "node_modules/flatted": { + "version": "3.2.7", + "license": "ISC" }, - "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/focus-lock": { + "version": "0.11.2", + "license": "MIT", "dependencies": { - "side-channel": "^1.0.4" + "tslib": "^2.0.3" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, + "node_modules/follow-redirects": { + "version": "1.15.1", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT" - }, - "node_modules/extend": { - "version": "3.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "dev": true, "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "engines": { + "node": ">=4.0" }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/font-awesome": { + "version": "4.7.0", + "license": "(OFL-1.1 AND MIT)", "engines": { - "node": ">=0.10.0" + "node": ">=0.10.3" } }, - "node_modules/extglob": { - "version": "2.0.4", - "dev": true, + "node_modules/for-each": { + "version": "0.3.3", "license": "MIT", "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } } }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", "license": "MIT", "dependencies": { - "is-extendable": "^0.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/extglob/node_modules/is-extendable": { - "version": "0.1.1", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-defer": { - "version": "1.1.7", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8.6.0" + "node": ">=7.0.0" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", "license": "MIT" }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "dev": true, - "license": "Apache-2.0", "dependencies": { - "websocket-driver": ">=0.5.1" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" }, "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "license": "ISC", "dependencies": { - "flat-cache": "^3.0.4" + "yallist": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10" } }, - "node_modules/file-loader": { - "version": "6.2.0", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", "license": "MIT", "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 8.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/file-selector": { - "version": "0.6.0", - "license": "MIT", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "7.3.8", + "license": "ISC", "dependencies": { - "tslib": "^2.4.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 12" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 0.4.0" + "node": ">=10" } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "dev": true, + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/filter-obj": { - "version": "1.1.0", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/finalhandler": { - "version": "1.2.0", - "dev": true, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/form-data": { + "version": "4.0.0", "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">= 6" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "dev": true, + "node_modules/form-urlencoded": { + "version": "4.1.4", "license": "MIT" }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "dev": true, - "license": "MIT", + "node_modules/formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/formik": { + "version": "2.2.6", + "funding": [ + { + "type": "individual", + "url": "https://opencollective.com/formik" + } + ], + "license": "Apache-2.0", "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.14", + "lodash-es": "^4.17.14", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^1.10.0" }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/formik/node_modules/deepmerge": { + "version": "2.2.1", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" + } + }, + "node_modules/formik/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz", + "integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==", + "engines": { + "node": "*" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "type": "patreon", + "url": "https://github.com/sponsors/rawify" } }, - "node_modules/find-cache-dir/node_modules/make-dir": { - "version": "3.1.0", - "dev": true, + "node_modules/fragment-cache": { + "version": "0.2.1", "license": "MIT", "dependencies": { - "semver": "^6.0.0" + "map-cache": "^0.2.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/find-up": { - "version": "5.0.0", - "dev": true, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs-extra": { + "version": "9.1.0", "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "dev": true, + "node_modules/fs-monkey": { + "version": "1.0.3", + "license": "Unlicense" + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", + "node_modules/function-bind": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flatted": { - "version": "3.2.7", - "dev": true, - "license": "ISC" - }, - "node_modules/focus-lock": { - "version": "0.11.2", + "node_modules/functions-have-names": { + "version": "1.2.3", "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/follow-redirects": { - "version": "1.15.1", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], + "node_modules/gensync": { + "version": "1.0.0-beta.2", "license": "MIT", "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "node": ">=6.9.0" } }, - "node_modules/font-awesome": { - "version": "4.7.0", - "license": "(OFL-1.1 AND MIT)", + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", "engines": { - "node": ">=0.10.3" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/for-each": { - "version": "0.3.3", - "dev": true, - "license": "MIT", + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { - "is-callable": "^1.1.3" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/for-in": { - "version": "1.0.2", - "dev": true, + "node_modules/get-nonce": { + "version": "1.0.1", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.3", - "dev": true, + "node_modules/get-package-type": { + "version": "0.1.0", "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } + "engines": { + "node": ">=6" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/get-symbol-description": { + "version": "1.0.0", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { - "version": "4.1.2", - "dev": true, + "node_modules/get-value": { + "version": "2.0.6", "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "*" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/glob-parent": { + "version": "5.1.2", + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">= 6" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "dev": true, + "node_modules/global": { + "version": "4.4.0", "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" + "min-document": "^2.19.0", + "process": "^0.11.10" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, + "node_modules/global-modules": { + "version": "2.0.0", "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", + "node_modules/global-prefix": { + "version": "3.0.0", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" }, "engines": { - "node": ">=10" + "node": ">=6" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "dev": true, + "node_modules/globals": { + "version": "11.12.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" + "define-properties": "^1.1.3" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, + "node_modules/globby/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true + }, + "node_modules/gopd": { + "version": "1.0.1", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", + "optional": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { - "version": "1.1.3", + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" + "node_modules/harmony-reflect": { + "version": "1.6.2", + "license": "(Apache-2.0 OR MPL-1.1)" }, - "node_modules/form-data": { - "version": "4.0.0", + "node_modules/has": { + "version": "1.0.3", "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "function-bind": "^1.1.1" }, "engines": { - "node": ">= 6" + "node": ">= 0.4.0" } }, - "node_modules/form-urlencoded": { - "version": "4.1.4", - "license": "MIT" - }, - "node_modules/formidable": { - "version": "1.2.6", - "dev": true, + "node_modules/has-bigints": { + "version": "1.0.2", "license": "MIT", "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/formik": { - "version": "2.2.6", - "funding": [ - { - "type": "individual", - "url": "https://opencollective.com/formik" - } - ], - "license": "Apache-2.0", + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "license": "MIT", "dependencies": { - "deepmerge": "^2.1.1", - "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.14", - "lodash-es": "^4.17.14", - "react-fast-compare": "^2.0.1", - "tiny-warning": "^1.0.2", - "tslib": "^1.10.0" + "get-intrinsic": "^1.1.1" }, - "peerDependencies": { - "react": ">=16.8.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/formik/node_modules/deepmerge": { - "version": "2.2.1", + "node_modules/has-proto": { + "version": "1.0.1", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/formik/node_modules/tslib": { - "version": "1.14.1", - "license": "0BSD" - }, - "node_modules/forwarded": { - "version": "0.2.0", - "dev": true, + "node_modules/has-symbols": { + "version": "1.0.3", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fraction.js": { - "version": "4.2.0", - "dev": true, + "node_modules/has-tostringtag": { + "version": "1.0.0", "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, "engines": { - "node": "*" + "node": ">= 0.4" }, "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "dev": true, + "node_modules/has-value": { + "version": "1.0.0", "license": "MIT", "dependencies": { - "map-cache": "^0.2.2" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/fresh": { - "version": "0.5.2", - "dev": true, + "node_modules/has-values": { + "version": "1.0.0", "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "dev": true, + "node_modules/has-values/node_modules/is-buffer": { + "version": "1.1.6", "license": "MIT" }, - "node_modules/fs-extra": { - "version": "9.1.0", - "dev": true, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/fs-monkey": { - "version": "1.0.3", - "dev": true, - "license": "Unlicense" - }, - "node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "dev": true, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=0.10.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "dev": true, - "license": "MIT" + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "dev": true, + "node_modules/history": { + "version": "4.10.1", "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "license": "ISC" + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/html-element-map": { + "version": "1.3.1", "dev": true, "license": "MIT", + "dependencies": { + "array.prototype.filter": "^1.0.0", + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gauge": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "whatwg-encoding": "^1.0.5" }, "engines": { "node": ">=10" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "license": "MIT", + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", "dev": true, - "license": "ISC", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" } }, - "node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/htmlparser2": { + "version": "8.0.1", "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "license": "MIT", + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "dev": true, - "license": "MIT", + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, "engines": { "node": ">=8.0.0" } }, - "node_modules/get-stdin": { - "version": "7.0.0", - "dev": true, - "license": "MIT", + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "dev": true, - "license": "MIT", + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dependencies": { - "pump": "^3.0.0" + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" }, "engines": { - "node": ">=6" + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/get-value": { - "version": "2.0.6", - "dev": true, - "license": "MIT", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "engines": { - "node": ">=0.10.0" + "node": ">=10.17.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/glob": { - "version": "7.1.6", + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "bin": { + "husky": "lib/bin.js" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/typicode" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", + "node_modules/hyphenate-style-name": { + "version": "1.0.4", + "license": "BSD-3-Clause" + }, + "node_modules/i18n-iso-countries": { + "version": "4.3.1", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "diacritics": "^1.3.0" }, "engines": { "node": ">= 6" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/global": { - "version": "4.4.0", + "node_modules/iconv-lite": { + "version": "0.6.3", "license": "MIT", "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/global-modules": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "global-prefix": "^3.0.0" - }, + "node_modules/icss-utils": { + "version": "5.1.0", + "license": "ISC", "engines": { - "node": ">=6" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/global-prefix": { + "node_modules/identity-obj-proxy": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" + "harmony-reflect": "^1.4.6" }, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/globals": { - "version": "11.12.0", - "dev": true, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 4" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "dev": true, - "license": "MIT", + "node_modules/image-minimizer-webpack-plugin": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/image-minimizer-webpack-plugin/-/image-minimizer-webpack-plugin-3.8.3.tgz", + "integrity": "sha512-Ex0cjNJc2FUSuwN7WHNyxkIZINP0M9lrN+uWJznMcsehiM5Z7ELwk+SEkSGEookK1GUd2wf+09jy1PEH5a5XmQ==", "dependencies": { - "define-properties": "^1.1.3" + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@squoosh/lib": { + "optional": true + }, + "imagemin": { + "optional": true + }, + "sharp": { + "optional": true + }, + "svgo": { + "optional": true + } } }, - "node_modules/globby": { - "version": "6.1.0", - "dev": true, - "license": "MIT", + "node_modules/image-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node_modules/image-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/globjoin": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", - "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", - "dev": true + "node_modules/image-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, - "node_modules/gopd": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "node_modules/image-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dependencies": { - "get-intrinsic": "^1.1.3" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "dev": true, + "node_modules/immediate": { + "version": "3.0.6", "license": "MIT" }, - "node_modules/growly": { - "version": "1.3.0", - "dev": true, + "node_modules/immer": { + "version": "8.0.4", "license": "MIT", - "optional": true + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } }, - "node_modules/gzip-size": { - "version": "6.0.0", - "dev": true, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", "license": "MIT", "dependencies": { - "duplexer": "^0.1.2" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/handle-thing": { - "version": "2.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/harmony-reflect": { - "version": "1.6.2", + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", "dev": true, - "license": "(Apache-2.0 OR MPL-1.1)" + "engines": { + "node": ">=8" + } }, - "node_modules/has": { - "version": "1.0.3", - "dev": true, + "node_modules/import-local": { + "version": "3.1.0", "license": "MIT", "dependencies": { - "function-bind": "^1.1.1" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">= 0.4.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "dev": true, + "node_modules/imurmurhash": { + "version": "0.1.4", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.8.19" } }, - "node_modules/has-flag": { - "version": "3.0.0", + "node_modules/indent-string": { + "version": "4.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/individual": { + "version": "2.0.0" + }, + "node_modules/inflight": { + "version": "1.0.6", + "license": "ISC", "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/has-proto": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "license": "ISC" + }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=12.0.0" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "dev": true, - "license": "MIT", + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "has-symbols": "^1.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/has-unicode": { + "node_modules/inquirer/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, - "node_modules/has-value": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/has-values": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-values/node_modules/is-buffer": { - "version": "1.1.6", - "dev": true, - "license": "MIT" - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "kind-of": "^3.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "dev": true, - "license": "MIT", + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dependencies": { - "is-buffer": "^1.1.5" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "dev": true, + "node_modules/internal-slot": { + "version": "1.0.5", "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/he": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "engines": { + "node": ">=10.13.0" } }, - "node_modules/history": { - "version": "4.10.1", - "license": "MIT", + "node_modules/intl-messageformat": { + "version": "9.13.0", + "license": "BSD-3-Clause", "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "tslib": "^2.1.0" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "license": "BSD-3-Clause", + "node_modules/invariant": { + "version": "2.2.4", + "license": "MIT", "dependencies": { - "react-is": "^16.7.0" + "loose-envify": "^1.0.0" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "dev": true, - "license": "ISC" + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } }, - "node_modules/hpack.js": { - "version": "2.1.6", - "dev": true, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/html-element-map": { - "version": "1.3.1", - "dev": true, + "node_modules/is-array-buffer": { + "version": "3.0.2", "license": "MIT", "dependencies": { - "array.prototype.filter": "^1.0.0", - "call-bind": "^1.0.2" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "dev": true, + "node_modules/is-arrayish": { + "version": "0.2.1", + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", "license": "MIT", "dependencies": { - "whatwg-encoding": "^1.0.5" + "has-bigints": "^1.0.1" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/html-entities": { - "version": "2.3.3", - "dev": true, - "license": "MIT" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "dev": true, + "node_modules/is-binary-path": { + "version": "2.1.0", "license": "MIT", "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", + "node_modules/is-blob": { + "version": "2.1.0", "dev": true, "license": "MIT", "engines": { - "node": ">= 12" - } - }, - "node_modules/html-tags": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", - "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/html-webpack-plugin": { - "version": "5.5.0", - "dev": true, + "node_modules/is-boolean-object": { + "version": "1.1.2", "license": "MIT", "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/htmlparser2": { - "version": "8.0.1", - "dev": true, + "node_modules/is-buffer": { + "version": "2.0.5", "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", { "type": "github", - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } ], "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "entities": "^4.3.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, "engines": { - "node": ">= 0.8" + "node": ">=4" } }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "dev": true, - "license": "MIT" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "dev": true, + "node_modules/is-callable": { + "version": "1.2.7", "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "node": ">= 0.4" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "dev": true, + "node_modules/is-ci": { + "version": "2.0.0", "license": "MIT", "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" + "ci-info": "^2.0.0" }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } + "bin": { + "is-ci": "bin.js" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "dev": true, - "license": "MIT", + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dependencies": { - "agent-base": "6", - "debug": "4" + "has": "^1.0.3" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.0" + }, "engines": { - "node": ">=10.17.0" + "node": ">=0.10.0" } }, - "node_modules/husky": { - "version": "3.1.0", - "dev": true, - "hasInstallScript": true, + "node_modules/is-date-object": { + "version": "1.0.5", "license": "MIT", "dependencies": { - "chalk": "^2.4.2", - "ci-info": "^2.0.0", - "cosmiconfig": "^5.2.1", - "execa": "^1.0.0", - "get-stdin": "^7.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.2.0", - "run-node": "^1.0.0", - "slash": "^3.0.0" - }, - "bin": { - "husky-run": "run.js", - "husky-upgrade": "lib/upgrader/bin.js" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=8.6.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/husky" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/husky/node_modules/cosmiconfig": { - "version": "5.2.1", - "dev": true, + "node_modules/is-descriptor": { + "version": "1.0.2", "license": "MIT", "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/husky/node_modules/import-fresh": { - "version": "2.0.0", - "dev": true, + "node_modules/is-docker": { + "version": "2.2.1", "license": "MIT", - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/husky/node_modules/parse-json": { - "version": "4.0.0", - "dev": true, + "node_modules/is-extendable": { + "version": "1.0.1", "license": "MIT", "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "is-plain-object": "^2.0.4" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/husky/node_modules/resolve-from": { - "version": "3.0.0", - "dev": true, + "node_modules/is-extglob": { + "version": "2.1.1", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/husky/node_modules/slash": { + "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/hyphenate-style-name": { - "version": "1.0.4", - "license": "BSD-3-Clause" + "node_modules/is-function": { + "version": "1.0.2", + "license": "MIT" }, - "node_modules/i18n-iso-countries": { - "version": "4.3.1", - "license": "MIT", - "dependencies": { - "diacritics": "^1.3.0" - }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "dev": true, + "node_modules/is-glob": { + "version": "4.0.3", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/icss-utils": { - "version": "5.1.0", - "dev": true, - "license": "ISC", + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=8" } }, - "node_modules/identity-obj-proxy": { - "version": "3.0.0", - "dev": true, + "node_modules/is-invalid-path": { + "version": "0.1.0", "license": "MIT", "dependencies": { - "harmony-reflect": "^1.4.6" + "is-glob": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.2.4", - "dev": true, + "node_modules/is-invalid-path/node_modules/is-extglob": { + "version": "1.0.0", "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=0.10.0" } }, - "node_modules/image-minimizer-webpack-plugin": { - "version": "3.3.0", - "dev": true, + "node_modules/is-invalid-path/node_modules/is-glob": { + "version": "2.0.1", "license": "MIT", "dependencies": { - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" + "is-extglob": "^1.0.0" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@squoosh/lib": { - "optional": true - }, - "imagemin": { - "optional": true - }, - "sharp": { - "optional": true - } + "node": ">=0.10.0" } }, - "node_modules/image-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.12.0", - "dev": true, + "node_modules/is-negative-zero": { + "version": "2.0.2", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/image-minimizer-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "dev": true, + "node_modules/is-number": { + "version": "7.0.0", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": ">=0.12.0" } }, - "node_modules/image-minimizer-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/image-minimizer-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "dev": true, + "node_modules/is-number-object": { + "version": "1.0.7", "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/immediate": { - "version": "3.0.6", - "license": "MIT" - }, - "node_modules/immer": { - "version": "8.0.4", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" } }, - "node_modules/immutable": { - "version": "4.3.0", - "dev": true, - "license": "MIT" + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "dev": true, - "license": "MIT", + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "path-is-inside": "^1.0.2" }, "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, + "node_modules/is-plain-object": { + "version": "2.0.4", "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" }, - "node_modules/import-local": { - "version": "3.1.0", - "dev": true, + "node_modules/is-regex": { + "version": "1.1.4", "license": "MIT", "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, + "node_modules/is-root": { + "version": "2.1.0", "license": "MIT", "engines": { - "node": ">=0.8.19" + "node": ">=6" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "dev": true, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/individual": { - "version": "2.0.0" - }, - "node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "dev": true, - "license": "ISC" + "node_modules/is-stream": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/internal-slot": { - "version": "1.0.5", - "dev": true, + "node_modules/is-string": { + "version": "1.0.7", "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/interpret": { - "version": "3.1.1", + "node_modules/is-subset": { + "version": "0.1.1", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } + "license": "MIT" }, - "node_modules/intl-messageformat": { - "version": "9.13.0", - "license": "BSD-3-Clause", + "node_modules/is-symbol": { + "version": "1.0.4", + "license": "MIT", "dependencies": { - "@formatjs/ecma402-abstract": "1.11.4", - "@formatjs/fast-memoize": "1.2.1", - "@formatjs/icu-messageformat-parser": "2.1.0", - "tslib": "^2.1.0" + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/intl-messageformat-parser": { - "version": "5.5.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dependencies": { - "@formatjs/intl-numberformat": "^5.5.2" + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/invariant": { - "version": "2.2.4", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } + "node_modules/is-typedarray": { + "version": "1.0.0", + "license": "MIT" }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "engines": { - "node": ">= 10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "dev": true, + "node_modules/is-valid-path": { + "version": "0.1.1", "license": "MIT", "dependencies": { - "kind-of": "^6.0.0" + "is-invalid-path": "^0.1.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "dev": true, + "node_modules/is-weakref": { + "version": "1.0.2", "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "dev": true, + "node_modules/is-windows": { + "version": "1.0.2", "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "dev": true, + "node_modules/is-wsl": { + "version": "2.2.0", "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "is-docker": "^2.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/is-blob": { - "version": "2.1.0", - "dev": true, + "node_modules/isarray": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "license": "BSD-3-Clause", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "2.0.5", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-report/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { - "ci-info": "^2.0.0" + "yallist": "^4.0.0" }, - "bin": { - "is-ci": "bin.js" + "engines": { + "node": ">=10" } }, - "node_modules/is-core-module": { - "version": "2.11.0", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dependencies": { - "has": "^1.0.3" + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-data-descriptor": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { - "kind-of": "^6.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "has-tostringtag": "^1.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-descriptor": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-report/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/is-directory": { - "version": "0.3.1", - "dev": true, - "license": "MIT", + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extendable": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "node_modules/jest": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", "dependencies": { - "is-plain-object": "^2.0.4" + "@jest/core": "^26.6.3", + "import-local": "^3.0.2", + "jest-cli": "^26.6.3" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.14.2" } }, - "node_modules/is-extglob": { - "version": "2.1.1", + "node_modules/jest-canvas-mock": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.5.2.tgz", + "integrity": "sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "cssfontparser": "^1.2.1", + "moo-color": "^1.0.2" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "dependencies": { + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 10.14.2" } }, - "node_modules/is-function": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dependencies": { - "is-extglob": "^2.1.1" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/is-invalid-path": { - "version": "0.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dependencies": { - "is-glob": "^2.0.0" + "pump": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-invalid-path/node_modules/is-extglob": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "engines": { - "node": ">=0.10.0" + "node": ">=8.12.0" } }, - "node_modules/is-invalid-path/node_modules/is-glob": { + "node_modules/jest-changed-files/node_modules/is-stream": { "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^1.0.0" - }, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "node_modules/jest-changed-files/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dependencies": { - "has-tostringtag": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "dev": true, - "license": "MIT", + "node_modules/jest-changed-files/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/is-path-in-cwd": { - "version": "2.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "optional": true, + "peer": true, "dependencies": { - "is-path-inside": "^2.1.0" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-path-in-cwd/node_modules/is-path-inside": { - "version": "2.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "optional": true, + "peer": true, "dependencies": { - "path-is-inside": "^1.0.2" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node_modules/jest-circus/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "optional": true, + "peer": true, "dependencies": { - "isobject": "^3.0.1" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.1.4", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "optional": true, + "peer": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-root": { - "version": "2.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "optional": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "optional": true, + "peer": true, "dependencies": { - "call-bind": "^1.0.2" + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-stream": { - "version": "1.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-string": { - "version": "1.0.7", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "optional": true, + "peer": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-subset": { - "version": "0.1.1", - "dev": true, - "license": "MIT" + "node_modules/jest-circus/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "optional": true, + "peer": true }, - "node_modules/is-symbol": { - "version": "1.0.4", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "peer": true, "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "type-detect": "4.0.8" } }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "optional": true, + "peer": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" + "node_modules/jest-circus/node_modules/@types/yargs": { + "version": "17.0.28", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", + "integrity": "sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==", + "optional": true, + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } }, - "node_modules/is-valid-path": { - "version": "0.1.1", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "peer": true, "dependencies": { - "is-invalid-path": "^0.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "peer": true, "dependencies": { - "call-bind": "^1.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "optional": true, + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "optional": true, + "peer": true + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "peer": true, "dependencies": { - "is-docker": "^2.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, - "node_modules/isarray": { - "version": "0.0.1", - "license": "MIT" + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true, + "peer": true }, - "node_modules/isexe": { + "node_modules/jest-circus/node_modules/convert-source-map": { "version": "2.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "optional": true, + "peer": true }, - "node_modules/isobject": { - "version": "3.0.1", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "optional": true, + "peer": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jest-circus/node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "optional": true, + "peer": true, "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "optional": true, + "peer": true, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "optional": true, + "peer": true, "dependencies": { - "semver": "^6.0.0" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "optional": true, + "peer": true, "dependencies": { - "has-flag": "^4.0.0" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "optional": true, + "peer": true, "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jest-circus/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "optional": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/jest-circus/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "optional": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "optional": true, + "peer": true, "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest": { - "version": "26.6.3", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "optional": true, + "peer": true, "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, - "bin": { - "jest": "bin/jest.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files": { - "version": "26.6.2", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "optional": true, + "peer": true, "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">= 10.14.2" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "optional": true, + "peer": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "4.1.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "optional": true, + "peer": true, "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", + "@types/node": "*", + "jest-util": "^29.7.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "supports-color": "^8.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "5.2.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "peer": true, "dependencies": { - "pump": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/human-signals": { - "version": "1.1.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.12.0" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node_modules/jest-circus/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "peer": true, + "dependencies": { + "yallist": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "optional": true, + "peer": true, "dependencies": { - "path-key": "^3.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "optional": true, + "peer": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-changed-files/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "optional": true, + "peer": true + }, + "node_modules/jest-circus/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "peer": true, "dependencies": { - "shebang-regex": "^3.0.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/jest-changed-files/node_modules/shebang-regex": { + "node_modules/jest-circus/node_modules/slash": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, - "node_modules/jest-changed-files/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "peer": true, "dependencies": { - "isexe": "^2.0.0" + "has-flag": "^4.0.0" }, - "bin": { - "node-which": "bin/node-which" + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "optional": true, + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": ">= 8" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/jest-circus/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true, + "peer": true + }, "node_modules/jest-cli": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", "dependencies": { "@jest/core": "^26.6.3", "@jest/test-result": "^26.6.2", @@ -12317,8 +16084,8 @@ }, "node_modules/jest-cli/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -12331,16 +16098,16 @@ }, "node_modules/jest-cli/node_modules/camelcase": { "version": "5.3.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "engines": { "node": ">=6" } }, "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12354,8 +16121,8 @@ }, "node_modules/jest-cli/node_modules/cliui": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -12364,8 +16131,8 @@ }, "node_modules/jest-cli/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -12375,13 +16142,13 @@ }, "node_modules/jest-cli/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-cli/node_modules/find-up": { "version": "4.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -12392,16 +16159,16 @@ }, "node_modules/jest-cli/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-cli/node_modules/locate-path": { "version": "5.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dependencies": { "p-locate": "^4.1.0" }, @@ -12411,8 +16178,8 @@ }, "node_modules/jest-cli/node_modules/p-limit": { "version": "2.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dependencies": { "p-try": "^2.0.0" }, @@ -12425,8 +16192,8 @@ }, "node_modules/jest-cli/node_modules/p-locate": { "version": "4.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dependencies": { "p-limit": "^2.2.0" }, @@ -12436,8 +16203,8 @@ }, "node_modules/jest-cli/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -12447,8 +16214,8 @@ }, "node_modules/jest-cli/node_modules/wrap-ansi": { "version": "6.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -12460,13 +16227,13 @@ }, "node_modules/jest-cli/node_modules/y18n": { "version": "4.0.3", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, "node_modules/jest-cli/node_modules/yargs": { "version": "15.4.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -12486,8 +16253,8 @@ }, "node_modules/jest-cli/node_modules/yargs-parser": { "version": "18.1.3", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -12498,8 +16265,8 @@ }, "node_modules/jest-config": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", "dependencies": { "@babel/core": "^7.1.0", "@jest/test-sequencer": "^26.6.3", @@ -12534,8 +16301,8 @@ }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -12548,8 +16315,8 @@ }, "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12563,8 +16330,8 @@ }, "node_modules/jest-config/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -12574,21 +16341,21 @@ }, "node_modules/jest-config/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-config/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-config/node_modules/pretty-format": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -12601,13 +16368,13 @@ }, "node_modules/jest-config/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/jest-config/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -12733,8 +16500,8 @@ }, "node_modules/jest-docblock": { "version": "26.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", "dependencies": { "detect-newline": "^3.0.0" }, @@ -12742,108 +16509,10 @@ "node": ">= 10.14.2" } }, - "node_modules/jest-each": { - "version": "26.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "26.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/jest-each/node_modules/react-is": { - "version": "17.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-environment-jsdom": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", "dependencies": { "@jest/environment": "^26.6.2", "@jest/fake-timers": "^26.6.2", @@ -12859,8 +16528,8 @@ }, "node_modules/jest-environment-node": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", "dependencies": { "@jest/environment": "^26.6.2", "@jest/fake-timers": "^26.6.2", @@ -12875,15 +16544,14 @@ }, "node_modules/jest-get-type": { "version": "26.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", "engines": { "node": ">= 10.14.2" } }, "node_modules/jest-haste-map": { "version": "26.6.2", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^26.6.2", @@ -12909,8 +16577,8 @@ }, "node_modules/jest-jasmine2": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", "dependencies": { "@babel/traverse": "^7.1.0", "@jest/environment": "^26.6.2", @@ -12937,8 +16605,8 @@ }, "node_modules/jest-jasmine2/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -12951,8 +16619,8 @@ }, "node_modules/jest-jasmine2/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12966,8 +16634,8 @@ }, "node_modules/jest-jasmine2/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -12977,29 +16645,29 @@ }, "node_modules/jest-jasmine2/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-jasmine2/node_modules/diff-sequences": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "engines": { "node": ">= 10.14.2" } }, "node_modules/jest-jasmine2/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-jasmine2/node_modules/jest-diff": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^26.6.2", @@ -13010,10 +16678,25 @@ "node": ">= 10.14.2" } }, + "node_modules/jest-jasmine2/node_modules/jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "dependencies": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, "node_modules/jest-jasmine2/node_modules/jest-matcher-utils": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^26.6.2", @@ -13026,8 +16709,8 @@ }, "node_modules/jest-jasmine2/node_modules/pretty-format": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -13040,13 +16723,13 @@ }, "node_modules/jest-jasmine2/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/jest-jasmine2/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -13056,8 +16739,8 @@ }, "node_modules/jest-leak-detector": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", "dependencies": { "jest-get-type": "^26.3.0", "pretty-format": "^26.6.2" @@ -13068,8 +16751,8 @@ }, "node_modules/jest-leak-detector/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -13082,8 +16765,8 @@ }, "node_modules/jest-leak-detector/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -13093,13 +16776,13 @@ }, "node_modules/jest-leak-detector/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-leak-detector/node_modules/pretty-format": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -13112,8 +16795,8 @@ }, "node_modules/jest-leak-detector/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/jest-matcher-utils": { "version": "28.1.1", @@ -13233,8 +16916,8 @@ }, "node_modules/jest-message-util": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", "dependencies": { "@babel/code-frame": "^7.0.0", "@jest/types": "^26.6.2", @@ -13252,8 +16935,8 @@ }, "node_modules/jest-message-util/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -13266,8 +16949,8 @@ }, "node_modules/jest-message-util/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13281,8 +16964,8 @@ }, "node_modules/jest-message-util/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -13292,21 +16975,21 @@ }, "node_modules/jest-message-util/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-message-util/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-message-util/node_modules/pretty-format": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -13319,21 +17002,21 @@ }, "node_modules/jest-message-util/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/jest-message-util/node_modules/slash": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { "node": ">=8" } }, "node_modules/jest-message-util/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -13343,8 +17026,8 @@ }, "node_modules/jest-mock": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", "dependencies": { "@jest/types": "^26.6.2", "@types/node": "*" @@ -13355,8 +17038,8 @@ }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "engines": { "node": ">=6" }, @@ -13371,7 +17054,6 @@ }, "node_modules/jest-regex-util": { "version": "26.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.14.2" @@ -13379,8 +17061,8 @@ }, "node_modules/jest-resolve": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", "dependencies": { "@jest/types": "^26.6.2", "chalk": "^4.0.0", @@ -13397,8 +17079,8 @@ }, "node_modules/jest-resolve-dependencies": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", "dependencies": { "@jest/types": "^26.6.2", "jest-regex-util": "^26.0.0", @@ -13410,8 +17092,8 @@ }, "node_modules/jest-resolve/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -13424,8 +17106,8 @@ }, "node_modules/jest-resolve/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13439,8 +17121,8 @@ }, "node_modules/jest-resolve/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -13450,29 +17132,29 @@ }, "node_modules/jest-resolve/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-resolve/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-resolve/node_modules/slash": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { "node": ">=8" } }, "node_modules/jest-resolve/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -13482,8 +17164,8 @@ }, "node_modules/jest-runner": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", "dependencies": { "@jest/console": "^26.6.2", "@jest/environment": "^26.6.2", @@ -13512,8 +17194,8 @@ }, "node_modules/jest-runner/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -13526,8 +17208,8 @@ }, "node_modules/jest-runner/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13541,8 +17223,8 @@ }, "node_modules/jest-runner/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -13552,21 +17234,21 @@ }, "node_modules/jest-runner/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-runner/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-runner/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -13576,8 +17258,8 @@ }, "node_modules/jest-runtime": { "version": "26.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", "dependencies": { "@jest/console": "^26.6.2", "@jest/environment": "^26.6.2", @@ -13616,8 +17298,8 @@ }, "node_modules/jest-runtime/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -13630,16 +17312,16 @@ }, "node_modules/jest-runtime/node_modules/camelcase": { "version": "5.3.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "engines": { "node": ">=6" } }, "node_modules/jest-runtime/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13653,8 +17335,8 @@ }, "node_modules/jest-runtime/node_modules/cliui": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -13663,8 +17345,8 @@ }, "node_modules/jest-runtime/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -13674,13 +17356,13 @@ }, "node_modules/jest-runtime/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-runtime/node_modules/find-up": { "version": "4.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -13691,16 +17373,16 @@ }, "node_modules/jest-runtime/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-runtime/node_modules/locate-path": { "version": "5.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dependencies": { "p-locate": "^4.1.0" }, @@ -13710,8 +17392,8 @@ }, "node_modules/jest-runtime/node_modules/p-limit": { "version": "2.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dependencies": { "p-try": "^2.0.0" }, @@ -13724,8 +17406,8 @@ }, "node_modules/jest-runtime/node_modules/p-locate": { "version": "4.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dependencies": { "p-limit": "^2.2.0" }, @@ -13735,16 +17417,16 @@ }, "node_modules/jest-runtime/node_modules/slash": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "engines": { "node": ">=8" } }, "node_modules/jest-runtime/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -13754,8 +17436,8 @@ }, "node_modules/jest-runtime/node_modules/wrap-ansi": { "version": "6.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -13767,13 +17449,13 @@ }, "node_modules/jest-runtime/node_modules/y18n": { "version": "4.0.3", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, "node_modules/jest-runtime/node_modules/yargs": { "version": "15.4.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -13793,8 +17475,8 @@ }, "node_modules/jest-runtime/node_modules/yargs-parser": { "version": "18.1.3", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -13805,7 +17487,6 @@ }, "node_modules/jest-serializer": { "version": "26.6.2", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -13817,8 +17498,8 @@ }, "node_modules/jest-snapshot": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", "dependencies": { "@babel/types": "^7.0.0", "@jest/types": "^26.6.2", @@ -13843,8 +17524,8 @@ }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -13857,8 +17538,8 @@ }, "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13872,8 +17553,8 @@ }, "node_modules/jest-snapshot/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -13883,29 +17564,29 @@ }, "node_modules/jest-snapshot/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-snapshot/node_modules/diff-sequences": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "engines": { "node": ">= 10.14.2" } }, "node_modules/jest-snapshot/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-snapshot/node_modules/jest-diff": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^26.6.2", @@ -13918,8 +17599,8 @@ }, "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^26.6.2", @@ -13932,8 +17613,8 @@ }, "node_modules/jest-snapshot/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { "yallist": "^4.0.0" }, @@ -13943,8 +17624,8 @@ }, "node_modules/jest-snapshot/node_modules/pretty-format": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -13957,13 +17638,13 @@ }, "node_modules/jest-snapshot/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -13976,8 +17657,8 @@ }, "node_modules/jest-snapshot/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -13987,12 +17668,11 @@ }, "node_modules/jest-snapshot/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/jest-util": { "version": "26.6.2", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^26.6.2", @@ -14008,7 +17688,6 @@ }, "node_modules/jest-util/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -14022,7 +17701,6 @@ }, "node_modules/jest-util/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -14037,7 +17715,6 @@ }, "node_modules/jest-util/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -14048,12 +17725,10 @@ }, "node_modules/jest-util/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14061,7 +17736,6 @@ }, "node_modules/jest-util/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -14072,8 +17746,8 @@ }, "node_modules/jest-validate": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", "dependencies": { "@jest/types": "^26.6.2", "camelcase": "^6.0.0", @@ -14088,8 +17762,8 @@ }, "node_modules/jest-validate/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -14102,8 +17776,8 @@ }, "node_modules/jest-validate/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14117,8 +17791,8 @@ }, "node_modules/jest-validate/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -14128,21 +17802,21 @@ }, "node_modules/jest-validate/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-validate/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-validate/node_modules/pretty-format": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -14155,13 +17829,13 @@ }, "node_modules/jest-validate/node_modules/react-is": { "version": "17.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/jest-validate/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -14171,8 +17845,8 @@ }, "node_modules/jest-watcher": { "version": "26.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", "dependencies": { "@jest/test-result": "^26.6.2", "@jest/types": "^26.6.2", @@ -14188,8 +17862,8 @@ }, "node_modules/jest-watcher/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { "color-convert": "^2.0.1" }, @@ -14202,8 +17876,8 @@ }, "node_modules/jest-watcher/node_modules/chalk": { "version": "4.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14217,8 +17891,8 @@ }, "node_modules/jest-watcher/node_modules/color-convert": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { "color-name": "~1.1.4" }, @@ -14228,21 +17902,21 @@ }, "node_modules/jest-watcher/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-watcher/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/jest-watcher/node_modules/supports-color": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { "has-flag": "^4.0.0" }, @@ -14252,7 +17926,6 @@ }, "node_modules/jest-worker": { "version": "26.6.2", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -14265,7 +17938,6 @@ }, "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14273,7 +17945,6 @@ }, "node_modules/jest-worker/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -14282,27 +17953,26 @@ "node": ">=8" } }, + "node_modules/jiti": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", + "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/jquery": { - "version": "3.6.1", - "license": "MIT", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", "peer": true }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.1", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -14314,8 +17984,8 @@ }, "node_modules/jsdom": { "version": "16.7.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dependencies": { "abab": "^2.0.5", "acorn": "^8.2.4", @@ -14359,8 +18029,8 @@ }, "node_modules/jsdom/node_modules/form-data": { "version": "3.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -14372,12 +18042,11 @@ }, "node_modules/jsdom/node_modules/parse5": { "version": "6.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, "node_modules/jsesc": { "version": "2.5.2", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -14386,29 +18055,32 @@ "node": ">=4" } }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", + "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", + "dependencies": { + "jsonify": "^0.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "node_modules/json5": { "version": "2.2.3", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -14419,7 +18091,6 @@ }, "node_modules/jsonfile": { "version": "6.1.0", - "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -14428,13 +18099,23 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "dev": true, - "license": "MIT", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" }, "engines": { "node": ">=4.0" @@ -14469,7 +18150,6 @@ }, "node_modules/kind-of": { "version": "6.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -14477,20 +18157,11 @@ }, "node_modules/kleur": { "version": "3.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/klona": { - "version": "2.0.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/known-css-properties": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", @@ -14499,38 +18170,38 @@ }, "node_modules/language-subtag-registry": { "version": "0.3.22", - "dev": true, - "license": "CC0-1.0" + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" }, "node_modules/language-tags": { - "version": "1.0.8", - "dev": true, - "license": "MIT", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", "dependencies": { - "language-subtag-registry": "^0.3.20" + "language-subtag-registry": "~0.3.2" } }, "node_modules/launch-editor": { - "version": "2.6.0", - "dev": true, - "license": "MIT", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dependencies": { "picocolors": "^1.0.0", - "shell-quote": "^1.7.3" + "shell-quote": "^1.8.1" } }, "node_modules/leven": { "version": "3.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "engines": { "node": ">=6" } }, "node_modules/levn": { "version": "0.4.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -14548,28 +18219,26 @@ }, "node_modules/lilconfig": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "engines": { "node": ">=10" } }, "node_modules/lines-and-columns": { "version": "1.2.4", - "dev": true, "license": "MIT" }, "node_modules/loader-runner": { "version": "4.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "engines": { "node": ">=6.11.5" } }, "node_modules/loader-utils": { "version": "2.0.4", - "dev": true, "license": "MIT", "dependencies": { "big.js": "^5.2.2", @@ -14595,7 +18264,6 @@ }, "node_modules/locate-path": { "version": "6.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -14621,19 +18289,28 @@ }, "node_modules/lodash.debounce": { "version": "4.0.8", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.escape": { "version": "4.0.1", - "dev": true, "license": "MIT" }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, "node_modules/lodash.flattendeep": { "version": "4.4.0", "dev": true, "license": "MIT" }, + "node_modules/lodash.invokemap": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz", + "integrity": "sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w==" + }, "node_modules/lodash.isequal": { "version": "4.5.0", "dev": true, @@ -14651,6 +18328,11 @@ "version": "4.6.2", "license": "MIT" }, + "node_modules/lodash.pullall": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.pullall/-/lodash.pullall-4.2.0.tgz", + "integrity": "sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==" + }, "node_modules/lodash.snakecase": { "version": "4.1.1", "license": "MIT" @@ -14667,13 +18349,92 @@ }, "node_modules/lodash.uniq": { "version": "4.5.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, "node_modules/lodash.uniqby": { "version": "4.7.0", "license": "MIT" }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "license": "MIT", @@ -14686,24 +18447,25 @@ }, "node_modules/lower-case": { "version": "2.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dependencies": { "tslib": "^2.0.3" } }, "node_modules/lru-cache": { "version": "5.1.1", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/lz-string": { - "version": "1.4.4", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, - "license": "WTFPL", "bin": { "lz-string": "bin/bin.js" } @@ -14732,8 +18494,8 @@ }, "node_modules/make-dir": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -14743,16 +18505,22 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "5.7.1", - "dev": true, - "license": "ISC", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "optional": true, + "peer": true + }, "node_modules/makeerror": { "version": "1.0.12", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" @@ -14760,7 +18528,6 @@ }, "node_modules/map-cache": { "version": "0.2.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -14780,7 +18547,6 @@ }, "node_modules/map-visit": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "object-visit": "^1.0.0" @@ -14807,21 +18573,20 @@ } }, "node_modules/mdn-data": { - "version": "2.0.14", - "dev": true, - "license": "CC0-1.0" + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, "node_modules/media-typer": { "version": "0.3.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { "node": ">= 0.6" } }, "node_modules/memfs": { "version": "3.4.13", - "dev": true, "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.3" @@ -14939,17 +18704,15 @@ }, "node_modules/merge-descriptors": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -14957,15 +18720,14 @@ }, "node_modules/methods": { "version": "1.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { "version": "4.0.5", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.2", @@ -14977,8 +18739,8 @@ }, "node_modules/mime": { "version": "1.6.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "bin": { "mime": "cli.js" }, @@ -15005,7 +18767,6 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -15013,8 +18774,8 @@ }, "node_modules/mimic-response": { "version": "3.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "engines": { "node": ">=10" }, @@ -15038,7 +18799,6 @@ }, "node_modules/mini-css-extract-plugin": { "version": "1.6.2", - "dev": true, "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", @@ -15058,8 +18818,8 @@ }, "node_modules/minimalistic-assert": { "version": "1.0.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -15073,7 +18833,6 @@ }, "node_modules/minimist": { "version": "1.2.8", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15102,50 +18861,8 @@ "node": ">=0.10.0" } }, - "node_modules/minipass": { - "version": "3.3.4", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, "node_modules/mixin-deep": { "version": "1.3.2", - "dev": true, "license": "MIT", "dependencies": { "for-in": "^1.0.2", @@ -15157,12 +18874,13 @@ }, "node_modules/mkdirp-classic": { "version": "0.5.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "node_modules/moment": { - "version": "2.29.2", - "license": "MIT", + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "engines": { "node": "*" } @@ -15182,6 +18900,21 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/moo-color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz", + "integrity": "sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==", + "dev": true, + "dependencies": { + "color-name": "^1.1.4" + } + }, + "node_modules/moo-color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/mpd-parser": { "version": "0.21.1", "license": "Apache-2.0", @@ -15197,21 +18930,20 @@ }, "node_modules/mrmime": { "version": "1.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", "engines": { "node": ">=10" } }, "node_modules/ms": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -15220,6 +18952,11 @@ "multicast-dns": "cli.js" } }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/mux.js": { "version": "6.0.1", "license": "Apache-2.0", @@ -15235,16 +18972,8 @@ "npm": ">=5" } }, - "node_modules/nan": { - "version": "2.17.0", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/nanoid": { "version": "3.3.6", - "dev": true, "funding": [ { "type": "github", @@ -15261,7 +18990,6 @@ }, "node_modules/nanomatch": { "version": "1.2.13", - "dev": true, "license": "MIT", "dependencies": { "arr-diff": "^4.0.0", @@ -15282,12 +19010,11 @@ }, "node_modules/napi-build-utils": { "version": "1.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, "node_modules/natural-compare": { "version": "1.4.0", - "dev": true, "license": "MIT" }, "node_modules/nearley": { @@ -15318,35 +19045,34 @@ }, "node_modules/negotiator": { "version": "0.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } }, "node_modules/neo-async": { "version": "2.6.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/nice-try": { "version": "1.0.5", - "dev": true, "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "node_modules/node-abi": { - "version": "3.34.0", - "dev": true, - "license": "MIT", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.49.0.tgz", + "integrity": "sha512-ji8IK8VT2zAQv9BeOqwnpuvJnCivxPCe2HNiPe8P1z1SDhqEFpm7GqctqTWkujb8mLfZ1PWDrjMeiq6l9TN7fA==", "dependencies": { "semver": "^7.3.5" }, @@ -15356,8 +19082,8 @@ }, "node_modules/node-abi/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { "yallist": "^4.0.0" }, @@ -15366,92 +19092,45 @@ } }, "node_modules/node-abi/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/node-addon-api": { - "version": "5.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" + "lru-cache": "^6.0.0" }, - "peerDependencies": { - "encoding": "^0.1.0" + "bin": { + "semver": "bin/semver.js" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "engines": { + "node": ">=10" } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true + "node_modules/node-abi/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, "node_modules/node-forge": { "version": "1.3.1", - "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-int64": { "version": "0.4.0", - "dev": true, "license": "MIT" }, "node_modules/node-notifier": { "version": "8.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "optional": true, "dependencies": { "growly": "^1.3.0", @@ -15464,8 +19143,8 @@ }, "node_modules/node-notifier/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "optional": true, "dependencies": { "yallist": "^4.0.0" @@ -15475,9 +19154,9 @@ } }, "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "optional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -15491,8 +19170,8 @@ }, "node_modules/node-notifier/node_modules/uuid": { "version": "8.3.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "optional": true, "bin": { "uuid": "dist/bin/uuid" @@ -15500,8 +19179,8 @@ }, "node_modules/node-notifier/node_modules/which": { "version": "2.0.2", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "optional": true, "dependencies": { "isexe": "^2.0.0" @@ -15515,34 +19194,17 @@ }, "node_modules/node-notifier/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "optional": true }, "node_modules/node-releases": { - "version": "2.0.10", - "dev": true, - "license": "MIT" - }, - "node_modules/nopt": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, "node_modules/normalize-package-data": { "version": "2.5.0", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", @@ -15553,7 +19215,6 @@ }, "node_modules/normalize-package-data/node_modules/semver": { "version": "5.7.1", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -15561,7 +19222,6 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15569,26 +19229,14 @@ }, "node_modules/normalize-range": { "version": "0.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "engines": { "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/npm-run-path": { "version": "2.0.2", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^2.0.0" @@ -15597,22 +19245,8 @@ "node": ">=4" } }, - "node_modules/npmlog": { - "version": "5.0.1", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -15622,9 +19256,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.2", - "dev": true, - "license": "MIT" + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -15639,7 +19273,6 @@ }, "node_modules/object-copy": { "version": "0.1.0", - "dev": true, "license": "MIT", "dependencies": { "copy-descriptor": "^0.1.0", @@ -15652,7 +19285,6 @@ }, "node_modules/object-copy/node_modules/define-property": { "version": "0.2.5", - "dev": true, "license": "MIT", "dependencies": { "is-descriptor": "^0.1.0" @@ -15663,7 +19295,6 @@ }, "node_modules/object-copy/node_modules/is-accessor-descriptor": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -15674,12 +19305,10 @@ }, "node_modules/object-copy/node_modules/is-buffer": { "version": "1.1.6", - "dev": true, "license": "MIT" }, "node_modules/object-copy/node_modules/is-data-descriptor": { "version": "0.1.4", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -15690,7 +19319,6 @@ }, "node_modules/object-copy/node_modules/is-descriptor": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "is-accessor-descriptor": "^0.1.6", @@ -15703,7 +19331,6 @@ }, "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { "version": "5.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15711,7 +19338,6 @@ }, "node_modules/object-copy/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -15726,7 +19352,6 @@ }, "node_modules/object-inspect": { "version": "1.12.3", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15749,7 +19374,6 @@ }, "node_modules/object-keys": { "version": "1.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -15757,7 +19381,6 @@ }, "node_modules/object-visit": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "isobject": "^3.0.0" @@ -15768,7 +19391,6 @@ }, "node_modules/object.assign": { "version": "4.1.4", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -15785,7 +19407,6 @@ }, "node_modules/object.entries": { "version": "1.1.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -15798,7 +19419,6 @@ }, "node_modules/object.fromentries": { "version": "2.0.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -15813,12 +19433,12 @@ } }, "node_modules/object.hasown": { - "version": "1.1.2", - "dev": true, - "license": "MIT", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15826,7 +19446,6 @@ }, "node_modules/object.pick": { "version": "1.3.0", - "dev": true, "license": "MIT", "dependencies": { "isobject": "^3.0.1" @@ -15837,7 +19456,6 @@ }, "node_modules/object.values": { "version": "1.1.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -15853,13 +19471,13 @@ }, "node_modules/obuf": { "version": "1.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "node_modules/on-finished": { "version": "2.4.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { "ee-first": "1.1.1" }, @@ -15869,8 +19487,8 @@ }, "node_modules/on-headers": { "version": "1.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "engines": { "node": ">= 0.8" } @@ -15884,7 +19502,6 @@ }, "node_modules/onetime": { "version": "5.1.2", - "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -15898,7 +19515,6 @@ }, "node_modules/open": { "version": "8.4.2", - "dev": true, "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -15912,42 +19528,128 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/opencollective-postinstall": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "bin": { - "opencollective-postinstall": "index.js" - } - }, "node_modules/opener": { "version": "1.5.2", - "dev": true, - "license": "(WTFPL OR MIT)", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "bin": { "opener": "bin/opener-bin.js" } }, "node_modules/optionator": { - "version": "0.9.1", - "dev": true, - "license": "MIT", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-each-series": { "version": "2.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", "engines": { "node": ">=8" }, @@ -15957,7 +19659,6 @@ }, "node_modules/p-finally": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -15965,7 +19666,6 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -15979,7 +19679,6 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -15993,16 +19692,16 @@ }, "node_modules/p-map": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", "engines": { "node": ">=6" } }, "node_modules/p-retry": { "version": "4.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -16013,7 +19712,6 @@ }, "node_modules/p-try": { "version": "2.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -16026,8 +19724,8 @@ }, "node_modules/param-case": { "version": "3.0.4", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -16035,7 +19733,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -16046,7 +19743,6 @@ }, "node_modules/parse-json": { "version": "5.2.0", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -16086,16 +19782,16 @@ }, "node_modules/parseurl": { "version": "1.3.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "engines": { "node": ">= 0.8" } }, "node_modules/pascal-case": { "version": "3.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -16103,7 +19799,6 @@ }, "node_modules/pascalcase": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -16111,7 +19806,6 @@ }, "node_modules/path-exists": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16126,12 +19820,11 @@ }, "node_modules/path-is-inside": { "version": "1.0.2", - "dev": true, - "license": "(WTFPL OR MIT)" + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" }, "node_modules/path-key": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -16139,19 +19832,10 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, "license": "MIT" }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "license": "MIT", - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16164,12 +19848,10 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -16180,24 +19862,24 @@ }, "node_modules/pify": { "version": "4.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "engines": { "node": ">=6" } }, "node_modules/pinkie": { "version": "2.0.4", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "engines": { "node": ">=0.10.0" } }, "node_modules/pinkie-promise": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dependencies": { "pinkie": "^2.0.0" }, @@ -16207,7 +19889,6 @@ }, "node_modules/pirates": { "version": "4.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -16225,7 +19906,6 @@ }, "node_modules/pkg-dir": { "version": "4.2.0", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" @@ -16236,7 +19916,6 @@ }, "node_modules/pkg-dir/node_modules/find-up": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -16248,7 +19927,6 @@ }, "node_modules/pkg-dir/node_modules/locate-path": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -16259,7 +19937,6 @@ }, "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -16273,7 +19950,6 @@ }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -16284,7 +19960,6 @@ }, "node_modules/pkg-up": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^3.0.0" @@ -16295,7 +19970,6 @@ }, "node_modules/pkg-up/node_modules/find-up": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -16306,7 +19980,6 @@ }, "node_modules/pkg-up/node_modules/locate-path": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -16318,7 +19991,6 @@ }, "node_modules/pkg-up/node_modules/p-limit": { "version": "2.3.0", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -16332,7 +20004,6 @@ }, "node_modules/pkg-up/node_modules/p-locate": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -16343,23 +20014,16 @@ }, "node_modules/pkg-up/node_modules/path-exists": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver-compare": "^1.0.0" - } - }, "node_modules/popper.js": { "version": "1.16.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", "peer": true, "funding": { "type": "opencollective", @@ -16368,15 +20032,15 @@ }, "node_modules/posix-character-classes": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/postcss": { - "version": "8.4.21", - "dev": true, + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -16385,11 +20049,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -16398,21 +20065,24 @@ } }, "node_modules/postcss-calc": { - "version": "8.2.4", - "dev": true, - "license": "MIT", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", "dependencies": { - "postcss-selector-parser": "^6.0.9", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, "peerDependencies": { "postcss": "^8.2.2" } }, "node_modules/postcss-colormin": { - "version": "5.3.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", + "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -16420,103 +20090,109 @@ "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-convert-values": { - "version": "5.1.3", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", + "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-custom-media": { - "version": "9.1.2", - "dev": true, - "license": "MIT", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-10.0.2.tgz", + "integrity": "sha512-zcEFNRmDm2fZvTPdI1pIW3W//UruMcLosmMiCdpQnrCsTRzWlKQPYMa1ud9auL0BmrryKK1+JjIGn19K0UjO/w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "dependencies": { - "@csstools/cascade-layer-name-parser": "^1.0.0", - "@csstools/css-parser-algorithms": "^2.0.0", - "@csstools/css-tokenizer": "^2.0.0", - "@csstools/media-query-list-parser": "^2.0.0" + "@csstools/cascade-layer-name-parser": "^1.0.5", + "@csstools/css-parser-algorithms": "^2.3.2", + "@csstools/css-tokenizer": "^2.2.1", + "@csstools/media-query-list-parser": "^2.1.5" }, "engines": { "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, "peerDependencies": { "postcss": "^8.4" } }, "node_modules/postcss-discard-comments": { - "version": "5.1.2", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", + "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-discard-duplicates": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", + "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-discard-empty": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", + "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-discard-overridden": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", + "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-loader": { - "version": "6.2.1", - "dev": true, - "license": "MIT", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" + "cosmiconfig": "^8.2.0", + "jiti": "^1.18.2", + "semver": "^7.3.8" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", @@ -16527,10 +20203,51 @@ "webpack": "^5.0.0" } }, + "node_modules/postcss-loader/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.5.tgz", + "integrity": "sha512-A5Xry3xfS96wy2qbiLkQLAg4JUrR2wvfybxj6yqLmrUfMAvhS3MZxIP2oQn0grgYIvJqzpeTEWu4vK0t+12NNw==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss-loader/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/postcss-loader/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { "yallist": "^4.0.0" }, @@ -16539,9 +20256,9 @@ } }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16552,10 +20269,24 @@ "node": ">=10" } }, + "node_modules/postcss-loader/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/postcss-loader/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", @@ -16564,92 +20295,92 @@ "dev": true }, "node_modules/postcss-merge-longhand": { - "version": "5.1.7", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", + "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.1.1" + "stylehacks": "^6.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-merge-rules": { - "version": "5.1.4", - "dev": true, - "license": "MIT", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", + "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.1.0", + "cssnano-utils": "^4.0.0", "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-minify-font-values": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", + "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-minify-gradients": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", + "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", "dependencies": { "colord": "^2.9.1", - "cssnano-utils": "^3.1.0", + "cssnano-utils": "^4.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-minify-params": { - "version": "5.1.4", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", + "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", "dependencies": { "browserslist": "^4.21.4", - "cssnano-utils": "^3.1.0", + "cssnano-utils": "^4.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-minify-selectors": { - "version": "5.2.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", + "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", "dependencies": { "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" @@ -16657,7 +20388,6 @@ }, "node_modules/postcss-modules-extract-imports": { "version": "3.0.0", - "dev": true, "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" @@ -16668,7 +20398,6 @@ }, "node_modules/postcss-modules-local-by-default": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", @@ -16684,7 +20413,6 @@ }, "node_modules/postcss-modules-scope": { "version": "3.0.0", - "dev": true, "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" @@ -16698,7 +20426,6 @@ }, "node_modules/postcss-modules-values": { "version": "4.0.0", - "dev": true, "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" @@ -16711,169 +20438,168 @@ } }, "node_modules/postcss-normalize-charset": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", + "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-display-values": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", + "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-positions": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", + "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", + "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-string": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", + "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", + "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-unicode": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", + "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-url": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", + "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", "dependencies": { - "normalize-url": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-normalize-whitespace": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", + "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-ordered-values": { - "version": "5.1.3", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", + "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", "dependencies": { - "cssnano-utils": "^3.1.0", + "cssnano-utils": "^4.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-reduce-initial": { - "version": "5.1.2", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", + "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-reduce-transforms": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", + "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" @@ -16886,17 +20612,17 @@ "dev": true }, "node_modules/postcss-rtlcss": { - "version": "3.7.2", - "dev": true, - "license": "Apache-2.0", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-4.0.8.tgz", + "integrity": "sha512-CR2sY889PHnX6K8rjW9FG4Qvm9UJsIekDakMtEYGH3zgFp9XADMeaKcA0hPOmkClNh0jWbkaPBm0jZ6fHmqkJQ==", "dependencies": { - "rtlcss": "^3.5.0" + "rtlcss": "4.1.0" }, "engines": { "node": ">=12.0.0" }, "peerDependencies": { - "postcss": "^8.0.0" + "postcss": "^8.4.21" } }, "node_modules/postcss-safe-parser": { @@ -16939,7 +20665,6 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.11", - "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -16950,29 +20675,29 @@ } }, "node_modules/postcss-svgo": { - "version": "5.1.0", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", + "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", "dependencies": { "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" + "svgo": "^3.0.2" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >= 18" }, "peerDependencies": { "postcss": "^8.2.15" } }, "node_modules/postcss-unique-selectors": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", + "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", "dependencies": { "postcss-selector-parser": "^6.0.5" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" @@ -16980,13 +20705,12 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "dev": true, "license": "MIT" }, "node_modules/prebuild-install": { "version": "7.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -17008,42 +20732,57 @@ "node": ">=10" } }, - "node_modules/prebuild-install/node_modules/simple-get": { - "version": "4.0.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/prelude-ls": { "version": "1.2.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "engines": { "node": ">= 0.8.0" } }, "node_modules/pretty-error": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", "dependencies": { "lodash": "^4.17.20", "renderkid": "^3.0.0" @@ -17091,7 +20830,6 @@ }, "node_modules/prompts": { "version": "2.4.2", - "dev": true, "license": "MIT", "dependencies": { "kleur": "^3.0.3", @@ -17110,16 +20848,6 @@ "react-is": "^16.8.1" } }, - "node_modules/prop-types-exact": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3", - "object.assign": "^4.1.0", - "reflect.ownkeys": "^0.2.0" - } - }, "node_modules/prop-types-extra": { "version": "1.1.1", "license": "MIT", @@ -17136,9 +20864,9 @@ "license": "MIT" }, "node_modules/proxy-addr": { - "version": "2.0.7", - "dev": true, - "license": "MIT", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -17147,18 +20875,10 @@ "node": ">= 0.10" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/psl": { "version": "1.9.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, "node_modules/pubsub-js": { "version": "1.9.4", @@ -17166,7 +20886,6 @@ }, "node_modules/pump": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -17175,15 +20894,30 @@ }, "node_modules/punycode": { "version": "2.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "optional": true, + "peer": true + }, "node_modules/purgecss": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "commander": "^9.0.0", @@ -17197,7 +20931,6 @@ }, "node_modules/purgecss/node_modules/brace-expansion": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -17205,7 +20938,6 @@ }, "node_modules/purgecss/node_modules/commander": { "version": "9.5.0", - "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || >=14" @@ -17213,7 +20945,6 @@ }, "node_modules/purgecss/node_modules/glob": { "version": "8.1.0", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -17231,7 +20962,6 @@ }, "node_modules/purgecss/node_modules/minimatch": { "version": "5.1.6", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -17241,9 +20971,9 @@ } }, "node_modules/qs": { - "version": "6.11.1", - "dev": true, - "license": "BSD-3-Clause", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -17279,12 +21009,11 @@ }, "node_modules/querystringify": { "version": "2.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -17301,6 +21030,11 @@ ], "license": "MIT" }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, "node_modules/quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -17337,24 +21071,24 @@ }, "node_modules/randombytes": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dependencies": { "safe-buffer": "^5.1.0" } }, "node_modules/range-parser": { "version": "1.2.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { "version": "2.5.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -17365,18 +21099,10 @@ "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/raw-body/node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -17386,8 +21112,8 @@ }, "node_modules/rc": { "version": "1.2.8", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -17400,19 +21126,19 @@ }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "engines": { "node": ">=0.10.0" } }, "node_modules/react": { - "version": "16.14.0", - "license": "MIT", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" }, "engines": { "node": ">=0.10.0" @@ -17487,7 +21213,6 @@ }, "node_modules/react-dev-utils": { "version": "12.0.1", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.0", @@ -17521,7 +21246,6 @@ }, "node_modules/react-dev-utils/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -17533,17 +21257,8 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/react-dev-utils/node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/react-dev-utils/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -17558,7 +21273,6 @@ }, "node_modules/react-dev-utils/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -17569,12 +21283,10 @@ }, "node_modules/react-dev-utils/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/react-dev-utils/node_modules/cross-spawn": { "version": "7.0.3", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -17587,27 +21299,7 @@ }, "node_modules/react-dev-utils/node_modules/escape-string-regexp": { "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/globby": { - "version": "11.1.0", - "dev": true, "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, "engines": { "node": ">=10" }, @@ -17617,7 +21309,6 @@ }, "node_modules/react-dev-utils/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17625,7 +21316,6 @@ }, "node_modules/react-dev-utils/node_modules/immer": { "version": "9.0.21", - "dev": true, "license": "MIT", "funding": { "type": "opencollective", @@ -17634,7 +21324,6 @@ }, "node_modules/react-dev-utils/node_modules/loader-utils": { "version": "3.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 12.13.0" @@ -17642,7 +21331,6 @@ }, "node_modules/react-dev-utils/node_modules/path-key": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17650,7 +21338,6 @@ }, "node_modules/react-dev-utils/node_modules/shebang-command": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -17661,15 +21348,6 @@ }, "node_modules/react-dev-utils/node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/slash": { - "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17677,7 +21355,6 @@ }, "node_modules/react-dev-utils/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -17688,7 +21365,6 @@ }, "node_modules/react-dev-utils/node_modules/which": { "version": "2.0.2", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -17701,16 +21377,16 @@ } }, "node_modules/react-dom": { - "version": "16.14.0", - "license": "MIT", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.20.2" }, "peerDependencies": { - "react": "^16.14.0" + "react": "17.0.2" } }, "node_modules/react-dropzone": { @@ -17740,7 +21416,6 @@ }, "node_modules/react-error-overlay": { "version": "6.0.11", - "dev": true, "license": "MIT" }, "node_modules/react-fast-compare": { @@ -17902,29 +21577,20 @@ "version": "1.0.4", "license": "MIT" }, - "node_modules/react-ranger": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/react-ranger/-/react-ranger-2.1.0.tgz", - "integrity": "sha512-d8ezhyX3v/KlN8SkyoE5e8Dybsdmn94eUAqBDsAPrVhZde8sVt6pLJw4fC784KiMmS4LyAjvtjGxhAEqjjGYgw==", - "hasInstallScript": true, - "peerDependencies": { - "react": "^16.6.3" - } - }, "node_modules/react-redux": { - "version": "7.1.3", - "license": "MIT", + "version": "7.2.9", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", + "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", "dependencies": { - "@babel/runtime": "^7.5.5", - "hoist-non-react-statics": "^3.3.0", - "invariant": "^2.2.4", + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", "loose-envify": "^1.4.0", "prop-types": "^15.7.2", - "react-is": "^16.9.0" + "react-is": "^17.0.2" }, "peerDependencies": { - "react": "^16.8.3", - "redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0" + "react": "^16.8.3 || ^17 || ^18" }, "peerDependenciesMeta": { "react-dom": { @@ -17935,10 +21601,15 @@ } } }, + "node_modules/react-redux/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, "node_modules/react-refresh": { "version": "0.14.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", "engines": { "node": ">=0.10.0" } @@ -17987,66 +21658,63 @@ } }, "node_modules/react-responsive": { - "version": "8.1.0", - "license": "MIT", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-9.0.2.tgz", + "integrity": "sha512-+4CCab7z8G8glgJoRjAwocsgsv6VA2w7JPxFWHRc7kvz8mec1/K5LutNC2MG28Mn8mu6+bu04XZxHv5gyfT7xQ==", "dependencies": { "hyphenate-style-name": "^1.0.0", "matchmediaquery": "^0.3.0", "prop-types": "^15.6.1", - "shallow-equal": "^1.1.0" + "shallow-equal": "^1.2.1" }, "engines": { - "node": ">= 0.10" + "node": ">=0.10" }, "peerDependencies": { - "react": "^16.8.0" + "react": ">=16.8.0" } }, "node_modules/react-router": { - "version": "5.2.0", - "license": "MIT", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.16.0.tgz", + "integrity": "sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA==", "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.9.0" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "5.2.0", - "license": "MIT", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.16.0.tgz", + "integrity": "sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg==", "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.9.0", + "react-router": "6.16.0" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8", + "react-dom": ">=16.8" } }, - "node_modules/react-router/node_modules/mini-create-react-context": { - "version": "0.4.1", - "license": "MIT", + "node_modules/react-shallow-renderer": { + "version": "16.15.0", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", + "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" }, "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-side-effect": { @@ -18089,27 +21757,25 @@ } }, "node_modules/react-test-renderer": { - "version": "16.9.0", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz", + "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==", "dev": true, - "license": "MIT", "dependencies": { "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "react-is": "^16.9.0", - "scheduler": "^0.15.0" + "react-is": "^17.0.2", + "react-shallow-renderer": "^16.13.1", + "scheduler": "^0.20.2" }, "peerDependencies": { - "react": "^16.0.0" + "react": "17.0.2" } }, - "node_modules/react-test-renderer/node_modules/scheduler": { - "version": "0.15.0", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } + "node_modules/react-test-renderer/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/react-textarea-autosize": { "version": "8.4.1", @@ -18128,8 +21794,9 @@ } }, "node_modules/react-transition-group": { - "version": "4.4.1", - "license": "BSD-3-Clause", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -18151,7 +21818,6 @@ }, "node_modules/read-pkg": { "version": "5.2.0", - "dev": true, "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", @@ -18165,7 +21831,6 @@ }, "node_modules/read-pkg-up": { "version": "7.0.1", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.1.0", @@ -18181,7 +21846,6 @@ }, "node_modules/read-pkg-up/node_modules/find-up": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -18193,7 +21857,6 @@ }, "node_modules/read-pkg-up/node_modules/locate-path": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -18204,7 +21867,6 @@ }, "node_modules/read-pkg-up/node_modules/p-limit": { "version": "2.3.0", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -18218,7 +21880,6 @@ }, "node_modules/read-pkg-up/node_modules/p-locate": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -18229,7 +21890,6 @@ }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "0.8.1", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -18237,7 +21897,6 @@ }, "node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -18262,7 +21921,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -18273,8 +21931,8 @@ }, "node_modules/rechoir": { "version": "0.8.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dependencies": { "resolve": "^1.20.0" }, @@ -18284,7 +21942,6 @@ }, "node_modules/recursive-readdir": { "version": "2.2.3", - "dev": true, "license": "MIT", "dependencies": { "minimatch": "^3.0.5" @@ -18335,26 +21992,22 @@ } }, "node_modules/redux-thunk": { - "version": "2.4.1", - "license": "MIT", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", "peerDependencies": { "redux": "^4" } }, - "node_modules/reflect.ownkeys": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, "node_modules/regenerate": { "version": "1.4.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.0", - "dev": true, - "license": "MIT", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dependencies": { "regenerate": "^1.4.2" }, @@ -18367,16 +22020,15 @@ "license": "MIT" }, "node_modules/regenerator-transform": { - "version": "0.15.1", - "dev": true, - "license": "MIT", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regex-not": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "extend-shallow": "^3.0.2", @@ -18388,17 +22040,16 @@ }, "node_modules/regex-parser": { "version": "2.2.11", - "dev": true, "license": "MIT" }, "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "dev": true, - "license": "MIT", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -18407,21 +22058,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "5.3.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dependencies": { "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", @@ -18436,8 +22076,8 @@ }, "node_modules/regjsparser": { "version": "0.9.1", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dependencies": { "jsesc": "~0.5.0" }, @@ -18447,28 +22087,28 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", - "dev": true, + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "bin": { "jsesc": "bin/jsesc" } }, "node_modules/relateurl": { "version": "0.2.7", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "engines": { "node": ">= 0.10" } }, "node_modules/remove-trailing-separator": { "version": "1.1.0", - "dev": true, "license": "ISC" }, "node_modules/renderkid": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", "dependencies": { "css-select": "^4.1.3", "dom-converter": "^0.2.0", @@ -18479,8 +22119,8 @@ }, "node_modules/renderkid/node_modules/css-select": { "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -18494,8 +22134,8 @@ }, "node_modules/renderkid/node_modules/dom-serializer": { "version": "1.4.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -18507,8 +22147,8 @@ }, "node_modules/renderkid/node_modules/domhandler": { "version": "4.3.1", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dependencies": { "domelementtype": "^2.2.0" }, @@ -18521,8 +22161,8 @@ }, "node_modules/renderkid/node_modules/domutils": { "version": "2.8.0", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -18534,15 +22174,16 @@ }, "node_modules/renderkid/node_modules/entities": { "version": "2.2.0", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/renderkid/node_modules/htmlparser2": { "version": "6.1.0", - "dev": true, + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -18550,7 +22191,6 @@ "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.0.0", @@ -18560,7 +22200,6 @@ }, "node_modules/repeat-element": { "version": "1.1.4", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18568,7 +22207,6 @@ }, "node_modules/repeat-string": { "version": "1.6.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10" @@ -18576,7 +22214,6 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18584,7 +22221,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18592,21 +22228,20 @@ }, "node_modules/require-main-filename": { "version": "2.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "node_modules/requires-port": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/reselect": { - "version": "4.1.6", - "license": "MIT" + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" }, "node_modules/resolve": { "version": "1.22.1", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.9.0", @@ -18622,7 +22257,6 @@ }, "node_modules/resolve-cwd": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" @@ -18633,7 +22267,6 @@ }, "node_modules/resolve-from": { "version": "5.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -18645,12 +22278,10 @@ }, "node_modules/resolve-url": { "version": "0.2.1", - "dev": true, "license": "MIT" }, "node_modules/resolve-url-loader": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "adjust-sourcemap-loader": "^4.0.0", @@ -18660,20 +22291,40 @@ "source-map": "0.6.1" }, "engines": { - "node": ">=12" + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" } }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/ret": { "version": "0.1.15", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12" @@ -18681,15 +22332,14 @@ }, "node_modules/retry": { "version": "0.13.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "engines": { "node": ">= 4" } }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -18698,8 +22348,8 @@ }, "node_modules/rimraf": { "version": "2.7.1", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dependencies": { "glob": "^7.1.3" }, @@ -18718,40 +22368,38 @@ }, "node_modules/rsvp": { "version": "4.8.5", - "dev": true, "license": "MIT", "engines": { "node": "6.* || >= 7.*" } }, "node_modules/rtlcss": { - "version": "3.5.0", - "dev": true, - "license": "MIT", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.0.tgz", + "integrity": "sha512-W+N4hh0nVqVrrn3mRkHakxpB+c9cQ4CRT67O39kgA+1DjyhrdsqyCqIuHXyvWaXn4/835n+oX3fYJCi4+G/06A==", "dependencies": { - "find-up": "^5.0.0", + "escalade": "^3.1.1", "picocolors": "^1.0.0", - "postcss": "^8.3.11", + "postcss": "^8.4.21", "strip-json-comments": "^3.1.1" }, "bin": { "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" } }, - "node_modules/run-node": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "bin": { - "run-node": "run-node" - }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "engines": { - "node": ">=4" + "node": ">=0.12.0" } }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -18778,6 +22426,36 @@ "individual": "^2.0.0" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "node_modules/safe-buffer": { "version": "5.1.2", "license": "MIT" @@ -18790,7 +22468,6 @@ }, "node_modules/safe-regex": { "version": "1.1.0", - "dev": true, "license": "MIT", "dependencies": { "ret": "~0.1.10" @@ -18798,7 +22475,6 @@ }, "node_modules/safe-regex-test": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -18811,12 +22487,10 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/sane": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "@cnakazawa/watch": "^1.0.3", @@ -18838,7 +22512,6 @@ }, "node_modules/sane/node_modules/anymatch": { "version": "2.0.0", - "dev": true, "license": "ISC", "dependencies": { "micromatch": "^3.1.4", @@ -18847,7 +22520,6 @@ }, "node_modules/sane/node_modules/braces": { "version": "2.3.2", - "dev": true, "license": "MIT", "dependencies": { "arr-flatten": "^1.1.0", @@ -18867,7 +22539,6 @@ }, "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" @@ -18878,7 +22549,6 @@ }, "node_modules/sane/node_modules/fill-range": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", @@ -18892,7 +22562,6 @@ }, "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" @@ -18903,12 +22572,10 @@ }, "node_modules/sane/node_modules/is-buffer": { "version": "1.1.6", - "dev": true, "license": "MIT" }, "node_modules/sane/node_modules/is-extendable": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18916,7 +22583,6 @@ }, "node_modules/sane/node_modules/is-number": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -18927,7 +22593,6 @@ }, "node_modules/sane/node_modules/is-number/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -18938,7 +22603,6 @@ }, "node_modules/sane/node_modules/micromatch": { "version": "3.1.10", - "dev": true, "license": "MIT", "dependencies": { "arr-diff": "^4.0.0", @@ -18961,7 +22625,6 @@ }, "node_modules/sane/node_modules/normalize-path": { "version": "2.1.1", - "dev": true, "license": "MIT", "dependencies": { "remove-trailing-separator": "^1.0.1" @@ -18972,7 +22635,6 @@ }, "node_modules/sane/node_modules/to-regex-range": { "version": "2.1.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^3.0.0", @@ -18983,9 +22645,9 @@ } }, "node_modules/sass": { - "version": "1.60.0", - "dev": true, - "license": "MIT", + "version": "1.65.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.65.1.tgz", + "integrity": "sha512-9DINwtHmA41SEd36eVPQ9BJKpn7eKDQmUHmpI0y5Zv2Rcorrh0zS+cFrt050hdNbmmCNKTW3hV5mWfuegNRsEA==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -18995,19 +22657,18 @@ "sass": "sass.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/sass-loader": { - "version": "12.6.0", - "dev": true, - "license": "MIT", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dependencies": { - "klona": "^2.0.4", "neo-async": "^2.6.2" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", @@ -19015,7 +22676,7 @@ }, "peerDependencies": { "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" @@ -19037,8 +22698,8 @@ }, "node_modules/saxes": { "version": "5.0.1", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dependencies": { "xmlchars": "^2.2.0" }, @@ -19047,8 +22708,9 @@ } }, "node_modules/scheduler": { - "version": "0.19.1", - "license": "MIT", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -19056,7 +22718,6 @@ }, "node_modules/schema-utils": { "version": "3.1.1", - "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", @@ -19073,13 +22734,13 @@ }, "node_modules/select-hose": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" }, "node_modules/selfsigned": { "version": "2.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", "dependencies": { "node-forge": "^1" }, @@ -19089,21 +22750,15 @@ }, "node_modules/semver": { "version": "6.3.0", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/send": { "version": "0.18.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -19125,34 +22780,34 @@ }, "node_modules/send/node_modules/debug": { "version": "2.6.9", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { "ms": "2.0.0" } }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/send/node_modules/ms": { "version": "2.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serialize-javascript": { "version": "6.0.1", - "dev": true, - "license": "BSD-3-Clause", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/serve-index": { "version": "1.9.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -19168,24 +22823,24 @@ }, "node_modules/serve-index/node_modules/debug": { "version": "2.6.9", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "engines": { "node": ">= 0.6" } }, "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -19198,31 +22853,31 @@ }, "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { "version": "1.15.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -19235,12 +22890,11 @@ }, "node_modules/set-blocking": { "version": "2.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/set-value": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", @@ -19254,7 +22908,6 @@ }, "node_modules/set-value/node_modules/extend-shallow": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" @@ -19265,7 +22918,6 @@ }, "node_modules/set-value/node_modules/is-extendable": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19278,13 +22930,13 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shallow-clone": { "version": "3.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dependencies": { "kind-of": "^6.0.2" }, @@ -19297,18 +22949,18 @@ "license": "MIT" }, "node_modules/sharp": { - "version": "0.31.3", - "dev": true, + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", - "semver": "^7.3.8", + "semver": "^7.5.4", "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", + "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" }, "engines": { @@ -19320,8 +22972,8 @@ }, "node_modules/sharp/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dependencies": { "yallist": "^4.0.0" }, @@ -19330,9 +22982,9 @@ } }, "node_modules/sharp/node_modules/semver": { - "version": "7.3.8", - "dev": true, - "license": "ISC", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -19343,38 +22995,13 @@ "node": ">=10" } }, - "node_modules/sharp/node_modules/simple-get": { - "version": "4.0.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/sharp/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/shebang-command": { "version": "1.2.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^1.0.0" @@ -19385,29 +23012,27 @@ }, "node_modules/shebang-regex": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/shell-quote": { - "version": "1.8.0", - "dev": true, - "license": "MIT", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shellwords": { "version": "0.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "optional": true }, "node_modules/side-channel": { "version": "1.0.4", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.0", @@ -19420,12 +23045,12 @@ }, "node_modules/signal-exit": { "version": "3.0.7", - "dev": true, "license": "ISC" }, "node_modules/simple-concat": { "version": "1.0.1", - "dev": true, + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "funding": [ { "type": "github", @@ -19439,68 +23064,53 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/simple-get": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "decompress-response": "^4.2.0", + "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, - "node_modules/simple-get/node_modules/decompress-response": { - "version": "4.2.1", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/simple-get/node_modules/mimic-response": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/simple-swizzle": { "version": "0.2.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "dependencies": { "is-arrayish": "^0.3.1" } }, "node_modules/simple-swizzle/node_modules/is-arrayish": { "version": "0.3.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/sirv": { - "version": "1.0.19", - "dev": true, - "license": "MIT", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", "dependencies": { "@polka/url": "^1.0.0-next.20", "mrmime": "^1.0.0", - "totalist": "^1.0.0" + "totalist": "^3.0.0" }, "engines": { "node": ">= 10" @@ -19508,13 +23118,12 @@ }, "node_modules/sisteransi": { "version": "1.0.5", - "dev": true, "license": "MIT" }, "node_modules/slash": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "engines": { "node": ">=6" } @@ -19569,9 +23178,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/snapdragon": { "version": "0.8.2", - "dev": true, "license": "MIT", "dependencies": { "base": "^0.11.1", @@ -19589,7 +23206,6 @@ }, "node_modules/snapdragon-node": { "version": "2.1.1", - "dev": true, "license": "MIT", "dependencies": { "define-property": "^1.0.0", @@ -19602,7 +23218,6 @@ }, "node_modules/snapdragon-node/node_modules/define-property": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "is-descriptor": "^1.0.0" @@ -19613,7 +23228,6 @@ }, "node_modules/snapdragon-util": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.2.0" @@ -19624,12 +23238,10 @@ }, "node_modules/snapdragon-util/node_modules/is-buffer": { "version": "1.1.6", - "dev": true, "license": "MIT" }, "node_modules/snapdragon-util/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -19640,7 +23252,6 @@ }, "node_modules/snapdragon/node_modules/debug": { "version": "2.6.9", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -19648,7 +23259,6 @@ }, "node_modules/snapdragon/node_modules/define-property": { "version": "0.2.5", - "dev": true, "license": "MIT", "dependencies": { "is-descriptor": "^0.1.0" @@ -19659,7 +23269,6 @@ }, "node_modules/snapdragon/node_modules/extend-shallow": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" @@ -19670,7 +23279,6 @@ }, "node_modules/snapdragon/node_modules/is-accessor-descriptor": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -19681,7 +23289,6 @@ }, "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -19692,12 +23299,10 @@ }, "node_modules/snapdragon/node_modules/is-buffer": { "version": "1.1.6", - "dev": true, "license": "MIT" }, "node_modules/snapdragon/node_modules/is-data-descriptor": { "version": "0.1.4", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -19708,7 +23313,6 @@ }, "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -19719,7 +23323,6 @@ }, "node_modules/snapdragon/node_modules/is-descriptor": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "is-accessor-descriptor": "^0.1.6", @@ -19732,7 +23335,6 @@ }, "node_modules/snapdragon/node_modules/is-extendable": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19740,7 +23342,6 @@ }, "node_modules/snapdragon/node_modules/kind-of": { "version": "5.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19748,12 +23349,10 @@ }, "node_modules/snapdragon/node_modules/ms": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/snapdragon/node_modules/source-map": { "version": "0.5.7", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -19761,7 +23360,6 @@ }, "node_modules/snapdragon/node_modules/source-map-resolve": { "version": "0.5.3", - "dev": true, "license": "MIT", "dependencies": { "atob": "^2.1.2", @@ -19773,8 +23371,8 @@ }, "node_modules/sockjs": { "version": "0.3.24", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -19783,20 +23381,18 @@ }, "node_modules/sockjs/node_modules/uuid": { "version": "8.3.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/source-list-map": { "version": "2.0.1", - "dev": true, "license": "MIT" }, "node_modules/source-map": { "version": "0.7.4", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">= 8" @@ -19804,7 +23400,6 @@ }, "node_modules/source-map-js": { "version": "1.0.2", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -19812,7 +23407,6 @@ }, "node_modules/source-map-loader": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "abab": "^2.0.6", @@ -19830,18 +23424,8 @@ "webpack": "^5.72.1" } }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -19850,7 +23434,6 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -19858,12 +23441,10 @@ }, "node_modules/source-map-url": { "version": "0.4.1", - "dev": true, "license": "MIT" }, "node_modules/spdx-correct": { "version": "3.1.1", - "dev": true, "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -19872,12 +23453,10 @@ }, "node_modules/spdx-exceptions": { "version": "2.3.0", - "dev": true, "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", @@ -19886,13 +23465,12 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.11", - "dev": true, "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -19906,8 +23484,8 @@ }, "node_modules/spdy-transport": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -19919,8 +23497,8 @@ }, "node_modules/spdy-transport/node_modules/readable-stream": { "version": "3.6.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -19939,7 +23517,6 @@ }, "node_modules/split-string": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "extend-shallow": "^3.0.0" @@ -19950,18 +23527,12 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "dev": true, "license": "BSD-3-Clause" }, - "node_modules/stable": { - "version": "0.1.8", - "dev": true, - "license": "MIT" - }, "node_modules/stack-utils": { "version": "2.0.6", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -19971,20 +23542,19 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "engines": { "node": ">=8" } }, "node_modules/stackframe": { "version": "1.3.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" }, "node_modules/static-extend": { "version": "0.1.2", - "dev": true, "license": "MIT", "dependencies": { "define-property": "^0.2.5", @@ -19996,7 +23566,6 @@ }, "node_modules/static-extend/node_modules/define-property": { "version": "0.2.5", - "dev": true, "license": "MIT", "dependencies": { "is-descriptor": "^0.1.0" @@ -20007,7 +23576,6 @@ }, "node_modules/static-extend/node_modules/is-accessor-descriptor": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -20018,7 +23586,6 @@ }, "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -20029,12 +23596,10 @@ }, "node_modules/static-extend/node_modules/is-buffer": { "version": "1.1.6", - "dev": true, "license": "MIT" }, "node_modules/static-extend/node_modules/is-data-descriptor": { "version": "0.1.4", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -20045,7 +23610,6 @@ }, "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -20056,7 +23620,6 @@ }, "node_modules/static-extend/node_modules/is-descriptor": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "is-accessor-descriptor": "^0.1.6", @@ -20069,7 +23632,6 @@ }, "node_modules/static-extend/node_modules/kind-of": { "version": "5.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -20077,12 +23639,21 @@ }, "node_modules/statuses": { "version": "2.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { "node": ">= 0.8" } }, + "node_modules/streamx": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", + "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "license": "MIT", @@ -20092,8 +23663,8 @@ }, "node_modules/string-length": { "version": "4.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -20104,7 +23675,6 @@ }, "node_modules/string-width": { "version": "4.2.3", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -20117,21 +23687,20 @@ }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "dev": true, - "license": "MIT", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz", + "integrity": "sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", "side-channel": "^1.0.4" }, "funding": { @@ -20140,12 +23709,11 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.7", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -20156,12 +23724,11 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -20169,12 +23736,11 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.6", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -20182,7 +23748,6 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -20193,15 +23758,14 @@ }, "node_modules/strip-bom": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "engines": { "node": ">=8" } }, "node_modules/strip-eof": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -20209,7 +23773,6 @@ }, "node_modules/strip-final-newline": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -20228,8 +23791,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "engines": { "node": ">=8" }, @@ -20242,9 +23805,9 @@ "license": "MIT" }, "node_modules/style-loader": { - "version": "3.3.2", - "dev": true, - "license": "MIT", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", "engines": { "node": ">= 12.13.0" }, @@ -20267,15 +23830,15 @@ "dev": true }, "node_modules/stylehacks": { - "version": "5.1.1", - "dev": true, - "license": "MIT", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", + "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", "dependencies": { "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { "postcss": "^8.2.15" @@ -20396,41 +23959,12 @@ "stylelint": "^14.5.1 || ^15.0.0" } }, - "node_modules/stylelint/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, - "node_modules/stylelint/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stylelint/node_modules/is-plain-object": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", @@ -20440,15 +23974,6 @@ "node": ">=0.10.0" } }, - "node_modules/stylelint/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/stylelint/node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", @@ -20464,8 +23989,9 @@ }, "node_modules/superagent": { "version": "3.8.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "deprecated": "Please upgrade to v7.0.2+ of superagent. We have fixed numerous issues with streams, form-data, attach(), filesystem errors not bubbling up (ENOENT on attach()), and all tests are now passing. See the releases tab for more information at .", "dependencies": { "component-emitter": "^1.2.0", "cookiejar": "^2.1.0", @@ -20484,16 +24010,16 @@ }, "node_modules/superagent/node_modules/debug": { "version": "3.2.7", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { "ms": "^2.1.1" } }, "node_modules/superagent/node_modules/form-data": { "version": "2.5.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -20505,8 +24031,8 @@ }, "node_modules/supports-color": { "version": "5.5.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { "has-flag": "^3.0.0" }, @@ -20516,7 +24042,6 @@ }, "node_modules/supports-hyperlinks": { "version": "2.3.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0", @@ -20528,7 +24053,6 @@ }, "node_modules/supports-hyperlinks/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -20536,7 +24060,6 @@ }, "node_modules/supports-hyperlinks/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -20547,7 +24070,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -20558,8 +24080,8 @@ }, "node_modules/svg-parser": { "version": "2.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, "node_modules/svg-tags": { "version": "1.0.0", @@ -20568,96 +24090,36 @@ "dev": true }, "node_modules/svgo": { - "version": "2.8.0", - "dev": true, - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", + "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" + "css-select": "^5.1.0", + "css-tree": "^2.2.1", + "csso": "^5.0.5", + "picocolors": "^1.0.0" }, "bin": { "svgo": "bin/svgo" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, "node_modules/svgo/node_modules/commander": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "engines": { "node": ">= 10" } }, - "node_modules/svgo/node_modules/css-select": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "4.3.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "2.8.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/svgo/node_modules/entities": { - "version": "2.2.0", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/symbol-observable": { "version": "1.2.0", "license": "MIT", @@ -20667,8 +24129,8 @@ }, "node_modules/symbol-tree": { "version": "3.2.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "node_modules/tabbable": { "version": "5.3.3", @@ -20712,100 +24174,38 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, - "node_modules/tapable": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "6.1.11", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "dev": true, - "license": "ISC" - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "engines": { "node": ">=6" } }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "dev": true, - "license": "MIT", + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" + "node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true - }, "node_modules/terminal-link": { "version": "2.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" @@ -20818,12 +24218,12 @@ } }, "node_modules/terser": { - "version": "5.16.8", - "dev": true, - "license": "BSD-2-Clause", + "version": "5.19.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.4.tgz", + "integrity": "sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -20835,15 +24235,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "dev": true, - "license": "MIT", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.16.8" }, "engines": { "node": ">= 10.13.0" @@ -20869,16 +24269,16 @@ }, "node_modules/terser-webpack-plugin/node_modules/has-flag": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { "node": ">=8" } }, "node_modules/terser-webpack-plugin/node_modules/jest-worker": { "version": "27.5.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -20890,8 +24290,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dependencies": { "has-flag": "^4.0.0" }, @@ -20904,12 +24304,11 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/test-exclude": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -20922,18 +24321,22 @@ }, "node_modules/text-table": { "version": "0.2.0", - "dev": true, "license": "MIT" }, "node_modules/throat": { "version": "5.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/thunky": { "version": "1.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, "node_modules/tiny-invariant": { "version": "1.2.0", @@ -20947,14 +24350,23 @@ "version": "5.10.5", "license": "LGPL-2.1" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/to-fast-properties": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -20962,7 +24374,6 @@ }, "node_modules/to-object-path": { "version": "0.3.0", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^3.0.2" @@ -20973,12 +24384,10 @@ }, "node_modules/to-object-path/node_modules/is-buffer": { "version": "1.1.6", - "dev": true, "license": "MIT" }, "node_modules/to-object-path/node_modules/kind-of": { "version": "3.2.2", - "dev": true, "license": "MIT", "dependencies": { "is-buffer": "^1.1.5" @@ -20989,7 +24398,6 @@ }, "node_modules/to-regex": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "define-property": "^2.0.2", @@ -21003,7 +24411,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -21014,8 +24421,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -21025,17 +24432,17 @@ "license": "MIT" }, "node_modules/totalist": { - "version": "1.1.0", - "dev": true, - "license": "MIT", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "engines": { "node": ">=6" } }, "node_modules/tough-cookie": { - "version": "4.1.2", - "dev": true, - "license": "BSD-3-Clause", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -21048,16 +24455,16 @@ }, "node_modules/tough-cookie/node_modules/universalify": { "version": "0.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "engines": { "node": ">= 4.0.0" } }, "node_modules/tr46": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dependencies": { "punycode": "^2.1.1" }, @@ -21074,10 +24481,133 @@ "node": ">=8" } }, + "node_modules/ts-loader": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.0.tgz", + "integrity": "sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/tsconfig-paths": { "version": "3.14.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -21087,8 +24617,8 @@ }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dependencies": { "minimist": "^1.2.0" }, @@ -21098,8 +24628,8 @@ }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "engines": { "node": ">=4" } @@ -21110,8 +24640,8 @@ }, "node_modules/tunnel-agent": { "version": "0.6.0", - "dev": true, - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -21121,8 +24651,8 @@ }, "node_modules/type-check": { "version": "0.4.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -21132,15 +24662,14 @@ }, "node_modules/type-detect": { "version": "4.0.8", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "engines": { "node": ">=4" } }, "node_modules/type-fest": { "version": "0.21.3", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -21151,8 +24680,8 @@ }, "node_modules/type-is": { "version": "1.6.18", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -21161,9 +24690,56 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-array-length": { "version": "1.0.4", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -21176,16 +24752,15 @@ }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", - "dev": true, "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } }, "node_modules/typescript": { - "version": "4.7.4", - "devOptional": true, - "license": "Apache-2.0", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -21196,7 +24771,6 @@ }, "node_modules/unbox-primitive": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -21223,16 +24797,16 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -21243,23 +24817,22 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "engines": { "node": ">=4" } }, "node_modules/union-value": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "arr-union": "^3.1.0", @@ -21273,7 +24846,6 @@ }, "node_modules/union-value/node_modules/is-extendable": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -21289,7 +24861,6 @@ }, "node_modules/universalify": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -21297,15 +24868,14 @@ }, "node_modules/unpipe": { "version": "1.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } }, "node_modules/unset-value": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "has-value": "^0.3.1", @@ -21317,7 +24887,6 @@ }, "node_modules/unset-value/node_modules/has-value": { "version": "0.3.1", - "dev": true, "license": "MIT", "dependencies": { "get-value": "^2.0.3", @@ -21330,7 +24899,6 @@ }, "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "isarray": "1.0.0" @@ -21341,7 +24909,6 @@ }, "node_modules/unset-value/node_modules/has-values": { "version": "0.1.4", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -21349,12 +24916,12 @@ }, "node_modules/unset-value/node_modules/isarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "dev": true, + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -21363,15 +24930,18 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -21379,7 +24949,6 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -21387,12 +24956,10 @@ }, "node_modules/urix": { "version": "0.1.0", - "dev": true, "license": "MIT" }, "node_modules/url-loader": { "version": "4.1.1", - "dev": true, "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", @@ -21418,8 +24985,8 @@ }, "node_modules/url-parse": { "version": "1.5.10", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -21431,7 +24998,6 @@ }, "node_modules/use": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -21513,19 +25079,27 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" }, "node_modules/utila": { "version": "0.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" }, "node_modules/utils-merge": { "version": "1.0.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } @@ -21545,8 +25119,8 @@ }, "node_modules/v8-to-istanbul": { "version": "7.1.2", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", "dependencies": { "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", @@ -21558,7 +25132,6 @@ }, "node_modules/validate-npm-package-license": { "version": "3.0.4", - "dev": true, "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", @@ -21571,8 +25144,8 @@ }, "node_modules/vary": { "version": "1.1.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "engines": { "node": ">= 0.8" } @@ -21624,8 +25197,9 @@ }, "node_modules/w3c-hr-time": { "version": "1.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", "dependencies": { "browser-process-hrtime": "^1.0.0" } @@ -21636,8 +25210,8 @@ }, "node_modules/w3c-xmlserializer": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "dependencies": { "xml-name-validator": "^3.0.0" }, @@ -21647,7 +25221,6 @@ }, "node_modules/walker": { "version": "1.0.8", - "dev": true, "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" @@ -21662,8 +25235,8 @@ }, "node_modules/watchpack": { "version": "2.4.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -21674,36 +25247,44 @@ }, "node_modules/wbuf": { "version": "1.7.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dependencies": { "minimalistic-assert": "^1.0.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/webidl-conversions": { "version": "6.1.0", - "dev": true, - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "engines": { "node": ">=10.4" } }, "node_modules/webpack": { - "version": "5.76.0", - "dev": true, - "license": "MIT", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -21712,9 +25293,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -21735,18 +25316,26 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.5.0", - "dev": true, - "license": "MIT", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.1.tgz", + "integrity": "sha512-jnd6EoYrf9yMxCyYDPj8eutJvtjQNp8PHmni/e/ulydHBWhT5J3menXt3HEkScsu9YqMAcG4CfFjs3rj5pVU1w==", "dependencies": { + "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", "commander": "^7.2.0", + "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", - "lodash": "^4.17.20", + "is-plain-object": "^5.0.0", + "lodash.debounce": "^4.0.8", + "lodash.escape": "^4.0.1", + "lodash.flatten": "^4.4.0", + "lodash.invokemap": "^4.6.0", + "lodash.pullall": "^4.2.0", + "lodash.uniqby": "^4.7.0", "opener": "^1.5.2", - "sirv": "^1.0.7", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", "ws": "^7.3.1" }, "bin": { @@ -21758,95 +25347,50 @@ }, "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { "version": "8.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "engines": { "node": ">=0.4.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/webpack-bundle-analyzer/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-bundle-analyzer/node_modules/commander": { "version": "7.2.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "engines": { "node": ">= 10" } }, - "node_modules/webpack-bundle-analyzer/node_modules/has-flag": { + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { "version": "4.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "node_modules/webpack-bundle-analyzer/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/webpack-cli": { - "version": "5.0.1", - "dev": true, - "license": "MIT", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.1", - "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.1", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", "colorette": "^2.0.14", - "commander": "^9.4.1", + "commander": "^10.0.1", "cross-spawn": "^7.0.3", "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", @@ -21881,17 +25425,17 @@ } }, "node_modules/webpack-cli/node_modules/commander": { - "version": "9.5.0", - "dev": true, - "license": "MIT", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "engines": { - "node": "^12.20.0 || >=14" + "node": ">=14" } }, "node_modules/webpack-cli/node_modules/cross-spawn": { "version": "7.0.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -21903,16 +25447,16 @@ }, "node_modules/webpack-cli/node_modules/path-key": { "version": "3.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "engines": { "node": ">=8" } }, "node_modules/webpack-cli/node_modules/shebang-command": { "version": "2.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -21922,16 +25466,16 @@ }, "node_modules/webpack-cli/node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "engines": { "node": ">=8" } }, "node_modules/webpack-cli/node_modules/which": { "version": "2.0.2", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dependencies": { "isexe": "^2.0.0" }, @@ -21944,8 +25488,8 @@ }, "node_modules/webpack-dev-middleware": { "version": "5.3.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -21966,8 +25510,8 @@ }, "node_modules/webpack-dev-middleware/node_modules/ajv": { "version": "8.12.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -21981,8 +25525,8 @@ }, "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { "version": "5.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -21992,18 +25536,18 @@ }, "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dependencies": { "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", + "ajv": "^8.9.0", "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 12.13.0" @@ -22014,9 +25558,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.13.2", - "dev": true, - "license": "MIT", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -22024,7 +25568,7 @@ "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/ws": "^8.5.5", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", @@ -22073,8 +25617,8 @@ }, "node_modules/webpack-dev-server/node_modules/ajv": { "version": "8.12.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -22088,8 +25632,8 @@ }, "node_modules/webpack-dev-server/node_modules/ajv-keywords": { "version": "5.1.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -22097,15 +25641,23 @@ "ajv": "^8.8.2" } }, + "node_modules/webpack-dev-server/node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/webpack-dev-server/node_modules/rimraf": { "version": "3.0.2", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dependencies": { "glob": "^7.1.3" }, @@ -22117,14 +25669,14 @@ } }, "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dependencies": { "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", + "ajv": "^8.9.0", "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 12.13.0" @@ -22135,9 +25687,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.13.0", - "dev": true, - "license": "MIT", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { "node": ">=10.0.0" }, @@ -22155,9 +25707,9 @@ } }, "node_modules/webpack-merge": { - "version": "5.8.0", - "dev": true, - "license": "MIT", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", "dependencies": { "clone-deep": "^4.0.1", "wildcard": "^2.0.0" @@ -22168,7 +25720,6 @@ }, "node_modules/webpack-sources": { "version": "1.4.3", - "dev": true, "license": "MIT", "dependencies": { "source-list-map": "^2.0.0", @@ -22177,24 +25728,40 @@ }, "node_modules/webpack-sources/node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/webpack/node_modules/webpack-sources": { "version": "3.2.3", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "engines": { "node": ">=10.13.0" } }, "node_modules/websocket-driver": { "version": "0.7.4", - "dev": true, - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -22206,24 +25773,24 @@ }, "node_modules/websocket-extensions": { "version": "0.1.4", - "dev": true, - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "engines": { "node": ">=0.8.0" } }, "node_modules/whatwg-encoding": { "version": "1.0.5", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", "dependencies": { "iconv-lite": "0.4.24" } }, "node_modules/whatwg-encoding/node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -22233,13 +25800,13 @@ }, "node_modules/whatwg-mimetype": { "version": "2.3.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "node_modules/whatwg-url": { "version": "8.7.0", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dependencies": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -22251,7 +25818,6 @@ }, "node_modules/which": { "version": "1.3.1", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -22262,7 +25828,6 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", @@ -22276,21 +25841,20 @@ } }, "node_modules/which-module": { - "version": "2.0.0", - "dev": true, - "license": "ISC" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, "node_modules/which-typed-array": { - "version": "1.1.9", - "dev": true, - "license": "MIT", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -22299,32 +25863,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/wildcard": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" }, "node_modules/wrap-ansi": { "version": "7.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -22340,7 +25885,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -22354,7 +25898,6 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -22365,7 +25908,6 @@ }, "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/wrappy": { @@ -22374,7 +25916,6 @@ }, "node_modules/write-file-atomic": { "version": "3.0.3", - "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -22385,7 +25926,6 @@ }, "node_modules/ws": { "version": "7.5.9", - "dev": true, "license": "MIT", "engines": { "node": ">=8.3.0" @@ -22405,13 +25945,13 @@ }, "node_modules/xml-name-validator": { "version": "3.0.0", - "dev": true, - "license": "Apache-2.0" + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, "node_modules/xmlchars": { "version": "2.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, "node_modules/xmlchecker": { "version": "0.1.0", @@ -22422,7 +25962,6 @@ }, "node_modules/y18n": { "version": "5.0.8", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -22430,12 +25969,11 @@ }, "node_modules/yallist": { "version": "3.1.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", - "dev": true, "license": "ISC", "engines": { "node": ">= 6" @@ -22443,7 +25981,7 @@ }, "node_modules/yargs": { "version": "17.5.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "cliui": "^7.0.2", @@ -22460,7 +25998,7 @@ }, "node_modules/yargs-parser": { "version": "21.0.1", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=12" @@ -22468,7 +26006,6 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" diff --git a/package.json b/package.json index 9f26e4f24f..b0180c4f80 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,14 @@ ], "scripts": { "build": "fedx-scripts webpack", - "i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null", + "i18n_extract": "fedx-scripts formatjs extract", "stylelint": "stylelint \"src/**/*.scss\" \"scss/**/*.scss\" --config .stylelintrc.json", "lint": "npm run stylelint && fedx-scripts eslint --ext .js --ext .jsx .", "lint:fix": "npm run stylelint && fedx-scripts eslint --ext .js --ext .jsx . --fix", "snapshot": "fedx-scripts jest --updateSnapshot", "start": "fedx-scripts webpack-dev-server --progress", - "test": "fedx-scripts jest --coverage --passWithNoTests" + "test": "fedx-scripts jest --coverage --passWithNoTests", + "types": "tsc --noEmit" }, "husky": { "hooks": { @@ -34,57 +35,63 @@ "url": "https://github.com/openedx/frontend-app-course-authoring/issues" }, "dependencies": { - "@edx/brand": "npm:@edx/brand-openedx@1.1.0", - "@edx/frontend-component-footer": "12.0.0", - "@edx/frontend-enterprise-hotjar": "^1.2.1", - "@edx/frontend-lib-content-components": "^1.169.0", - "@edx/frontend-platform": "4.2.0", - "@edx/paragon": "^20.45.4", - "@fortawesome/fontawesome-svg-core": "1.2.28", - "@fortawesome/free-brands-svg-icons": "5.11.2", - "@fortawesome/free-regular-svg-icons": "5.11.2", - "@fortawesome/free-solid-svg-icons": "5.11.2", - "@fortawesome/react-fontawesome": "0.1.9", + "@edx/brand": "npm:@openedx/brand-openedx@^1.2.2", + "@edx/frontend-component-footer": "^12.3.0", + "@edx/frontend-component-header": "^4.7.0", + "@edx/frontend-enterprise-hotjar": "^2.0.0", + "@edx/frontend-lib-content-components": "1.175.1", + "@edx/frontend-platform": "5.6.1", + "@edx/paragon": "^21.5.6", + "@fortawesome/fontawesome-svg-core": "1.2.36", + "@fortawesome/free-brands-svg-icons": "5.15.4", + "@fortawesome/free-regular-svg-icons": "5.15.4", + "@fortawesome/free-solid-svg-icons": "5.15.4", + "@fortawesome/react-fontawesome": "0.2.0", "@reduxjs/toolkit": "1.5.0", + "@tanstack/react-query": "4.36.1", "classnames": "2.2.6", "core-js": "3.8.1", "email-validator": "2.0.4", + "file-saver": "^2.0.5", "formik": "2.2.6", "jszip": "^3.10.1", "lodash": "4.17.21", - "moment": "2.29.2", + "moment": "2.29.4", "prop-types": "15.7.2", - "react": "16.14.0", + "react": "17.0.2", "react-datepicker": "^4.13.0", - "react-dom": "16.14.0", + "react-dom": "17.0.2", "react-helmet": "^6.1.0", - "react-ranger": "^2.1.0", - "react-redux": "7.1.3", - "react-responsive": "8.1.0", - "react-router": "5.2.0", - "react-router-dom": "5.2.0", + "react-redux": "7.2.9", + "react-responsive": "9.0.2", + "react-router": "6.16.0", + "react-router-dom": "6.16.0", "react-textarea-autosize": "^8.4.1", - "react-transition-group": "4.4.1", + "react-transition-group": "4.4.5", "redux": "4.0.5", "regenerator-runtime": "0.13.7", + "universal-cookie": "^4.0.4", "uuid": "^3.4.0", "yup": "0.31.1" }, "devDependencies": { - "@edx/browserslist-config": "1.0.0", - "@edx/frontend-build": "12.8.6", + "@edx/browserslist-config": "1.2.0", + "@edx/frontend-build": "13.0.4", "@edx/reactifex": "^1.0.3", "@edx/stylelint-config-edx": "^2.3.0", - "@testing-library/jest-dom": "5.16.4", - "@testing-library/react": "12.1.1", + "@edx/typescript-config": "^1.0.1", + "@testing-library/jest-dom": "5.17.0", + "@testing-library/react": "12.1.5", "@testing-library/user-event": "^13.2.1", + "@wojtekmaj/enzyme-adapter-react-17": "0.8.0", "axios-mock-adapter": "1.20.0", "enzyme": "3.11.0", - "enzyme-adapter-react-16": "1.15.6", "enzyme-to-json": "^3.6.2", - "glob": "7.1.6", - "husky": "3.1.0", - "react-test-renderer": "16.9.0", - "reactifex": "1.1.1" + "glob": "7.2.3", + "husky": "7.0.4", + "jest-canvas-mock": "^2.5.2", + "react-test-renderer": "17.0.2", + "reactifex": "1.1.1", + "ts-loader": "^9.5.0" } } diff --git a/public/index.html b/public/index.html index 98e0b7732b..8565c8098e 100644 --- a/public/index.html +++ b/public/index.html @@ -4,7 +4,7 @@ Course Authoring | <%= process.env.SITE_NAME %> - +
diff --git a/renovate.json b/renovate.json index 62ffad03ec..dae6f07d08 100644 --- a/renovate.json +++ b/renovate.json @@ -1,19 +1,33 @@ { "extends": [ "config:base", - "schedule:daily", + "schedule:weekly", ":rebaseStalePrs", - ":semanticCommits" + ":semanticCommits", + ":dependencyDashboard" ], + "timezone": "America/New_York", "patch": { - "automerge": true + "automerge": false }, "rebaseStalePrs": true, "packageRules": [ { - "matchPackagePatterns": ["@edx"], + "extends": [ + "schedule:daily" + ], + "matchPackagePatterns": ["@edx", "@openedx"], "matchUpdateTypes": ["minor", "patch"], - "automerge": true + "automerge": false + }, + { + "matchPackagePatterns": ["@edx/frontend-lib-content-components"], + "matchUpdateTypes": ["minor", "patch"], + "automerge": false, + "schedule": [ + "after 1am", + "before 11pm" + ] } ] } diff --git a/src/CourseAuthoringPage.jsx b/src/CourseAuthoringPage.jsx index dea6503c8e..b11dcc7948 100644 --- a/src/CourseAuthoringPage.jsx +++ b/src/CourseAuthoringPage.jsx @@ -5,8 +5,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { useLocation, } from 'react-router-dom'; -import { Footer } from '@edx/frontend-lib-content-components'; -import Header from './studio-header/Header'; +import { StudioFooter } from '@edx/frontend-component-footer'; +import Header from './header'; import { fetchCourseDetail } from './data/thunks'; import { useModel } from './generic/model-store'; import PermissionDeniedAlert from './generic/PermissionDeniedAlert'; @@ -37,21 +37,6 @@ AppHeader.defaultProps = { courseOrg: null, }; -const AppFooter = () => ( -
-
-
-); - const CourseAuthoringPage = ({ courseId, children }) => { const dispatch = useDispatch(); @@ -91,7 +76,7 @@ const CourseAuthoringPage = ({ courseId, children }) => { ) )} {children} - {!inProgress && showHeader && } + {!inProgress && showHeader && } ); }; diff --git a/src/CourseAuthoringRoutes.jsx b/src/CourseAuthoringRoutes.jsx index 29bb15ae16..0aa1043a6d 100644 --- a/src/CourseAuthoringRoutes.jsx +++ b/src/CourseAuthoringRoutes.jsx @@ -1,18 +1,22 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { Switch, useRouteMatch } from 'react-router'; -import { PageRoute } from '@edx/frontend-platform/react'; +import { + Navigate, Routes, Route, useParams, +} from 'react-router-dom'; +import { PageWrap } from '@edx/frontend-platform/react'; import Placeholder from '@edx/frontend-lib-content-components'; import CourseAuthoringPage from './CourseAuthoringPage'; import { PagesAndResources } from './pages-and-resources'; -import ProctoredExamSettings from './proctored-exam-settings/ProctoredExamSettings'; import EditorContainer from './editors/EditorContainer'; import VideoSelectorContainer from './selectors/VideoSelectorContainer'; import CustomPages from './custom-pages'; -import FilesAndUploads from './files-and-uploads'; +import { FilesPage, VideosPage } from './files-and-videos'; import { AdvancedSettings } from './advanced-settings'; import ScheduleAndDetails from './schedule-and-details'; import { GradingSettings } from './grading-settings'; +import CourseTeam from './course-team/CourseTeam'; +import { CourseUpdates } from './course-updates'; +import CourseExportPage from './export-page/CourseExportPage'; +import CourseImportPage from './import-page/CourseImportPage'; /** * As of this writing, these routes are mounted at a path prefixed with the following: @@ -30,97 +34,79 @@ import { GradingSettings } from './grading-settings'; * can move the Header/Footer rendering to this component and likely pull the course detail loading * in as well, and it'd feel a bit better-factored and the roles would feel more clear. */ -const CourseAuthoringRoutes = ({ courseId }) => { - const { path } = useRouteMatch(); +const CourseAuthoringRoutes = () => { + const { courseId } = useParams(); + return ( - - - {process.env.ENABLE_NEW_COURSE_OUTLINE_PAGE === 'true' - && ( - - )} - - - {process.env.ENABLE_NEW_UPDATES_PAGE === 'true' - && ( - - )} - - - - - - {process.env.ENABLE_NEW_VIDEO_UPLOAD_PAGE === 'true' - && ( - - )} - - - - - - - - - - - - {process.env.ENABLE_UNIT_PAGE === 'true' - && ( - - )} - - - {process.env.ENABLE_NEW_EDITOR_PAGES === 'true' - && ( - - )} - - - {process.env.ENABLE_NEW_EDITOR_PAGES === 'true' - && ( - - )} - - - - - - - - - {process.env.ENABLE_NEW_COURSE_TEAM_PAGE === 'true' - && ( - - )} - - - - - - {process.env.ENABLE_NEW_IMPORT_PAGE === 'true' - && ( - - )} - - - {process.env.ENABLE_NEW_EXPORT_PAGE === 'true' - && ( - - )} - - + + : null} + /> + } + /> + } + /> + : null} + /> + } + /> + } + /> + } + /> + : null} + /> + : null} + /> + : null} + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + ); }; -CourseAuthoringRoutes.propTypes = { - courseId: PropTypes.string.isRequired, -}; - export default CourseAuthoringRoutes; diff --git a/src/CourseAuthoringRoutes.test.jsx b/src/CourseAuthoringRoutes.test.jsx index e82963c3af..3a38fe7c24 100644 --- a/src/CourseAuthoringRoutes.test.jsx +++ b/src/CourseAuthoringRoutes.test.jsx @@ -8,13 +8,19 @@ import initializeStore from './store'; const courseId = 'course-v1:edX+TestX+Test_Course'; const pagesAndResourcesMockText = 'Pages And Resources'; -const proctoredExamSeetingsMockText = 'Proctored Exam Settings'; const editorContainerMockText = 'Editor Container'; const videoSelectorContainerMockText = 'Video Selector Container'; const customPagesMockText = 'Custom Pages'; let store; const mockComponentFn = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ + courseId, + }), +})); + // Mock the TinyMceWidget from frontend-lib-content-components jest.mock('@edx/frontend-lib-content-components', () => ({ TinyMceWidget: () =>
Widget
, @@ -25,20 +31,10 @@ jest.mock('@edx/frontend-lib-content-components', () => ({ })), })); -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), - useRouteMatch: () => ({ - path: `/course/${courseId}`, - }), -})); jest.mock('./pages-and-resources/PagesAndResources', () => (props) => { mockComponentFn(props); return pagesAndResourcesMockText; }); -jest.mock('./proctored-exam-settings/ProctoredExamSettings', () => (props) => { - mockComponentFn(props); - return proctoredExamSeetingsMockText; -}); jest.mock('./editors/EditorContainer', () => (props) => { mockComponentFn(props); return editorContainerMockText; @@ -65,39 +61,16 @@ describe('', () => { store = initializeStore(); }); - // TODO: This test needs to be corrected. - // The problem arose after moving new commits (https://github.com/raccoongang/frontend-app-course-authoring/pull/25) - it.skip('renders the PagesAndResources component when the pages and resources route is active', () => { - render( - - - - - , - ); - - expect(screen.queryByText(pagesAndResourcesMockText)).toBeInTheDocument(); - expect(screen.queryByText(proctoredExamSeetingsMockText)).not.toBeInTheDocument(); - expect(mockComponentFn).toHaveBeenCalledWith( - expect.objectContaining({ - courseId, - }), - ); - }); - - // TODO: This test needs to be corrected. - // The problem arose after moving new commits (https://github.com/raccoongang/frontend-app-course-authoring/pull/25) - it.skip('renders the ProctoredExamSettings component when the proctored exam settings route is active', () => { + fit('renders the PagesAndResources component when the pages and resources route is active', () => { render( - - - + + + , ); - expect(screen.queryByText(proctoredExamSeetingsMockText)).toBeInTheDocument(); - expect(screen.queryByText(pagesAndResourcesMockText)).not.toBeInTheDocument(); + expect(screen.getByText(pagesAndResourcesMockText)).toBeVisible(); expect(mockComponentFn).toHaveBeenCalledWith( expect.objectContaining({ courseId, @@ -107,9 +80,9 @@ describe('', () => { it('renders the EditorContainer component when the course editor route is active', () => { render( - - - + + + , ); @@ -125,9 +98,9 @@ describe('', () => { it('renders the VideoSelectorContainer component when the course videos route is active', () => { render( - - - + + + , ); diff --git a/src/advanced-settings/AdvancedSettings.jsx b/src/advanced-settings/AdvancedSettings.jsx index 9b9f8b720a..654a33441d 100644 --- a/src/advanced-settings/AdvancedSettings.jsx +++ b/src/advanced-settings/AdvancedSettings.jsx @@ -9,6 +9,7 @@ import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/ import Placeholder from '@edx/frontend-lib-content-components'; import AlertProctoringError from '../generic/AlertProctoringError'; +import { useModel } from '../generic/model-store'; import InternetConnectionAlert from '../generic/internet-connection-alert'; import { parseArrayOrObjectValues } from '../utils'; import { RequestStatus } from '../data/constants'; @@ -23,6 +24,7 @@ import SettingsSidebar from './settings-sidebar/SettingsSidebar'; import validateAdvancedSettingsData from './utils'; import messages from './messages'; import ModalError from './modal-error/ModalError'; +import getPageHeadTitle from '../generic/utils'; const AdvancedSettings = ({ intl, courseId }) => { const dispatch = useDispatch(); @@ -36,6 +38,9 @@ const AdvancedSettings = ({ intl, courseId }) => { const [isEditableState, setIsEditableState] = useState(false); const [hasInternetConnectionError, setInternetConnectionError] = useState(false); + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.headingTitle)); + useEffect(() => { dispatch(fetchCourseAppSettings(courseId)); dispatch(fetchProctoringExamErrors(courseId)); @@ -125,7 +130,7 @@ const AdvancedSettings = ({ intl, courseId }) => { return ( <> - +
{(proctoringErrors?.length > 0) && ( { ) : null}
-
{ xl={[{ span: 9 }, { span: 3 }]} > +
diff --git a/src/advanced-settings/scss/AdvancedSettings.scss b/src/advanced-settings/scss/AdvancedSettings.scss index 676c6dc81c..c4252d6147 100644 --- a/src/advanced-settings/scss/AdvancedSettings.scss +++ b/src/advanced-settings/scss/AdvancedSettings.scss @@ -1,23 +1,29 @@ @import "variables"; -.setting-items-policies { - .setting-items-deprecated-setting { - float: right; - margin-bottom: 1.75rem; +.advanced-settings { + .help-sidebar { + margin-top: 8.75rem; } - .instructions, - strong { - color: $text-color-base; - font-weight: 400; + .setting-items-policies { + .setting-items-deprecated-setting { + float: right; + margin-bottom: 1.75rem; + } + + .instructions, + strong { + color: $text-color-base; + font-weight: 400; + } } -} -.setting-card { - margin-bottom: 1.75rem; + .setting-card { + margin-bottom: 1.75rem; - .pgn__card-header .pgn__card-header-title-md { - font-size: 1.125rem; + .pgn__card-header .pgn__card-header-title-md { + font-size: 1.125rem; + } } } @@ -40,16 +46,11 @@ .form-control { min-height: 2.75rem; - width: $setting-form-control-width; - } - - .pgn__card-section { - max-width: $setting-form-control-width; + flex-grow: 1; } .pgn__card-header { padding: 0 0 0 1.5rem; - flex-grow: 1; } .pgn__card-status { @@ -59,8 +60,6 @@ .pgn__card-header-content { margin-top: 1.438rem; margin-bottom: 1.438rem; - display: flex; - flex-direction: revert; } } diff --git a/src/advanced-settings/scss/_variables.scss b/src/advanced-settings/scss/_variables.scss index 915aecc19e..22c26a836f 100644 --- a/src/advanced-settings/scss/_variables.scss +++ b/src/advanced-settings/scss/_variables.scss @@ -1,2 +1 @@ $text-color-base: $gray-700; -$setting-form-control-width: 34.375rem; diff --git a/src/advanced-settings/setting-card/SettingCard.jsx b/src/advanced-settings/setting-card/SettingCard.jsx index 15cef8ad9f..e522963f84 100644 --- a/src/advanced-settings/setting-card/SettingCard.jsx +++ b/src/advanced-settings/setting-card/SettingCard.jsx @@ -58,8 +58,9 @@ const SettingCard = ({ return (
  • - + {capitalize(displayName)} @@ -86,10 +87,11 @@ const SettingCard = ({ dangerouslySetInnerHTML={{ __html: help }} /> + )} /> - + ( diff --git a/src/assets/scss/_animations.scss b/src/assets/scss/_animations.scss new file mode 100644 index 0000000000..2100b62a41 --- /dev/null +++ b/src/assets/scss/_animations.scss @@ -0,0 +1,9 @@ +@keyframes rotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/src/constants.js b/src/constants.js index aeb09d1a63..6305606e70 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,9 +1,36 @@ export const DATE_FORMAT = 'MM/dd/yyyy'; export const TIME_FORMAT = 'HH:mm'; export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss\\Z'; -export const FORMATTED_DATE_FORMAT = 'MMMM D, YYYY'; +export const COMMA_SEPARATED_DATE_FORMAT = 'MMMM D, YYYY'; export const DEFAULT_EMPTY_WYSIWYG_VALUE = '

     

    '; export const STATEFUL_BUTTON_STATES = { - pending: 'pending', default: 'default', + pending: 'pending', + error: 'error', +}; + +export const USER_ROLES = { + admin: 'instructor', + staff: 'staff', +}; + +export const BADGE_STATES = { + danger: 'danger', + secondary: 'secondary', +}; + +export const NOTIFICATION_MESSAGES = { + saving: 'Saving', + duplicating: 'Duplicating', + deleting: 'Deleting', +}; + +export const DEFAULT_TIME_STAMP = '00:00'; + +export const COURSE_CREATOR_STATES = { + unrequested: 'unrequested', + pending: 'pending', + granted: 'granted', + denied: 'denied', + disallowedForThisSite: 'disallowed_for_this_site', }; diff --git a/src/course-rerun/CourseRerun.test.jsx b/src/course-rerun/CourseRerun.test.jsx new file mode 100644 index 0000000000..9c403b368b --- /dev/null +++ b/src/course-rerun/CourseRerun.test.jsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { MemoryRouter } from 'react-router-dom'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { + act, fireEvent, render, waitFor, +} from '@testing-library/react'; +import MockAdapter from 'axios-mock-adapter'; + +import initializeStore from '../store'; +import { studioHomeMock } from '../studio-home/__mocks__'; +import { getStudioHomeApiUrl } from '../studio-home/data/api'; +import { RequestStatus } from '../data/constants'; +import messages from './messages'; +import CourseRerun from '.'; + +let axiosMock; +let store; +const mockPathname = '/foo-bar'; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: mockPathname, + }), +})); + +const RootWrapper = () => ( + + + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock); + useSelector.mockReturnValue(studioHomeMock); + }); + + it('should render successfully', () => { + const { getByText, getAllByRole } = render(); + expect(getByText(messages.rerunTitle.defaultMessage)); + expect(getAllByRole('button', { name: messages.cancelButton.defaultMessage }).length).toBe(2); + }); + + it('should navigate to /home on cancel button click', () => { + const { getAllByRole } = render(); + const cancelButton = getAllByRole('button', { name: messages.cancelButton.defaultMessage })[0]; + + fireEvent.click(cancelButton); + waitFor(() => { + expect(window.location.pathname).toBe('/home'); + }); + }); + + it('shows the spinner before the query is complete', async () => { + useSelector.mockReturnValue({ organizationLoadingStatus: RequestStatus.IN_PROGRESS }); + + await act(async () => { + const { getByRole } = render(); + const spinner = getByRole('status'); + expect(spinner.textContent).toEqual('Loading...'); + }); + }); + + it('should show footer', () => { + const { getByText } = render(); + expect(getByText('Looking for help with Studio?')).toBeInTheDocument(); + expect(getByText('LMS')).toHaveAttribute('href', process.env.LMS_BASE_URL); + }); +}); diff --git a/src/course-rerun/course-rerun-form/CourseRerunForm.test.jsx b/src/course-rerun/course-rerun-form/CourseRerunForm.test.jsx new file mode 100644 index 0000000000..5b73f1db3c --- /dev/null +++ b/src/course-rerun/course-rerun-form/CourseRerunForm.test.jsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { render } from '@testing-library/react'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { AppProvider } from '@edx/frontend-platform/react'; + +import { studioHomeMock } from '../../studio-home/__mocks__'; +import initializeStore from '../../store'; +import CourseRerunForm from '.'; + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +let store; + +const onClickCancelMock = jest.fn(); + +const RootWrapper = (props) => ( + + + + + +); + +const props = { + initialFormValues: { + displayName: '', + org: '', + number: '', + run: '', + }, + onClickCancel: onClickCancelMock, +}; + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + useSelector.mockReturnValue(studioHomeMock); + }); + + it('renders description successfully', () => { + const { getByText } = render(); + expect(getByText('Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run', { exact: false })).toBeInTheDocument(); + }); +}); diff --git a/src/course-rerun/course-rerun-form/index.jsx b/src/course-rerun/course-rerun-form/index.jsx new file mode 100644 index 0000000000..426166e5ad --- /dev/null +++ b/src/course-rerun/course-rerun-form/index.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { CreateOrRerunCourseForm } from '../../generic/create-or-rerun-course'; +import messages from './messages'; + +const CourseRerunForm = ({ initialFormValues, onClickCancel }) => { + const intl = useIntl(); + return ( +
    +
    {intl.formatMessage(messages.rerunCourseDescription, { + strong: ( + {intl.formatMessage(messages.rerunCourseDescriptionStrong)} + ), + })} +
    + +
    + ); +}; + +CourseRerunForm.propTypes = { + initialFormValues: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + org: PropTypes.string.isRequired, + number: PropTypes.string.isRequired, + run: PropTypes.string, + }).isRequired, + onClickCancel: PropTypes.func.isRequired, +}; + +export default CourseRerunForm; diff --git a/src/course-rerun/course-rerun-form/messages.js b/src/course-rerun/course-rerun-form/messages.js new file mode 100644 index 0000000000..db103fa153 --- /dev/null +++ b/src/course-rerun/course-rerun-form/messages.js @@ -0,0 +1,14 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + rerunCourseDescription: { + id: 'course-authoring.course-rerun.form.description', + defaultMessage: 'Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run. {strong}', + }, + rerunCourseDescriptionStrong: { + id: 'course-authoring.course-rerun.form.description.strong', + defaultMessage: 'Note: Together, the organization, course number, and course run must uniquely identify this new course instance.', + }, +}); + +export default messages; diff --git a/src/course-rerun/course-rerun-sidebar/CourseRerunSidebar.test.jsx b/src/course-rerun/course-rerun-sidebar/CourseRerunSidebar.test.jsx new file mode 100644 index 0000000000..d497d873f1 --- /dev/null +++ b/src/course-rerun/course-rerun-sidebar/CourseRerunSidebar.test.jsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { AppProvider } from '@edx/frontend-platform/react'; + +import initializeStore from '../../store'; +import CourseRerunSideBar from '.'; +import messages from './messages'; + +let store; +const mockPathname = '/foo-bar'; +const courseId = '123'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: mockPathname, + }), +})); + +const renderComponent = (props) => render( + + + + + , +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + }); + + it('render CourseRerunSideBar successfully', () => { + const { getByText } = renderComponent(); + + expect(getByText(messages.sectionTitle1.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sectionDescription1.defaultMessage, { exact: false })).toBeInTheDocument(); + expect(getByText(messages.sectionTitle2.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sectionDescription2.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sectionTitle3.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sectionDescription3.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sectionLink4.defaultMessage)).toBeInTheDocument(); + }); +}); diff --git a/src/course-rerun/course-rerun-sidebar/index.jsx b/src/course-rerun/course-rerun-sidebar/index.jsx new file mode 100644 index 0000000000..32437b13a6 --- /dev/null +++ b/src/course-rerun/course-rerun-sidebar/index.jsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { v4 as uuid } from 'uuid'; +import { Hyperlink } from '@edx/paragon'; +import { FormattedDate, useIntl } from '@edx/frontend-platform/i18n'; + +import { useHelpUrls } from '../../help-urls/hooks'; +import { HelpSidebar } from '../../generic/help-sidebar'; +import messages from './messages'; + +const CourseRerunSideBar = () => { + const intl = useIntl(); + const { default: learnMoreUrl } = useHelpUrls(['default']); + const defaultCourseDate = new Date(Date.UTC(2030, 0, 1, 0, 0)); + const localizedCourseDate = ( + + ); + + const sidebarMessages = [ + { + title: intl.formatMessage(messages.sectionTitle1), + description: `${intl.formatMessage(messages.sectionDescription1)}`, + date: localizedCourseDate, + }, + { + title: intl.formatMessage(messages.sectionTitle2), + description: intl.formatMessage(messages.sectionDescription2), + }, + { + title: intl.formatMessage(messages.sectionTitle3), + description: intl.formatMessage(messages.sectionDescription3), + }, + { + link: { + text: intl.formatMessage(messages.sectionLink4), + href: learnMoreUrl, + }, + }, + ]; + + return ( + + {sidebarMessages.map(({ + title, + description, + link, + date, + }, index) => { + const isLastSection = index === sidebarMessages.length - 1; + + return ( +
    +

    {title}

    +

    {description} {date}

    + {!!link && ( + + {link.text} + + )} + {!isLastSection &&
    } +
    + ); + })} +
    + ); +}; + +export default CourseRerunSideBar; diff --git a/src/course-rerun/course-rerun-sidebar/messages.js b/src/course-rerun/course-rerun-sidebar/messages.js new file mode 100644 index 0000000000..594545bee8 --- /dev/null +++ b/src/course-rerun/course-rerun-sidebar/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + sectionTitle1: { + id: 'course-authoring.course-rerun.sidebar.section-1.title', + defaultMessage: 'When will my course re-run start?', + }, + sectionDescription1: { + id: 'course-authoring.course-rerun.sidebar.section-1.description', + defaultMessage: 'The new course is set to start on', + }, + sectionTitle2: { + id: 'course-authoring.course-rerun.sidebar.section-2.title', + defaultMessage: 'What transfers from the original course?', + }, + sectionDescription2: { + id: 'course-authoring.course-rerun.sidebar.section-2.description', + defaultMessage: 'The new course has the same course outline and content as the original course. All problems, videos, announcements, and other files are duplicated to the new course.', + }, + sectionTitle3: { + id: 'course-authoring.course-rerun.sidebar.section-3.title', + defaultMessage: 'What does not transfer from the original course?', + }, + sectionDescription3: { + id: 'course-authoring.course-rerun.sidebar.section-3.description', + defaultMessage: 'You are the only member of the new course\'s staff. No students are enrolled in the course, and there is no student data. There is no content in the discussion topics or wiki.', + }, + sectionLink4: { + id: 'course-authoring.course-rerun.sidebar.section-4.link', + defaultMessage: 'Learn more about course re-runs', + }, +}); + +export default messages; diff --git a/src/course-rerun/hooks.jsx b/src/course-rerun/hooks.jsx new file mode 100644 index 0000000000..87fb97041f --- /dev/null +++ b/src/course-rerun/hooks.jsx @@ -0,0 +1,68 @@ +import { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { useNavigate } from 'react-router-dom'; + +import { RequestStatus } from '../data/constants'; +import { updateSavingStatus } from '../generic/data/slice'; +import { + getSavingStatus, + getRedirectUrlObj, + getCourseRerunData, + getCourseData, +} from '../generic/data/selectors'; +import { fetchCourseRerunQuery, fetchOrganizationsQuery } from '../generic/data/thunks'; +import { fetchStudioHomeData } from '../studio-home/data/thunks'; + +const useCourseRerun = (courseId) => { + const intl = useIntl(); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const savingStatus = useSelector(getSavingStatus); + const courseData = useSelector(getCourseData); + const courseRerunData = useSelector(getCourseRerunData); + const redirectUrlObj = useSelector(getRedirectUrlObj); + + const { + displayName = '', + org = '', + run = '', + number = '', + } = courseRerunData; + const originalCourseData = `${org} ${number} ${run}`; + const initialFormValues = { + displayName, + org, + number, + run: '', + }; + + useEffect(() => { + dispatch(fetchStudioHomeData()); + dispatch(fetchCourseRerunQuery(courseId)); + dispatch(fetchOrganizationsQuery()); + }, []); + + useEffect(() => { + if (savingStatus === RequestStatus.SUCCESSFUL) { + dispatch(updateSavingStatus({ status: '' })); + const { url } = redirectUrlObj; + if (url) { + navigate('/home'); + } + } + }, [savingStatus]); + + return { + intl, + courseData, + displayName, + savingStatus, + initialFormValues, + originalCourseData, + dispatch, + }; +}; + +// eslint-disable-next-line import/prefer-default-export +export { useCourseRerun }; diff --git a/src/course-rerun/index.jsx b/src/course-rerun/index.jsx new file mode 100644 index 0000000000..b6626df6d0 --- /dev/null +++ b/src/course-rerun/index.jsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { + Container, + Layout, + Stack, + ActionRow, + Button, +} from '@edx/paragon'; +import { StudioFooter } from '@edx/frontend-component-footer'; +import { useNavigate, useParams } from 'react-router-dom'; + +import Header from '../header'; +import Loading from '../generic/Loading'; +import { getLoadingStatuses } from '../generic/data/selectors'; +import InternetConnectionAlert from '../generic/internet-connection-alert'; +import { RequestStatus } from '../data/constants'; +import CourseRerunForm from './course-rerun-form'; +import CourseRerunSideBar from './course-rerun-sidebar'; +import messages from './messages'; +import { useCourseRerun } from './hooks'; + +const CourseRerun = () => { + const { courseId } = useParams(); + const navigate = useNavigate(); + const { + intl, + displayName, + savingStatus, + initialFormValues, + originalCourseData, + } = useCourseRerun(courseId); + const { organizationLoadingStatus } = useSelector(getLoadingStatuses); + + if (organizationLoadingStatus === RequestStatus.IN_PROGRESS) { + return ; + } + + const handleRerunCourseCancel = () => { + navigate('/home'); + }; + + return ( + <> +
    + +
    +
    +
    +
    + +

    + {intl.formatMessage(messages.rerunTitle)} {displayName} +

    + {originalCourseData} +
    + + + +
    +
    +
    +
    + + + + + + + + +
    +
    +
    + +
    + + + ); +}; + +export default CourseRerun; diff --git a/src/course-rerun/messages.js b/src/course-rerun/messages.js new file mode 100644 index 0000000000..21f6943cc2 --- /dev/null +++ b/src/course-rerun/messages.js @@ -0,0 +1,14 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + rerunTitle: { + id: 'course-authoring.course-rerun.title', + defaultMessage: 'Create a re-run of', + }, + cancelButton: { + id: 'course-authoring.course-rerun.actions.button.cancel', + defaultMessage: 'Cancel', + }, +}); + +export default messages; diff --git a/src/course-team/CourseTeam.jsx b/src/course-team/CourseTeam.jsx new file mode 100644 index 0000000000..e22b1721b6 --- /dev/null +++ b/src/course-team/CourseTeam.jsx @@ -0,0 +1,168 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl, injectIntl } from '@edx/frontend-platform/i18n'; +import { + Button, + Container, + Layout, +} from '@edx/paragon'; +import { Add as IconAdd } from '@edx/paragon/icons'; + +import InternetConnectionAlert from '../generic/internet-connection-alert'; +import { useModel } from '../generic/model-store'; +import SubHeader from '../generic/sub-header/SubHeader'; +import { USER_ROLES } from '../constants'; +import messages from './messages'; +import CourseTeamSideBar from './course-team-sidebar/CourseTeamSidebar'; +import AddUserForm from './add-user-form/AddUserForm'; +import AddTeamMember from './add-team-member/AddTeamMember'; +import CourseTeamMember from './course-team-member/CourseTeamMember'; +import InfoModal from './info-modal/InfoModal'; +import { useCourseTeam } from './hooks'; +import getPageHeadTitle from '../generic/utils'; + +const CourseTeam = ({ courseId }) => { + const intl = useIntl(); + + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.headingTitle)); + + const { + modalType, + errorMessage, + courseName, + currentEmail, + courseTeamUsers, + currentUserEmail, + isLoading, + isSingleAdmin, + isFormVisible, + isQueryPending, + isAllowActions, + isInfoModalOpen, + isOwnershipHint, + isShowAddTeamMember, + isShowInitialSidebar, + isShowUserFilledSidebar, + isInternetConnectionAlertFailed, + openForm, + hideForm, + closeInfoModal, + handleAddUserSubmit, + handleOpenDeleteModal, + handleDeleteUserSubmit, + handleChangeRoleUserSubmit, + handleInternetConnectionFailed, + } = useCourseTeam({ intl, courseId }); + + if (isLoading) { + // eslint-disable-next-line react/jsx-no-useless-fragment + return <>; + } + + return ( + <> + +
    + + +
    +
    + + {intl.formatMessage(messages.addNewMemberButton)} + + )} + /> +
    +
    + {isFormVisible && ( + + )} + {courseTeamUsers.length ? courseTeamUsers.map(({ username, role, email }) => ( + + )) : null} + {isShowAddTeamMember && ( + + )} +
    + {isShowInitialSidebar && ( +
    + +
    + )} + +
    +
    +
    +
    + + {isShowUserFilledSidebar && ( + + )} + +
    +
    +
    +
    + +
    + + ); +}; + +CourseTeam.propTypes = { + courseId: PropTypes.string.isRequired, +}; + +export default injectIntl(CourseTeam); diff --git a/src/course-team/CourseTeam.scss b/src/course-team/CourseTeam.scss new file mode 100644 index 0000000000..02598367bf --- /dev/null +++ b/src/course-team/CourseTeam.scss @@ -0,0 +1,29 @@ +@import "./course-team-sidebar/CourseTeamSidebar"; +@import "./add-user-form/AddUserForm"; +@import "./add-team-member/AddTeamMember"; +@import "./course-team-member/CourseTeamMember"; + +.course-team { + .help-sidebar { + margin-top: 6.563rem; + } + + .course-team-section { + .sidebar-container { + width: 30%; + + .help-sidebar { + margin-top: 0; + + hr { + display: none; + } + } + } + + .members-container { + flex-grow: 1; + padding-top: 1.25rem; + } + } +} diff --git a/src/course-team/CourseTeam.test.jsx b/src/course-team/CourseTeam.test.jsx new file mode 100644 index 0000000000..4f33788744 --- /dev/null +++ b/src/course-team/CourseTeam.test.jsx @@ -0,0 +1,222 @@ +import React from 'react'; +import { + render, + fireEvent, + cleanup, + waitFor, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { initializeMockApp } from '@edx/frontend-platform'; +import MockAdapter from 'axios-mock-adapter'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import initializeStore from '../store'; +import { courseTeamMock, courseTeamWithOneUser, courseTeamWithoutUsers } from './__mocks__'; +import { getCourseTeamApiUrl, updateCourseTeamUserApiUrl } from './data/api'; +import CourseTeam from './CourseTeam'; +import messages from './messages'; +import { USER_ROLES } from '../constants'; +import { executeThunk } from '../utils'; +import { changeRoleTeamUserQuery, deleteCourseTeamQuery } from './data/thunk'; + +let axiosMock; +let store; +const mockPathname = '/foo-bar'; +const courseId = '123'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: mockPathname, + }), +})); + +const RootWrapper = () => ( + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + it('render CourseTeam component with 3 team members correctly', async () => { + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamMock); + + const { + getByText, getByRole, getByTestId, queryAllByTestId, + } = render(); + + await waitFor(() => { + expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.addNewMemberButton.defaultMessage })).toBeInTheDocument(); + expect(getByTestId('course-team-sidebar')).toBeInTheDocument(); + expect(queryAllByTestId('course-team-member')).toHaveLength(3); + }); + }); + + it('render CourseTeam component with 1 team member correctly', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamWithOneUser); + + const { + getByText, getByRole, getByTestId, getAllByTestId, + } = render(); + + await waitFor(() => { + expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.addNewMemberButton.defaultMessage })).toBeInTheDocument(); + expect(getByTestId('course-team-sidebar')).toBeInTheDocument(); + expect(getAllByTestId('course-team-member')).toHaveLength(1); + }); + }); + + it('render CourseTeam component without team member correctly', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamWithoutUsers); + + const { + getByText, getByRole, getByTestId, queryAllByTestId, + } = render(); + + await waitFor(() => { + expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.addNewMemberButton.defaultMessage })).toBeInTheDocument(); + expect(getByTestId('course-team-sidebar__initial')).toBeInTheDocument(); + expect(queryAllByTestId('course-team-member')).toHaveLength(0); + }); + }); + + it('render CourseTeam component with initial sidebar correctly', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamWithoutUsers); + + const { getByTestId, queryByTestId } = render(); + + await waitFor(() => { + expect(getByTestId('course-team-sidebar__initial')).toBeInTheDocument(); + expect(queryByTestId('course-team-sidebar')).not.toBeInTheDocument(); + }); + }); + + it('render CourseTeam component without initial sidebar correctly', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamMock); + + const { getByTestId, queryByTestId } = render(); + + await waitFor(() => { + expect(queryByTestId('course-team-sidebar__initial')).not.toBeInTheDocument(); + expect(getByTestId('course-team-sidebar')).toBeInTheDocument(); + }); + }); + + it('displays AddUserForm when clicking the "Add New Member" button', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamWithOneUser); + + const { getByRole, queryByTestId } = render(); + + await waitFor(() => { + expect(queryByTestId('add-user-form')).not.toBeInTheDocument(); + const addButton = getByRole('button', { name: messages.addNewMemberButton.defaultMessage }); + fireEvent.click(addButton); + expect(queryByTestId('add-user-form')).toBeInTheDocument(); + }); + }); + + it('displays AddUserForm when clicking the "Add a New Team member" button', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamWithOneUser); + + const { getByRole, queryByTestId } = render(); + + await waitFor(() => { + expect(queryByTestId('add-user-form')).not.toBeInTheDocument(); + const addButton = getByRole('button', { name: 'Add a new team member' }); + fireEvent.click(addButton); + expect(queryByTestId('add-user-form')).toBeInTheDocument(); + }); + }); + + it('not displays "Add New Member" and AddTeamMember component when isAllowActions is false', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, { + ...courseTeamWithOneUser, + allowActions: false, + }); + + const { queryByRole, queryByTestId } = render(); + + await waitFor(() => { + expect(queryByRole('button', { name: messages.addNewMemberButton.defaultMessage })).not.toBeInTheDocument(); + expect(queryByTestId('add-team-member')).not.toBeInTheDocument(); + }); + }); + + it('should delete user', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamMock); + + const { queryByText } = render(); + + axiosMock + .onDelete(updateCourseTeamUserApiUrl(courseId, 'staff@example.com')) + .reply(200); + + await executeThunk(deleteCourseTeamQuery(courseId, 'staff@example.com'), store.dispatch); + expect(queryByText('staff@example.com')).not.toBeInTheDocument(); + }); + + it('should change role user', async () => { + cleanup(); + axiosMock + .onGet(getCourseTeamApiUrl(courseId)) + .reply(200, courseTeamMock); + + const { getAllByText } = render(); + + axiosMock + .onPut(updateCourseTeamUserApiUrl(courseId, 'staff@example.com', { role: USER_ROLES.admin })) + .reply(200, { role: USER_ROLES.admin }); + + await executeThunk(changeRoleTeamUserQuery(courseId, 'staff@example.com', { role: USER_ROLES.admin }), store.dispatch); + expect(getAllByText('Admin')).toHaveLength(1); + }); +}); diff --git a/src/course-team/__mocks__/courseTeam.js b/src/course-team/__mocks__/courseTeam.js new file mode 100644 index 0000000000..3a7d479a2d --- /dev/null +++ b/src/course-team/__mocks__/courseTeam.js @@ -0,0 +1,24 @@ +module.exports = { + showTransferOwnershipHint: true, + users: [ + { + email: 'staff@example.com', + id: '2', + role: 'staff', + username: 'Staff_Name', + }, + { + email: 'audit@example.com', + id: '3', + role: 'staff', + username: 'Audit_Name', + }, + { + email: 'vladislav.keblysh@raccoongang.com', + id: '1', + role: 'instructor', + username: 'Vladislav_Keblysh', + }, + ], + allowActions: true, +}; diff --git a/src/course-team/__mocks__/courseTeamWithOneUser.js b/src/course-team/__mocks__/courseTeamWithOneUser.js new file mode 100644 index 0000000000..136e1f7317 --- /dev/null +++ b/src/course-team/__mocks__/courseTeamWithOneUser.js @@ -0,0 +1,12 @@ +module.exports = { + showTransferOwnershipHint: true, + users: [ + { + email: 'staff@example.com', + id: '2', + role: 'staff', + username: 'Staff_Name', + }, + ], + allowActions: true, +}; diff --git a/src/course-team/__mocks__/courseTeamWithoutUsers.js b/src/course-team/__mocks__/courseTeamWithoutUsers.js new file mode 100644 index 0000000000..357caf9565 --- /dev/null +++ b/src/course-team/__mocks__/courseTeamWithoutUsers.js @@ -0,0 +1,5 @@ +module.exports = { + showTransferOwnershipHint: true, + users: [], + allowActions: true, +}; diff --git a/src/course-team/__mocks__/index.js b/src/course-team/__mocks__/index.js new file mode 100644 index 0000000000..787cfc14de --- /dev/null +++ b/src/course-team/__mocks__/index.js @@ -0,0 +1,3 @@ +export { default as courseTeamMock } from './courseTeam'; +export { default as courseTeamWithOneUser } from './courseTeamWithOneUser'; +export { default as courseTeamWithoutUsers } from './courseTeamWithoutUsers'; diff --git a/src/course-team/add-team-member/AddTeamMember.jsx b/src/course-team/add-team-member/AddTeamMember.jsx new file mode 100644 index 0000000000..e6e08dcd42 --- /dev/null +++ b/src/course-team/add-team-member/AddTeamMember.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Add as IconAdd } from '@edx/paragon/icons'; +import { Button } from '@edx/paragon'; + +import messages from './messages'; + +const AddTeamMember = ({ onFormOpen, isButtonDisable }) => { + const intl = useIntl(); + + return ( +
    +
    +

    {intl.formatMessage(messages.title)}

    + {intl.formatMessage(messages.description)} +
    + +
    + ); +}; + +AddTeamMember.propTypes = { + onFormOpen: PropTypes.func.isRequired, + isButtonDisable: PropTypes.bool, +}; + +AddTeamMember.defaultProps = { + isButtonDisable: false, +}; + +export default AddTeamMember; diff --git a/src/course-team/add-team-member/AddTeamMember.scss b/src/course-team/add-team-member/AddTeamMember.scss new file mode 100644 index 0000000000..6859a2dced --- /dev/null +++ b/src/course-team/add-team-member/AddTeamMember.scss @@ -0,0 +1,17 @@ +.add-team-member { + display: flex; + align-items: center; + justify-content: space-between; + border: .0625rem solid $gray-200; + border-radius: .375rem; + box-shadow: inset inset 0 1px .125rem 1px $gray-200; + padding: 1.25rem 1.875rem; + + .add-team-member-info { + width: 60%; + } + + .add-team-member-title { + font-size: $spacer; + } +} diff --git a/src/course-team/add-team-member/AddTeamMember.test.jsx b/src/course-team/add-team-member/AddTeamMember.test.jsx new file mode 100644 index 0000000000..bb20a93ebf --- /dev/null +++ b/src/course-team/add-team-member/AddTeamMember.test.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import AddTeamMember from './AddTeamMember'; +import messages from './messages'; + +const onFormOpenMock = jest.fn(); + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('render AddTeamMember component correctly', () => { + const { getByText, getByRole } = renderComponent(); + + expect(getByText(messages.title.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.description.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.button.defaultMessage })).toBeInTheDocument(); + }); + + it('calls onFormOpen when the button is clicked', () => { + const { getByText } = renderComponent(); + + const addButton = getByText(messages.button.defaultMessage); + fireEvent.click(addButton); + expect(onFormOpenMock).toHaveBeenCalledTimes(1); + }); + + it('"Add a New Team member" button is disabled when isButtonDisable is true', () => { + const { getByRole } = renderComponent({ isButtonDisable: true }); + + const addButton = getByRole('button', { name: messages.button.defaultMessage }); + expect(addButton).toBeDisabled(); + }); + + it('"Add a New Team member" button is not disabled when isButtonDisable is false', () => { + const { getByRole } = renderComponent(); + + const addButton = getByRole('button', { name: messages.button.defaultMessage }); + expect(addButton).not.toBeDisabled(); + }); +}); diff --git a/src/course-team/add-team-member/messages.js b/src/course-team/add-team-member/messages.js new file mode 100644 index 0000000000..3def097045 --- /dev/null +++ b/src/course-team/add-team-member/messages.js @@ -0,0 +1,18 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + title: { + id: 'course-authoring.course-team.add-team-member.title', + defaultMessage: 'Add team members to this course', + }, + description: { + id: 'course-authoring.course-team.add-team-member.description', + defaultMessage: 'Adding team members makes course authoring collaborative. Users must be signed up for Studio and have an active account.', + }, + button: { + id: 'course-authoring.course-team.add-team-member.button', + defaultMessage: 'Add a new team member', + }, +}); + +export default messages; diff --git a/src/course-team/add-user-form/AddUserForm.jsx b/src/course-team/add-user-form/AddUserForm.jsx new file mode 100644 index 0000000000..284288c86f --- /dev/null +++ b/src/course-team/add-user-form/AddUserForm.jsx @@ -0,0 +1,66 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { + Button, + Form, + ActionRow, +} from '@edx/paragon'; +import { Formik } from 'formik'; + +import messages from './messages'; +import FormikControl from '../../generic/FormikControl'; +import { EXAMPLE_USER_EMAIL } from '../constants'; + +const AddUserForm = ({ onSubmit, onCancel }) => { + const intl = useIntl(); + + return ( +
    + + {({ handleSubmit, values }) => ( + <> + +

    {intl.formatMessage(messages.formTitle)}

    + + {intl.formatMessage(messages.formLabel)} + + + + {intl.formatMessage(messages.formHelperText)} + +
    + + + + + + )} +
    +
    + ); +}; + +AddUserForm.propTypes = { + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, +}; + +export default AddUserForm; diff --git a/src/course-team/add-user-form/AddUserForm.scss b/src/course-team/add-user-form/AddUserForm.scss new file mode 100644 index 0000000000..0286372cae --- /dev/null +++ b/src/course-team/add-user-form/AddUserForm.scss @@ -0,0 +1,42 @@ +.add-user-form { + display: flex; + flex-direction: column; + border: .0625rem solid $gray-200; + border-radius: .375rem; + box-shadow: 0 1px 1px $gray-200; + margin-bottom: 1.25rem; + background-color: $white; + + .form-title { + font-size: 1.5rem; + margin-bottom: 1.875rem; + } + + .form-field { + padding: 1.25rem 1.875rem; + margin-bottom: $spacer; + + .pgn__form-group { + margin-bottom: 0; + } + } + + .form-label { + position: relative; + + &::after { + margin-left: .3125rem; + content: "*"; + } + } + + .form-helper-text { + font-size: $font-size-xs; + } + + .pgn__action-row { + padding: $spacer 1.875rem; + border-top: .0625rem solid $gray-200; + justify-content: flex-start; + } +} diff --git a/src/course-team/add-user-form/AddUserForm.test.jsx b/src/course-team/add-user-form/AddUserForm.test.jsx new file mode 100644 index 0000000000..d3716b14c1 --- /dev/null +++ b/src/course-team/add-user-form/AddUserForm.test.jsx @@ -0,0 +1,128 @@ +import React from 'react'; +import { + render, + fireEvent, + act, + waitFor, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { initializeMockApp } from '@edx/frontend-platform'; +import MockAdapter from 'axios-mock-adapter'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { EXAMPLE_USER_EMAIL } from '../constants'; +import initializeStore from '../../store'; +import { USER_ROLES } from '../../constants'; +import { updateCourseTeamUserApiUrl } from '../data/api'; +import { createCourseTeamQuery } from '../data/thunk'; +import { executeThunk } from '../../utils'; +import AddUserForm from './AddUserForm'; +import messages from './messages'; + +let axiosMock; +let store; +const mockPathname = '/foo-bar'; +const courseId = '123'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: mockPathname, + }), +})); + +const onSubmitMock = jest.fn(); +const onCancelMock = jest.fn(); + +const RootWrapper = () => ( + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + it('render AddUserForm component correctly', () => { + const { getByText, getByPlaceholderText } = render(); + + expect(getByText(messages.formTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.formLabel.defaultMessage)).toBeInTheDocument(); + expect(getByPlaceholderText(messages.formPlaceholder.defaultMessage + .replace('{email}', EXAMPLE_USER_EMAIL))).toBeInTheDocument(); + expect(getByText(messages.cancelButton.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.addUserButton.defaultMessage)).toBeInTheDocument(); + }); + + it('calls onSubmit when the "Add User" button is clicked with a valid email', async () => { + const { getByPlaceholderText, getByRole } = render(); + + const emailInput = getByPlaceholderText(messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL)); + const addUserButton = getByRole('button', { name: messages.addUserButton.defaultMessage }); + + fireEvent.change(emailInput, { target: { value: EXAMPLE_USER_EMAIL } }); + + await act(async () => { + fireEvent.click(addUserButton); + }); + + await waitFor(() => { + expect(onSubmitMock).toHaveBeenCalledTimes(1); + expect(onSubmitMock).toHaveBeenCalledWith( + { email: EXAMPLE_USER_EMAIL }, + expect.objectContaining({ submitForm: expect.any(Function) }), + ); + }); + + axiosMock + .onPost(updateCourseTeamUserApiUrl(courseId, EXAMPLE_USER_EMAIL), { role: USER_ROLES.staff }) + .reply(200, { role: USER_ROLES.staff }); + + await executeThunk(createCourseTeamQuery(courseId, EXAMPLE_USER_EMAIL), store.dispatch); + }); + + it('calls onCancel when the "Cancel" button is clicked', () => { + const { getByText } = render(); + + const cancelButton = getByText(messages.cancelButton.defaultMessage); + fireEvent.click(cancelButton); + expect(onCancelMock).toHaveBeenCalledTimes(1); + }); + + it('"Add User" button is disabled when the email input field is empty', () => { + const { getByText } = render(); + + const addUserButton = getByText(messages.addUserButton.defaultMessage); + expect(addUserButton).toBeDisabled(); + }); + + it('"Add User" button is not disabled when the email input field is not empty', () => { + const { getByPlaceholderText, getByText } = render(); + + const emailInput = getByPlaceholderText( + messages.formPlaceholder.defaultMessage.replace('{email}', EXAMPLE_USER_EMAIL), + ); + const addUserButton = getByText(messages.addUserButton.defaultMessage); + + fireEvent.change(emailInput, { target: { value: 'user@example.com' } }); + expect(addUserButton).not.toBeDisabled(); + }); +}); diff --git a/src/course-team/add-user-form/messages.js b/src/course-team/add-user-form/messages.js new file mode 100644 index 0000000000..c61543b170 --- /dev/null +++ b/src/course-team/add-user-form/messages.js @@ -0,0 +1,31 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + formTitle: { + id: 'course-authoring.course-team.form.title', + defaultMessage: 'Add a user to your course\'s team', + }, + formLabel: { + id: 'course-authoring.course-team.form.label', + defaultMessage: 'User\'s email address', + }, + formPlaceholder: { + id: 'course-authoring.course-team.form.placeholder', + defaultMessage: 'example: {email}', + }, + formHelperText: { + id: 'course-authoring.course-team.form.helperText', + defaultMessage: 'Provide the email address of the user you want to add as Staff', + }, + addUserButton: { + id: 'course-authoring.course-team.form.button.addUser', + defaultMessage: 'Add user', + }, + cancelButton: { + id: 'course-authoring.course-team.form.button.cancel', + defaultMessage: 'Cancel', + }, + +}); + +export default messages; diff --git a/src/course-team/constants.js b/src/course-team/constants.js new file mode 100644 index 0000000000..f7d6a11d2a --- /dev/null +++ b/src/course-team/constants.js @@ -0,0 +1,17 @@ +export const MODAL_TYPES = { + error: 'error', + delete: 'delete', + warning: 'warning', +}; + +export const BADGE_STATES = { + admin: 'primary-700', + staff: 'gray-500', +}; + +export const USER_ROLES = { + admin: 'instructor', + staff: 'staff', +}; + +export const EXAMPLE_USER_EMAIL = 'username@domain.com'; diff --git a/src/course-team/course-team-member/CourseTeamMember.jsx b/src/course-team/course-team-member/CourseTeamMember.jsx new file mode 100644 index 0000000000..d0e53709a5 --- /dev/null +++ b/src/course-team/course-team-member/CourseTeamMember.jsx @@ -0,0 +1,85 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { + Badge, + Button, + Icon, + IconButtonWithTooltip, + MailtoLink, +} from '@edx/paragon'; +import { DeleteOutline } from '@edx/paragon/icons'; + +import messages from './messages'; +import { USER_ROLES, BADGE_STATES } from '../constants'; + +const CourseTeamMember = ({ + userName, + role, + email, + onChangeRole, + onDelete, + currentUserEmail, + isHideActions, + isAllowActions, +}) => { + const intl = useIntl(); + const isAdminRole = role === USER_ROLES.admin; + const badgeColor = isAdminRole ? BADGE_STATES.admin : BADGE_STATES.staff; + + return ( +
    +
    + + {isAdminRole + ? intl.formatMessage(messages.roleAdmin) + : intl.formatMessage(messages.roleStaff)} + {currentUserEmail === email && ( + {intl.formatMessage(messages.roleYou)} + )} + + {userName} + {email} +
    + {/* eslint-disable-next-line no-nested-ternary */} + {isAllowActions && ( + !isHideActions ? ( +
    + + onDelete(email)} + iconAs={Icon} + alt={intl.formatMessage(messages.deleteUserButton)} + data-testid="delete-button" + /> +
    + ) : ( +
    + {intl.formatMessage(messages.hint)} +
    + ) + )} +
    + ); +}; + +CourseTeamMember.propTypes = { + userName: PropTypes.string.isRequired, + role: PropTypes.string.isRequired, + email: PropTypes.string.isRequired, + onChangeRole: PropTypes.func.isRequired, + onDelete: PropTypes.func.isRequired, + currentUserEmail: PropTypes.string.isRequired, + isHideActions: PropTypes.bool.isRequired, + isAllowActions: PropTypes.bool.isRequired, +}; + +export default CourseTeamMember; diff --git a/src/course-team/course-team-member/CourseTeamMember.scss b/src/course-team/course-team-member/CourseTeamMember.scss new file mode 100644 index 0000000000..61969a3cfb --- /dev/null +++ b/src/course-team/course-team-member/CourseTeamMember.scss @@ -0,0 +1,52 @@ +.course-team-container { + margin-top: 3rem; +} + +.course-team-member { + display: flex; + align-items: center; + justify-content: space-between; + position: relative; + padding: 1.563rem 1.875rem 1.25rem; + background-color: $white; + border: .0625rem solid $gray-200; + border-radius: .375rem; + box-shadow: 0 1px 1px $gray-200; + + &:not(:last-child) { + margin-bottom: 1.25rem; + } + + .member-info { + position: relative; + display: flex; + flex-direction: column; + + .badge { + position: absolute; + top: -2.25rem; + left: -.25rem; + } + + .badge-current-user { + margin-left: .25rem; + } + + .member-info-name { + font-size: 1.5rem; + margin-bottom: .25rem; + } + } + + .member-hint { + width: 45%; + margin-right: 3.875rem; + color: $gray-300; + font-size: $font-size-sm; + } + + .member-actions { + display: flex; + gap: $spacer; + } +} diff --git a/src/course-team/course-team-member/CourseTeamMember.test.jsx b/src/course-team/course-team-member/CourseTeamMember.test.jsx new file mode 100644 index 0000000000..be6719ac6a --- /dev/null +++ b/src/course-team/course-team-member/CourseTeamMember.test.jsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { USER_ROLES } from '../../constants'; +import CourseTeamMember from './CourseTeamMember'; +import messages from './messages'; + +const userNameMock = 'User'; +const emailMock = 'user@example.com'; +const currentUserEmailMock = 'user@example.com'; +const onChangeRoleMock = jest.fn(); +const onDeleteMock = jest.fn(); + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('render CourseTeamMember component correctly', () => { + const { getByText, getByRole, getByTestId } = renderComponent(); + + expect(getByText(userNameMock)).toBeInTheDocument(); + expect(getByText(emailMock)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.removeButton.defaultMessage })).toBeInTheDocument(); + expect(getByTestId('delete-button')).toBeInTheDocument(); + expect(getByText(messages.roleAdmin.defaultMessage)).toBeInTheDocument(); + }); + + it('displays correct badge and "You" label for the current user', () => { + const { getByText } = renderComponent({ + role: USER_ROLES.staff, + currentUserEmail: currentUserEmailMock, + }); + + expect(getByText(messages.roleStaff.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.roleYou.defaultMessage)).toBeInTheDocument(); + }); + + it('not displays actions when isAllowActions is false', () => { + const { queryByRole, queryByTestId } = renderComponent({ + role: USER_ROLES.admin, + currentUserEmail: currentUserEmailMock, + isAllowActions: false, + }); + + expect(queryByRole('button', { name: messages.removeButton.defaultMessage })).not.toBeInTheDocument(); + expect(queryByTestId('delete-button')).not.toBeInTheDocument(); + }); + + it('calls onChangeRole when the "Add"/"Remove" button is clicked', () => { + const { getByRole } = renderComponent({ + role: USER_ROLES.staff, + }); + + const addButton = getByRole('button', { name: messages.addButton.defaultMessage }); + fireEvent.click(addButton); + expect(onChangeRoleMock).toHaveBeenCalledTimes(1); + expect(onChangeRoleMock).toHaveBeenCalledWith(emailMock, USER_ROLES.admin); + }); + + it('calls onDelete when the "Delete" button is clicked', () => { + const { getByTestId } = renderComponent(); + + const deleteButton = getByTestId('delete-button'); + fireEvent.click(deleteButton); + expect(onDeleteMock).toHaveBeenCalledTimes(1); + }); + + it('renders the "Hint" when isHideActions is true', () => { + const { getByText, queryByRole, queryByTestId } = renderComponent({ + isHideActions: true, + }); + + expect(queryByRole('button', { name: messages.addButton.defaultMessage })).not.toBeInTheDocument(); + expect(queryByTestId('delete-button')).not.toBeInTheDocument(); + expect(getByText(messages.hint.defaultMessage)).toBeInTheDocument(); + }); +}); diff --git a/src/course-team/course-team-member/messages.js b/src/course-team/course-team-member/messages.js new file mode 100644 index 0000000000..87bb371682 --- /dev/null +++ b/src/course-team/course-team-member/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + roleAdmin: { + id: 'course-authoring.course-team.member.role.admin', + defaultMessage: 'Admin', + }, + roleStaff: { + id: 'course-authoring.course-team.member.role.staff', + defaultMessage: 'Staff', + }, + roleYou: { + id: 'course-authoring.course-team.member.role.you', + defaultMessage: 'You!', + }, + hint: { + id: 'course-authoring.course-team.member.hint', + defaultMessage: 'Promote another member to Admin to remove your admin rights', + }, + addButton: { + id: 'course-authoring.course-team.member.button.add', + defaultMessage: 'Add admin access', + }, + removeButton: { + id: 'course-authoring.course-team.member.button.remove', + defaultMessage: 'Remove admin access', + }, + deleteUserButton: { + id: 'course-authoring.course-team.member.button.delete', + defaultMessage: 'Delete user', + }, +}); + +export default messages; diff --git a/src/course-team/course-team-sidebar/CourseTeamSideBar.test.jsx b/src/course-team/course-team-sidebar/CourseTeamSideBar.test.jsx new file mode 100644 index 0000000000..7218ba40b5 --- /dev/null +++ b/src/course-team/course-team-sidebar/CourseTeamSideBar.test.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { AppProvider } from '@edx/frontend-platform/react'; + +import CourseTeamSidebar from './CourseTeamSidebar'; +import messages from './messages'; +import initializeStore from '../../store'; + +const courseId = 'course-123'; +let store; + +const renderComponent = (props) => render( + + + + + , +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + }); + + it('render CourseTeamSidebar component correctly', () => { + const { getByText } = renderComponent(); + + expect(getByText(messages.sidebarTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sidebarAbout_1.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sidebarAbout_2.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sidebarAbout_3.defaultMessage)).toBeInTheDocument(); + }); + + it('render CourseTeamSidebar when isOwnershipHint is true', () => { + const { getByText } = renderComponent({ isOwnershipHint: true }); + + expect(getByText(messages.ownershipTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText( + 'Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click to make another user the Admin, then ask that user to remove you from the Course Team list.', + )).toBeInTheDocument(); + }); +}); diff --git a/src/course-team/course-team-sidebar/CourseTeamSidebar.jsx b/src/course-team/course-team-sidebar/CourseTeamSidebar.jsx new file mode 100644 index 0000000000..2b7f42c457 --- /dev/null +++ b/src/course-team/course-team-sidebar/CourseTeamSidebar.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { HelpSidebar } from '../../generic/help-sidebar'; +import messages from './messages'; + +const CourseTeamSideBar = ({ courseId, isOwnershipHint, isShowInitialSidebar }) => { + const intl = useIntl(); + + return ( +
    + +

    + {intl.formatMessage(messages.sidebarTitle)} +

    +

    + {intl.formatMessage(messages.sidebarAbout_1)} +

    +

    + {intl.formatMessage(messages.sidebarAbout_2)} +

    +

    + {intl.formatMessage(messages.sidebarAbout_3)} +

    +
    + {isOwnershipHint && ( + <> +
    + +

    + {intl.formatMessage(messages.ownershipTitle)} +

    +

    + {intl.formatMessage( + messages.ownershipDescription, + { strong: {intl.formatMessage(messages.addAdminAccess)} }, + )} +

    +
    + + )} +
    + ); +}; + +CourseTeamSideBar.defaultProps = { + isShowInitialSidebar: false, +}; + +CourseTeamSideBar.propTypes = { + courseId: PropTypes.string.isRequired, + isOwnershipHint: PropTypes.bool.isRequired, + isShowInitialSidebar: PropTypes.bool, +}; + +export default CourseTeamSideBar; diff --git a/src/course-team/course-team-sidebar/CourseTeamSidebar.scss b/src/course-team/course-team-sidebar/CourseTeamSidebar.scss new file mode 100644 index 0000000000..42a8acf52a --- /dev/null +++ b/src/course-team/course-team-sidebar/CourseTeamSidebar.scss @@ -0,0 +1,11 @@ +.course-team-sidebar { + .help-sidebar { + &:not(:first-child) { + margin-top: 0; + } + + hr { + display: none; + } + } +} diff --git a/src/course-team/course-team-sidebar/messages.js b/src/course-team/course-team-sidebar/messages.js new file mode 100644 index 0000000000..a1934c19b2 --- /dev/null +++ b/src/course-team/course-team-sidebar/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + sidebarTitle: { + id: 'course-authoring.course-team.sidebar.title', + defaultMessage: 'Course team roles', + }, + sidebarAbout_1: { + id: 'course-authoring.course-team.sidebar.about-1', + defaultMessage: 'Course team members with the Staff role are course co-authors. They have full writing and editing privileges on all course content.', + }, + sidebarAbout_2: { + id: 'course-authoring.course-team.sidebar.about-2', + defaultMessage: 'Admins are course team members who can add and remove other course team members.', + }, + sidebarAbout_3: { + id: 'course-authoring.course-team.sidebar.about-3', + defaultMessage: 'All course team members can access content in Studio, the LMS, and Insights, but are not automatically enrolled in the course.', + }, + ownershipTitle: { + id: 'course-authoring.course-team.sidebar.ownership.title', + defaultMessage: 'Transferring ownership', + }, + ownershipDescription: { + id: 'course-authoring.course-team.sidebar.ownership.description', + defaultMessage: 'Every course must have an Admin. If you are the Admin and you want to transfer ownership of the course, click {strong} to make another user the Admin, then ask that user to remove you from the Course Team list.', + }, + addAdminAccess: { + id: 'course-authoring.course-team.sidebar.ownership.addAdminAccess', + defaultMessage: 'Add admin access', + }, +}); + +export default messages; diff --git a/src/course-team/data/api.js b/src/course-team/data/api.js new file mode 100644 index 0000000000..321671600d --- /dev/null +++ b/src/course-team/data/api.js @@ -0,0 +1,54 @@ +import { camelCaseObject, getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { USER_ROLES } from '../../constants'; + +const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; +export const getCourseTeamApiUrl = (courseId) => `${getApiBaseUrl()}/api/contentstore/v1/course_team/${courseId}`; +export const updateCourseTeamUserApiUrl = (courseId, email) => `${getApiBaseUrl()}/course_team/${courseId}/${email}`; + +/** + * Get course team. + * @param {string} courseId + * @returns {Promise} + */ +export async function getCourseTeam(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(getCourseTeamApiUrl(courseId)); + + return camelCaseObject(data); +} + +/** + * Create course team user. + * @param {string} courseId + * @param {string} email + * @returns {Promise} + */ +export async function createTeamUser(courseId, email) { + await getAuthenticatedHttpClient() + .post(updateCourseTeamUserApiUrl(courseId, email), { role: USER_ROLES.staff }); +} + +/** + * Change role course team user. + * @param {string} courseId + * @param {string} email + * @param {string} role + * @returns {Promise} + */ +export async function changeRoleTeamUser(courseId, email, role) { + await getAuthenticatedHttpClient() + .put(updateCourseTeamUserApiUrl(courseId, email), { role }); +} + +/** + * Delete course team user. + * @param {string} courseId + * @param {string} email + * @returns {Promise} + */ +export async function deleteTeamUser(courseId, email) { + await getAuthenticatedHttpClient() + .delete(updateCourseTeamUserApiUrl(courseId, email)); +} diff --git a/src/course-team/data/selectors.js b/src/course-team/data/selectors.js new file mode 100644 index 0000000000..99c602fdad --- /dev/null +++ b/src/course-team/data/selectors.js @@ -0,0 +1,6 @@ +export const getCourseTeamUsers = (state) => state.courseTeam.users; +export const getCourseTeamLoadingStatus = (state) => state.courseTeam.loadingCourseTeamStatus; +export const getErrorMessage = (state) => state.courseTeam.errorMessage; +export const getIsAllowActions = (state) => state.courseTeam.allowActions; +export const getIsOwnershipHint = (state) => state.courseTeam.showTransferOwnershipHint; +export const getSavingStatus = (state) => state.courseTeam.savingStatus; diff --git a/src/course-team/data/slice.js b/src/course-team/data/slice.js new file mode 100644 index 0000000000..374210b034 --- /dev/null +++ b/src/course-team/data/slice.js @@ -0,0 +1,46 @@ +/* eslint-disable no-param-reassign */ +import { createSlice } from '@reduxjs/toolkit'; +import { RequestStatus } from '../../data/constants'; + +const slice = createSlice({ + name: 'courseTeam', + initialState: { + loadingCourseTeamStatus: RequestStatus.IN_PROGRESS, + savingStatus: '', + users: [], + showTransferOwnershipHint: false, + allowActions: false, + errorMessage: '', + }, + reducers: { + fetchCourseTeamSuccess: (state, { payload }) => { + state.users = payload.users; + state.showTransferOwnershipHint = payload.showTransferOwnershipHint; + state.allowActions = payload.allowActions; + }, + updateLoadingCourseTeamStatus: (state, { payload }) => { + state.loadingCourseTeamStatus = payload.status; + }, + deleteCourseTeamUser: (state, { payload }) => { + state.users = state.users.filter((user) => user.email !== payload); + }, + updateSavingStatus: (state, { payload }) => { + state.savingStatus = payload.status; + }, + setErrorMessage: (state, { payload }) => { + state.errorMessage = payload; + }, + }, +}); + +export const { + fetchCourseTeamSuccess, + updateLoadingCourseTeamStatus, + deleteCourseTeamUser, + updateSavingStatus, + setErrorMessage, +} = slice.actions; + +export const { + reducer, +} = slice; diff --git a/src/course-team/data/thunk.js b/src/course-team/data/thunk.js new file mode 100644 index 0000000000..78012870f6 --- /dev/null +++ b/src/course-team/data/thunk.js @@ -0,0 +1,87 @@ +import { RequestStatus } from '../../data/constants'; +import { + getCourseTeam, + deleteTeamUser, + createTeamUser, + changeRoleTeamUser, +} from './api'; +import { + fetchCourseTeamSuccess, + updateLoadingCourseTeamStatus, + deleteCourseTeamUser, + updateSavingStatus, + setErrorMessage, +} from './slice'; + +export function fetchCourseTeamQuery(courseId) { + return async (dispatch) => { + dispatch(updateLoadingCourseTeamStatus({ status: RequestStatus.IN_PROGRESS })); + + try { + const courseTeam = await getCourseTeam(courseId); + dispatch(fetchCourseTeamSuccess(courseTeam)); + + dispatch(updateLoadingCourseTeamStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch (error) { + dispatch(updateLoadingCourseTeamStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} + +export function createCourseTeamQuery(courseId, email) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS })); + + try { + await createTeamUser(courseId, email); + const courseTeam = await getCourseTeam(courseId); + dispatch(fetchCourseTeamSuccess(courseTeam)); + + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch (error) { + const message = error?.response?.data?.error || ''; + dispatch(setErrorMessage(message)); + + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} + +export function changeRoleTeamUserQuery(courseId, email, role) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS })); + + try { + await changeRoleTeamUser(courseId, email, role); + const courseTeam = await getCourseTeam(courseId); + dispatch(fetchCourseTeamSuccess(courseTeam)); + + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch ({ message }) { + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} + +export function deleteCourseTeamQuery(courseId, email) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS })); + + try { + await deleteTeamUser(courseId, email); + dispatch(deleteCourseTeamUser(email)); + + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch (error) { + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} diff --git a/src/course-team/hooks.jsx b/src/course-team/hooks.jsx new file mode 100644 index 0000000000..6fceb5aac9 --- /dev/null +++ b/src/course-team/hooks.jsx @@ -0,0 +1,139 @@ +import { useDispatch, useSelector } from 'react-redux'; +import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; +import { useEffect, useState } from 'react'; +import { useToggle } from '@edx/paragon'; + +import { USER_ROLES } from '../constants'; +import { RequestStatus } from '../data/constants'; +import { useModel } from '../generic/model-store'; +import { + changeRoleTeamUserQuery, + createCourseTeamQuery, + deleteCourseTeamQuery, + fetchCourseTeamQuery, +} from './data/thunk'; +import { + getCourseTeamLoadingStatus, + getCourseTeamUsers, + getErrorMessage, + getIsAllowActions, + getIsOwnershipHint, getSavingStatus, +} from './data/selectors'; +import { setErrorMessage } from './data/slice'; +import { MODAL_TYPES } from './constants'; + +const useCourseTeam = ({ courseId }) => { + const dispatch = useDispatch(); + + const { email: currentUserEmail } = getAuthenticatedUser(); + const courseDetails = useModel('courseDetails', courseId); + + const [modalType, setModalType] = useState(MODAL_TYPES.delete); + const [isInfoModalOpen, openInfoModal, closeInfoModal] = useToggle(false); + const [isFormVisible, openForm, hideForm] = useToggle(false); + const [currentEmail, setCurrentEmail] = useState(''); + const [isQueryPending, setIsQueryPending] = useState(false); + const courseTeamUsers = useSelector(getCourseTeamUsers); + const errorMessage = useSelector(getErrorMessage); + const savingStatus = useSelector(getSavingStatus); + const isAllowActions = useSelector(getIsAllowActions); + const isOwnershipHint = useSelector(getIsOwnershipHint); + const loadingCourseTeamStatus = useSelector(getCourseTeamLoadingStatus); + + const isSingleAdmin = courseTeamUsers.filter((user) => user.role === USER_ROLES.admin).length === 1; + + const handleOpenInfoModal = (type, email) => { + setCurrentEmail(email); + setModalType(type); + openInfoModal(); + }; + + const handleCloseInfoModal = () => { + dispatch(setErrorMessage('')); + closeInfoModal(); + }; + + const handleAddUserSubmit = (data) => { + setIsQueryPending(true); + + const { email } = data; + const isUserContains = courseTeamUsers.some((user) => user.email === email); + + if (isUserContains) { + handleOpenInfoModal(MODAL_TYPES.warning, email); + return; + } + + dispatch(createCourseTeamQuery(courseId, email)).then((result) => { + if (result) { + hideForm(); + dispatch(setErrorMessage('')); + return; + } + + handleOpenInfoModal(MODAL_TYPES.error, email); + }); + }; + + const handleDeleteUserSubmit = () => { + setIsQueryPending(true); + dispatch(deleteCourseTeamQuery(courseId, currentEmail)); + handleCloseInfoModal(); + }; + + const handleChangeRoleUserSubmit = (email, role) => { + setIsQueryPending(true); + dispatch(changeRoleTeamUserQuery(courseId, email, role)); + }; + + const handleInternetConnectionFailed = () => { + setIsQueryPending(false); + }; + + const handleOpenDeleteModal = (email) => { + handleOpenInfoModal(MODAL_TYPES.delete, email); + }; + + useEffect(() => { + dispatch(fetchCourseTeamQuery(courseId)); + }, [courseId]); + + useEffect(() => { + if (savingStatus === RequestStatus.SUCCESSFUL) { + setIsQueryPending(false); + window.scrollTo({ top: 0, behavior: 'smooth' }); + } + }, [savingStatus]); + + return { + modalType, + errorMessage, + courseName: courseDetails?.name || '', + currentEmail, + courseTeamUsers, + currentUserEmail, + isLoading: loadingCourseTeamStatus === RequestStatus.IN_PROGRESS, + isSingleAdmin, + isFormVisible, + isAllowActions, + isInfoModalOpen, + isOwnershipHint, + isQueryPending, + isInternetConnectionAlertFailed: savingStatus === RequestStatus.FAILED, + isShowAddTeamMember: courseTeamUsers.length === 1 && isAllowActions, + isShowInitialSidebar: !courseTeamUsers.length && !isFormVisible, + isShowUserFilledSidebar: Boolean(courseTeamUsers.length) || isFormVisible, + openForm, + hideForm, + closeInfoModal, + handleAddUserSubmit, + handleOpenInfoModal, + handleOpenDeleteModal, + handleDeleteUserSubmit, + handleChangeRoleUserSubmit, + handleInternetConnectionFailed, + }; +}; + +// eslint-disable-next-line import/prefer-default-export +export { useCourseTeam }; diff --git a/src/course-team/info-modal/InfoModal.jsx b/src/course-team/info-modal/InfoModal.jsx new file mode 100644 index 0000000000..3c489bfe58 --- /dev/null +++ b/src/course-team/info-modal/InfoModal.jsx @@ -0,0 +1,74 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + ActionRow, + Button, + AlertModal, +} from '@edx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import { MODAL_TYPES } from '../constants'; +import { getInfoModalSettings } from '../utils'; + +const InfoModal = ({ + modalType, + isOpen, + close, + onDeleteSubmit, + currentEmail, + errorMessage, + courseName, +}) => { + const intl = useIntl(); + + const { + title, + message, + variant, + closeButtonText, + submitButtonText, + closeButtonVariant, + } = getInfoModalSettings(modalType, currentEmail, errorMessage, courseName, intl); + + const isEmptyErrorMessage = modalType === MODAL_TYPES.error && !errorMessage; + + return ( + + + {modalType === MODAL_TYPES.delete && ( + + )} + + )} + > +

    {message}

    +
    + ); +}; + +InfoModal.propTypes = { + modalType: PropTypes.string.isRequired, + isOpen: PropTypes.bool.isRequired, + close: PropTypes.func.isRequired, + currentEmail: PropTypes.string.isRequired, + errorMessage: PropTypes.string.isRequired, + courseName: PropTypes.string.isRequired, + onDeleteSubmit: PropTypes.func.isRequired, +}; + +export default InfoModal; diff --git a/src/course-team/info-modal/InfoModal.test.jsx b/src/course-team/info-modal/InfoModal.test.jsx new file mode 100644 index 0000000000..f97f8a0baf --- /dev/null +++ b/src/course-team/info-modal/InfoModal.test.jsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import { MODAL_TYPES } from '../constants'; +import InfoModal from './InfoModal'; +import messages from './messages'; + +const closeMock = jest.fn(); +const onDeleteSubmitMock = jest.fn(); +const currentEmailMock = 'user@example.com'; +const errorMessageMock = 'Error text error@example.com'; +const courseNameMock = 'Course Name'; + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('render InfoModal component with type delete correctly', () => { + const { getByText, getByRole } = renderComponent({ + modalType: MODAL_TYPES.delete, + }); + + expect(getByText(messages.deleteModalTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText( + messages.deleteModalMessage.defaultMessage + .replace('{email}', currentEmailMock) + .replace('{courseName}', courseNameMock), + )).toBeInTheDocument(); + expect(getByRole('button', { name: messages.deleteModalCancelButton.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.deleteModalDeleteButton.defaultMessage })).toBeInTheDocument(); + }); + + it('render InfoModal component with type error correctly', () => { + const { getByText, getByRole } = renderComponent({ + modalType: MODAL_TYPES.error, + }); + + expect(getByText(messages.errorModalTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(errorMessageMock)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.errorModalOkButton.defaultMessage })).toBeInTheDocument(); + }); + + it('render InfoModal component with type warning correctly', () => { + const { getByText, getByRole } = renderComponent({ + modalType: MODAL_TYPES.warning, + }); + + expect(getByText(messages.warningModalTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText( + messages.warningModalMessage.defaultMessage + .replace('{email}', currentEmailMock) + .replace('{courseName}', courseNameMock), + )).toBeInTheDocument(); + expect(getByRole('button', { name: messages.warningModalReturnButton.defaultMessage })).toBeInTheDocument(); + }); + + it('calls close handler when the close button is clicked', () => { + const { getByRole } = renderComponent(); + + const closeButton = getByRole('button', { name: messages.deleteModalCancelButton.defaultMessage }); + fireEvent.click(closeButton); + expect(closeMock).toHaveBeenCalledTimes(1); + }); + + it('calls onDeleteSubmit handler when the delete button is clicked', () => { + const { getByRole } = renderComponent(); + + const deleteButton = getByRole('button', { name: messages.deleteModalDeleteButton.defaultMessage }); + fireEvent.click(deleteButton); + expect(onDeleteSubmitMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/course-team/info-modal/messages.js b/src/course-team/info-modal/messages.js new file mode 100644 index 0000000000..8e8a965e6f --- /dev/null +++ b/src/course-team/info-modal/messages.js @@ -0,0 +1,42 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + deleteModalTitle: { + id: 'course-authoring.course-team.member.button.remove', + defaultMessage: 'Delete course team member', + }, + deleteModalMessage: { + id: 'course-authoring.course-team.delete-modal.message', + defaultMessage: 'Are you sure you want to delete {email} from the course team for “{courseName}”?', + }, + deleteModalDeleteButton: { + id: 'course-authoring.course-team.delete-modal.button.delete', + defaultMessage: 'Delete', + }, + deleteModalCancelButton: { + id: 'course-authoring.course-team.delete-modal.button.cancel', + defaultMessage: 'Cancel', + }, + errorModalTitle: { + id: 'course-authoring.course-team.error-modal.title', + defaultMessage: 'Error adding user', + }, + errorModalOkButton: { + id: 'course-authoring.course-team.error-modal.button.ok', + defaultMessage: 'Ok', + }, + warningModalTitle: { + id: 'course-authoring.course-team.warning-modal.title', + defaultMessage: 'Already a course team member', + }, + warningModalMessage: { + id: 'course-authoring.course-team.warning-modal.message', + defaultMessage: '{email} is already on the {courseName} team. Recheck the email address if you want to add a new member.', + }, + warningModalReturnButton: { + id: 'course-authoring.course-team.warning-modal.button.return', + defaultMessage: 'Return to team listing', + }, +}); + +export default messages; diff --git a/src/course-team/messages.js b/src/course-team/messages.js new file mode 100644 index 0000000000..c6a6ebc059 --- /dev/null +++ b/src/course-team/messages.js @@ -0,0 +1,18 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + headingTitle: { + id: 'course-authoring.course-team.headingTitle', + defaultMessage: 'Course team', + }, + headingSubtitle: { + id: 'course-authoring.course-team.subTitle', + defaultMessage: 'Settings', + }, + addNewMemberButton: { + id: 'course-authoring.course-team.button.new-team-member', + defaultMessage: 'New team member', + }, +}); + +export default messages; diff --git a/src/course-team/utils.js b/src/course-team/utils.js new file mode 100644 index 0000000000..ee8a15d2af --- /dev/null +++ b/src/course-team/utils.js @@ -0,0 +1,53 @@ +import { MODAL_TYPES } from './constants'; +import messages from './info-modal/messages'; + +/** + * Create an info modal settings dependent on modal type + * @param {typeof MODAL_TYPES} modalType - one of MODAL_TYPES + * @param {string} currentEmail - email in current user + * @param {string} errorEmail - email from wrong request + * @param {string} courseName - current course name + * @returns {{ + * title: string, + * message: string, + * variant: string, + * closeButtonText: string, + * submitButtonText: string, + * closeButtonVariant: string + * }} + */ + +const getInfoModalSettings = (modalType, currentEmail, errorMessage, courseName, intl) => { + switch (modalType) { + case MODAL_TYPES.delete: + return { + title: intl.formatMessage(messages.deleteModalTitle), + message: intl.formatMessage(messages.deleteModalMessage, { email: currentEmail, courseName }), + variant: '', + closeButtonText: intl.formatMessage(messages.deleteModalCancelButton), + submitButtonText: intl.formatMessage(messages.deleteModalDeleteButton), + closeButtonVariant: 'tertiary', + }; + case MODAL_TYPES.error: + return { + title: intl.formatMessage(messages.errorModalTitle), + message: errorMessage, + variant: 'danger', + closeButtonText: intl.formatMessage(messages.errorModalOkButton), + closeButtonVariant: 'primary', + }; + case MODAL_TYPES.warning: + return { + title: intl.formatMessage(messages.warningModalTitle), + message: intl.formatMessage(messages.warningModalMessage, { email: currentEmail, courseName }), + variant: 'warning', + closeButtonText: intl.formatMessage(messages.warningModalReturnButton), + mainButtonVariant: 'primary', + }; + default: + return ''; + } +}; + +// eslint-disable-next-line import/prefer-default-export +export { getInfoModalSettings }; diff --git a/src/course-updates/CourseUpdates.jsx b/src/course-updates/CourseUpdates.jsx new file mode 100644 index 0000000000..ce63ade49e --- /dev/null +++ b/src/course-updates/CourseUpdates.jsx @@ -0,0 +1,168 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { + Button, + Container, + Layout, +} from '@edx/paragon'; +import { Add as AddIcon } from '@edx/paragon/icons'; +import { useSelector } from 'react-redux'; + +import { useModel } from '../generic/model-store'; +import { getProcessingNotification } from '../generic/processing-notification/data/selectors'; +import ProcessingNotification from '../generic/processing-notification'; +import SubHeader from '../generic/sub-header/SubHeader'; +import InternetConnectionAlert from '../generic/internet-connection-alert'; +import { RequestStatus } from '../data/constants'; +import CourseHandouts from './course-handouts/CourseHandouts'; +import CourseUpdate from './course-update/CourseUpdate'; +import DeleteModal from './delete-modal/DeleteModal'; +import UpdateForm from './update-form/UpdateForm'; +import { REQUEST_TYPES } from './constants'; +import messages from './messages'; +import { useCourseUpdates } from './hooks'; +import { getLoadingStatuses, getSavingStatuses } from './data/selectors'; +import { matchesAnyStatus } from './utils'; +import getPageHeadTitle from '../generic/utils'; + +const CourseUpdates = ({ courseId }) => { + const intl = useIntl(); + + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.headingTitle)); + + const { + requestType, + courseUpdates, + courseHandouts, + courseUpdatesInitialValues, + isMainFormOpen, + isInnerFormOpen, + isUpdateFormOpen, + isDeleteModalOpen, + closeUpdateForm, + closeDeleteModal, + handleUpdatesSubmit, + handleOpenUpdateForm, + handleOpenDeleteForm, + handleDeleteUpdateSubmit, + } = useCourseUpdates({ courseId }); + + const { + isShow: isShowProcessingNotification, + title: processingNotificationTitle, + } = useSelector(getProcessingNotification); + + const loadingStatuses = useSelector(getLoadingStatuses); + const savingStatuses = useSelector(getSavingStatuses); + + const anyStatusFailed = matchesAnyStatus({ ...loadingStatuses, ...savingStatuses }, RequestStatus.FAILED); + const anyStatusInProgress = matchesAnyStatus({ ...loadingStatuses, ...savingStatuses }, RequestStatus.IN_PROGRESS); + const anyStatusPending = matchesAnyStatus({ ...loadingStatuses, ...savingStatuses }, RequestStatus.PENDING); + + return ( + <> + +
    + + +
    +
    + handleOpenUpdateForm(REQUEST_TYPES.add_new_update)} + disabled={isUpdateFormOpen} + > + {intl.formatMessage(messages.newUpdateButton)} + + )} + /> +
    + {isMainFormOpen && ( + + )} +
    +
    + {courseUpdates.length ? courseUpdates.map((courseUpdate, index) => ( + isInnerFormOpen(courseUpdate.id) ? ( + + ) : ( + handleOpenUpdateForm(REQUEST_TYPES.edit_update, courseUpdate)} + onDelete={() => handleOpenDeleteForm(courseUpdate)} + isDisabledButtons={isUpdateFormOpen} + /> + ))) : null} +
    +
    + handleOpenUpdateForm(REQUEST_TYPES.edit_handouts)} + isDisabledButtons={isUpdateFormOpen} + /> +
    + + {isShowProcessingNotification && ( + + )} +
    +
    +
    +
    +
    +
    +
    +
    +
    + null} + /> +
    + + ); +}; + +CourseUpdates.propTypes = { + courseId: PropTypes.string.isRequired, +}; + +export default CourseUpdates; diff --git a/src/course-updates/CourseUpdates.scss b/src/course-updates/CourseUpdates.scss new file mode 100644 index 0000000000..72a9ff7ab6 --- /dev/null +++ b/src/course-updates/CourseUpdates.scss @@ -0,0 +1,20 @@ +@import "./course-handouts/CourseHandouts"; +@import "./course-update/CourseUpdate"; +@import "./update-form/UpdateForm"; + +.updates-container { + @include pgn-box-shadow(1, "centered"); + + display: grid; + grid-template-columns: 65% 35%; + border: .0625rem solid $gray-200; + border-radius: .375rem; + background: $white; + overflow: hidden; +} + +.updates-handouts-container { + border-left: .0625rem solid $gray-200; + padding: 1.875rem; + background: $white; +} diff --git a/src/course-updates/CourseUpdates.test.jsx b/src/course-updates/CourseUpdates.test.jsx new file mode 100644 index 0000000000..d136665e85 --- /dev/null +++ b/src/course-updates/CourseUpdates.test.jsx @@ -0,0 +1,224 @@ +import React from 'react'; +import { render, waitFor, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { initializeMockApp } from '@edx/frontend-platform'; +import MockAdapter from 'axios-mock-adapter'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { + getCourseUpdatesApiUrl, + getCourseHandoutApiUrl, + updateCourseUpdatesApiUrl, +} from './data/api'; +import { + createCourseUpdateQuery, + deleteCourseUpdateQuery, + editCourseHandoutsQuery, + editCourseUpdateQuery, +} from './data/thunk'; +import initializeStore from '../store'; +import { executeThunk } from '../utils'; +import { courseUpdatesMock, courseHandoutsMock } from './__mocks__'; +import CourseUpdates from './CourseUpdates'; +import messages from './messages'; + +let axiosMock; +let store; +const mockPathname = '/foo-bar'; +const courseId = '123'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: mockPathname, + }), +})); + +jest.mock('@tinymce/tinymce-react', () => { + const originalModule = jest.requireActual('@tinymce/tinymce-react'); + return { + __esModule: true, + ...originalModule, + Editor: () => 'foo bar', + }; +}); + +jest.mock('@edx/frontend-lib-content-components', () => ({ + TinyMceWidget: () =>
    Widget
    , + prepareEditorRef: jest.fn(() => ({ + refReady: true, + setEditorRef: jest.fn().mockName('prepareEditorRef.setEditorRef'), + })), +})); + +const RootWrapper = () => ( + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + axiosMock + .onGet(getCourseUpdatesApiUrl(courseId)) + .reply(200, courseUpdatesMock); + axiosMock + .onGet(getCourseHandoutApiUrl(courseId)) + .reply(200, courseHandoutsMock); + }); + + it('render CourseUpdates component correctly', async () => { + const { + getByText, getAllByTestId, getByTestId, getByRole, + } = render(); + + await waitFor(() => { + expect(getByText(messages.headingTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.sectionInfo.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.newUpdateButton.defaultMessage })).toBeInTheDocument(); + expect(getAllByTestId('course-update')).toHaveLength(3); + expect(getByTestId('course-handouts')).toBeInTheDocument(); + }); + }); + + it('should create course update', async () => { + const { getByText } = render(); + + const data = { + content: '

    Some text

    ', + date: 'August 29, 2023', + }; + + axiosMock + .onPost(getCourseUpdatesApiUrl(courseId)) + .reply(200, data); + + await executeThunk(createCourseUpdateQuery(courseId, data), store.dispatch); + expect(getByText('Some text')).toBeInTheDocument(); + expect(getByText(data.date)).toBeInTheDocument(); + }); + + it('should edit course update', async () => { + const { getByText, queryByText } = render(); + + const data = { + id: courseUpdatesMock[0].id, + content: '

    Some text

    ', + date: 'August 29, 2023', + }; + + axiosMock + .onPut(updateCourseUpdatesApiUrl(courseId, courseUpdatesMock[0].id)) + .reply(200, data); + + await executeThunk(editCourseUpdateQuery(courseId, data), store.dispatch); + expect(getByText('Some text')).toBeInTheDocument(); + expect(getByText(data.date)).toBeInTheDocument(); + expect(queryByText(courseUpdatesMock[0].date)).not.toBeInTheDocument(); + expect(queryByText(courseUpdatesMock[0].content)).not.toBeInTheDocument(); + }); + + it('should delete course update', async () => { + const { queryByText } = render(); + + axiosMock + .onDelete(updateCourseUpdatesApiUrl(courseId, courseUpdatesMock[0].id)) + .reply(200); + + await executeThunk(deleteCourseUpdateQuery(courseId, courseUpdatesMock[0].id), store.dispatch); + expect(queryByText(courseUpdatesMock[0].date)).not.toBeInTheDocument(); + expect(queryByText(courseUpdatesMock[0].content)).not.toBeInTheDocument(); + }); + + it('should edit course handouts', async () => { + const { getByText, queryByText } = render(); + + const data = { + ...courseHandoutsMock, + data: '

    Some handouts 1

    ', + }; + + axiosMock + .onPut(getCourseHandoutApiUrl(courseId)) + .reply(200, data); + + await executeThunk(editCourseHandoutsQuery(courseId, data), store.dispatch); + expect(getByText('Some handouts 1')).toBeInTheDocument(); + expect(queryByText(courseHandoutsMock.data)).not.toBeInTheDocument(); + }); + + it('Add new update form is visible after clicking "New update" button', async () => { + const { getByText, getByRole, getAllByTestId } = render(); + + await waitFor(() => { + const editUpdateButtons = getAllByTestId('course-update-edit-button'); + const deleteButtons = getAllByTestId('course-update-delete-button'); + const editHandoutsButtons = getAllByTestId('course-handouts-edit-button'); + const newUpdateButton = getByRole('button', { name: messages.newUpdateButton.defaultMessage }); + + fireEvent.click(newUpdateButton); + + expect(newUpdateButton).toBeDisabled(); + editUpdateButtons.forEach((button) => expect(button).toBeDisabled()); + editHandoutsButtons.forEach((button) => expect(button).toBeDisabled()); + deleteButtons.forEach((button) => expect(button).toBeDisabled()); + expect(getByText('Add new update')).toBeInTheDocument(); + }); + }); + + it('Edit handouts form is visible after clicking "Edit" button', async () => { + const { getByText, getByRole, getAllByTestId } = render(); + + await waitFor(() => { + const editUpdateButtons = getAllByTestId('course-update-edit-button'); + const deleteButtons = getAllByTestId('course-update-delete-button'); + const editHandoutsButtons = getAllByTestId('course-handouts-edit-button'); + const editHandoutsButton = editHandoutsButtons[0]; + + fireEvent.click(editHandoutsButton); + + expect(editHandoutsButton).toBeDisabled(); + expect(getByRole('button', { name: messages.newUpdateButton.defaultMessage })).toBeDisabled(); + editUpdateButtons.forEach((button) => expect(button).toBeDisabled()); + editHandoutsButtons.forEach((button) => expect(button).toBeDisabled()); + deleteButtons.forEach((button) => expect(button).toBeDisabled()); + expect(getByText('Edit handouts')).toBeInTheDocument(); + }); + }); + + it('Edit update form is visible after clicking "Edit" button', async () => { + const { + getByText, getByRole, getAllByTestId, queryByText, + } = render(); + + await waitFor(() => { + const editUpdateButtons = getAllByTestId('course-update-edit-button'); + const deleteButtons = getAllByTestId('course-update-delete-button'); + const editHandoutsButtons = getAllByTestId('course-handouts-edit-button'); + const editUpdateFirstButton = editUpdateButtons[0]; + + fireEvent.click(editUpdateFirstButton); + expect(getByText('Edit update')).toBeInTheDocument(); + expect(getByRole('button', { name: messages.newUpdateButton.defaultMessage })).toBeDisabled(); + editUpdateButtons.forEach((button) => expect(button).toBeDisabled()); + editHandoutsButtons.forEach((button) => expect(button).toBeDisabled()); + deleteButtons.forEach((button) => expect(button).toBeDisabled()); + expect(queryByText(courseUpdatesMock[0].content)).not.toBeInTheDocument(); + }); + }); +}); diff --git a/src/course-updates/__mocks__/courseHandouts.js b/src/course-updates/__mocks__/courseHandouts.js new file mode 100644 index 0000000000..55a6b25794 --- /dev/null +++ b/src/course-updates/__mocks__/courseHandouts.js @@ -0,0 +1,83 @@ +module.exports = { + id: 'block-v1:edX+DemoX+Demo_Course+type@course_info+block@handouts', + display_name: 'Text', + category: 'course_info', + has_children: false, + edited_on: 'Jul 12, 2023 at 17:52 UTC', + published: true, + published_on: 'Jul 12, 2023 at 17:52 UTC', + studio_url: null, + released_to_students: false, + release_date: null, + visibility_state: 'unscheduled', + has_explicit_staff_lock: false, + start: '2030-01-01T00:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: null, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + data: 'Some handouts', + metadata: {}, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, +}; diff --git a/src/course-updates/__mocks__/courseUpdates.js b/src/course-updates/__mocks__/courseUpdates.js new file mode 100644 index 0000000000..dca2909eb0 --- /dev/null +++ b/src/course-updates/__mocks__/courseUpdates.js @@ -0,0 +1,5 @@ +module.exports = [ + { id: 1, date: 'July 11, 2023', content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' }, + { id: 2, date: 'August 20, 2023', content: 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.' }, + { id: 3, date: 'January 30, 2023', content: 'But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself' }, +]; diff --git a/src/course-updates/__mocks__/index.js b/src/course-updates/__mocks__/index.js new file mode 100644 index 0000000000..bb4cba111d --- /dev/null +++ b/src/course-updates/__mocks__/index.js @@ -0,0 +1,2 @@ +export { default as courseUpdatesMock } from './courseUpdates'; +export { default as courseHandoutsMock } from './courseHandouts'; diff --git a/src/course-updates/constants.js b/src/course-updates/constants.js new file mode 100644 index 0000000000..fd082b7d5d --- /dev/null +++ b/src/course-updates/constants.js @@ -0,0 +1,7 @@ +// eslint-disable-next-line import/prefer-default-export +export const REQUEST_TYPES = { + add_new_update: 'add_new_update', + edit_update: 'edit_update', + edit_handouts: 'edit_handouts', + delete_update: 'delete_update', +}; diff --git a/src/course-updates/course-handouts/CourseHandouts.jsx b/src/course-updates/course-handouts/CourseHandouts.jsx new file mode 100644 index 0000000000..2dc7d5ee16 --- /dev/null +++ b/src/course-updates/course-handouts/CourseHandouts.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Icon, IconButtonWithTooltip } from '@edx/paragon'; +import { EditOutline } from '@edx/paragon/icons'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import messages from './messages'; + +const CourseHandouts = ({ contentForHandouts, onEdit, isDisabledButtons }) => { + const intl = useIntl(); + + return ( +
    +
    +

    {intl.formatMessage(messages.handoutsTitle)}

    + +
    +
    +
    + ); +}; + +CourseHandouts.propTypes = { + contentForHandouts: PropTypes.string.isRequired, + onEdit: PropTypes.func.isRequired, + isDisabledButtons: PropTypes.bool.isRequired, +}; + +export default CourseHandouts; diff --git a/src/course-updates/course-handouts/CourseHandouts.scss b/src/course-updates/course-handouts/CourseHandouts.scss new file mode 100644 index 0000000000..731ddae5d9 --- /dev/null +++ b/src/course-updates/course-handouts/CourseHandouts.scss @@ -0,0 +1,16 @@ +.course-handouts { + .course-handouts-header { + display: flex; + justify-content: space-between; + margin-bottom: $spacer; + + .course-handouts-header__title { + font-weight: 300; + color: $gray-800; + } + + .course-handouts-header__btn { + align-self: flex-start; + } + } +} diff --git a/src/course-updates/course-handouts/CourseHandouts.test.jsx b/src/course-updates/course-handouts/CourseHandouts.test.jsx new file mode 100644 index 0000000000..994d7a7b9d --- /dev/null +++ b/src/course-updates/course-handouts/CourseHandouts.test.jsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import CourseHandouts from './CourseHandouts'; +import messages from './messages'; + +const onEditMock = jest.fn(); +const handoutsContentMock = 'Handouts Content'; + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('render CourseHandouts component correctly', () => { + const { getByText, getByTestId } = renderComponent(); + + expect(getByText(messages.handoutsTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(handoutsContentMock)).toBeInTheDocument(); + expect(getByTestId('course-handouts-edit-button')).toBeInTheDocument(); + }); + + it('calls the onEdit function when the edit button is clicked', () => { + const { getByTestId } = renderComponent(); + + const editButton = getByTestId('course-handouts-edit-button'); + fireEvent.click(editButton); + expect(onEditMock).toHaveBeenCalledTimes(1); + }); + + it('"Edit" button is disabled when isDisabledButtons is true', () => { + const { getByTestId } = renderComponent({ isDisabledButtons: true }); + + const editButton = getByTestId('course-handouts-edit-button'); + expect(editButton).toBeDisabled(); + }); +}); diff --git a/src/course-updates/course-handouts/messages.js b/src/course-updates/course-handouts/messages.js new file mode 100644 index 0000000000..ea412c6a42 --- /dev/null +++ b/src/course-updates/course-handouts/messages.js @@ -0,0 +1,14 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + handoutsTitle: { + id: 'course-authoring.course-updates.handouts.title', + defaultMessage: 'Course handouts', + }, + editButton: { + id: 'course-authoring.course-updates.actions.edit', + defaultMessage: 'Edit', + }, +}); + +export default messages; diff --git a/src/course-updates/course-update/CourseUpdate.jsx b/src/course-updates/course-update/CourseUpdate.jsx new file mode 100644 index 0000000000..51d8194e33 --- /dev/null +++ b/src/course-updates/course-update/CourseUpdate.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Icon, IconButtonWithTooltip } from '@edx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { DeleteOutline, EditOutline, Error as ErrorIcon } from '@edx/paragon/icons'; + +import { isDateForUpdateValid } from './utils'; +import messages from './messages'; + +const CourseUpdate = ({ + dateForUpdate, + contentForUpdate, + onEdit, + onDelete, + isDisabledButtons, +}) => { + const intl = useIntl(); + + return ( +
    +
    + {dateForUpdate} + {!isDateForUpdateValid(dateForUpdate) && ( +
    + +

    {intl.formatMessage(messages.errorMessage)}

    +
    + )} +
    + + +
    +
    + {Boolean(contentForUpdate) && ( +
    + )} +
    + ); +}; + +CourseUpdate.propTypes = { + dateForUpdate: PropTypes.string.isRequired, + contentForUpdate: PropTypes.string.isRequired, + onEdit: PropTypes.func.isRequired, + onDelete: PropTypes.func.isRequired, + isDisabledButtons: PropTypes.bool.isRequired, +}; + +export default CourseUpdate; diff --git a/src/course-updates/course-update/CourseUpdate.scss b/src/course-updates/course-update/CourseUpdate.scss new file mode 100644 index 0000000000..43f98bdfa1 --- /dev/null +++ b/src/course-updates/course-update/CourseUpdate.scss @@ -0,0 +1,36 @@ +.course-update { + &:not(:first-child) { + padding-top: 1.875rem; + margin-top: 1.875rem; + border-top: 1px solid $light-400; + } + + .course-update-header { + display: flex; + align-items: center; + margin-bottom: 1.125rem; + gap: .5rem; + + .course-update-header__date { + line-height: 1.875rem; + letter-spacing: 1px; + } + + .course-update-header__error { + display: flex; + align-items: center; + gap: .25rem; + + svg { + color: $warning-300; + } + } + + .course-update-header__action { + display: flex; + width: auto; + margin-left: auto; + gap: .5rem; + } + } +} diff --git a/src/course-updates/course-update/CourseUpdate.test.jsx b/src/course-updates/course-update/CourseUpdate.test.jsx new file mode 100644 index 0000000000..9ce99248ba --- /dev/null +++ b/src/course-updates/course-update/CourseUpdate.test.jsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import CourseUpdate from './CourseUpdate'; +import messages from './messages'; + +const onEditMock = jest.fn(); +const onDeleteMock = jest.fn(); +const dateForUpdateMock = 'May 1, 2023'; +const contentForUpdateMock = 'Update Content'; + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('render CourseUpdate component correctly', () => { + const { getByText, getByTestId } = renderComponent(); + + expect(getByText(dateForUpdateMock)).toBeInTheDocument(); + expect(getByTestId('course-update-edit-button')).toBeInTheDocument(); + expect(getByTestId('course-update-delete-button')).toBeInTheDocument(); + }); + + it('render CourseUpdate component without content correctly', () => { + const { getByText, queryByTestId, getByTestId } = renderComponent({ contentForUpdate: '' }); + + expect(getByText(dateForUpdateMock)).toBeInTheDocument(); + expect(queryByTestId('course-update-content')).not.toBeInTheDocument(); + expect(getByTestId('course-update-edit-button')).toBeInTheDocument(); + expect(getByTestId('course-update-delete-button')).toBeInTheDocument(); + }); + + it('render error message when dateForUpdate is inValid', () => { + const { getByText } = renderComponent({ dateForUpdate: 'Welcome' }); + + expect(getByText(messages.errorMessage.defaultMessage)).toBeInTheDocument(); + }); + + it('calls the onEdit function when the "Edit" button is clicked', () => { + const { getByTestId } = renderComponent(); + + const editButton = getByTestId('course-update-edit-button'); + fireEvent.click(editButton); + expect(onEditMock).toHaveBeenCalledTimes(1); + }); + + it('calls the onDelete function when the "Delete" button is clicked', () => { + const { getByTestId } = renderComponent(); + + const deleteButton = getByTestId('course-update-delete-button'); + fireEvent.click(deleteButton); + expect(onDeleteMock).toHaveBeenCalledTimes(1); + }); + + it('"Edit" and "Delete" buttons is disabled when isDisabledButtons is true', () => { + const { getByTestId } = renderComponent({ isDisabledButtons: true }); + + expect(getByTestId('course-update-edit-button')).toBeDisabled(); + expect(getByTestId('course-update-delete-button')).toBeDisabled(); + }); +}); diff --git a/src/course-updates/course-update/messages.js b/src/course-updates/course-update/messages.js new file mode 100644 index 0000000000..0814df91d2 --- /dev/null +++ b/src/course-updates/course-update/messages.js @@ -0,0 +1,18 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + editButton: { + id: 'course-authoring.course-updates.button.edit', + defaultMessage: 'Edit', + }, + deleteButton: { + id: 'course-authoring.course-updates.button.delete', + defaultMessage: 'Delete', + }, + errorMessage: { + id: 'course-authoring.course-updates.date-invalid', + defaultMessage: 'Action required: Enter a valid date.', + }, +}); + +export default messages; diff --git a/src/course-updates/course-update/utils.js b/src/course-updates/course-update/utils.js new file mode 100644 index 0000000000..a063c1962f --- /dev/null +++ b/src/course-updates/course-update/utils.js @@ -0,0 +1,17 @@ +import moment from 'moment'; + +import { COMMA_SEPARATED_DATE_FORMAT } from '../../constants'; + +/** + * Check is valid date format in course update + * @param {string} date - date for update + * @returns {boolean} - is valid date format + */ +const isDateForUpdateValid = (date) => { + const parsedDate = moment(date, COMMA_SEPARATED_DATE_FORMAT, true); + + return parsedDate.isValid() && parsedDate.format(COMMA_SEPARATED_DATE_FORMAT) === date; +}; + +// eslint-disable-next-line import/prefer-default-export +export { isDateForUpdateValid }; diff --git a/src/course-updates/data/api.js b/src/course-updates/data/api.js new file mode 100644 index 0000000000..818ccd1ed1 --- /dev/null +++ b/src/course-updates/data/api.js @@ -0,0 +1,84 @@ +import { getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; +export const getCourseUpdatesApiUrl = (courseId) => `${getApiBaseUrl()}/course_info_update/${courseId}/`; +export const updateCourseUpdatesApiUrl = (courseId, updateId) => `${getApiBaseUrl()}/course_info_update/${courseId}/${updateId}`; +export const getCourseHandoutApiUrl = (courseId) => { + const formattedCourseId = courseId.split('course-v1:')[1]; + return `${getApiBaseUrl()}/xblock/block-v1:${formattedCourseId}+type@course_info+block@handouts`; +}; + +/** + * Get course updates. + * @param {string} courseId + * @returns {Promise} + */ +export async function getCourseUpdates(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(getCourseUpdatesApiUrl(courseId)); + + return data; +} + +/** + * Create new course update. + * @param {string} courseId + * @param {object} courseUpdate + * @returns {Promise} + */ +export async function createUpdate(courseId, courseUpdate) { + const { data } = await getAuthenticatedHttpClient() + .post(getCourseUpdatesApiUrl(courseId), courseUpdate); + + return data; +} + +/** + * Edit course update. + * @param {string} courseId + * @param {object} courseUpdate + * @returns {Promise} + */ +export async function editUpdate(courseId, courseUpdate) { + const { data } = await getAuthenticatedHttpClient() + .put(updateCourseUpdatesApiUrl(courseId, courseUpdate.id), courseUpdate); + + return data; +} + +/** + * Delete course update. + * @param {string} courseId + * @param {number} updateId +1 */ +export async function deleteUpdate(courseId, updateId) { + const { data } = await getAuthenticatedHttpClient() + .delete(updateCourseUpdatesApiUrl(courseId, updateId)); + + return data; +} + +/** + * Get course handouts. + * @param {string} courseId + * @returns {Promise} + */ +export async function getCourseHandouts(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(getCourseHandoutApiUrl(courseId)); + return data; +} + +/** + * Edit course handouts. + * @param {string} courseId + * @param {object} courseHandouts + * @returns {Promise} + */ +export async function editHandouts(courseId, courseHandouts) { + const { data } = await getAuthenticatedHttpClient() + .put(getCourseHandoutApiUrl(courseId), courseHandouts); + + return data; +} diff --git a/src/course-updates/data/selectors.js b/src/course-updates/data/selectors.js new file mode 100644 index 0000000000..947ad0f8ab --- /dev/null +++ b/src/course-updates/data/selectors.js @@ -0,0 +1,4 @@ +export const getCourseUpdates = (state) => state.courseUpdates.courseUpdates; +export const getCourseHandouts = (state) => state.courseUpdates.courseHandouts; +export const getSavingStatuses = (state) => state.courseUpdates.savingStatuses; +export const getLoadingStatuses = (state) => state.courseUpdates.loadingStatuses; diff --git a/src/course-updates/data/slice.js b/src/course-updates/data/slice.js new file mode 100644 index 0000000000..18cd86a1a6 --- /dev/null +++ b/src/course-updates/data/slice.js @@ -0,0 +1,72 @@ +/* eslint-disable no-param-reassign */ +import { createSlice } from '@reduxjs/toolkit'; +import { sortBy } from 'lodash'; + +const initialState = { + courseUpdates: [], + courseHandouts: {}, + savingStatuses: { + createCourseUpdateQuery: '', + editCourseUpdateQuery: '', + deleteCourseUpdateQuery: '', + editCourseHandoutsQuery: '', + }, + loadingStatuses: { + fetchCourseUpdatesQuery: '', + fetchCourseHandoutsQuery: '', + }, +}; + +const slice = createSlice({ + name: 'courseUpdates', + initialState, + reducers: { + fetchCourseUpdatesSuccess: (state, { payload }) => { + state.courseUpdates = payload; + }, + createCourseUpdate: (state, { payload }) => { + state.courseUpdates = [payload, ...state.courseUpdates]; + }, + editCourseUpdate: (state, { payload }) => { + state.courseUpdates = state.courseUpdates.map((courseUpdate) => { + if (courseUpdate.id === payload.id) { + return payload; + } + return courseUpdate; + }); + }, + deleteCourseUpdate: (state, { payload }) => { + state.courseUpdates = sortBy(payload, 'id').reverse(); + }, + fetchCourseHandoutsSuccess: (state, { payload }) => { + state.courseHandouts = payload; + }, + editCourseHandouts: (state, { payload }) => { + state.courseHandouts = { + ...state.courseHandouts, + ...payload, + }; + }, + updateSavingStatuses: (state, { payload }) => { + state.savingStatuses = { ...state.savingStatuses, ...payload }; + }, + updateLoadingStatuses: (state, { payload }) => { + state.loadingStatuses = { ...state.loadingStatuses, ...payload }; + }, + }, +}); + +export const { + fetchCourseUpdatesSuccess, + createCourseUpdate, + editCourseUpdate, + deleteCourseUpdate, + fetchCourseHandoutsSuccess, + editCourseHandouts, + updateSavingStatuses, + updateLoadingStatuses, +} = slice.actions; + +export const { + reducer, +} = slice; diff --git a/src/course-updates/data/thunk.js b/src/course-updates/data/thunk.js new file mode 100644 index 0000000000..8713b808c4 --- /dev/null +++ b/src/course-updates/data/thunk.js @@ -0,0 +1,111 @@ +import { NOTIFICATION_MESSAGES } from '../../constants'; +import { RequestStatus } from '../../data/constants'; +import { hideProcessingNotification, showProcessingNotification } from '../../generic/processing-notification/data/slice'; +import { + getCourseUpdates, + getCourseHandouts, + createUpdate, + editUpdate, + deleteUpdate, + editHandouts, +} from './api'; +import { + fetchCourseUpdatesSuccess, + createCourseUpdate, + editCourseUpdate, + deleteCourseUpdate, + fetchCourseHandoutsSuccess, + editCourseHandouts, + updateLoadingStatuses, + updateSavingStatuses, +} from './slice'; + +export function fetchCourseUpdatesQuery(courseId) { + return async (dispatch) => { + try { + dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.IN_PROGRESS })); + const courseUpdates = await getCourseUpdates(courseId); + dispatch(fetchCourseUpdatesSuccess(courseUpdates)); + dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.FAILED })); + } + }; +} + +export function createCourseUpdateQuery(courseId, data) { + return async (dispatch) => { + try { + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving)); + const courseUpdate = await createUpdate(courseId, data); + dispatch(createCourseUpdate(courseUpdate)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED })); + } + }; +} + +export function editCourseUpdateQuery(courseId, data) { + return async (dispatch) => { + try { + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving)); + const courseUpdate = await editUpdate(courseId, data); + dispatch(editCourseUpdate(courseUpdate)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED })); + } + }; +} + +export function deleteCourseUpdateQuery(courseId, updateId) { + return async (dispatch) => { + try { + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.deleting)); + const courseUpdates = await deleteUpdate(courseId, updateId); + dispatch(deleteCourseUpdate(courseUpdates)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED })); + } + }; +} + +export function fetchCourseHandoutsQuery(courseId) { + return async (dispatch) => { + try { + dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.IN_PROGRESS })); + const courseHandouts = await getCourseHandouts(courseId); + dispatch(fetchCourseHandoutsSuccess(courseHandouts)); + dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateLoadingStatuses({ fetchCourseHandoutsQuery: RequestStatus.FAILED })); + } + }; +} + +export function editCourseHandoutsQuery(courseId, data) { + return async (dispatch) => { + try { + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving)); + const courseHandouts = await editHandouts(courseId, data); + dispatch(editCourseHandouts(courseHandouts)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatuses({ createCourseUpdateQuery: RequestStatus.FAILED })); + } + }; +} diff --git a/src/course-updates/delete-modal/DeleteModal.jsx b/src/course-updates/delete-modal/DeleteModal.jsx new file mode 100644 index 0000000000..4190a1b94d --- /dev/null +++ b/src/course-updates/delete-modal/DeleteModal.jsx @@ -0,0 +1,47 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + ActionRow, + Button, + AlertModal, +} from '@edx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; + +import messages from './messages'; + +const DeleteModal = ({ isOpen, close, onDeleteSubmit }) => { + const intl = useIntl(); + + return ( + + + + + )} + > +

    {intl.formatMessage(messages.deleteModalDescription)}

    +
    + ); +}; + +DeleteModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + close: PropTypes.func.isRequired, + onDeleteSubmit: PropTypes.func.isRequired, +}; + +export default DeleteModal; diff --git a/src/course-updates/delete-modal/DeleteModal.test.jsx b/src/course-updates/delete-modal/DeleteModal.test.jsx new file mode 100644 index 0000000000..54403cf603 --- /dev/null +++ b/src/course-updates/delete-modal/DeleteModal.test.jsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import DeleteModal from './DeleteModal'; +import messages from './messages'; + +const onDeleteSubmitMock = jest.fn(); +const closeMock = jest.fn(); + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('render DeleteModal component correctly', () => { + const { getByText, getByRole } = renderComponent(); + + expect(getByText(messages.deleteModalTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.deleteModalDescription.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.cancelButton.defaultMessage })).toBeInTheDocument(); + expect(getByRole('button', { name: messages.deleteButton.defaultMessage })).toBeInTheDocument(); + }); + + it('calls onDeleteSubmit function when the "Ok" button is clicked', () => { + const { getByRole } = renderComponent(); + + const deleteButton = getByRole('button', { name: messages.deleteButton.defaultMessage }); + fireEvent.click(deleteButton); + expect(onDeleteSubmitMock).toHaveBeenCalledTimes(1); + }); + + it('calls the close function when the "Cancel" button is clicked', () => { + const { getByRole } = renderComponent(); + + const cancelButton = getByRole('button', { name: messages.cancelButton.defaultMessage }); + fireEvent.click(cancelButton); + expect(closeMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/course-updates/delete-modal/messages.js b/src/course-updates/delete-modal/messages.js new file mode 100644 index 0000000000..af946884b3 --- /dev/null +++ b/src/course-updates/delete-modal/messages.js @@ -0,0 +1,22 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + deleteModalTitle: { + id: 'course-authoring.course-updates.delete-modal.title', + defaultMessage: 'Are you sure you want to delete this update?', + }, + deleteModalDescription: { + id: 'course-authoring.course-updates.delete-modal.description', + defaultMessage: 'This action cannot be undone.', + }, + cancelButton: { + id: 'course-authoring.course-updates.actions.cancel', + defaultMessage: 'Cancel', + }, + deleteButton: { + id: 'course-authoring.course-updates.button.delete', + defaultMessage: 'Delete', + }, +}); + +export default messages; diff --git a/src/course-updates/hooks.jsx b/src/course-updates/hooks.jsx new file mode 100644 index 0000000000..20c9c29475 --- /dev/null +++ b/src/course-updates/hooks.jsx @@ -0,0 +1,114 @@ +import { useDispatch, useSelector } from 'react-redux'; +import moment from 'moment/moment'; +import { useEffect, useState } from 'react'; +import { useToggle } from '@edx/paragon'; + +import { COMMA_SEPARATED_DATE_FORMAT } from '../constants'; +import { getCourseHandouts, getCourseUpdates } from './data/selectors'; +import { REQUEST_TYPES } from './constants'; +import { + createCourseUpdateQuery, + deleteCourseUpdateQuery, + editCourseHandoutsQuery, + editCourseUpdateQuery, + fetchCourseHandoutsQuery, + fetchCourseUpdatesQuery, +} from './data/thunk'; + +const useCourseUpdates = ({ courseId }) => { + const dispatch = useDispatch(); + const initialUpdate = { id: 0, date: moment().utc().toDate(), content: '' }; + + const [requestType, setRequestType] = useState(''); + const [isUpdateFormOpen, openUpdateForm, closeUpdateForm] = useToggle(false); + const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useToggle(false); + const [currentUpdate, setCurrentUpdate] = useState(initialUpdate); + + const courseUpdates = useSelector(getCourseUpdates); + const courseHandouts = useSelector(getCourseHandouts); + + const courseUpdatesInitialValues = requestType === REQUEST_TYPES.edit_handouts + ? courseHandouts + : currentUpdate; + + const handleOpenUpdateForm = (type, courseUpdate) => { + setRequestType(type); + + switch (type) { + case REQUEST_TYPES.add_new_update: + setCurrentUpdate(initialUpdate); + break; + case REQUEST_TYPES.edit_update: + setCurrentUpdate(courseUpdate); + break; + default: + window.scrollTo(0, 0); + } + + openUpdateForm(); + }; + + const handleOpenDeleteForm = (courseUpdate) => { + setRequestType(REQUEST_TYPES.delete_update); + setCurrentUpdate(courseUpdate); + openDeleteModal(); + }; + + const handleUpdatesSubmit = (data) => { + const dataToSend = { + ...data, + date: moment(data.date).format(COMMA_SEPARATED_DATE_FORMAT), + }; + const { id, date, content } = dataToSend; + + const handleQuerySubmit = (handler) => { + closeUpdateForm(); + setCurrentUpdate(initialUpdate); + return handler(); + }; + + switch (requestType) { + case REQUEST_TYPES.add_new_update: + return handleQuerySubmit(dispatch(createCourseUpdateQuery(courseId, { date, content }))); + case REQUEST_TYPES.edit_update: + return handleQuerySubmit(dispatch(editCourseUpdateQuery(courseId, { id, date, content }))); + case REQUEST_TYPES.edit_handouts: + return handleQuerySubmit(dispatch(editCourseHandoutsQuery(courseId, { ...data, data: data?.data || '' }))); + default: + return true; + } + }; + + const handleDeleteUpdateSubmit = () => { + const { id } = currentUpdate; + + dispatch(deleteCourseUpdateQuery(courseId, id)); + setCurrentUpdate(initialUpdate); + closeDeleteModal(); + }; + + useEffect(() => { + dispatch(fetchCourseUpdatesQuery(courseId)); + dispatch(fetchCourseHandoutsQuery(courseId)); + }, [courseId]); + + return { + requestType, + courseUpdates, + courseHandouts, + courseUpdatesInitialValues, + isMainFormOpen: isUpdateFormOpen && requestType !== REQUEST_TYPES.edit_update, + isInnerFormOpen: (id) => isUpdateFormOpen && currentUpdate.id === id && requestType === REQUEST_TYPES.edit_update, + isUpdateFormOpen, + isDeleteModalOpen, + closeUpdateForm, + closeDeleteModal, + handleUpdatesSubmit, + handleOpenUpdateForm, + handleDeleteUpdateSubmit, + handleOpenDeleteForm, + }; +}; + +// eslint-disable-next-line import/prefer-default-export +export { useCourseUpdates }; diff --git a/src/course-updates/index.js b/src/course-updates/index.js new file mode 100644 index 0000000000..886e19e97f --- /dev/null +++ b/src/course-updates/index.js @@ -0,0 +1,2 @@ +/* eslint-disable import/prefer-default-export */ +export { default as CourseUpdates } from './CourseUpdates'; diff --git a/src/course-updates/messages.js b/src/course-updates/messages.js new file mode 100644 index 0000000000..a04a4b5cee --- /dev/null +++ b/src/course-updates/messages.js @@ -0,0 +1,22 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + headingTitle: { + id: 'course-authoring.course-updates.header.title', + defaultMessage: 'Course updates', + }, + headingSubtitle: { + id: 'course-authoring.course-updates.header.subtitle', + defaultMessage: 'Content', + }, + sectionInfo: { + id: 'course-authoring.course-updates.section-info', + defaultMessage: 'Use course updates to notify students of important dates or exams, highlight particular discussions in the forums, announce schedule changes, and respond to student questions.', + }, + newUpdateButton: { + id: 'course-authoring.course-updates.actions.new-update', + defaultMessage: 'New update', + }, +}); + +export default messages; diff --git a/src/course-updates/update-form/UpdateForm.jsx b/src/course-updates/update-form/UpdateForm.jsx new file mode 100644 index 0000000000..44eb42c527 --- /dev/null +++ b/src/course-updates/update-form/UpdateForm.jsx @@ -0,0 +1,141 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + ActionRow, + Button, + Form, + Icon, +} from '@edx/paragon'; +import classNames from 'classnames'; +import DatePicker from 'react-datepicker/dist'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Calendar as CalendarIcon, Error as ErrorIcon } from '@edx/paragon/icons'; +import { Formik } from 'formik'; + +import { + convertToStringFromDate, + convertToDateFromString, + isValidDate, +} from '../../utils'; +import { DATE_FORMAT, DEFAULT_EMPTY_WYSIWYG_VALUE } from '../../constants'; +import { WysiwygEditor } from '../../generic/WysiwygEditor'; +import { REQUEST_TYPES } from '../constants'; +import { geUpdateFormSettings } from './utils'; +import messages from './messages'; + +const UpdateForm = ({ + close, + requestType, + onSubmit, + courseUpdatesInitialValues, + isInnerForm, + isFirstUpdate, +}) => { + const intl = useIntl(); + + const { + currentContent, + formTitle, + validationSchema, + contentFieldName, + submitButtonText, + } = geUpdateFormSettings(requestType, courseUpdatesInitialValues, intl); + + return ( +
    + + {({ + values, handleSubmit, isValid, setFieldValue, + }) => ( + <> +

    {formTitle}

    + {(requestType !== REQUEST_TYPES.edit_handouts) && ( + + + {intl.formatMessage(messages.updateFormDate)} + +
    + + { + if (!isValidDate(value)) { + return; + } + setFieldValue('date', convertToStringFromDate(value)); + }} + /> +
    + {!isValid && ( +
    + + {intl.formatMessage(messages.updateFormInValid)} +
    + )} +
    + )} + + { + setFieldValue(contentFieldName, value || DEFAULT_EMPTY_WYSIWYG_VALUE); + }} + /> + + + + + + + )} +
    +
    + ); +}; + +UpdateForm.defaultProps = { + isInnerForm: false, + isFirstUpdate: false, +}; + +UpdateForm.propTypes = { + // eslint-disable-next-line react/forbid-prop-types + courseUpdatesInitialValues: PropTypes.object.isRequired, + close: PropTypes.func.isRequired, + requestType: PropTypes.string.isRequired, + onSubmit: PropTypes.func.isRequired, + isInnerForm: PropTypes.bool, + isFirstUpdate: PropTypes.bool, +}; + +export default UpdateForm; diff --git a/src/course-updates/update-form/UpdateForm.scss b/src/course-updates/update-form/UpdateForm.scss new file mode 100644 index 0000000000..a7a0ad0d15 --- /dev/null +++ b/src/course-updates/update-form/UpdateForm.scss @@ -0,0 +1,59 @@ +.update-form { + @include pgn-box-shadow(1, "centered"); + + border: .0625rem solid $gray-200; + border-radius: .375rem; + background: $white; + margin-bottom: map-get($spacers, 4); + padding: $spacer 1.875rem; + + .update-form-title { + font-size: 1.5rem; + font-weight: 600; + margin-bottom: $spacer; + } + + .datepicker-field { + display: flex; + align-items: center; + gap: .5rem; + position: relative; + + .datepicker-float-labels { + position: absolute; + padding: 0 .1875rem; + top: -.625rem; + left: .3125rem; + z-index: 9; + background-color: $white; + } + + .datepicker-field-error { + display: flex; + align-items: center; + gap: .25rem; + } + + .react-datepicker-popper { + z-index: $zindex-dropdown; + } + } +} + +.update-form__inner { + margin-bottom: 0; + margin-top: 1.875rem; + padding: map-get($spacers, 4) 0 0; + border-top: .0625rem solid $light-400; + border-bottom: none; + border-left: none; + border-right: none; + border-radius: 0; + box-shadow: none; +} + +.update-form__inner-first { + border-top: none; + padding-top: 0; + margin-top: 0; +} diff --git a/src/course-updates/update-form/UpdateForm.test.jsx b/src/course-updates/update-form/UpdateForm.test.jsx new file mode 100644 index 0000000000..569efb7252 --- /dev/null +++ b/src/course-updates/update-form/UpdateForm.test.jsx @@ -0,0 +1,140 @@ +import React from 'react'; +import { + render, + fireEvent, + waitFor, + act, +} from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import moment from 'moment/moment'; + +import { REQUEST_TYPES } from '../constants'; +import { courseHandoutsMock, courseUpdatesMock } from '../__mocks__'; +import UpdateForm from './UpdateForm'; +import messages from './messages'; + +const closeMock = jest.fn(); +const onSubmitMock = jest.fn(); +const addNewUpdateMock = { id: 0, date: moment().utc().toDate(), content: 'Some content' }; +const formattedDateMock = '07/11/2023'; +const contentMock = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; + +jest.mock('@tinymce/tinymce-react', () => { + const originalModule = jest.requireActual('@tinymce/tinymce-react'); + return { + __esModule: true, + ...originalModule, + Editor: () => 'foo bar', + }; +}); + +jest.mock('@edx/frontend-lib-content-components', () => ({ + TinyMceWidget: () =>
    Widget
    , + prepareEditorRef: jest.fn(() => ({ + refReady: true, + setEditorRef: jest.fn().mockName('prepareEditorRef.setEditorRef'), + })), +})); + +const courseUpdatesInitialValues = (requestType) => { + switch (requestType) { + case REQUEST_TYPES.add_new_update: + return addNewUpdateMock; + case REQUEST_TYPES.edit_update: + return courseUpdatesMock[0]; + default: + return courseHandoutsMock; + } +}; + +const renderComponent = ({ requestType }) => render( + + + , +); + +describe('', () => { + it('render Add new update form correctly', async () => { + const { getByText, getByDisplayValue, getByRole } = renderComponent({ requestType: REQUEST_TYPES.add_new_update }); + const { date } = courseUpdatesInitialValues(REQUEST_TYPES.add_new_update); + const formattedDate = moment(date).utc().format('MM/DD/yyyy'); + + expect(getByText(messages.addNewUpdateTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.updateFormDate.defaultMessage)).toBeInTheDocument(); + expect(getByDisplayValue(formattedDate)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.cancelButton.defaultMessage })); + expect(getByRole('button', { name: messages.postButton.defaultMessage })); + }); + + it('render Edit update form correctly', async () => { + const { getByText, getByDisplayValue, getByRole } = renderComponent({ requestType: REQUEST_TYPES.edit_update }); + + expect(getByText(messages.editUpdateTitle.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.updateFormDate.defaultMessage)).toBeInTheDocument(); + expect(getByDisplayValue(formattedDateMock)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.cancelButton.defaultMessage })); + expect(getByRole('button', { name: messages.postButton.defaultMessage })); + }); + + it('render Edit handouts form correctly', async () => { + const { + getByText, getByRole, queryByTestId, queryByText, + } = renderComponent({ requestType: REQUEST_TYPES.edit_handouts }); + + expect(getByText(messages.editHandoutsTitle.defaultMessage)).toBeInTheDocument(); + expect(queryByText(messages.updateFormDate.defaultMessage)).not.toBeInTheDocument(); + expect(queryByTestId('course-updates-datepicker')).not.toBeInTheDocument(); + expect(getByRole('button', { name: messages.cancelButton.defaultMessage })); + expect(getByRole('button', { name: messages.saveButton.defaultMessage })); + }); + + it('calls closeMock when clicking cancel button', () => { + const { getByRole } = renderComponent({ requestType: REQUEST_TYPES.add_new_update }); + + const cancelButton = getByRole('button', { name: messages.cancelButton.defaultMessage }); + fireEvent.click(cancelButton); + expect(closeMock).toHaveBeenCalledTimes(1); + }); + + it('calls onSubmitMock with correct values when clicking post button', async () => { + const { getByDisplayValue, getByRole } = renderComponent({ requestType: REQUEST_TYPES.edit_update }); + const datePicker = getByDisplayValue(formattedDateMock); + const postButton = getByRole('button', { name: messages.postButton.defaultMessage }); + + fireEvent.change(datePicker, { target: { value: formattedDateMock } }); + + await act(async () => { + fireEvent.click(postButton); + }); + + await waitFor(() => { + expect(onSubmitMock).toHaveBeenCalledTimes(1); + expect(onSubmitMock).toHaveBeenCalledWith( + { + id: 1, + date: 'July 11, 2023', + content: contentMock, + }, + expect.objectContaining({ submitForm: expect.any(Function) }), + ); + }); + }); + + it('render error message when date is inValid', async () => { + const { getByDisplayValue, getByText, getByRole } = renderComponent({ requestType: REQUEST_TYPES.edit_update }); + const datePicker = getByDisplayValue(formattedDateMock); + + fireEvent.change(datePicker, { target: { value: '' } }); + + await waitFor(() => { + expect(getByText(messages.updateFormInValid.defaultMessage)).toBeInTheDocument(); + expect(getByRole('button', { name: messages.postButton.defaultMessage })).toBeDisabled(); + }); + }); +}); diff --git a/src/course-updates/update-form/messages.js b/src/course-updates/update-form/messages.js new file mode 100644 index 0000000000..8f36a9ff05 --- /dev/null +++ b/src/course-updates/update-form/messages.js @@ -0,0 +1,46 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + updateFormDate: { + id: 'course-authoring.course-updates.update-form.date', + defaultMessage: 'Date', + }, + updateFormInValid: { + id: 'course-authoring.course-updates.update-form.inValid', + defaultMessage: 'Action required: Enter a valid date.', + }, + updateFormCalendarAltText: { + id: 'course-authoring.course-updates.update-form.calendar-alt-text', + defaultMessage: 'Calendar for datepicker input', + }, + updateFormErrorAltText: { + id: 'course-authoring.course-updates.update-form.error-alt-text', + defaultMessage: 'Error icon', + }, + addNewUpdateTitle: { + id: 'course-authoring.course-updates.update-form.new-update-title', + defaultMessage: 'Add new update', + }, + editUpdateTitle: { + id: 'course-authoring.course-updates.update-form.edit-update-title', + defaultMessage: 'Edit update', + }, + editHandoutsTitle: { + id: 'course-authoring.course-updates.update-form.edit-handouts-title', + defaultMessage: 'Edit handouts', + }, + saveButton: { + id: 'course-authoring.course-updates.actions.save', + defaultMessage: 'Save', + }, + postButton: { + id: 'course-authoring.course-updates.actions.post', + defaultMessage: 'Post', + }, + cancelButton: { + id: 'course-authoring.course-updates.actions.cancel', + defaultMessage: 'Cancel', + }, +}); + +export default messages; diff --git a/src/course-updates/update-form/utils.js b/src/course-updates/update-form/utils.js new file mode 100644 index 0000000000..7f6ce9d053 --- /dev/null +++ b/src/course-updates/update-form/utils.js @@ -0,0 +1,56 @@ +import * as Yup from 'yup'; + +import { REQUEST_TYPES } from '../constants'; +import messages from './messages'; + +/** + * Get Update form settings depending on requestType + * @param {typeof REQUEST_TYPES} requestType - one of REQUEST_TYPES + * @param {object} courseUpdatesInitialValues - form initial values depending on requestType + * @returns {{ + * currentContent: string, + * validationSchema: object, + * formTitle: string, + * submitButtonText: string, + * contentFieldName: string + * }} + */ +const geUpdateFormSettings = (requestType, courseUpdatesInitialValues, intl) => { + const updatesValidationSchema = Yup.object().shape({ + id: Yup.number().required(), + date: Yup.date().required(), + content: Yup.string(), + }); + + switch (requestType) { + case REQUEST_TYPES.edit_handouts: + return { + currentContent: courseUpdatesInitialValues.data, + formTitle: intl.formatMessage(messages.editHandoutsTitle), + validationSchema: Yup.object().shape(), + contentFieldName: 'data', + submitButtonText: intl.formatMessage(messages.saveButton), + }; + case REQUEST_TYPES.add_new_update: + return { + currentContent: courseUpdatesInitialValues.content, + formTitle: intl.formatMessage(messages.addNewUpdateTitle), + validationSchema: updatesValidationSchema, + contentFieldName: 'content', + submitButtonText: intl.formatMessage(messages.postButton), + }; + case REQUEST_TYPES.edit_update: + return { + currentContent: courseUpdatesInitialValues.content, + formTitle: intl.formatMessage(messages.editUpdateTitle), + validationSchema: updatesValidationSchema, + contentFieldName: 'content', + submitButtonText: intl.formatMessage(messages.postButton), + }; + default: + return ''; + } +}; + +// eslint-disable-next-line import/prefer-default-export +export { geUpdateFormSettings }; diff --git a/src/course-updates/utils.js b/src/course-updates/utils.js new file mode 100644 index 0000000000..f1fc95c465 --- /dev/null +++ b/src/course-updates/utils.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/prefer-default-export +export const matchesAnyStatus = (statuses, status) => Object.values(statuses).some(s => s === status); diff --git a/src/custom-pages/CustomPageCard.jsx b/src/custom-pages/CustomPageCard.jsx index c0abfa7b66..2d01335456 100644 --- a/src/custom-pages/CustomPageCard.jsx +++ b/src/custom-pages/CustomPageCard.jsx @@ -1,6 +1,5 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; -import { history } from '@edx/frontend-platform'; import { intlShape, injectIntl } from '@edx/frontend-platform/i18n'; import { ActionRow, @@ -18,6 +17,7 @@ import { Visibility, VisibilityOff, } from '@edx/paragon/icons'; +import { useNavigate } from 'react-router-dom'; import { deleteSingleCustomPage, updateCustomPageVisibility } from './data/thunks'; import messages from './messages'; import { CustomPagesContext } from './CustomPagesProvider'; @@ -32,6 +32,8 @@ const CustomPageCard = ({ }) => { const [isDeleteConfirmationOpen, openDeleteConfirmation, closeDeleteConfirmation] = useToggle(false); const { path: customPagesPath } = useContext(CustomPagesContext); + const navigate = useNavigate(); + const handleDelete = () => { dispatch(deleteSingleCustomPage({ blockId: page.id, @@ -47,7 +49,7 @@ const CustomPageCard = ({ }; const handleEditOpen = () => { setCurrentPage(page.id); - history.push(`${customPagesPath}/editor`); + navigate(`${customPagesPath}/editor`); }; const deletePageStateProps = { diff --git a/src/custom-pages/CustomPages.jsx b/src/custom-pages/CustomPages.jsx index b7019ba10e..634a6f4e7e 100644 --- a/src/custom-pages/CustomPages.jsx +++ b/src/custom-pages/CustomPages.jsx @@ -1,9 +1,8 @@ import React, { useEffect, useContext, useState } from 'react'; import PropTypes from 'prop-types'; -import { Switch, useRouteMatch } from 'react-router'; +import { Routes, Route, useNavigate } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; -import { history } from '@edx/frontend-platform'; -import { AppContext, PageRoute } from '@edx/frontend-platform/react'; +import { AppContext, PageWrap } from '@edx/frontend-platform/react'; import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; import { ActionRow, @@ -26,7 +25,7 @@ import Placeholder, { } from '@edx/frontend-lib-content-components'; import { RequestStatus } from '../data/constants'; -import { useModels } from '../generic/model-store'; +import { useModels, useModel } from '../generic/model-store'; import { getLoadingStatus, getSavingStatus } from './data/selectors'; import { addSingleCustomPage, @@ -40,20 +39,23 @@ import CustomPageCard from './CustomPageCard'; import messages from './messages'; import CustomPagesProvider from './CustomPagesProvider'; import EditModal from './EditModal'; +import getPageHeadTitle from '../generic/utils'; const CustomPages = ({ courseId, // injected intl, }) => { + const navigate = useNavigate(); const dispatch = useDispatch(); const [orderedPages, setOrderedPages] = useState([]); const [currentPage, setCurrentPage] = useState(); const [isOpen, open, close] = useToggle(false); - const [isEditModalOpen, openEditModal, closeEditModal] = useToggle(false); + + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.heading)); const { config } = useContext(AppContext); - const { path, url } = useRouteMatch(); const learningCourseURL = `${config.LEARNING_BASE_URL}/course/${courseId}`; useEffect(() => { @@ -73,15 +75,14 @@ const CustomPages = ({ dispatch(updatePageOrder(courseId, newPageOrder)); }; const handleEditClose = () => (content) => { - history.push(url); + navigate(`/course/${courseId}/custom-pages`); if (!content?.metadata) { - closeEditModal(); + setCurrentPage(null); return; } dispatch(updateSingleCustomPage({ blockId: currentPage, metadata: { displayName: content.metadata.display_name }, - onClose: closeEditModal, setCurrentPage, })); }; @@ -186,7 +187,6 @@ const CustomPages = ({ deletePageStatus, courseId, setCurrentPage, - openEditModal, }} /> @@ -249,13 +249,20 @@ const CustomPages = ({ - - - {currentPage && ( - + + + + )} - - + /> + ); diff --git a/src/custom-pages/messages.js b/src/custom-pages/messages.js index af6b7ca6d4..60e8da9e04 100644 --- a/src/custom-pages/messages.js +++ b/src/custom-pages/messages.js @@ -95,7 +95,7 @@ const messages = defineMessages({ }, deletePageLabel: { id: 'course-authoring.custom-pages.deleteConfirmation.deletePage.label', - defaultMessage: 'Ok', + defaultMessage: 'Delete', }, deletingPageBodyLabel: { id: 'course-authoring.custom-pages.deleteConfirmation.deletingPage.label', diff --git a/src/data/constants.js b/src/data/constants.js index 42e1562536..d91b6bfb5d 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -11,6 +11,7 @@ export const RequestStatus = { FAILED: 'failed', DENIED: 'denied', PENDING: 'pending', + CLEAR: 'clear', }; /** diff --git a/src/editors/EditorContainer.jsx b/src/editors/EditorContainer.jsx index 46dcfc2985..c9e821daf7 100644 --- a/src/editors/EditorContainer.jsx +++ b/src/editors/EditorContainer.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { useParams } from 'react-router'; +import { useParams } from 'react-router-dom'; import { EditorPage } from '@edx/frontend-lib-content-components'; import { getConfig } from '@edx/frontend-platform'; diff --git a/src/export-page/CourseExportPage.jsx b/src/export-page/CourseExportPage.jsx new file mode 100644 index 0000000000..55ae670649 --- /dev/null +++ b/src/export-page/CourseExportPage.jsx @@ -0,0 +1,127 @@ +import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { useDispatch, useSelector } from 'react-redux'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + Container, Layout, Button, Card, +} from '@edx/paragon'; +import { ArrowCircleDown as ArrowCircleDownIcon } from '@edx/paragon/icons'; +import Cookies from 'universal-cookie'; +import { getConfig } from '@edx/frontend-platform'; +import { Helmet } from 'react-helmet'; + +import InternetConnectionAlert from '../generic/internet-connection-alert'; +import SubHeader from '../generic/sub-header/SubHeader'; +import { RequestStatus } from '../data/constants'; +import { useModel } from '../generic/model-store'; +import messages from './messages'; +import ExportSidebar from './export-sidebar/ExportSidebar'; +import { + getCurrentStage, getError, getExportTriggered, getLoadingStatus, getSavingStatus, +} from './data/selectors'; +import { startExportingCourse } from './data/thunks'; +import { EXPORT_STAGES, LAST_EXPORT_COOKIE_NAME } from './data/constants'; +import { updateExportTriggered, updateSavingStatus, updateSuccessDate } from './data/slice'; +import ExportModalError from './export-modal-error/ExportModalError'; +import ExportFooter from './export-footer/ExportFooter'; +import ExportStepper from './export-stepper/ExportStepper'; + +const CourseExportPage = ({ intl, courseId }) => { + const dispatch = useDispatch(); + const exportTriggered = useSelector(getExportTriggered); + const courseDetails = useModel('courseDetails', courseId); + const currentStage = useSelector(getCurrentStage); + const { msg: errorMessage } = useSelector(getError); + const loadingStatus = useSelector(getLoadingStatus); + const savingStatus = useSelector(getSavingStatus); + const cookies = new Cookies(); + const isShowExportButton = !exportTriggered || errorMessage || currentStage === EXPORT_STAGES.SUCCESS; + const anyRequestFailed = savingStatus === RequestStatus.FAILED || loadingStatus === RequestStatus.FAILED; + const anyRequestInProgress = savingStatus === RequestStatus.PENDING || loadingStatus === RequestStatus.IN_PROGRESS; + + useEffect(() => { + const cookieData = cookies.get(LAST_EXPORT_COOKIE_NAME); + if (cookieData) { + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + dispatch(updateExportTriggered(true)); + dispatch(updateSuccessDate(cookieData.date)); + } + }, []); + + return ( + <> + + + {intl.formatMessage(messages.pageTitle, { + headingTitle: intl.formatMessage(messages.headingTitle), + courseName: courseDetails?.name, + siteName: process.env.SITE_NAME, + })} + + + +
    + + +
    + +

    {intl.formatMessage(messages.description1, { studioShortName: getConfig().STUDIO_SHORT_NAME })}

    +

    {intl.formatMessage(messages.description2)}

    + + + {isShowExportButton && ( + + + + )} + + {exportTriggered && } + +
    +
    + + + +
    +
    + +
    +
    + null} + /> +
    + + ); +}; + +CourseExportPage.propTypes = { + intl: intlShape.isRequired, + courseId: PropTypes.string.isRequired, +}; + +CourseExportPage.defaultProps = {}; + +export default injectIntl(CourseExportPage); diff --git a/src/export-page/CourseExportPage.scss b/src/export-page/CourseExportPage.scss new file mode 100644 index 0000000000..80eced90ec --- /dev/null +++ b/src/export-page/CourseExportPage.scss @@ -0,0 +1,11 @@ +@import "./export-footer/ExportFooter"; + +.export { + .help-sidebar { + margin-top: 7.188rem; + } + + .pgn__stepper-header-step-list { + flex-direction: column; + } +} diff --git a/src/export-page/CourseExportPage.test.jsx b/src/export-page/CourseExportPage.test.jsx new file mode 100644 index 0000000000..05db07d5bf --- /dev/null +++ b/src/export-page/CourseExportPage.test.jsx @@ -0,0 +1,140 @@ +import React from 'react'; +import { getConfig, initializeMockApp } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import MockAdapter from 'axios-mock-adapter'; +import { Helmet } from 'react-helmet'; + +import Cookies from 'universal-cookie'; +import initializeStore from '../store'; +import stepperMessages from './export-stepper/messages'; +import modalErrorMessages from './export-modal-error/messages'; +import { getExportStatusApiUrl, postExportCourseApiUrl } from './data/api'; +import { EXPORT_STAGES } from './data/constants'; +import { exportPageMock } from './__mocks__'; +import messages from './messages'; +import CourseExportPage from './CourseExportPage'; + +let store; +let axiosMock; +let cookies; +const courseId = '123'; +const courseName = 'About Node JS'; + +jest.mock('../generic/model-store', () => ({ + useModel: jest.fn().mockReturnValue({ + name: courseName, + }), +})); + +jest.mock('universal-cookie', () => { + const mCookie = { + get: jest.fn(), + set: jest.fn(), + }; + return jest.fn(() => mCookie); +}); + +const RootWrapper = () => ( + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + axiosMock + .onGet(postExportCourseApiUrl(courseId)) + .reply(200, exportPageMock); + cookies = new Cookies(); + cookies.get.mockReturnValue(null); + }); + it('should render page title correctly', async () => { + render(); + await waitFor(() => { + const helmet = Helmet.peek(); + expect(helmet.title).toEqual( + `${messages.headingTitle.defaultMessage} | ${courseName} | ${process.env.SITE_NAME}`, + ); + }); + }); + it('should render without errors', async () => { + const { getByText } = render(); + await waitFor(() => { + expect(getByText(messages.headingSubtitle.defaultMessage)).toBeInTheDocument(); + const exportPageElement = getByText(messages.headingTitle.defaultMessage, { + selector: 'h2.sub-header-title', + }); + expect(exportPageElement).toBeInTheDocument(); + expect(getByText(messages.titleUnderButton.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.description2.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.buttonTitle.defaultMessage)).toBeInTheDocument(); + }); + }); + it('should start exporting on click', async () => { + const { getByText, container } = render(); + const button = container.querySelector('.btn-primary'); + fireEvent.click(button); + expect(getByText(stepperMessages.stepperPreparingDescription.defaultMessage)).toBeInTheDocument(); + }); + it('should show modal error', async () => { + axiosMock + .onGet(getExportStatusApiUrl(courseId)) + .reply(200, { exportStatus: EXPORT_STAGES.EXPORTING, exportError: { rawErrorMsg: 'test error', editUnitUrl: 'http://test-url.test' } }); + const { getByText, queryByText, container } = render(); + const startExportButton = container.querySelector('.btn-primary'); + fireEvent.click(startExportButton); + // eslint-disable-next-line no-promise-executor-return + await new Promise((r) => setTimeout(r, 3500)); + expect(getByText(/There has been a failure to export to XML at least one component. It is recommended that you go to the edit page and repair the error before attempting another export. Please check that all components on the page are valid and do not display any error messages. The raw error message is: test error/i)); + const closeModalWindowButton = getByText('Return to export'); + fireEvent.click(closeModalWindowButton); + expect(queryByText(modalErrorMessages.errorCancelButtonUnit.defaultMessage)).not.toBeInTheDocument(); + fireEvent.click(closeModalWindowButton); + }); + it('should fetch status without clicking when cookies has', async () => { + cookies.get.mockReturnValue({ date: 1679787000 }); + const { getByText } = render(); + expect(getByText(stepperMessages.stepperPreparingDescription.defaultMessage)).toBeInTheDocument(); + }); + it('should show download path for relative path', async () => { + axiosMock + .onGet(getExportStatusApiUrl(courseId)) + .reply(200, { exportStatus: EXPORT_STAGES.SUCCESS, exportOutput: '/test-download-path.test' }); + const { getByText, container } = render(); + const startExportButton = container.querySelector('.btn-primary'); + fireEvent.click(startExportButton); + // eslint-disable-next-line no-promise-executor-return + await new Promise((r) => setTimeout(r, 3500)); + const downloadButton = getByText(stepperMessages.downloadCourseButtonTitle.defaultMessage); + expect(downloadButton).toBeInTheDocument(); + expect(downloadButton.getAttribute('href')).toEqual(`${getConfig().STUDIO_BASE_URL}/test-download-path.test`); + }); + it('should show download path for absolute path', async () => { + axiosMock + .onGet(getExportStatusApiUrl(courseId)) + .reply(200, { exportStatus: EXPORT_STAGES.SUCCESS, exportOutput: 'http://test-download-path.test' }); + const { getByText, container } = render(); + const startExportButton = container.querySelector('.btn-primary'); + fireEvent.click(startExportButton); + // eslint-disable-next-line no-promise-executor-return + await new Promise((r) => setTimeout(r, 3500)); + const downloadButton = getByText(stepperMessages.downloadCourseButtonTitle.defaultMessage); + expect(downloadButton).toBeInTheDocument(); + expect(downloadButton.getAttribute('href')).toEqual('http://test-download-path.test'); + }); +}); diff --git a/src/export-page/__mocks__/exportPage.js b/src/export-page/__mocks__/exportPage.js new file mode 100644 index 0000000000..5380633d9c --- /dev/null +++ b/src/export-page/__mocks__/exportPage.js @@ -0,0 +1,3 @@ +module.exports = { + exportStatus: 1, +}; diff --git a/src/export-page/__mocks__/index.js b/src/export-page/__mocks__/index.js new file mode 100644 index 0000000000..ca6970871f --- /dev/null +++ b/src/export-page/__mocks__/index.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/prefer-default-export +export { default as exportPageMock } from './exportPage'; diff --git a/src/export-page/data/api.js b/src/export-page/data/api.js new file mode 100644 index 0000000000..68d61c10ee --- /dev/null +++ b/src/export-page/data/api.js @@ -0,0 +1,19 @@ +/* eslint-disable import/prefer-default-export */ +import { camelCaseObject, getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; +export const postExportCourseApiUrl = (courseId) => new URL(`export/${courseId}`, getApiBaseUrl()).href; +export const getExportStatusApiUrl = (courseId) => new URL(`export_status/${courseId}`, getApiBaseUrl()).href; + +export async function startCourseExporting(courseId) { + const { data } = await getAuthenticatedHttpClient() + .post(postExportCourseApiUrl(courseId)); + return camelCaseObject(data); +} + +export async function getExportStatus(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(getExportStatusApiUrl(courseId)); + return camelCaseObject(data); +} diff --git a/src/export-page/data/api.test.js b/src/export-page/data/api.test.js new file mode 100644 index 0000000000..70acc8b243 --- /dev/null +++ b/src/export-page/data/api.test.js @@ -0,0 +1,47 @@ +import MockAdapter from 'axios-mock-adapter'; +import { initializeMockApp, getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { getExportStatus, postExportCourseApiUrl, startCourseExporting } from './api'; + +let axiosMock; +const courseId = 'course-123'; + +describe('API Functions', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should fetch status on start exporting', async () => { + const data = { exportStatus: 1 }; + axiosMock.onPost(postExportCourseApiUrl(courseId)).reply(200, data); + + const result = await startCourseExporting(courseId); + + expect(axiosMock.history.post[0].url).toEqual(postExportCourseApiUrl(courseId)); + expect(result).toEqual(data); + }); + + it('should fetch on get export status', async () => { + const data = { exportStatus: 2 }; + const queryUrl = new URL(`export_status/${courseId}`, getConfig().STUDIO_BASE_URL).href; + axiosMock.onGet(queryUrl).reply(200, data); + + const result = await getExportStatus(courseId); + + expect(axiosMock.history.get[0].url).toEqual(queryUrl); + expect(result).toEqual(data); + }); +}); diff --git a/src/export-page/data/constants.js b/src/export-page/data/constants.js new file mode 100644 index 0000000000..5824c61c7d --- /dev/null +++ b/src/export-page/data/constants.js @@ -0,0 +1,8 @@ +export const LAST_EXPORT_COOKIE_NAME = 'lastexport'; +export const EXPORT_STAGES = { + PREPARING: 0, + EXPORTING: 1, + COMPRESSING: 2, + SUCCESS: 3, +}; +export const SUCCESS_DATE_FORMAT = 'MM/DD/yyyy'; diff --git a/src/export-page/data/selectors.js b/src/export-page/data/selectors.js new file mode 100644 index 0000000000..2c6d0d737f --- /dev/null +++ b/src/export-page/data/selectors.js @@ -0,0 +1,8 @@ +export const getExportTriggered = (state) => state.courseExport.exportTriggered; +export const getCurrentStage = (state) => state.courseExport.currentStage; +export const getDownloadPath = (state) => state.courseExport.downloadPath; +export const getSuccessDate = (state) => state.courseExport.successDate; +export const getError = (state) => state.courseExport.error; +export const getIsErrorModalOpen = (state) => state.courseExport.isErrorModalOpen; +export const getLoadingStatus = (state) => state.courseExport.loadingStatus; +export const getSavingStatus = (state) => state.courseExport.savingStatus; diff --git a/src/export-page/data/slice.js b/src/export-page/data/slice.js new file mode 100644 index 0000000000..f431a69369 --- /dev/null +++ b/src/export-page/data/slice.js @@ -0,0 +1,63 @@ +/* eslint-disable no-param-reassign */ +import { createSlice } from '@reduxjs/toolkit'; + +const initialState = { + exportTriggered: false, + currentStage: 0, + error: { msg: null, unitUrl: null }, + downloadPath: null, + successDate: null, + isErrorModalOpen: false, + loadingStatus: '', + savingStatus: '', +}; + +const slice = createSlice({ + name: 'exportPage', + initialState, + reducers: { + updateExportTriggered: (state, { payload }) => { + state.exportTriggered = payload; + }, + updateCurrentStage: (state, { payload }) => { + if (payload >= state.currentStage) { + state.currentStage = payload; + } + }, + updateDownloadPath: (state, { payload }) => { + state.downloadPath = payload; + }, + updateSuccessDate: (state, { payload }) => { + state.successDate = payload; + }, + updateError: (state, { payload }) => { + state.error = payload; + }, + updateIsErrorModalOpen: (state, { payload }) => { + state.isErrorModalOpen = payload; + }, + reset: () => initialState, + updateLoadingStatus: (state, { payload }) => { + state.loadingStatus = payload.status; + }, + updateSavingStatus: (state, { payload }) => { + state.savingStatus = payload.status; + }, + }, +}); + +export const { + updateExportTriggered, + updateCurrentStage, + updateDownloadPath, + updateSuccessDate, + updateError, + updateIsErrorModalOpen, + reset, + updateLoadingStatus, + updateSavingStatus, +} = slice.actions; + +export const { + reducer, +} = slice; diff --git a/src/export-page/data/thunks.js b/src/export-page/data/thunks.js new file mode 100644 index 0000000000..0bfdd410bf --- /dev/null +++ b/src/export-page/data/thunks.js @@ -0,0 +1,80 @@ +import Cookies from 'universal-cookie'; +import moment from 'moment'; +import { getConfig } from '@edx/frontend-platform'; + +import { RequestStatus } from '../../data/constants'; +import { setExportCookie } from '../utils'; +import { EXPORT_STAGES, LAST_EXPORT_COOKIE_NAME } from './constants'; + +import { + startCourseExporting, + getExportStatus, +} from './api'; +import { + updateExportTriggered, + updateCurrentStage, + updateDownloadPath, + updateSuccessDate, + updateError, + updateIsErrorModalOpen, + reset, + updateLoadingStatus, + updateSavingStatus, +} from './slice'; + +export function startExportingCourse(courseId) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); + try { + dispatch(reset()); + dispatch(updateExportTriggered(true)); + const exportData = await startCourseExporting(courseId); + dispatch(updateCurrentStage(exportData.exportStatus)); + setExportCookie(moment().valueOf(), exportData.exportStatus === EXPORT_STAGES.SUCCESS); + + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch (error) { + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} + +export function fetchExportStatus(courseId) { + return async (dispatch) => { + dispatch(updateLoadingStatus({ status: RequestStatus.IN_PROGRESS })); + try { + const { exportStatus, exportOutput, exportError } = await getExportStatus(courseId); + dispatch(updateCurrentStage(Math.abs(exportStatus))); + + if (exportOutput) { + if (exportOutput.startsWith('/')) { + dispatch(updateDownloadPath(`${getConfig().STUDIO_BASE_URL}${exportOutput}`)); + } else { + dispatch(updateDownloadPath(exportOutput)); + } + dispatch(updateSuccessDate(moment().valueOf())); + } + + const cookies = new Cookies(); + const cookieData = cookies.get(LAST_EXPORT_COOKIE_NAME); + if (!cookieData?.completed) { + setExportCookie(moment().valueOf(), exportStatus === EXPORT_STAGES.SUCCESS); + } + + if (exportError) { + const errorMessage = exportError.rawErrorMsg || exportError; + const errorUnitUrl = exportError.editUnitUrl || null; + dispatch(updateError({ msg: errorMessage, unitUrl: errorUnitUrl })); + dispatch(updateIsErrorModalOpen(true)); + } + + dispatch(updateLoadingStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch (error) { + dispatch(updateLoadingStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} diff --git a/src/export-page/export-footer/ExportFooter.jsx b/src/export-page/export-footer/ExportFooter.jsx new file mode 100644 index 0000000000..7709709b54 --- /dev/null +++ b/src/export-page/export-footer/ExportFooter.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { + injectIntl, + intlShape, +} from '@edx/frontend-platform/i18n'; +import { Layout } from '@edx/paragon'; + +import messages from './messages'; + +const ExportFooter = ({ intl }) => ( +
    + + +

    {intl.formatMessage(messages.exportedDataTitle)}

    +
      +
    • {intl.formatMessage(messages.exportedDataItem1)}
    • +
    • {intl.formatMessage(messages.exportedDataItem2)}
    • +
    • {intl.formatMessage(messages.exportedDataItem3)}
    • +
    • {intl.formatMessage(messages.exportedDataItem4)}
    • +
    • {intl.formatMessage(messages.exportedDataItem5)}
    • +
    • {intl.formatMessage(messages.exportedDataItem6)}
    • +
    • {intl.formatMessage(messages.exportedDataItem7)}
    • +
    +
    + + +

    {intl.formatMessage(messages.notExportedDataTitle)}

    +
      +
    • {intl.formatMessage(messages.notExportedDataItem1)}
    • +
    • {intl.formatMessage(messages.notExportedDataItem2)}
    • +
    • {intl.formatMessage(messages.notExportedDataItem3)}
    • +
    • {intl.formatMessage(messages.notExportedDataItem4)}
    • +
    +
    +
    +
    +); + +ExportFooter.propTypes = { + intl: intlShape.isRequired, +}; + +export default injectIntl(ExportFooter); diff --git a/src/export-page/export-footer/ExportFooter.scss b/src/export-page/export-footer/ExportFooter.scss new file mode 100644 index 0000000000..33c04ac650 --- /dev/null +++ b/src/export-page/export-footer/ExportFooter.scss @@ -0,0 +1,14 @@ +.export-footer-list { + list-style: none; + padding-left: 0; + + li { + padding-bottom: .3125rem; + border-bottom: 1px solid #E5E5E5; + margin-bottom: .3125rem; + } + + li:last-child { + border-bottom: none; + } +} diff --git a/src/export-page/export-footer/messages.js b/src/export-page/export-footer/messages.js new file mode 100644 index 0000000000..a11d5b7ade --- /dev/null +++ b/src/export-page/export-footer/messages.js @@ -0,0 +1,58 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + exportedDataTitle: { + id: 'course-authoring.export.footer.exportedData.title', + defaultMessage: 'Data exported with your course:', + }, + exportedDataItem1: { + id: 'course-authoring.export.footer.exportedData.item.1', + defaultMessage: 'Values from Advanced settings, including MATLAB API keys and LTI passports', + }, + exportedDataItem2: { + id: 'course-authoring.export.footer.exportedData.item.2', + defaultMessage: 'Course content (all sections, sub-sections, and units)', + }, + exportedDataItem3: { + id: 'course-authoring.export.footer.exportedData.item.3', + defaultMessage: 'Course structure', + }, + exportedDataItem4: { + id: 'course-authoring.export.footer.exportedData.item.4', + defaultMessage: 'Individual problems', + }, + exportedDataItem5: { + id: 'course-authoring.export.footer.exportedData.item.5', + defaultMessage: 'Pages', + }, + exportedDataItem6: { + id: 'course-authoring.export.footer.exportedData.item.6', + defaultMessage: 'Course assets', + }, + exportedDataItem7: { + id: 'course-authoring.export.footer.exportedData.item.7', + defaultMessage: 'Course settings', + }, + notExportedDataTitle: { + id: 'course-authoring.export.footer.notExportedData.title', + defaultMessage: 'Data not exported with your course:', + }, + notExportedDataItem1: { + id: 'course-authoring.export.footer.notExportedData.item.1', + defaultMessage: 'User data', + }, + notExportedDataItem2: { + id: 'course-authoring.export.footer.notExportedData.item.2', + defaultMessage: 'Course team data', + }, + notExportedDataItem3: { + id: 'course-authoring.export.footer.notExportedData.item.3', + defaultMessage: 'Forum/discussion data', + }, + notExportedDataItem4: { + id: 'course-authoring.export.footer.notExportedData.item.4', + defaultMessage: 'Certificates', + }, +}); + +export default messages; diff --git a/src/export-page/export-modal-error/ExportModalError.jsx b/src/export-page/export-modal-error/ExportModalError.jsx new file mode 100644 index 0000000000..56921a84c4 --- /dev/null +++ b/src/export-page/export-modal-error/ExportModalError.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useDispatch, useSelector } from 'react-redux'; +import { getConfig } from '@edx/frontend-platform'; +import PropTypes from 'prop-types'; + +import ModalError from '../../generic/modal-error/ModalError'; +import { getError, getIsErrorModalOpen } from '../data/selectors'; +import { updateIsErrorModalOpen } from '../data/slice'; +import messages from './messages'; + +const ExportModalError = ({ + intl, + courseId, +}) => { + const dispatch = useDispatch(); + const isErrorModalOpen = useSelector(getIsErrorModalOpen); + const { msg: errorMessage, unitUrl: unitErrorUrl } = useSelector(getError); + + const handleUnitRedirect = () => { window.location.assign(unitErrorUrl); }; + const handleRedirectCourseHome = () => { window.location.assign(`${getConfig().STUDIO_BASE_URL}/course/${courseId}`); }; + return ( + dispatch(updateIsErrorModalOpen(false))} + handleAction={unitErrorUrl ? handleUnitRedirect : handleRedirectCourseHome} + /> + ); +}; + +ExportModalError.propTypes = { + intl: intlShape.isRequired, + courseId: PropTypes.string.isRequired, +}; + +ExportModalError.defaultProps = {}; + +export default injectIntl(ExportModalError); diff --git a/src/export-page/export-modal-error/messages.js b/src/export-page/export-modal-error/messages.js new file mode 100644 index 0000000000..b691db3ebc --- /dev/null +++ b/src/export-page/export-modal-error/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + errorTitle: { + id: 'course-authoring.export.modal.error.title', + defaultMessage: 'There has been an error while exporting.', + }, + errorDescriptionNotUnit: { + id: 'course-authoring.export.modal.error.description.not.unit', + defaultMessage: 'Your course could not be exported to XML. There is not enough information to identify the failed component. Inspect your course to identify any problematic components and try again. The raw error message is: {errorMessage}', + }, + errorDescriptionUnit: { + id: 'course-authoring.export.modal.error.description.unit', + defaultMessage: 'There has been a failure to export to XML at least one component. It is recommended that you go to the edit page and repair the error before attempting another export. Please check that all components on the page are valid and do not display any error messages. The raw error message is: {errorMessage}', + }, + errorCancelButtonUnit: { + id: 'course-authoring.export.modal.error.button.cancel.unit', + defaultMessage: 'Return to export', + }, + errorCancelButtonNotUnit: { + id: 'course-authoring.export.modal.error.button.cancel.not.unit', + defaultMessage: 'Cancel', + }, + errorActionButtonNotUnit: { + id: 'course-authoring.export.modal.error.button.action.not.unit', + defaultMessage: 'Take me to the main course page', + }, + errorActionButtonUnit: { + id: 'course-authoring.export.modal.error.button.action.unit', + defaultMessage: 'Correct failed component', + }, +}); + +export default messages; diff --git a/src/export-page/export-sidebar/ExportSidebar.jsx b/src/export-page/export-sidebar/ExportSidebar.jsx new file mode 100644 index 0000000000..6daf541e00 --- /dev/null +++ b/src/export-page/export-sidebar/ExportSidebar.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { + injectIntl, + intlShape, +} from '@edx/frontend-platform/i18n'; +import PropTypes from 'prop-types'; +import { Hyperlink } from '@edx/paragon'; +import { getConfig } from '@edx/frontend-platform'; + +import { HelpSidebar } from '../../generic/help-sidebar'; +import { useHelpUrls } from '../../help-urls/hooks'; +import messages from './messages'; + +const ExportSidebar = ({ intl, courseId }) => { + const { exportCourse: exportLearnMoreUrl } = useHelpUrls(['exportCourse']); + return ( + +

    {intl.formatMessage(messages.title1)}

    +

    {intl.formatMessage(messages.description1, { studioShortName: getConfig().STUDIO_SHORT_NAME })}

    +
    +

    {intl.formatMessage(messages.exportedContent)}

    +

    {intl.formatMessage(messages.exportedContentHeading)}

    +
      +
    • {intl.formatMessage(messages.content1)}
    • +
    • {intl.formatMessage(messages.content2)}
    • +
    • {intl.formatMessage(messages.content3)}
    • +
    • {intl.formatMessage(messages.content4)}
    • +
    • {intl.formatMessage(messages.content5)}
    • +
    +

    {intl.formatMessage(messages.notExportedContent)}

    +
      +
    • {intl.formatMessage(messages.content6)}
    • +
    • {intl.formatMessage(messages.content7)}
    • +
    +
    +

    {intl.formatMessage(messages.openDownloadFile)}

    +

    {intl.formatMessage(messages.openDownloadFileDescription)}

    +
    + {intl.formatMessage(messages.learnMoreButtonTitle)} +
    + ); +}; + +ExportSidebar.propTypes = { + intl: intlShape.isRequired, + courseId: PropTypes.string.isRequired, +}; + +export default injectIntl(ExportSidebar); diff --git a/src/export-page/export-sidebar/ExportSidebar.test.jsx b/src/export-page/export-sidebar/ExportSidebar.test.jsx new file mode 100644 index 0000000000..d770f4b156 --- /dev/null +++ b/src/export-page/export-sidebar/ExportSidebar.test.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { AppProvider } from '@edx/frontend-platform/react'; + +import initializeStore from '../../store'; +import messages from './messages'; +import ExportSidebar from './ExportSidebar'; + +const courseId = 'course-123'; +let store; + +const RootWrapper = () => ( + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + }); + it('render sidebar correctly', () => { + const { getByText } = render(); + expect(getByText(messages.title1.defaultMessage)).toBeInTheDocument(); + expect(getByText(messages.exportedContentHeading.defaultMessage)).toBeInTheDocument(); + }); +}); diff --git a/src/export-page/export-sidebar/messages.js b/src/export-page/export-sidebar/messages.js new file mode 100644 index 0000000000..0917cd866e --- /dev/null +++ b/src/export-page/export-sidebar/messages.js @@ -0,0 +1,66 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + title1: { + id: 'course-authoring.export.sidebar.title1', + defaultMessage: 'Why export a course?', + }, + description1: { + id: 'course-authoring.export.sidebar.description1', + defaultMessage: 'You may want to edit the XML in your course directly, outside of {studioShortName}. You may want to create a backup copy of your course. Or, you may want to create a copy of your course that you can later import into another course instance and customize.', + }, + exportedContent: { + id: 'course-authoring.export.sidebar.exportedContent', + defaultMessage: 'What content is exported?', + }, + exportedContentHeading: { + id: 'course-authoring.export.sidebar.exportedContentHeading', + defaultMessage: 'The following content is exported.', + }, + content1: { + id: 'course-authoring.export.sidebar.content1', + defaultMessage: 'Course content and structure', + }, + content2: { + id: 'course-authoring.export.sidebar.content2', + defaultMessage: 'Course dates', + }, + content3: { + id: 'course-authoring.export.sidebar.content3', + defaultMessage: 'Grading policy', + }, + content4: { + id: 'course-authoring.export.sidebar.content4', + defaultMessage: 'Any group configurations', + }, + content5: { + id: 'course-authoring.export.sidebar.content5', + defaultMessage: 'Settings on the Advanced settings page, including MATLAB API keys and LTI passports', + }, + notExportedContent: { + id: 'course-authoring.export.sidebar.notExportedContent', + defaultMessage: 'The following content is not exported.', + }, + content6: { + id: 'course-authoring.export.sidebar.content6', + defaultMessage: 'Learner-specific content, such as learner grades and discussion forum data', + }, + content7: { + id: 'course-authoring.export.sidebar.content7', + defaultMessage: 'The course team', + }, + openDownloadFile: { + id: 'course-authoring.export.sidebar.openDownloadFile', + defaultMessage: 'Opening the downloaded file', + }, + openDownloadFileDescription: { + id: 'course-authoring.export.sidebar.openDownloadFileDescription', + defaultMessage: 'Use an archive program to extract the data from the .tar.gz file. Extracted data includes the course.xml file, as well as subfolders that contain course content.', + }, + learnMoreButtonTitle: { + id: 'course-authoring.export.sidebar.learnMoreButtonTitle', + defaultMessage: 'Learn more about exporting a course', + }, +}); + +export default messages; diff --git a/src/export-page/export-stepper/ExportStepper.jsx b/src/export-page/export-stepper/ExportStepper.jsx new file mode 100644 index 0000000000..0fbbe66e58 --- /dev/null +++ b/src/export-page/export-stepper/ExportStepper.jsx @@ -0,0 +1,103 @@ +import React, { useEffect } from 'react'; +import { + FormattedDate, + injectIntl, + intlShape, +} from '@edx/frontend-platform/i18n'; +import PropTypes from 'prop-types'; +import { useDispatch, useSelector } from 'react-redux'; +import { Button } from '@edx/paragon'; + +import CourseStepper from '../../generic/course-stepper'; +import { + getCurrentStage, getDownloadPath, getError, getLoadingStatus, getSuccessDate, +} from '../data/selectors'; +import { fetchExportStatus } from '../data/thunks'; +import { EXPORT_STAGES } from '../data/constants'; +import { RequestStatus } from '../../data/constants'; +import messages from './messages'; + +const ExportStepper = ({ intl, courseId }) => { + const currentStage = useSelector(getCurrentStage); + const downloadPath = useSelector(getDownloadPath); + const successDate = useSelector(getSuccessDate); + const loadingStatus = useSelector(getLoadingStatus); + const { msg: errorMessage } = useSelector(getError); + const dispatch = useDispatch(); + const isStopFetching = currentStage === EXPORT_STAGES.SUCCESS + || loadingStatus === RequestStatus.FAILED + || errorMessage; + + useEffect(() => { + const id = setInterval(() => { + if (isStopFetching) { + clearInterval(id); + } else { + dispatch(fetchExportStatus(courseId)); + } + }, 3000); + return () => clearInterval(id); + }); + + let successTitle = intl.formatMessage(messages.stepperSuccessTitle); + const localizedSuccessDate = successDate ? ( + + ) : null; + + if (localizedSuccessDate && currentStage === EXPORT_STAGES.SUCCESS) { + const successWithDate = ( + <> + {successTitle} ({localizedSuccessDate}) + + ); + successTitle = successWithDate; + } + + const steps = [ + { + title: intl.formatMessage(messages.stepperPreparingTitle), + description: intl.formatMessage(messages.stepperPreparingDescription), + key: EXPORT_STAGES.PREPARING, + }, { + title: intl.formatMessage(messages.stepperExportingTitle), + description: intl.formatMessage(messages.stepperExportingDescription), + key: EXPORT_STAGES.EXPORTING, + }, { + title: intl.formatMessage(messages.stepperCompressingTitle), + description: intl.formatMessage(messages.stepperCompressingDescription), + key: EXPORT_STAGES.COMPRESSING, + }, { + title: successTitle, + description: intl.formatMessage(messages.stepperSuccessDescription), + key: EXPORT_STAGES.SUCCESS, + }, + ]; + + return ( +
    +

    {intl.formatMessage(messages.stepperHeaderTitle)}

    + + {downloadPath && currentStage === EXPORT_STAGES.SUCCESS && } +
    + ); +}; + +ExportStepper.propTypes = { + intl: intlShape.isRequired, + courseId: PropTypes.string.isRequired, +}; + +export default injectIntl(ExportStepper); diff --git a/src/export-page/export-stepper/ExportStepper.test.jsx b/src/export-page/export-stepper/ExportStepper.test.jsx new file mode 100644 index 0000000000..c8ca1e4855 --- /dev/null +++ b/src/export-page/export-stepper/ExportStepper.test.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { AppProvider } from '@edx/frontend-platform/react'; + +import initializeStore from '../../store'; +import messages from './messages'; +import ExportStepper from './ExportStepper'; + +const courseId = 'course-123'; +let store; + +const RootWrapper = () => ( + + + + + +); + +describe('', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + }); + it('render stepper correctly', () => { + const { getByText } = render(); + expect(getByText(messages.stepperHeaderTitle.defaultMessage)).toBeInTheDocument(); + }); +}); diff --git a/src/export-page/export-stepper/messages.js b/src/export-page/export-stepper/messages.js new file mode 100644 index 0000000000..e0f4adfa1b --- /dev/null +++ b/src/export-page/export-stepper/messages.js @@ -0,0 +1,46 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + stepperPreparingTitle: { + id: 'course-authoring.export.stepper.title.preparing', + defaultMessage: 'Preparing', + }, + stepperExportingTitle: { + id: 'course-authoring.export.stepper.title.exporting', + defaultMessage: 'Exporting', + }, + stepperCompressingTitle: { + id: 'course-authoring.export.stepper.title.compressing', + defaultMessage: 'Compressing', + }, + stepperSuccessTitle: { + id: 'course-authoring.export.stepper.title.success', + defaultMessage: 'Success', + }, + stepperPreparingDescription: { + id: 'course-authoring.export.stepper.description.preparing', + defaultMessage: 'Preparing to start the export', + }, + stepperExportingDescription: { + id: 'course-authoring.export.stepper.description.exporting', + defaultMessage: 'Creating the export data files (You can now leave this page safely, but avoid making drastic changes to content until this export is complete)', + }, + stepperCompressingDescription: { + id: 'course-authoring.export.stepper.description.compressing', + defaultMessage: 'Compressing the exported data and preparing it for download', + }, + stepperSuccessDescription: { + id: 'course-authoring.export.stepper.description.success', + defaultMessage: 'Your exported course can now be downloaded', + }, + downloadCourseButtonTitle: { + id: 'course-authoring.export.stepper.download.button.title', + defaultMessage: 'Download exported course', + }, + stepperHeaderTitle: { + id: 'course-authoring.export.stepper.header.title', + defaultMessage: 'Course export status', + }, +}); + +export default messages; diff --git a/src/export-page/messages.js b/src/export-page/messages.js new file mode 100644 index 0000000000..2c8a44a8b2 --- /dev/null +++ b/src/export-page/messages.js @@ -0,0 +1,34 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + pageTitle: { + id: 'course-authoring.export.page.title', + defaultMessage: '{headingTitle} | {courseName} | {siteName}', + }, + headingTitle: { + id: 'course-authoring.export.heading.title', + defaultMessage: 'Course export', + }, + headingSubtitle: { + id: 'course-authoring.export.heading.subtitle', + defaultMessage: 'Tools', + }, + description1: { + id: 'course-authoring.export.description1', + defaultMessage: 'You can export courses and edit them outside of {studioShortName}. The exported file is a .tar.gz file (that is, a .tar file compressed with GNU Zip) that contains the course structure and content. You can also re-import courses that you\'ve exported.', + }, + description2: { + id: 'course-authoring.export.description2', + defaultMessage: 'Caution: When you export a course, information such as MATLAB API keys, LTI passports, annotation secret token strings, and annotation storage URLs are included in the exported data. If you share your exported files, you may also be sharing sensitive or license-specific information.', + }, + titleUnderButton: { + id: 'course-authoring.export.title-under-button', + defaultMessage: 'Export my course content', + }, + buttonTitle: { + id: 'course-authoring.export.button.title', + defaultMessage: 'Export course content', + }, +}); + +export default messages; diff --git a/src/export-page/utils.js b/src/export-page/utils.js new file mode 100644 index 0000000000..9f24b743b7 --- /dev/null +++ b/src/export-page/utils.js @@ -0,0 +1,29 @@ +import Cookies from 'universal-cookie'; +import moment from 'moment'; + +import { TIME_FORMAT } from '../constants'; +import { LAST_EXPORT_COOKIE_NAME, SUCCESS_DATE_FORMAT } from './data/constants'; + +/** + * Sets an export-related cookie with the provided information. + * + * @param {Date} date - Date of export. + * @param {boolean} completed - Indicates if export was completed successfully. + * @returns {void} + */ +export const setExportCookie = (date, completed) => { + const cookies = new Cookies(); + cookies.set(LAST_EXPORT_COOKIE_NAME, { date, completed }, { path: window.location.pathname }); +}; + +/** + * Formats a Unix timestamp as a formatted success date string. + * + * @param {number} unixDate - Unix timestamp to be formatted. + * @returns {string|null} Formatted success date string, including date and time in UTC, or null if the input is falsy. + */ +export const getFormattedSuccessDate = (unixDate) => { + const formattedDate = moment(unixDate).utc().format(SUCCESS_DATE_FORMAT); + const formattedTime = moment(unixDate).utc().format(TIME_FORMAT); + return unixDate ? ` (${formattedDate} at ${formattedTime} UTC)` : null; +}; diff --git a/src/export-page/utils.test.js b/src/export-page/utils.test.js new file mode 100644 index 0000000000..276f76ce47 --- /dev/null +++ b/src/export-page/utils.test.js @@ -0,0 +1,51 @@ +import Cookies from 'universal-cookie'; +import moment from 'moment'; + +import { LAST_EXPORT_COOKIE_NAME } from './data/constants'; +import { setExportCookie, getFormattedSuccessDate } from './utils'; + +global.window = Object.create(window); +Object.defineProperty(window, 'location', { + value: { + pathname: '/some-path', + }, +}); + +describe('setExportCookie', () => { + it('should set the export cookie with the provided date and completed status', () => { + const cookiesSetMock = jest.spyOn(Cookies.prototype, 'set'); + const date = '2023-07-24'; + const completed = true; + setExportCookie(date, completed); + + expect(cookiesSetMock).toHaveBeenCalledWith( + LAST_EXPORT_COOKIE_NAME, + { date, completed }, + { path: '/some-path' }, + ); + + cookiesSetMock.mockRestore(); + }); +}); + +describe('getFormattedSuccessDate', () => { + it('should return formatted success date with valid input', () => { + const mockCurrentUtcDate = moment.utc('2023-07-24T12:34:56'); + const momentMock = jest.spyOn(moment, 'utc').mockReturnValue(mockCurrentUtcDate); + + const unixDate = 1679787000; + + const expectedFormattedDate = ' (01/20/1970 at 10:36 UTC)'; + + const result = getFormattedSuccessDate(unixDate); + expect(result).toBe(expectedFormattedDate); + + momentMock.mockRestore(); + }); + + it('should return null with null input', () => { + const unixDate = null; + const result = getFormattedSuccessDate(unixDate); + expect(result).toBeNull(); + }); +}); diff --git a/src/files-and-uploads/FileInfo.jsx b/src/files-and-uploads/FileInfo.jsx deleted file mode 100644 index a1ee502adc..0000000000 --- a/src/files-and-uploads/FileInfo.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import React, { useState } from 'react'; -import PropTypes from 'prop-types'; -import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; - -import { - ModalDialog, - Stack, - IconButton, - ActionRow, - Icon, - Truncate, - IconButtonWithTooltip, - CheckboxControl, -} from '@edx/paragon'; -import { ContentCopy, InfoOutline } from '@edx/paragon/icons'; -import AssetThumbnail from './FileThumbnail'; - -import messages from './messages'; - -const FileInfo = ({ - asset, - isOpen, - onClose, - handleLockedAsset, - // injected - intl, -}) => { - const [lockedState, setLockedState] = useState(asset.locked); - const handleLock = (e) => { - const locked = e.target.checked; - setLockedState(locked); - handleLockedAsset(asset.id, locked); - }; - - return ( - - - - {asset.displayName} - - - -
    -
    -
    - -
    - -
    - -
    - {asset.dateAdded} -
    - -
    - {/* {asset.fileSize} */} -
    -
    - -
    - - - {asset.portableUrl} - - - navigator.clipboard.writeText(asset.portableUrl)} - /> - -
    - -
    - - - {asset.externalUrl} - - - navigator.clipboard.writeText(asset.externalUrl)} - /> - -
    - -
    - -
    - - - -
    -
    -
    -
    - -
    -
    -
    - ); -}; - -FileInfo.propTypes = { - asset: PropTypes.shape({ - displayName: PropTypes.string.isRequired, - wrapperType: PropTypes.string.isRequired, - locked: PropTypes.bool.isRequired, - externalUrl: PropTypes.string.isRequired, - thumbnail: PropTypes.string, - id: PropTypes.string.isRequired, - portableUrl: PropTypes.string.isRequired, - dateAdded: PropTypes.string.isRequired, - }).isRequired, - onClose: PropTypes.func.isRequired, - isOpen: PropTypes.bool.isRequired, - handleLockedAsset: PropTypes.func.isRequired, - // injected - intl: intlShape.isRequired, -}; - -export default injectIntl(FileInfo); diff --git a/src/files-and-uploads/FileMenu.jsx b/src/files-and-uploads/FileMenu.jsx deleted file mode 100644 index 0bfab16fb6..0000000000 --- a/src/files-and-uploads/FileMenu.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { - Dropdown, - IconButton, - Icon, -} from '@edx/paragon'; -import messages from './messages'; - -const FileMenu = ({ - externalUrl, - handleDelete, - handleLock, - locked, - openAssetInfo, - portableUrl, - iconSrc, - id, - // injected - intl, -}) => ( - - - - navigator.clipboard.writeText(portableUrl)} - > - {intl.formatMessage(messages.copyStudioUrlTitle)} - - navigator.clipboard.writeText(externalUrl)} - > - {intl.formatMessage(messages.copyWebUrlTitle)} - - - {intl.formatMessage(messages.downloadTitle)} - - - {locked ? intl.formatMessage(messages.unlockMenuTitle) : intl.formatMessage(messages.lockMenuTitle)} - - - {intl.formatMessage(messages.infoTitle)} - - - - {intl.formatMessage(messages.deleteTitle)} - - - -); - -FileMenu.propTypes = { - externalUrl: PropTypes.string.isRequired, - handleDelete: PropTypes.func.isRequired, - handleLock: PropTypes.func.isRequired, - locked: PropTypes.bool.isRequired, - openAssetInfo: PropTypes.func.isRequired, - portableUrl: PropTypes.string.isRequired, - iconSrc: PropTypes.func.isRequired, - id: PropTypes.string.isRequired, - // injected - intl: intlShape.isRequired, -}; - -export default injectIntl(FileMenu); diff --git a/src/files-and-uploads/FileThumbnail.jsx b/src/files-and-uploads/FileThumbnail.jsx deleted file mode 100644 index ca0aeb309c..0000000000 --- a/src/files-and-uploads/FileThumbnail.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { - Icon, - Image, -} from '@edx/paragon'; -import { getSrc } from './data/utils'; - -const AssetThumbnail = ({ - thumbnail, - wrapperType, - externalUrl, - displayName, -}) => { - const src = getSrc({ - thumbnail, - externalUrl, - wrapperType, - }); - - return ( -
    - {thumbnail ? ( - {`Thumbnail - ) : ( -
    - -
    - )} -
    - ); -}; -AssetThumbnail.defaultProps = { - thumbnail: null, -}; -AssetThumbnail.propTypes = { - thumbnail: PropTypes.string, - wrapperType: PropTypes.string.isRequired, - externalUrl: PropTypes.string.isRequired, - displayName: PropTypes.string.isRequired, -}; - -export default AssetThumbnail; diff --git a/src/files-and-uploads/FilesAndUploads.jsx b/src/files-and-uploads/FilesAndUploads.jsx deleted file mode 100644 index 416866fbbf..0000000000 --- a/src/files-and-uploads/FilesAndUploads.jsx +++ /dev/null @@ -1,274 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { useDispatch, useSelector } from 'react-redux'; -import _ from 'lodash'; -import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; -import { - DataTable, - TextFilter, - CheckboxFilter, - Dropzone, - CardView, - useToggle, -} from '@edx/paragon'; -import Placeholder, { ErrorAlert } from '@edx/frontend-lib-content-components'; - -import { RequestStatus } from '../data/constants'; -import { useModels } from '../generic/model-store'; -import { - addAssetFile, - deleteAssetFile, - fetchAssets, - updateAssetLock, -} from './data/thunks'; -import messages from './messages'; - -import FileInput, { fileInput } from './FileInput'; -import FilesAndUploadsProvider from './FilesAndUploadsProvider'; -import { - GalleryCard, - ListCard, - TableActions, -} from './table-components'; -import ApiStatusToast from './ApiStatusToast'; - -const FilesAndUploads = ({ - courseId, - // injected - intl, -}) => { - const dispatch = useDispatch(); - const defaultVal = 'card'; - const columnSizes = { - xs: 12, - sm: 6, - md: 4, - lg: 2, - }; - const [currentView, setCurrentView] = useState(defaultVal); - const [isDeleteOpen, setDeleteOpen, setDeleteClose] = useToggle(false); - const [isAddOpen, setAddOpen, setAddClose] = useToggle(false); - const [selectedRowCount, setSelectedRowCount] = useState(0); - - useEffect(() => { - dispatch(fetchAssets(courseId)); - }, [courseId]); - const { - totalCount, - assetIds, - loadingStatus, - addingStatus: addAssetStatus, - deletingStatus: deleteAssetStatus, - savingStatus: saveAssetStatus, - } = useSelector(state => state.assets); - const errorMessages = useSelector(state => state.assets.errors); - const fileInputControl = fileInput({ - onAddFile: (file) => dispatch(addAssetFile(courseId, file, totalCount)), - setSelectedRowCount, - setAddOpen, - }); - const assets = useModels('assets', assetIds); - - const handleDropzoneAsset = ({ fileData, handleError }) => { - try { - const file = fileData.get('file'); - dispatch(addAssetFile(courseId, file, totalCount)); - } catch (error) { - handleError(error); - } - }; - - const handleBulkDelete = (selectedFlatRows) => { - setSelectedRowCount(selectedFlatRows.length); - setDeleteOpen(); - const assetIdsToDelete = selectedFlatRows.map(row => row.original.id); - assetIdsToDelete.forEach(id => dispatch(deleteAssetFile(courseId, id, totalCount))); - }; - - const handleBulkDownload = (selectedFlatRows) => { - selectedFlatRows.forEach(row => { - const { externalUrl } = row.original; - const link = document.createElement('a'); - link.target = '_blank'; - link.download = true; - link.href = externalUrl; - link.click(); - }); - /* ********** TODO *********** - * implement a zip file function when there are multiple files - */ - }; - - const handleLockedAsset = (assetId, locked) => { - dispatch(updateAssetLock({ courseId, assetId, locked })); - }; - - const headerActions = ({ selectedFlatRows }) => ( - - ); - - const fileCard = ({ className, original }) => { - if (currentView === defaultVal) { - return ( - - ); - } - return ( - - ); - }; - - if (loadingStatus === RequestStatus.DENIED) { - return ( -
    - -
    - ); - } - - return ( - -
    -
    - - {intl.formatMessage(messages.errorAlertMessage, { message: errorMessages.upload })} - - - {intl.formatMessage(messages.errorAlertMessage, { message: errorMessages.delete })} - - - {intl.formatMessage(messages.errorAlertMessage, { message: errorMessages.lock })} - -
    - -
    -
    - setCurrentView(val), - defaultActiveStateValue: defaultVal, - togglePlacement: 'left', - }} - initialState={{ - pageSize: 50, - }} - tableActions={headerActions} - bulkActions={headerActions} - columns={[ - { - Header: 'Name', - accessor: 'displayName', - }, - { - Header: 'Type', - accessor: 'wrapperType', - Filter: CheckboxFilter, - filter: 'includesValue', - filterChoices: [ - { - name: 'Code', - value: 'code', - }, - { - name: 'Images', - value: 'image', - }, - { - name: 'Documents', - value: 'document', - }, - { - name: 'Audio', - value: 'audio', - }, - ], - }, - ]} - itemCount={totalCount} - pageCount={Math.ceil(totalCount / 50)} - data={assets} - > - {_.isEmpty(assets) && loadingStatus !== RequestStatus.IN_PROGRESS ? ( - - ) : ( -
    - - { currentView === 'card' && } - { currentView === 'list' && } - - - - -
    - )} -
    - -
    -
    - ); -}; - -FilesAndUploads.propTypes = { - courseId: PropTypes.string.isRequired, - // injected - intl: intlShape.isRequired, -}; - -export default injectIntl(FilesAndUploads); diff --git a/src/files-and-uploads/data/api.js b/src/files-and-uploads/data/api.js deleted file mode 100644 index d3601bbf2e..0000000000 --- a/src/files-and-uploads/data/api.js +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable import/prefer-default-export */ -import { camelCaseObject, ensureConfig, getConfig } from '@edx/frontend-platform'; -import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; - -ensureConfig([ - 'STUDIO_BASE_URL', -], 'Course Apps API service'); - -export const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; -export const getAssetsUrl = (courseId) => `${getApiBaseUrl()}/assets/${courseId}/`; - -/** - * Fetches the course custom pages for provided course - * @param {string} courseId - * @returns {Promise<[{}]>} - */ -export async function getAssets(courseId, totalCount) { - const pageCount = totalCount || 50; - const { data } = await getAuthenticatedHttpClient() - .get(`${getAssetsUrl(courseId)}?page_size=${pageCount}`); - return camelCaseObject(data); -} - -/** - * Delete custom page for provided block. - * @param {blockId} courseId Course ID for the course to operate on - - */ -export async function deleteAsset(courseId, assetId) { - await getAuthenticatedHttpClient() - .delete(`${getAssetsUrl(courseId)}${assetId}`); -} - -/** - * Add custom page for provided block. - * @param {blockId} courseId Course ID for the course to operate on - - */ -export async function addAsset(courseId, file) { - const formData = new FormData(); - formData.append('file', file); - const { data } = await getAuthenticatedHttpClient() - .post(getAssetsUrl(courseId), formData); - return camelCaseObject(data); -} - -/** - * Update locked attribute for provided asset. - * @param {blockId} courseId Course ID for the course to operate on - - */ -export async function updateLockStatus({ assetId, courseId, locked }) { - const { data } = await getAuthenticatedHttpClient() - .put(`${getAssetsUrl(courseId)}${assetId}`, { - locked, - }); - return camelCaseObject(data); -} diff --git a/src/files-and-uploads/data/thunks.js b/src/files-and-uploads/data/thunks.js deleted file mode 100644 index 21622e6a54..0000000000 --- a/src/files-and-uploads/data/thunks.js +++ /dev/null @@ -1,117 +0,0 @@ -import { RequestStatus } from '../../data/constants'; -import { - addModel, - addModels, - removeModel, - updateModel, -} from '../../generic/model-store'; -import { - getAssets, - addAsset, - deleteAsset, - updateLockStatus, -} from './api'; -import { - setAssetIds, - setTotalCount, - updateLoadingStatus, - updateSavingStatus, - deleteAssetSuccess, - updateDeletingStatus, - addAssetSuccess, - updateAddingStatus, - updateErrors, -} from './slice'; - -import { getWrapperType } from './utils'; - -export function fetchAssets(courseId) { - return async (dispatch) => { - dispatch(updateLoadingStatus({ courseId, status: RequestStatus.IN_PROGRESS })); - - try { - const { totalCount } = await getAssets(courseId); - const { assets } = await getAssets(courseId, totalCount); - const assetsWithWraperType = getWrapperType(assets); - dispatch(addModels({ modelType: 'assets', models: assetsWithWraperType })); - dispatch(setAssetIds({ - assetIds: assets.map(asset => asset.id), - })); - dispatch(setTotalCount({ totalCount })); - dispatch(updateLoadingStatus({ courseId, status: RequestStatus.SUCCESSFUL })); - } catch (error) { - if (error.response && error.response.status === 403) { - dispatch(updateLoadingStatus({ status: RequestStatus.DENIED })); - } else { - dispatch(updateLoadingStatus({ courseId, status: RequestStatus.FAILED })); - } - } - }; -} - -export function deleteAssetFile(courseId, id, totalCount) { - return async (dispatch) => { - dispatch(updateDeletingStatus({ status: RequestStatus.IN_PROGRESS })); - - try { - await deleteAsset(courseId, id); - dispatch(deleteAssetSuccess({ assetId: id })); - dispatch(removeModel({ modelType: 'assets', id })); - dispatch(setTotalCount({ totalCount: totalCount - 1 })); - dispatch(updateDeletingStatus({ status: RequestStatus.SUCCESSFUL })); - } catch (error) { - dispatch(updateErrors({ error: 'delete', message: `Failed to delete file id ${id}.` })); - dispatch(updateDeletingStatus({ status: RequestStatus.FAILED })); - } - }; -} - -export function addAssetFile(courseId, file, totalCount) { - return async (dispatch) => { - dispatch(updateAddingStatus({ status: RequestStatus.IN_PROGRESS })); - - try { - const { asset } = await addAsset(courseId, file); - const [assetsWithWraperType] = getWrapperType([asset]); - dispatch(addModel({ - modelType: 'assets', - model: { ...assetsWithWraperType }, - })); - dispatch(addAssetSuccess({ - assetId: asset.id, - })); - dispatch(setTotalCount({ totalCount: totalCount + 1 })); - dispatch(updateAddingStatus({ courseId, status: RequestStatus.SUCCESSFUL })); - } catch (error) { - if (error.response && error.response.status === 413) { - const message = error.response.data.error; - dispatch(updateErrors({ error: 'upload', message })); - } else { - dispatch(updateErrors({ error: 'upload', message: `Failed to add ${file.name}.` })); - } - dispatch(updateAddingStatus({ status: RequestStatus.FAILED })); - } - }; -} - -export function updateAssetLock({ assetId, courseId, locked }) { - return async (dispatch) => { - dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS })); - - try { - await updateLockStatus({ assetId, courseId, locked }); - dispatch(updateModel({ - modelType: 'assets', - model: { - id: assetId, - locked, - }, - })); - dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); - } catch (error) { - const lockStatus = locked ? 'lock' : 'unlock'; - dispatch(updateErrors({ error: 'lock', message: `Failed to ${lockStatus} file id ${assetId}.` })); - dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); - } - }; -} diff --git a/src/files-and-uploads/data/utils.js b/src/files-and-uploads/data/utils.js deleted file mode 100644 index ffa74fb87d..0000000000 --- a/src/files-and-uploads/data/utils.js +++ /dev/null @@ -1,41 +0,0 @@ -import { InsertDriveFile, Terminal, AudioFile } from '@edx/paragon/icons'; -import { ensureConfig, getConfig } from '@edx/frontend-platform'; -import FILES_AND_UPLOAD_TYPE_FILTERS from './constant'; - -ensureConfig([ - 'STUDIO_BASE_URL', -], 'Course Apps API service'); - -export const getWrapperType = (assets) => { - const assetsWithWraperType = []; - assets.forEach(asset => { - if (FILES_AND_UPLOAD_TYPE_FILTERS.images.includes(asset.contentType)) { - assetsWithWraperType.push({ wrapperType: 'image', ...asset }); - } else if (FILES_AND_UPLOAD_TYPE_FILTERS.documents.includes(asset.contentType)) { - assetsWithWraperType.push({ wrapperType: 'document', ...asset }); - } else if (FILES_AND_UPLOAD_TYPE_FILTERS.code.includes(asset.contentType)) { - assetsWithWraperType.push({ wrapperType: 'code', ...asset }); - } else if (FILES_AND_UPLOAD_TYPE_FILTERS.audio.includes(asset.contentType)) { - assetsWithWraperType.push({ wrapperType: 'audio', ...asset }); - } else { - assetsWithWraperType.push({ wrapperType: 'other', ...asset }); - } - }); - return assetsWithWraperType; -}; - -export const getSrc = ({ thumbnail, wrapperType, externalUrl }) => { - if (thumbnail) { - return externalUrl || `${getConfig().STUDIO_BASE_URL}${thumbnail}`; - } - switch (wrapperType) { - case 'document': - return InsertDriveFile; - case 'code': - return Terminal; - case 'audio': - return AudioFile; - default: - return InsertDriveFile; - } -}; diff --git a/src/files-and-uploads/index.js b/src/files-and-uploads/index.js deleted file mode 100644 index c0b84a0096..0000000000 --- a/src/files-and-uploads/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './FilesAndUploads'; diff --git a/src/files-and-uploads/messages.js b/src/files-and-uploads/messages.js deleted file mode 100644 index a1f7c7bb2b..0000000000 --- a/src/files-and-uploads/messages.js +++ /dev/null @@ -1,106 +0,0 @@ -import { defineMessages } from '@edx/frontend-platform/i18n'; - -const messages = defineMessages({ - heading: { - id: 'course-authoring.files-and-uploads.heading', - defaultMessage: 'Files and uploads', - }, - subheading: { - id: 'course-authoring.files-and-uploads.subheading', - defaultMessage: 'Content', - }, - apiStatusToastMessage: { - id: 'course-authoring.files-and-upload.apiStatus.message', - defaultMessage: '{actionType} {selectedRowCount} file(s)', - }, - apiStatusAddingAction: { - id: 'course-authoring.files-and-upload.apiStatus.addingAction.message', - defaultMessage: 'Adding', - }, - apiStatusDeletingAction: { - id: 'course-authoring.files-and-upload.apiStatus.deletingAction.message', - defaultMessage: 'Deleting', - }, - fileSizeError: { - id: 'course-authoring.files-and-upload.addFiles.error.fileSize', - defaultMessage: 'Uploaded file(s) must be 20 MB or less. Please resize file(s) and try again.', - }, - noResultsFoundMessage: { - id: 'course-authoring.files-and-upload.table.noResultsFound.message', - defaultMessage: 'No results found', - }, - addFilesButtonLabel: { - id: 'course-authoring.files-and-upload.addFiles.button.label', - defaultMessage: 'Add files', - }, - actionsButtonLabel: { - id: 'course-authoring.files-and-upload.action.button.label', - defaultMessage: 'Actions', - }, - errorAlertMessage: { - id: 'course-authoring.files-and-upload.errorAlert.message', - defaultMessage: '{message}', - }, - dateAddedTitle: { - id: 'course-authoring.files-and-uploads.dateAdded.title', - defaultMessage: 'Date added', - }, - fileSizeTitle: { - id: 'course-authoring.files-and-uploads.fileSize.title', - defaultMessage: 'File size', - }, - studioUrlTitle: { - id: 'course-authoring.files-and-uploads.studioUrl.title', - defaultMessage: 'Studio URL', - }, - webUrlTitle: { - id: 'course-authoring.files-and-uploads.webUrl.title', - defaultMessage: 'Web URL', - }, - lockFileTitle: { - id: 'course-authoring.files-and-uploads.lockFile.title', - defaultMessage: 'Lock file', - }, - lockFileTooltipContent: { - id: 'course-authoring.files-and-uploads.lockFile.tooltip.content', - defaultMessage: `By default, anyone can access a file you upload if - they know the web URL, even if they are not enrolled in your course. - You can prevent outside access to a file by locking the file. When - you lock a file, the web URL only allows learners who are enrolled - in your course and signed in to access the file.`, - }, - usageTitle: { - id: 'course-authoring.files-and-uploads.usage.title', - defaultMessage: 'Usage', - }, - copyStudioUrlTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.copyStudioUrlTitle', - defaultMessage: 'Copy Studio Url', - }, - copyWebUrlTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.copyWebUrlTitle', - defaultMessage: 'Copy Web Url', - }, - downloadTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.downloadTitle', - defaultMessage: 'Download', - }, - lockMenuTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.lockTitle', - defaultMessage: 'Lock', - }, - unlockMenuTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.unlockTitle', - defaultMessage: 'Unlock', - }, - infoTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.infoTitle', - defaultMessage: 'Info', - }, - deleteTitle: { - id: 'course-authoring.files-and-uploads.cardMenu.deleteTitle', - defaultMessage: 'Delete', - }, -}); - -export default messages; diff --git a/src/files-and-uploads/table-components/GalleryCard.jsx b/src/files-and-uploads/table-components/GalleryCard.jsx deleted file mode 100644 index 7d69de6d52..0000000000 --- a/src/files-and-uploads/table-components/GalleryCard.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { - ActionRow, - Icon, - Card, - useToggle, - Chip, - Truncate, - Image, -} from '@edx/paragon'; -import { - MoreVert, -} from '@edx/paragon/icons'; -import FileMenu from '../FileMenu'; -import FileInfo from '../FileInfo'; -import { getSrc } from '../data/utils'; - -const GalleryCard = ({ - className, - original, - handleBulkDelete, - handleLockedAsset, -}) => { - const [isAssetInfoOpen, openAssetInfo, closeAssetinfo] = useToggle(false); - const deleteAsset = () => { - handleBulkDelete([{ original }]); - }; - const lockAsset = () => { - const { locked } = original; - handleLockedAsset(original.id, !locked); - }; - const src = getSrc({ - thumbnail: original.thumbnail, - wrapperType: original.wrapperType, - }); - - return ( - <> - - - - - )} - /> - -
    - {original.thumbnail ? ( - - ) : ( -
    - -
    - )} -
    - - {original.displayName} - -
    - - - {original.wrapperType} - - -
    - - - ); -}; - -GalleryCard.defaultProps = { - className: null, -}; -GalleryCard.propTypes = { - className: PropTypes.string, - original: PropTypes.shape({ - displayName: PropTypes.string.isRequired, - wrapperType: PropTypes.string.isRequired, - locked: PropTypes.bool.isRequired, - externalUrl: PropTypes.string.isRequired, - thumbnail: PropTypes.string, - id: PropTypes.string.isRequired, - portableUrl: PropTypes.string.isRequired, - }).isRequired, - handleLockedAsset: PropTypes.func.isRequired, - handleBulkDelete: PropTypes.func.isRequired, -}; - -export default GalleryCard; diff --git a/src/files-and-uploads/table-components/ListCard.jsx b/src/files-and-uploads/table-components/ListCard.jsx deleted file mode 100644 index a2dd0cfab0..0000000000 --- a/src/files-and-uploads/table-components/ListCard.jsx +++ /dev/null @@ -1,107 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { - ActionRow, - Icon, - Card, - useToggle, - Chip, - Truncate, - Image, -} from '@edx/paragon'; -import { - MoreVert, -} from '@edx/paragon/icons'; -import FileMenu from '../FileMenu'; -import FileInfo from '../FileInfo'; -import { getSrc } from '../data/utils'; - -const ListCard = ({ - className, - original, - handleBulkDelete, - handleLockedAsset, -}) => { - const [isAssetInfoOpen, openAssetInfo, closeAssetinfo] = useToggle(false); - const deleteAsset = () => { - handleBulkDelete([{ original }]); - }; - const lockAsset = () => { - const { locked } = original; - handleLockedAsset(original.id, !locked); - }; - const src = getSrc({ - thumbnail: original.thumbnail, - wrapperType: original.wrapperType, - }); - - return ( - <> - -
    - {original.thumbnail ? ( - - ) : ( -
    - -
    - )} -
    - - - - {original.displayName} - - - {original.wrapperType} - - - - - - - - -
    - - - ); -}; - -ListCard.defaultProps = { - className: null, -}; -ListCard.propTypes = { - className: PropTypes.string, - original: PropTypes.shape({ - displayName: PropTypes.string.isRequired, - wrapperType: PropTypes.string.isRequired, - locked: PropTypes.bool.isRequired, - externalUrl: PropTypes.string.isRequired, - thumbnail: PropTypes.string, - id: PropTypes.string.isRequired, - portableUrl: PropTypes.string.isRequired, - }).isRequired, - handleLockedAsset: PropTypes.func.isRequired, - handleBulkDelete: PropTypes.func.isRequired, -}; - -export default ListCard; diff --git a/src/files-and-uploads/table-components/TableActions.jsx b/src/files-and-uploads/table-components/TableActions.jsx deleted file mode 100644 index db4ccdddf5..0000000000 --- a/src/files-and-uploads/table-components/TableActions.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react'; -import _ from 'lodash'; -import { PropTypes } from 'prop-types'; -import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; -import { Button, Dropdown } from '@edx/paragon'; -import { Add } from '@edx/paragon/icons'; -import messages from '../messages'; - -const TableActions = ({ - selectedFlatRows, - fileInputControl, - handleBulkDelete, - handleBulkDownload, -}) => ( - <> - - - - - - handleBulkDownload(selectedFlatRows)} - disabled={_.isEmpty(selectedFlatRows)} - > - - - - handleBulkDelete(selectedFlatRows)} - disabled={_.isEmpty(selectedFlatRows)} - > - - - - - - -); - -TableActions.defaultProps = { - selectedFlatRows: null, -}; -TableActions.propTypes = { - selectedFlatRows: PropTypes.arrayOf( - PropTypes.shape({ - original: PropTypes.shape({ - displayName: PropTypes.string.isRequired, - wrapperType: PropTypes.string.isRequired, - locked: PropTypes.bool.isRequired, - externalUrl: PropTypes.string.isRequired, - thumbnail: PropTypes.string, - id: PropTypes.string.isRequired, - portableUrl: PropTypes.string.isRequired, - }).isRequired, - }), - ), - fileInputControl: PropTypes.shape({ - click: PropTypes.func.isRequired, - }).isRequired, - handleBulkDelete: PropTypes.func.isRequired, - handleBulkDownload: PropTypes.func.isRequired, -}; - -export default injectIntl(TableActions); diff --git a/src/files-and-uploads/table-components/index.js b/src/files-and-uploads/table-components/index.js deleted file mode 100644 index 9df0da049c..0000000000 --- a/src/files-and-uploads/table-components/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import GalleryCard from './GalleryCard'; -import ListCard from './ListCard'; -import TableActions from './TableActions'; - -export { - TableActions, - GalleryCard, - ListCard, -}; diff --git a/src/files-and-videos/files-page/FileInfoModalSidebar.jsx b/src/files-and-videos/files-page/FileInfoModalSidebar.jsx new file mode 100644 index 0000000000..842c6e568c --- /dev/null +++ b/src/files-and-videos/files-page/FileInfoModalSidebar.jsx @@ -0,0 +1,130 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; + +import { + injectIntl, + FormattedMessage, + FormattedDate, + intlShape, +} from '@edx/frontend-platform/i18n'; +import { + Stack, + IconButton, + ActionRow, + Icon, + Truncate, + IconButtonWithTooltip, + CheckboxControl, +} from '@edx/paragon'; +import { ContentCopy, InfoOutline } from '@edx/paragon/icons'; + +import { getFileSizeToClosestByte } from '../generic/utils'; +import messages from './messages'; + +const FileInfoModalSidebar = ({ + asset, + handleLockedAsset, + // injected + intl, +}) => { + const [lockedState, setLockedState] = useState(asset?.locked); + const handleLock = (e) => { + const locked = e.target.checked; + setLockedState(locked); + handleLockedAsset(asset?.id, locked); + }; + const fileSize = getFileSizeToClosestByte(asset?.fileSize); + + return ( + +
    + +
    + +
    + +
    + {fileSize} +
    + +
    + +
    + + {asset?.portableUrl} + +
    + + navigator.clipboard.writeText(asset?.portableUrl)} + /> +
    +
    + +
    + +
    + + {asset?.externalUrl} + +
    + + navigator.clipboard.writeText(asset?.externalUrl)} + /> +
    + +
    + +
    + + + +
    +
    + ); +}; +FileInfoModalSidebar.propTypes = { + asset: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + wrapperType: PropTypes.string.isRequired, + locked: PropTypes.bool.isRequired, + externalUrl: PropTypes.string.isRequired, + thumbnail: PropTypes.string, + id: PropTypes.string.isRequired, + portableUrl: PropTypes.string.isRequired, + dateAdded: PropTypes.string.isRequired, + fileSize: PropTypes.number.isRequired, + usageLocations: PropTypes.arrayOf(PropTypes.string), + }).isRequired, + handleLockedAsset: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(FileInfoModalSidebar); diff --git a/src/files-and-videos/files-page/FileThumbnail.jsx b/src/files-and-videos/files-page/FileThumbnail.jsx new file mode 100644 index 0000000000..bf96fbda8b --- /dev/null +++ b/src/files-and-videos/files-page/FileThumbnail.jsx @@ -0,0 +1,72 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + Icon, + Image, +} from '@edx/paragon'; +import { getSrc } from './data/utils'; +import messages from './messages'; + +const FileThumbnail = ({ + thumbnail, + wrapperType, + externalUrl, + displayName, + imageSize, + // injected + intl, +}) => { + const src = getSrc({ + thumbnail, + externalUrl, + wrapperType, + }); + const { width, height } = imageSize; + + return ( +
    + {thumbnail ? ( + {intl.formatMessage(messages.thumbnailAltMessage, + ) : ( +
    + +
    + )} +
    + ); +}; +FileThumbnail.defaultProps = { + thumbnail: null, + wrapperType: null, + externalUrl: null, + displayName: null, +}; +FileThumbnail.propTypes = { + thumbnail: PropTypes.string, + wrapperType: PropTypes.string, + externalUrl: PropTypes.string, + displayName: PropTypes.string, + imageSize: PropTypes.shape({ + width: PropTypes.string, + height: PropTypes.string.isRequired, + }).isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(FileThumbnail); diff --git a/src/files-and-videos/files-page/FilesPage.jsx b/src/files-and-videos/files-page/FilesPage.jsx new file mode 100644 index 0000000000..318c5e333a --- /dev/null +++ b/src/files-and-videos/files-page/FilesPage.jsx @@ -0,0 +1,213 @@ +import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { isEmpty } from 'lodash'; +import { useDispatch, useSelector } from 'react-redux'; +import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; +import { CheckboxFilter } from '@edx/paragon'; +import Placeholder from '@edx/frontend-lib-content-components'; + +import { RequestStatus } from '../../data/constants'; +import { useModels, useModel } from '../../generic/model-store'; +import { + addAssetFile, + deleteAssetFile, + fetchAssets, + updateAssetLock, + fetchAssetDownload, + getUsagePaths, + resetErrors, + updateAssetOrder, +} from './data/thunks'; +import messages from './messages'; +import FilesPageProvider from './FilesPageProvider'; +import getPageHeadTitle from '../../generic/utils'; +import { + AccessColumn, + ActiveColumn, + EditFileErrors, + FileTable, + ThumbnailColumn, +} from '../generic'; +import { getFileSizeToClosestByte } from '../generic/utils'; +import FileThumbnail from './FileThumbnail'; +import FileInfoModalSidebar from './FileInfoModalSidebar'; + +const FilesPage = ({ + courseId, + // injected + intl, +}) => { + const dispatch = useDispatch(); + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.heading)); + + useEffect(() => { + dispatch(fetchAssets(courseId)); + }, [courseId]); + + const { + assetIds, + loadingStatus, + addingStatus: addAssetStatus, + deletingStatus: deleteAssetStatus, + updatingStatus: updateAssetStatus, + usageStatus: usagePathStatus, + errors: errorMessages, + } = useSelector(state => state.assets); + + const handleErrorReset = (error) => dispatch(resetErrors(error)); + const handleAddFile = (file) => dispatch(addAssetFile(courseId, file)); + const handleDeleteFile = (id) => dispatch(deleteAssetFile(courseId, id)); + const handleDownloadFile = (selectedRows) => dispatch(fetchAssetDownload({ selectedRows, courseId })); + const handleLockFile = (fileId, locked) => { + handleErrorReset({ errorType: 'lock' }); + dispatch(updateAssetLock({ courseId, assetId: fileId, locked })); + }; + const handleUsagePaths = (asset) => dispatch(getUsagePaths({ asset, courseId })); + const handleFileOrder = ({ newFileIdOrder, sortType }) => { + dispatch(updateAssetOrder(courseId, newFileIdOrder, sortType)); + }; + + const thumbnailPreview = (props) => FileThumbnail(props); + const infoModalSidebar = (asset) => FileInfoModalSidebar({ + asset, + handleLockedAsset: handleLockFile, + }); + + const assets = useModels('assets', assetIds); + const data = { + fileIds: assetIds, + loadingStatus, + usagePathStatus, + usageErrorMessages: errorMessages.usageMetrics, + }; + const maxFileSize = 20 * 1048576; + + const activeColumn = { + id: 'usageLocations', + Header: 'Active', + accessor: (({ usageLocations }) => !isEmpty(usageLocations)), + Cell: ({ row }) => ActiveColumn({ row }), + Filter: CheckboxFilter, + filterChoices: [ + { name: intl.formatMessage(messages.activeCheckboxLabel), value: true }, + { name: intl.formatMessage(messages.inactiveCheckboxLabel), value: false }, + ], + }; + const accessColumn = { + id: 'locked', + Header: 'Access', + accessor: 'locked', + Cell: ({ row }) => AccessColumn({ row }), + Filter: CheckboxFilter, + filterChoices: [ + { name: intl.formatMessage(messages.lockedCheckboxLabel), value: true }, + { name: intl.formatMessage(messages.publicCheckboxLabel), value: false }, + ], + }; + const thumbnailColumn = { + id: 'thumbnail', + Header: '', + Cell: ({ row }) => ThumbnailColumn({ row, thumbnailPreview }), + }; + const fileSizeColumn = { + id: 'fileSize', + Header: 'File size', + accessor: 'fileSize', + Cell: ({ row }) => { + const { fileSize } = row.original; + return getFileSizeToClosestByte(fileSize); + }, + }; + + const tableColumns = [ + { ...thumbnailColumn }, + { + Header: 'File name', + accessor: 'displayName', + }, + { ...fileSizeColumn }, + { + Header: 'Type', + accessor: 'wrapperType', + Filter: CheckboxFilter, + filter: 'includesValue', + filterChoices: [ + { + name: intl.formatMessage(messages.codeCheckboxLabel), + value: 'code', + }, + { + name: intl.formatMessage(messages.imageCheckboxLabel), + value: 'image', + }, + { + name: intl.formatMessage(messages.documentCheckboxLabel), + value: 'document', + }, + { + name: intl.formatMessage(messages.audioCheckboxLabel), + value: 'audio', + }, + { + name: intl.formatMessage(messages.otherCheckboxLabel), + value: 'other', + }, + ], + }, + { ...activeColumn }, + { ...accessColumn }, + ]; + + if (loadingStatus === RequestStatus.DENIED) { + return ( +
    + +
    + ); + } + return ( + +
    +
    + +
    + +
    +
    + +
    +
    + ); +}; + +FilesPage.propTypes = { + courseId: PropTypes.string.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(FilesPage); diff --git a/src/files-and-uploads/FilesAndUploads.test.jsx b/src/files-and-videos/files-page/FilesPage.test.jsx similarity index 58% rename from src/files-and-uploads/FilesAndUploads.test.jsx rename to src/files-and-videos/files-page/FilesPage.test.jsx index 0815025899..cd1bc65b62 100644 --- a/src/files-and-uploads/FilesAndUploads.test.jsx +++ b/src/files-and-videos/files-page/FilesPage.test.jsx @@ -8,6 +8,7 @@ import { } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import ReactDOM from 'react-dom'; +import { saveAs } from 'file-saver'; import { initializeMockApp } from '@edx/frontend-platform'; import MockAdapter from 'axios-mock-adapter'; @@ -15,10 +16,10 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; import { IntlProvider } from '@edx/frontend-platform/i18n'; -import initializeStore from '../store'; -import { executeThunk } from '../utils'; -import { RequestStatus } from '../data/constants'; -import FilesAndUploads from './FilesAndUploads'; +import initializeStore from '../../store'; +import { executeThunk } from '../../utils'; +import { RequestStatus } from '../../data/constants'; +import FilesPage from './FilesPage'; import { generateFetchAssetApiResponse, generateEmptyApiResponse, @@ -33,20 +34,22 @@ import { addAssetFile, deleteAssetFile, updateAssetLock, + getUsagePaths, } from './data/thunks'; import { getAssetsUrl } from './data/api'; -import messages from './messages'; +import messages from '../generic/messages'; let axiosMock; let store; let file; ReactDOM.createPortal = jest.fn(node => node); +jest.mock('file-saver'); const renderComponent = () => { render( - + , ); @@ -88,22 +91,27 @@ describe('FilesAndUploads', () => { axiosMock = new MockAdapter(getAuthenticatedHttpClient()); file = new File(['(⌐□_□)'], 'download.png', { type: 'image/png' }); }); + it('should return placeholder component', async () => { renderComponent(); await mockStore(RequestStatus.DENIED); expect(screen.getByTestId('under-construction-placeholder')).toBeVisible(); }); - it('should have Files and uploads title', async () => { + + it('should have Files title', async () => { renderComponent(); await emptyMockStore(RequestStatus.SUCCESSFUL); - expect(screen.getByText('Files and uploads')).toBeVisible(); + expect(screen.getByText('Files')).toBeVisible(); }); + it('should render dropzone', async () => { renderComponent(); await emptyMockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('files-dropzone')).toBeVisible(); + expect(screen.queryByTestId('files-data-table')).toBeNull(); }); + it('should upload a single file', async () => { renderComponent(); await emptyMockStore(RequestStatus.SUCCESSFUL); @@ -118,10 +126,13 @@ describe('FilesAndUploads', () => { }); const addStatus = store.getState().assets.addingStatus; expect(addStatus).toEqual(RequestStatus.SUCCESSFUL); + expect(screen.queryByTestId('files-dropzone')).toBeNull(); + expect(screen.getByTestId('files-data-table')).toBeVisible(); }); }); + describe('valid assets', () => { beforeEach(async () => { initializeMockApp({ @@ -136,27 +147,39 @@ describe('FilesAndUploads', () => { axiosMock = new MockAdapter(getAuthenticatedHttpClient()); file = new File(['(⌐□_□)'], 'download.png', { type: 'image/png' }); }); + + afterEach(() => { + saveAs.mockClear(); + }); + describe('table view', () => { it('should render table with gallery card', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('files-data-table')).toBeVisible(); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); }); + it('should switch table to list view', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('files-data-table')).toBeVisible(); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); - expect(screen.queryByTestId('list-card-mOckID1')).toBeNull(); + + expect(screen.queryByRole('table')).toBeNull(); + const listButton = screen.getByLabelText('List'); await act(async () => { fireEvent.click(listButton); }); expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull(); - expect(screen.getByTestId('list-card-mOckID1')).toBeVisible(); + + expect(screen.getByRole('table')).toBeVisible(); }); }); + describe('table actions', () => { it('should upload a single file', async () => { renderComponent(); @@ -170,17 +193,21 @@ describe('FilesAndUploads', () => { const addStatus = store.getState().assets.addingStatus; expect(addStatus).toEqual(RequestStatus.SUCCESSFUL); }); + it('should have disabled action buttons', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); expect(actionsButton).toBeVisible(); + await waitFor(() => { fireEvent.click(actionsButton); }); expect(screen.getByText(messages.downloadTitle.defaultMessage).closest('a')).toHaveClass('disabled'); + expect(screen.getByText(messages.deleteTitle.defaultMessage).closest('a')).toHaveClass('disabled'); }); + it('delete button should be enabled and delete selected file', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); @@ -188,45 +215,158 @@ describe('FilesAndUploads', () => { fireEvent.click(selectCardButton); const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); expect(actionsButton).toBeVisible(); + await waitFor(() => { fireEvent.click(actionsButton); }); const deleteButton = screen.getByText(messages.deleteTitle.defaultMessage).closest('a'); expect(deleteButton).not.toHaveClass('disabled'); + axiosMock.onDelete(`${getAssetsUrl(courseId)}mOckID1`).reply(204); + + fireEvent.click(deleteButton); + expect(screen.getByText(messages.deleteConfirmationTitle.defaultMessage)).toBeVisible(); + await act(async () => { + userEvent.click(deleteButton); + }); + + // Wait for the delete confirmation button to appear + const confirmDeleteButton = await screen.findByRole('button', { + name: messages.deleteFileButtonLabel.defaultMessage, + }); + await act(async () => { - fireEvent.click(deleteButton); - await executeThunk(deleteAssetFile(courseId, 'mOckID1', 5), store.dispatch); + userEvent.click(confirmDeleteButton); }); + + expect(screen.queryByText(messages.deleteConfirmationTitle.defaultMessage)).toBeNull(); + + // Check if the asset is deleted in the store and UI const deleteStatus = store.getState().assets.deletingStatus; expect(deleteStatus).toEqual(RequestStatus.SUCCESSFUL); expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull(); }); + + it('download button should be enabled and download single selected file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButton = screen.getAllByTestId('datatable-select-column-checkbox-cell')[0]; + fireEvent.click(selectCardButton); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + const downloadButton = screen.getByText(messages.downloadTitle.defaultMessage).closest('a'); + expect(downloadButton).not.toHaveClass('disabled'); + + fireEvent.click(downloadButton); + expect(saveAs).toHaveBeenCalled(); + }); + + it('download button should be enabled and download multiple selected files', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButtons = screen.getAllByTestId('datatable-select-column-checkbox-cell'); + fireEvent.click(selectCardButtons[0]); + fireEvent.click(selectCardButtons[1]); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + const mockResponseData = { ok: true, blob: () => 'Data' }; + const mockFetchResponse = Promise.resolve(mockResponseData); + const downloadButton = screen.getByText(messages.downloadTitle.defaultMessage).closest('a'); + expect(downloadButton).not.toHaveClass('disabled'); + + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + fireEvent.click(downloadButton); + expect(fetch).toHaveBeenCalledTimes(2); + }); + + it('sort button should be enabled and sort files by name', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const sortsButton = screen.getByText(messages.sortButtonLabel.defaultMessage); + expect(sortsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(sortsButton); + expect(screen.getByText(messages.sortModalTitleLabel.defaultMessage)).toBeVisible(); + }); + + const sortNameAscendingButton = screen.getByText(messages.sortByNameAscending.defaultMessage); + fireEvent.click(sortNameAscendingButton); + fireEvent.click(screen.getByText(messages.applySortButton.defaultMessage)); + expect(screen.queryByText(messages.sortModalTitleLabel.defaultMessage)).toBeNull(); + }); + + it('sort button should be enabled and sort files by file size', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const sortsButton = screen.getByText(messages.sortButtonLabel.defaultMessage); + expect(sortsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(sortsButton); + expect(screen.getByText(messages.sortModalTitleLabel.defaultMessage)).toBeVisible(); + }); + + const sortBySizeDescendingButton = screen.getByText(messages.sortBySizeDescending.defaultMessage); + fireEvent.click(sortBySizeDescendingButton); + fireEvent.click(screen.getByText(messages.applySortButton.defaultMessage)); + expect(screen.queryByText(messages.sortModalTitleLabel.defaultMessage)).toBeNull(); + }); }); + describe('card menu actions', () => { it('should open asset info', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); expect(assetMenuButton).toBeVisible(); + + axiosMock.onGet(`${getAssetsUrl(courseId)}mOckID1/usage`).reply(201, { usageLocations: ['subsection - unit / block'] }); await waitFor(() => { - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); fireEvent.click(screen.getByText('Info')); + executeThunk(getUsagePaths({ + courseId, + asset: { id: 'mOckID1', displayName: 'mOckID1' }, + setSelectedRows: jest.fn(), + }), store.dispatch); expect(screen.getAllByLabelText('mOckID1')[0]).toBeVisible(); }); + + const { usageStatus } = store.getState().assets; + expect(usageStatus).toEqual(RequestStatus.SUCCESSFUL); + expect(screen.getByText('subsection - unit / block')).toBeVisible(); }); + it('should open asset info and handle lock checkbox', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); expect(assetMenuButton).toBeVisible(); + axiosMock.onPut(`${getAssetsUrl(courseId)}mOckID1`).reply(201, { locked: false }); + axiosMock.onGet(`${getAssetsUrl(courseId)}mOckID1/usage`).reply(201, { usageLocations: [] }); await waitFor(() => { - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); fireEvent.click(screen.getByText('Info')); + executeThunk(getUsagePaths({ + courseId, + asset: { id: 'mOckID1', displayName: 'mOckID1' }, + setSelectedRows: jest.fn(), + }), store.dispatch); expect(screen.getAllByLabelText('mOckID1')[0]).toBeVisible(); + fireEvent.click(screen.getByLabelText('Checkbox')); executeThunk(updateAssetLock({ courseId, @@ -234,18 +374,23 @@ describe('FilesAndUploads', () => { locked: false, }), store.dispatch); }); - const saveStatus = store.getState().assets.savingStatus; - expect(saveStatus).toEqual(RequestStatus.SUCCESSFUL); + expect(screen.getByText(messages.usageNotInUseMessage.defaultMessage)).toBeVisible(); + + const updateStatus = store.getState().assets.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); }); + it('should unlock asset', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); expect(assetMenuButton).toBeVisible(); + await waitFor(() => { axiosMock.onPut(`${getAssetsUrl(courseId)}mOckID1`).reply(201, { locked: false }); - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); fireEvent.click(screen.getByText('Unlock')); executeThunk(updateAssetLock({ courseId, @@ -253,18 +398,21 @@ describe('FilesAndUploads', () => { locked: false, }), store.dispatch); }); - const saveStatus = store.getState().assets.savingStatus; - expect(saveStatus).toEqual(RequestStatus.SUCCESSFUL); + const updateStatus = store.getState().assets.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); }); + it('should lock asset', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('grid-card-mOckID3')).toBeVisible(); + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID3'); expect(assetMenuButton).toBeVisible(); + await waitFor(() => { axiosMock.onPut(`${getAssetsUrl(courseId)}mOckID3`).reply(201, { locked: true }); - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); fireEvent.click(screen.getByText('Lock')); executeThunk(updateAssetLock({ courseId, @@ -272,26 +420,51 @@ describe('FilesAndUploads', () => { locked: true, }), store.dispatch); }); - const saveStatus = store.getState().assets.savingStatus; - expect(saveStatus).toEqual(RequestStatus.SUCCESSFUL); + const updateStatus = store.getState().assets.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('download button should download file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(assetMenuButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Download')); + }); + expect(saveAs).toHaveBeenCalled(); }); + it('delete button should delete file', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); expect(assetMenuButton).toBeVisible(); + await waitFor(() => { axiosMock.onDelete(`${getAssetsUrl(courseId)}mOckID1`).reply(204); - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); - fireEvent.click(screen.getByText('Delete')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByTestId('open-delete-confirmation-button')); + expect(screen.getByText(messages.deleteConfirmationTitle.defaultMessage)).toBeVisible(); + + fireEvent.click(screen.getByText(messages.deleteFileButtonLabel.defaultMessage)); + expect(screen.queryByText(messages.deleteConfirmationTitle.defaultMessage)).toBeNull(); + executeThunk(deleteAssetFile(courseId, 'mOckID1', 5), store.dispatch); }); const deleteStatus = store.getState().assets.deletingStatus; expect(deleteStatus).toEqual(RequestStatus.SUCCESSFUL); + expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull(); }); }); + describe('api errors', () => { it('invalid file size should show error', async () => { const errorMessage = 'File download.png exceeds maximum size of 20 MB.'; @@ -305,8 +478,10 @@ describe('FilesAndUploads', () => { }); const addStatus = store.getState().assets.addingStatus; expect(addStatus).toEqual(RequestStatus.FAILED); + expect(screen.getByText('Error')).toBeVisible(); }); + it('404 upload should show error', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); @@ -318,35 +493,70 @@ describe('FilesAndUploads', () => { }); const addStatus = store.getState().assets.addingStatus; expect(addStatus).toEqual(RequestStatus.FAILED); + expect(screen.getByText('Error')).toBeVisible(); }); + it('404 delete should show error', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); - expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); expect(assetMenuButton).toBeVisible(); + await waitFor(() => { axiosMock.onDelete(`${getAssetsUrl(courseId)}mOckID1`).reply(404); - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); - fireEvent.click(screen.getByText('Delete')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByTestId('open-delete-confirmation-button')); + expect(screen.getByText(messages.deleteConfirmationTitle.defaultMessage)).toBeVisible(); + + fireEvent.click(screen.getByText(messages.deleteFileButtonLabel.defaultMessage)); + expect(screen.queryByText(messages.deleteConfirmationTitle.defaultMessage)).toBeNull(); + executeThunk(deleteAssetFile(courseId, 'mOckID1', 5), store.dispatch); }); const deleteStatus = store.getState().assets.deletingStatus; expect(deleteStatus).toEqual(RequestStatus.FAILED); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + expect(screen.getByText('Error')).toBeVisible(); }); + + it('404 usage path fetch should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID3')).toBeVisible(); + + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID3'); + expect(assetMenuButton).toBeVisible(); + + axiosMock.onGet(`${getAssetsUrl(courseId)}mOckID3/usage`).reply(404); + await waitFor(() => { + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Info')); + executeThunk(getUsagePaths({ + courseId, + asset: { id: 'mOckID3', displayName: 'mOckID3' }, + setSelectedRows: jest.fn(), + }), store.dispatch); + }); + const { usageStatus } = store.getState().assets; + expect(usageStatus).toEqual(RequestStatus.FAILED); + }); + it('404 lock update should show error', async () => { renderComponent(); await mockStore(RequestStatus.SUCCESSFUL); expect(screen.getByTestId('grid-card-mOckID3')).toBeVisible(); + const assetMenuButton = screen.getByTestId('file-menu-dropdown-mOckID3'); expect(assetMenuButton).toBeVisible(); + await waitFor(() => { axiosMock.onPut(`${getAssetsUrl(courseId)}mOckID3`).reply(404); - fireEvent.click(within(assetMenuButton).getByLabelText('asset-menu-toggle')); + fireEvent.click(within(assetMenuButton).getByLabelText('file-menu-toggle')); fireEvent.click(screen.getByText('Lock')); executeThunk(updateAssetLock({ courseId, @@ -354,8 +564,38 @@ describe('FilesAndUploads', () => { locked: true, }), store.dispatch); }); - const saveStatus = store.getState().assets.savingStatus; - expect(saveStatus).toEqual(RequestStatus.FAILED); + const updateStatus = store.getState().assets.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Error')).toBeVisible(); + }); + + it('multiple asset file fetch failure should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButtons = screen.getAllByTestId('datatable-select-column-checkbox-cell'); + fireEvent.click(selectCardButtons[0]); + fireEvent.click(selectCardButtons[1]); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + const mockResponseData = { ok: false }; + const mockFetchResponse = Promise.resolve(mockResponseData); + const downloadButton = screen.getByText(messages.downloadTitle.defaultMessage).closest('a'); + expect(downloadButton).not.toHaveClass('disabled'); + + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + await waitFor(() => { + fireEvent.click(downloadButton); + expect(fetch).toHaveBeenCalledTimes(2); + }); + + const updateStatus = store.getState().assets.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.FAILED); + expect(screen.getByText('Error')).toBeVisible(); }); }); diff --git a/src/files-and-uploads/FilesAndUploadsProvider.jsx b/src/files-and-videos/files-page/FilesPageProvider.jsx similarity index 54% rename from src/files-and-uploads/FilesAndUploadsProvider.jsx rename to src/files-and-videos/files-page/FilesPageProvider.jsx index fee357aae0..6b10fbfa33 100644 --- a/src/files-and-uploads/FilesAndUploadsProvider.jsx +++ b/src/files-and-videos/files-page/FilesPageProvider.jsx @@ -1,25 +1,25 @@ import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; -export const FilesAndUploadsContext = React.createContext({}); +export const FilesPageContext = React.createContext({}); -const FilesAndUploadsProvider = ({ courseId, children }) => { +const FilesPageProvider = ({ courseId, children }) => { const contextValue = useMemo(() => ({ courseId, path: `/course/${courseId}/assets`, }), []); return ( - {children} - + ); }; -FilesAndUploadsProvider.propTypes = { +FilesPageProvider.propTypes = { courseId: PropTypes.string.isRequired, children: PropTypes.node.isRequired, }; -export default FilesAndUploadsProvider; +export default FilesPageProvider; diff --git a/src/files-and-videos/files-page/data/api.js b/src/files-and-videos/files-page/data/api.js new file mode 100644 index 0000000000..357e3ff2cc --- /dev/null +++ b/src/files-and-videos/files-page/data/api.js @@ -0,0 +1,122 @@ +/* eslint-disable import/prefer-default-export */ +import { camelCaseObject, ensureConfig, getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import JSZip from 'jszip'; +import saveAs from 'file-saver'; + +ensureConfig([ + 'STUDIO_BASE_URL', +], 'Course Apps API service'); + +export const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; +export const getAssetsUrl = (courseId) => `${getApiBaseUrl()}/assets/${courseId}/`; + +/** + * Fetches the course custom pages for provided course + * @param {string} courseId + * @returns {Promise<[{}]>} + */ +export async function getAssets(courseId, totalCount) { + const pageCount = totalCount || 50; + const { data } = await getAuthenticatedHttpClient() + .get(`${getAssetsUrl(courseId)}?page_size=${pageCount}`); + return camelCaseObject(data); +} + +/** + * Fetch asset file. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function getDownload(selectedRows, courseId) { + const downloadErrors = []; + if (selectedRows?.length > 1) { + const zip = new JSZip(); + const date = new Date().toString(); + const folder = zip.folder(`${courseId}-assets-${date}`); + const assetNames = []; + const assetFetcher = await Promise.allSettled( + selectedRows.map(async (row) => { + const asset = row?.original; + try { + assetNames.push(asset.displayName); + const res = await fetch(`${getApiBaseUrl()}/${asset.id}`); + if (!res.ok) { + throw new Error(); + } + return res.blob(); + } catch (error) { + downloadErrors.push(`Failed to download ${asset?.displayName}.`); + return null; + } + }), + ); + const definedAssets = assetFetcher.filter(asset => asset.value !== null); + if (definedAssets.length > 0) { + definedAssets.forEach((assetBlob, index) => { + folder.file(assetNames[index], assetBlob.value, { blob: true }); + }); + zip.generateAsync({ type: 'blob' }).then(content => { + saveAs(content, `${courseId}-assets-${date}.zip`); + }); + } + } else if (selectedRows?.length === 1) { + const asset = selectedRows[0].original; + try { + saveAs(`${getApiBaseUrl()}/${asset.id}`, asset.displayName); + } catch (error) { + downloadErrors.push(`Failed to download ${asset?.displayName}.`); + } + } else { + downloadErrors.push('No files were selected to download'); + } + return downloadErrors; +} + +/** + * Fetch where asset is used in a course. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function getAssetUsagePaths({ courseId, assetId }) { + const { data } = await getAuthenticatedHttpClient() + .get(`${getAssetsUrl(courseId)}${assetId}/usage`); + return camelCaseObject(data); +} + +/** + * Delete asset to course. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function deleteAsset(courseId, assetId) { + await getAuthenticatedHttpClient() + .delete(`${getAssetsUrl(courseId)}${assetId}`); +} + +/** + * Add asset to course. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function addAsset(courseId, file) { + const formData = new FormData(); + formData.append('file', file); + const { data } = await getAuthenticatedHttpClient() + .post(getAssetsUrl(courseId), formData); + return camelCaseObject(data); +} + +/** + * Update locked attribute for provided asset. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function updateLockStatus({ assetId, courseId, locked }) { + const { data } = await getAuthenticatedHttpClient() + .put(`${getAssetsUrl(courseId)}${assetId}`, { + locked, + }); + return camelCaseObject(data); +} diff --git a/src/files-and-videos/files-page/data/api.test.js b/src/files-and-videos/files-page/data/api.test.js new file mode 100644 index 0000000000..e852bc4ec6 --- /dev/null +++ b/src/files-and-videos/files-page/data/api.test.js @@ -0,0 +1,57 @@ +import { getDownload } from './api'; +import 'file-saver'; + +jest.mock('file-saver'); + +describe('api.js', () => { + describe('getDownload', () => { + describe('selectedRows length is undefined or less than zero', () => { + it('should return with no files selected error if selectedRows is empty', async () => { + const expected = ['No files were selected to download']; + const actual = await getDownload([], 'courseId'); + expect(actual).toEqual(expected); + }); + it('should return with no files selected error if selectedRows is null', async () => { + const expected = ['No files were selected to download']; + const actual = await getDownload(null, 'courseId'); + expect(actual).toEqual(expected); + }); + }); + describe('selectedRows length is greater than one', () => { + it('should not throw error when blob returns null', async () => { + const mockResponseData = { ok: true, blob: () => null }; + const mockFetchResponse = Promise.resolve(mockResponseData); + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + const expected = []; + const actual = await getDownload([ + { original: { displayName: 'test1' } }, + { original: { displayName: 'test2', id: '2' } }, + ]); + expect(actual).toEqual(expected); + }); + it('should return error if row does not contain .original ancestor', async () => { + const mockResponseData = { ok: true, blob: () => 'data' }; + const mockFetchResponse = Promise.resolve(mockResponseData); + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + const expected = ['Failed to download undefined.']; + const actual = await getDownload([ + { asset: { displayName: 'test1', id: '1' } }, + { original: { displayName: 'test2', id: '2' } }, + ]); + expect(actual).toEqual(expected); + }); + }); + describe('selectedRows length equals one', () => { + it('should return error if row does not contain .original ancestor', async () => { + const mockResponseData = { ok: true, blob: () => 'data' }; + const mockFetchResponse = Promise.resolve(mockResponseData); + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + const expected = ['Failed to download undefined.']; + const actual = await getDownload([ + { asset: { displayName: 'test1', id: '1' } }, + ]); + expect(actual).toEqual(expected); + }); + }); + }); +}); diff --git a/src/files-and-uploads/data/slice.js b/src/files-and-videos/files-page/data/slice.js similarity index 58% rename from src/files-and-uploads/data/slice.js rename to src/files-and-videos/files-page/data/slice.js index 00d470b419..080f0ea023 100644 --- a/src/files-and-uploads/data/slice.js +++ b/src/files-and-videos/files-page/data/slice.js @@ -1,41 +1,53 @@ /* eslint-disable no-param-reassign */ import { createSlice } from '@reduxjs/toolkit'; -import { RequestStatus } from '../../data/constants'; +import { RequestStatus } from '../../../data/constants'; const slice = createSlice({ name: 'assets', initialState: { assetIds: [], loadingStatus: RequestStatus.IN_PROGRESS, - savingStatus: '', + updatingStatus: '', addingStatus: '', deletingStatus: '', + usageStatus: '', errors: { - upload: [], + add: [], delete: [], lock: [], + download: [], + usageMetrics: [], }, - totalCount: 0, }, reducers: { setAssetIds: (state, { payload }) => { state.assetIds = payload.assetIds; }, - setTotalCount: (state, { payload }) => { - state.totalCount = payload.totalCount; - }, updateLoadingStatus: (state, { payload }) => { state.loadingStatus = payload.status; }, - updateSavingStatus: (state, { payload }) => { - state.savingStatus = payload.status; - }, - updateAddingStatus: (state, { payload }) => { - state.addingStatus = payload.status; - }, - updateDeletingStatus: (state, { payload }) => { - state.deletingStatus = payload.status; + updateEditStatus: (state, { payload }) => { + const { editType, status } = payload; + switch (editType) { + case 'delete': + state.deletingStatus = status; + break; + case 'add': + state.addingStatus = status; + break; + case 'lock': + state.updatingStatus = status; + break; + case 'download': + state.updatingStatus = status; + break; + case 'usageMetrics': + state.usageStatus = status; + break; + default: + break; + } }, deleteAssetSuccess: (state, { payload }) => { state.assetIds = state.assetIds.filter(id => id !== payload.assetId); @@ -48,19 +60,21 @@ const slice = createSlice({ const currentErrorState = state.errors[error]; state.errors[error] = [...currentErrorState, message]; }, + clearErrors: (state, { payload }) => { + const { error } = payload; + state.errors[error] = []; + }, }, }); export const { setAssetIds, - setTotalCount, updateLoadingStatus, - updateSavingStatus, deleteAssetSuccess, - updateDeletingStatus, addAssetSuccess, - updateAddingStatus, updateErrors, + clearErrors, + updateEditStatus, } = slice.actions; export const { diff --git a/src/files-and-videos/files-page/data/thunks.js b/src/files-and-videos/files-page/data/thunks.js new file mode 100644 index 0000000000..490520431b --- /dev/null +++ b/src/files-and-videos/files-page/data/thunks.js @@ -0,0 +1,163 @@ +import { isEmpty } from 'lodash'; +import { RequestStatus } from '../../../data/constants'; +import { + addModel, + addModels, + removeModel, + updateModel, +} from '../../../generic/model-store'; +import { + getAssets, + getAssetUsagePaths, + addAsset, + deleteAsset, + updateLockStatus, + getDownload, +} from './api'; +import { + setAssetIds, + updateLoadingStatus, + deleteAssetSuccess, + addAssetSuccess, + updateErrors, + clearErrors, + updateEditStatus, +} from './slice'; + +import { updateFileValues } from './utils'; + +export function fetchAssets(courseId) { + return async (dispatch) => { + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.IN_PROGRESS })); + + try { + const { totalCount } = await getAssets(courseId); + const { assets } = await getAssets(courseId, totalCount); + const parsedAssests = updateFileValues(assets); + dispatch(addModels({ modelType: 'assets', models: parsedAssests })); + dispatch(setAssetIds({ + assetIds: assets.map(asset => asset.id), + })); + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.SUCCESSFUL })); + } catch (error) { + if (error.response && error.response.status === 403) { + dispatch(updateLoadingStatus({ status: RequestStatus.DENIED })); + } else { + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.FAILED })); + } + } + }; +} + +export function updateAssetOrder(courseId, assetIds) { + return async (dispatch) => { + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.IN_PROGRESS })); + dispatch(setAssetIds({ assetIds })); + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.SUCCESSFUL })); + }; +} + +export function deleteAssetFile(courseId, id) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'delete', status: RequestStatus.IN_PROGRESS })); + + try { + await deleteAsset(courseId, id); + dispatch(deleteAssetSuccess({ assetId: id })); + dispatch(removeModel({ modelType: 'assets', id })); + dispatch(updateEditStatus({ editType: 'delete', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'delete', message: `Failed to delete file id ${id}.` })); + dispatch(updateEditStatus({ editType: 'delete', status: RequestStatus.FAILED })); + } + }; +} + +export function addAssetFile(courseId, file) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.IN_PROGRESS })); + + try { + const { asset } = await addAsset(courseId, file); + const [parsedAssest] = updateFileValues([asset]); + dispatch(addModel({ + modelType: 'assets', + model: { ...parsedAssest }, + })); + dispatch(addAssetSuccess({ + assetId: asset.id, + })); + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + if (error.response && error.response.status === 413) { + const message = error.response.data.error; + dispatch(updateErrors({ error: 'add', message })); + } else { + dispatch(updateErrors({ error: 'add', message: `Failed to add ${file.name}.` })); + } + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.FAILED })); + } + }; +} + +export function updateAssetLock({ assetId, courseId, locked }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'lock', status: RequestStatus.IN_PROGRESS })); + + try { + await updateLockStatus({ assetId, courseId, locked }); + dispatch(updateModel({ + modelType: 'assets', + model: { + id: assetId, + locked, + }, + })); + dispatch(updateEditStatus({ editType: 'lock', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + const lockStatus = locked ? 'lock' : 'unlock'; + dispatch(updateErrors({ error: 'lock', message: `Failed to ${lockStatus} file id ${assetId}.` })); + dispatch(updateEditStatus({ editType: 'lock', status: RequestStatus.FAILED })); + } + }; +} + +export function resetErrors({ errorType }) { + return (dispatch) => { dispatch(clearErrors({ error: errorType })); }; +} + +export function getUsagePaths({ asset, courseId }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'usageMetrics', status: RequestStatus.IN_PROGRESS })); + + try { + const { usageLocations } = await getAssetUsagePaths({ assetId: asset.id, courseId }); + dispatch(updateModel({ + modelType: 'assets', + model: { + id: asset.id, + usageLocations, + }, + })); + dispatch(updateEditStatus({ editType: 'usageMetrics', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'usageMetrics', message: `Failed to get usage metrics for ${asset.displayName}.` })); + dispatch(updateEditStatus({ editType: 'usageMetrics', status: RequestStatus.FAILED })); + } + }; +} + +export function fetchAssetDownload({ selectedRows, courseId }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'download', status: RequestStatus.IN_PROGRESS })); + const errors = await getDownload(selectedRows, courseId); + if (isEmpty(errors)) { + dispatch(updateEditStatus({ editType: 'download', status: RequestStatus.SUCCESSFUL })); + } else { + errors.forEach(error => { + dispatch(updateErrors({ error: 'download', message: error })); + }); + dispatch(updateEditStatus({ editType: 'download', status: RequestStatus.FAILED })); + } + }; +} diff --git a/src/files-and-videos/files-page/data/utils.js b/src/files-and-videos/files-page/data/utils.js new file mode 100644 index 0000000000..71c73057dc --- /dev/null +++ b/src/files-and-videos/files-page/data/utils.js @@ -0,0 +1,56 @@ +import { + InsertDriveFile, + Terminal, + AudioFile, +} from '@edx/paragon/icons'; +import { ensureConfig, getConfig } from '@edx/frontend-platform'; +import FILES_AND_UPLOAD_TYPE_FILTERS from '../../generic/constants'; + +ensureConfig([ + 'STUDIO_BASE_URL', +], 'Course Apps API service'); + +export const updateFileValues = (files) => { + const updatedFiles = []; + files.forEach(file => { + let wrapperType = 'other'; + if (FILES_AND_UPLOAD_TYPE_FILTERS.images.includes(file.contentType)) { + wrapperType = 'image'; + } else if (FILES_AND_UPLOAD_TYPE_FILTERS.documents.includes(file.contentType)) { + wrapperType = 'document'; + } else if (FILES_AND_UPLOAD_TYPE_FILTERS.code.includes(file.contentType)) { + wrapperType = 'code'; + } else if (FILES_AND_UPLOAD_TYPE_FILTERS.audio.includes(file.contentType)) { + wrapperType = 'audio'; + } + + const { dateAdded } = file; + const utcDateString = dateAdded.replace(/\bat\b/g, ''); + const utcDateTime = new Date(utcDateString).toString(); + + updatedFiles.push({ + ...file, + wrapperType, + dateAdded: utcDateTime, + usageLocations: [], + }); + }); + + return updatedFiles; +}; + +export const getSrc = ({ thumbnail, wrapperType, externalUrl }) => { + if (thumbnail) { + return externalUrl || `${getConfig().STUDIO_BASE_URL}${thumbnail}`; + } + switch (wrapperType) { + case 'document': + return InsertDriveFile; + case 'code': + return Terminal; + case 'audio': + return AudioFile; + default: + return InsertDriveFile; + } +}; diff --git a/src/files-and-uploads/factories/mockApiResponses.jsx b/src/files-and-videos/files-page/factories/mockApiResponses.jsx similarity index 80% rename from src/files-and-uploads/factories/mockApiResponses.jsx rename to src/files-and-videos/files-page/factories/mockApiResponses.jsx index a71b60eeb0..e7df3d0e70 100644 --- a/src/files-and-uploads/factories/mockApiResponses.jsx +++ b/src/files-and-videos/files-page/factories/mockApiResponses.jsx @@ -1,4 +1,4 @@ -import { RequestStatus } from '../../data/constants'; +import { RequestStatus } from '../../../data/constants'; export const courseId = 'course-v1:edX+DemoX+Demo_Course'; @@ -10,13 +10,16 @@ export const initialState = { assets: { assetIds: ['mOckID1'], loadingStatus: 'successful', - savingStatus: '', + updatingStatus: '', deletingStatus: '', addingStatus: '', + usageStatus: '', errors: { - upload: [], + add: [], delete: [], lock: [], + download: [], + usageMetrics: [], }, }, models: { @@ -31,6 +34,7 @@ export const initialState = { wrapperType: 'document', dateAdded: '', thumbnail: null, + fileSize: 1234567, }, }, }, @@ -47,6 +51,17 @@ export const generateFetchAssetApiResponse = () => ({ contentType: 'image/png', dateAdded: '', thumbnail: '/asset', + fileSize: 123, + }, + { + id: 'mOckID5', + displayName: 'mOckID5', + locked: false, + externalUrl: 'static_tab_1', + portableUrl: '', + contentType: 'application/json', + dateAdded: 'Aug 13, 2023 at 22:08 UTC', + thumbnail: null, }, { id: 'mOckID3', @@ -55,8 +70,9 @@ export const generateFetchAssetApiResponse = () => ({ externalUrl: 'static_tab_1', portableUrl: '', contentType: 'application/pdf', - dateAdded: '', + dateAdded: 'Aug 17, 2023 at 22:08 UTC', thumbnail: null, + fileSize: 1234, }, { id: 'mOckID4', @@ -69,21 +85,22 @@ export const generateFetchAssetApiResponse = () => ({ thumbnail: null, }, { - id: 'mOckID5', - displayName: 'mOckID5', + id: 'mOckID6', + displayName: 'mOckID6', locked: false, externalUrl: 'static_tab_1', portableUrl: '', - contentType: 'application/json', + contentType: 'application/octet-stream', dateAdded: '', thumbnail: null, + fileSize: 0, }, { - id: 'mOckID6', + id: 'mOckID6-2', displayName: 'mOckID6', locked: false, externalUrl: 'static_tab_1', - portableUrl: '', + portableUrl: 'May 17, 2023 at 22:08 UTC', contentType: 'application/octet-stream', dateAdded: '', thumbnail: null, @@ -108,6 +125,7 @@ export const generateNewAssetApiResponse = () => ({ thumbnail: '/download.png', locked: false, id: 'mOckID2', + fileSize: 1234, }, }); diff --git a/src/files-and-videos/files-page/index.js b/src/files-and-videos/files-page/index.js new file mode 100644 index 0000000000..05939abc4b --- /dev/null +++ b/src/files-and-videos/files-page/index.js @@ -0,0 +1,5 @@ +import FilesPage from './FilesPage'; +import FileInfoModalSidebar from './FileInfoModalSidebar'; + +export default FilesPage; +export { FileInfoModalSidebar }; diff --git a/src/files-and-videos/files-page/messages.js b/src/files-and-videos/files-page/messages.js new file mode 100644 index 0000000000..b06b48d45d --- /dev/null +++ b/src/files-and-videos/files-page/messages.js @@ -0,0 +1,86 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + heading: { + id: 'course-authoring.files-and-uploads.heading', + defaultMessage: 'Files', + }, + thumbnailAltMessage: { + id: 'course-authoring.files-and-uploads.thumbnail.alt', + defaultMessage: '{displayName} file preview', + }, + copyStudioUrlTitle: { + id: 'course-authoring.files-and-uploads.file-info.copyStudioUrl.title', + defaultMessage: 'Copy Studio Url', + }, + copyWebUrlTitle: { + id: 'course-authoring.files-and-uploads.file-info.copyWebUrl.title', + defaultMessage: 'Copy Web Url', + }, + dateAddedTitle: { + id: 'course-authoring.files-and-uploads.file-info.dateAdded.title', + defaultMessage: 'Date added', + }, + fileSizeTitle: { + id: 'course-authoring.files-and-uploads.file-info.fileSize.title', + defaultMessage: 'File size', + }, + studioUrlTitle: { + id: 'course-authoring.files-and-uploads.file-info.studioUrl.title', + defaultMessage: 'Studio URL', + }, + webUrlTitle: { + id: 'course-authoring.files-and-uploads.file-info.webUrl.title', + defaultMessage: 'Web URL', + }, + lockFileTitle: { + id: 'course-authoring.files-and-uploads.file-info.lockFile.title', + defaultMessage: 'Lock file', + }, + lockFileTooltipContent: { + id: 'course-authoring.files-and-uploads.file-info.lockFile.tooltip.content', + defaultMessage: `By default, anyone can access a file you upload if + they know the web URL, even if they are not enrolled in your course. + You can prevent outside access to a file by locking the file. When + you lock a file, the web URL only allows learners who are enrolled + in your course and signed in to access the file.`, + }, + activeCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.activeCheckbox.label', + defaultMessage: 'Active', + }, + inactiveCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.inactiveCheckbox.label', + defaultMessage: 'Inactive', + }, + lockedCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.lockedCheckbox.label', + defaultMessage: 'Locked', + }, + publicCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.publicCheckbox.label', + defaultMessage: 'Public', + }, + codeCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.codeCheckbox.label', + defaultMessage: 'Code', + }, + imageCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.imageCheckbox.label', + defaultMessage: 'Images', + }, + documentCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.documentCheckbox.label', + defaultMessage: 'Documents', + }, + audioCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.audioCheckbox.label', + defaultMessage: 'Audio', + }, + otherCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.otherCheckbox.label', + defaultMessage: 'Other', + }, +}); + +export default messages; diff --git a/src/files-and-uploads/ApiStatusToast.jsx b/src/files-and-videos/generic/ApiStatusToast.jsx similarity index 89% rename from src/files-and-uploads/ApiStatusToast.jsx rename to src/files-and-videos/generic/ApiStatusToast.jsx index 4d997b7e05..ade1d2aa16 100644 --- a/src/files-and-uploads/ApiStatusToast.jsx +++ b/src/files-and-videos/generic/ApiStatusToast.jsx @@ -9,12 +9,12 @@ const ApiStatusToast = ({ selectedRowCount, isOpen, setClose, - setSelectedRowCount, + setSelectedRows, // injected intl, }) => { const handleClose = () => { - setSelectedRowCount(0); + setSelectedRows([]); setClose(); }; @@ -33,7 +33,7 @@ ApiStatusToast.propTypes = { selectedRowCount: PropTypes.number.isRequired, isOpen: PropTypes.bool.isRequired, setClose: PropTypes.func.isRequired, - setSelectedRowCount: PropTypes.func.isRequired, + setSelectedRows: PropTypes.func.isRequired, // injected intl: intlShape.isRequired, }; diff --git a/src/files-and-videos/generic/EditFileErrors.jsx b/src/files-and-videos/generic/EditFileErrors.jsx new file mode 100644 index 0000000000..d0de5db6da --- /dev/null +++ b/src/files-and-videos/generic/EditFileErrors.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { ErrorAlert } from '@edx/frontend-lib-content-components'; +import { RequestStatus } from '../../data/constants'; +import messages from './messages'; + +const EditFileErrors = ({ + resetErrors, + errorMessages, + addFileStatus, + deleteFileStatus, + updateFileStatus, + // injected + intl, +}) => ( + <> + resetErrors({ errorType: 'add' })} + isError={addFileStatus === RequestStatus.FAILED} + > +
      + {errorMessages.add.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} +
    +
    + resetErrors({ errorType: 'delete' })} + isError={deleteFileStatus === RequestStatus.FAILED} + > +
      + {errorMessages.delete.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} +
    +
    + resetErrors({ errorType: 'update' })} + isError={updateFileStatus === RequestStatus.FAILED} + > +
      + {errorMessages.lock?.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} + {errorMessages.download.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} + {errorMessages.thumbnail?.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} +
    +
    + +); + +EditFileErrors.propTypes = { + resetErrors: PropTypes.func.isRequired, + errorMessages: PropTypes.shape({ + add: PropTypes.arrayOf(PropTypes.string).isRequired, + delete: PropTypes.arrayOf(PropTypes.string).isRequired, + lock: PropTypes.arrayOf(PropTypes.string), + download: PropTypes.arrayOf(PropTypes.string).isRequired, + usageMetrics: PropTypes.arrayOf(PropTypes.string).isRequired, + thumbnail: PropTypes.arrayOf(PropTypes.string), + }).isRequired, + addFileStatus: PropTypes.string.isRequired, + deleteFileStatus: PropTypes.string.isRequired, + updateFileStatus: PropTypes.string.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(EditFileErrors); diff --git a/src/files-and-uploads/FileInput.jsx b/src/files-and-videos/generic/FileInput.jsx similarity index 61% rename from src/files-and-uploads/FileInput.jsx rename to src/files-and-videos/generic/FileInput.jsx index 9b0b8510d8..1de18b052a 100644 --- a/src/files-and-uploads/FileInput.jsx +++ b/src/files-and-videos/generic/FileInput.jsx @@ -1,17 +1,17 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { getSupportedFormats } from '../videos-page/data/utils'; -export const fileInput = ({ +export const useFileInput = ({ onAddFile, - setSelectedRowCount, + setSelectedRows, setAddOpen, }) => { - // eslint-disable-next-line react-hooks/rules-of-hooks const ref = React.useRef(); const click = () => ref.current.click(); const addFile = (e) => { const { files } = e.target; - setSelectedRowCount(files.length); + setSelectedRows(files); Object.values(files).forEach(file => { onAddFile(file); setAddOpen(); @@ -24,14 +24,15 @@ export const fileInput = ({ }; }; -const FileInput = ({ fileInput: hook }) => ( +const FileInput = ({ fileInput: hook, supportedFileFormats, allowMultiple }) => ( ); @@ -45,6 +46,16 @@ FileInput.propTypes = { PropTypes.shape({ current: PropTypes.instanceOf(Element) }), ]), }).isRequired, + supportedFileFormats: PropTypes.oneOfType([ + PropTypes.shape({}), + PropTypes.arrayOf(PropTypes.string), + ]), + allowMultiple: PropTypes.bool, +}; + +FileInput.defaultProps = { + supportedFileFormats: null, + allowMultiple: true, }; export default FileInput; diff --git a/src/files-and-videos/generic/FileMenu.jsx b/src/files-and-videos/generic/FileMenu.jsx new file mode 100644 index 0000000000..8a84511cdd --- /dev/null +++ b/src/files-and-videos/generic/FileMenu.jsx @@ -0,0 +1,96 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + Dropdown, + IconButton, + Icon, +} from '@edx/paragon'; +import { MoreHoriz } from '@edx/paragon/icons'; +import messages from './messages'; + +const FileMenu = ({ + externalUrl, + handleLock, + locked, + onDownload, + openAssetInfo, + openDeleteConfirmation, + portableUrl, + id, + wrapperType, + // injected + intl, +}) => ( + + + + {wrapperType === 'video' ? ( + navigator.clipboard.writeText(id)} + > + Copy video ID + + ) : ( + <> + navigator.clipboard.writeText(portableUrl)} + > + {intl.formatMessage(messages.copyStudioUrlTitle)} + + navigator.clipboard.writeText(externalUrl)} + > + {intl.formatMessage(messages.copyWebUrlTitle)} + + + {locked ? intl.formatMessage(messages.unlockMenuTitle) : intl.formatMessage(messages.lockMenuTitle)} + + + )} + + {intl.formatMessage(messages.downloadTitle)} + + + {intl.formatMessage(messages.infoTitle)} + + + + {intl.formatMessage(messages.deleteTitle)} + + + +); + +FileMenu.propTypes = { + externalUrl: PropTypes.string, + handleLock: PropTypes.func, + locked: PropTypes.bool, + onDownload: PropTypes.func.isRequired, + openAssetInfo: PropTypes.func.isRequired, + openDeleteConfirmation: PropTypes.func.isRequired, + portableUrl: PropTypes.string, + id: PropTypes.string.isRequired, + wrapperType: PropTypes.string.isRequired, + // injected + intl: intlShape.isRequired, +}; + +FileMenu.defaultProps = { + externalUrl: null, + handleLock: null, + locked: null, + portableUrl: null, +}; + +export default injectIntl(FileMenu); diff --git a/src/files-and-videos/generic/FileTable.jsx b/src/files-and-videos/generic/FileTable.jsx new file mode 100644 index 0000000000..9ad2a00871 --- /dev/null +++ b/src/files-and-videos/generic/FileTable.jsx @@ -0,0 +1,304 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import isEmpty from 'lodash/isEmpty'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + DataTable, + TextFilter, + Dropzone, + CardView, + useToggle, + AlertModal, + ActionRow, + Button, +} from '@edx/paragon'; + +import { RequestStatus } from '../../data/constants'; +import { sortFiles } from './utils'; +import messages from './messages'; + +import InfoModal from './InfoModal'; +import FileInput, { useFileInput } from './FileInput'; +import { + GalleryCard, + TableActions, + RowStatus, + MoreInfoColumn, + FilterStatus, +} from './table-components'; +import ApiStatusToast from './ApiStatusToast'; + +const FileTable = ({ + files, + data, + handleAddFile, + handleLockFile, + handleDeleteFile, + handleDownloadFile, + handleUsagePaths, + handleErrorReset, + handleFileOrder, + tableColumns, + maxFileSize, + thumbnailPreview, + infoModalSidebar, + // injected + intl, +}) => { + const defaultVal = 'card'; + const pageCount = Math.ceil(files.length / 50); + const columnSizes = { + xs: 12, + sm: 6, + md: 4, + lg: 2, + }; + const [currentView, setCurrentView] = useState(defaultVal); + const [isDeleteOpen, setDeleteOpen, setDeleteClose] = useToggle(false); + const [isAssetInfoOpen, openAssetInfo, closeAssetinfo] = useToggle(false); + const [isAddOpen, setAddOpen, setAddClose] = useToggle(false); + const [selectedRows, setSelectedRows] = useState([]); + const [isDeleteConfirmationOpen, openDeleteConfirmation, closeDeleteConfirmation] = useToggle(false); + + const { + loadingStatus, + usagePathStatus, + usageErrorMessages, + encodingsDownloadUrl, + supportedFileFormats, + } = data; + + useEffect(() => { + if (!isEmpty(selectedRows) && Object.keys(selectedRows[0]).length > 0) { + const updatedRows = []; + selectedRows.forEach(row => { + const currentFile = row.original; + if (currentFile) { + const [updatedFile] = files.filter(file => file.id === currentFile?.id); + updatedRows.push({ original: updatedFile }); + } + }); + setSelectedRows(updatedRows); + } + }, [files]); + + const fileInputControl = useFileInput({ + onAddFile: (file) => handleAddFile(file), + setSelectedRows, + setAddOpen, + }); + const handleDropzoneAsset = ({ fileData, handleError }) => { + try { + const file = fileData.get('file'); + handleAddFile(file); + } catch (error) { + handleError(error); + } + }; + + const handleSort = (sortType) => { + const newFileIdOrder = sortFiles(files, sortType); + handleFileOrder({ newFileIdOrder, sortType }); + }; + + const handleBulkDelete = () => { + closeDeleteConfirmation(); + setDeleteOpen(); + handleErrorReset({ errorType: 'delete' }); + const fileIdsToDelete = selectedRows.map(row => row.original.id); + fileIdsToDelete.forEach(id => handleDeleteFile(id)); + }; + + const handleBulkDownload = useCallback(async (selectedFlatRows) => { + handleErrorReset({ errorType: 'download' }); + handleDownloadFile(selectedFlatRows); + }, []); + + const handleOpenDeleteConfirmation = (selectedFlatRows) => { + setSelectedRows(selectedFlatRows); + openDeleteConfirmation(); + }; + + const handleOpenFileInfo = (original) => { + handleErrorReset({ errorType: 'usageMetrics' }); + setSelectedRows([{ original }]); + handleUsagePaths(original); + openAssetInfo(); + }; + + const headerActions = ({ selectedFlatRows }) => ( + + ); + + const fileCard = ({ className, original }) => ( + + ); + + const moreInfoColumn = { + id: 'moreInfo', + Header: '', + Cell: ({ row }) => MoreInfoColumn({ + row, + handleLock: handleLockFile, + handleBulkDownload, + handleOpenFileInfo, + handleOpenDeleteConfirmation, + }), + }; + + const hasMoreInfoColumn = tableColumns.filter(col => col.id === 'moreInfo').length === 1; + if (!hasMoreInfoColumn) { + tableColumns.push({ ...moreInfoColumn }); + } + + return ( +
    + setCurrentView(val), + defaultActiveStateValue: defaultVal, + togglePlacement: 'left', + }} + initialState={{ + pageSize: 50, + }} + tableActions={headerActions} + bulkActions={headerActions} + columns={tableColumns} + itemCount={files.length} + pageCount={pageCount} + data={files} + FilterStatusComponent={FilterStatus} + RowStatusComponent={RowStatus} + > + {isEmpty(files) && loadingStatus !== RequestStatus.IN_PROGRESS ? ( + + ) : ( +
    + + { currentView === 'card' && } + { currentView === 'list' && } + + +
    + )} + + + +
    + + {!isEmpty(selectedRows) && ( + + )} + + + + + )} + > + {intl.formatMessage(messages.deleteConfirmationMessage, { fileNumber: selectedRows.length })} + +
    + ); +}; + +FileTable.propTypes = { + courseId: PropTypes.string.isRequired, + files: PropTypes.arrayOf(PropTypes.shape({})), + data: PropTypes.shape({ + fileIds: PropTypes.arrayOf(PropTypes.string).isRequired, + loadingStatus: PropTypes.string.isRequired, + usagePathStatus: PropTypes.string.isRequired, + usageErrorMessages: PropTypes.arrayOf(PropTypes.string).isRequired, + encodingsDownloadUrl: PropTypes.string, + supportedFileFormats: PropTypes.shape({}), + }).isRequired, + handleAddFile: PropTypes.func.isRequired, + handleDeleteFile: PropTypes.func.isRequired, + handleDownloadFile: PropTypes.func.isRequired, + handleUsagePaths: PropTypes.func.isRequired, + handleLockFile: PropTypes.func, + handleErrorReset: PropTypes.func.isRequired, + handleFileOrder: PropTypes.func.isRequired, + tableColumns: PropTypes.arrayOf(PropTypes.shape({ + Header: PropTypes.string, + accessor: PropTypes.string, + })).isRequired, + maxFileSize: PropTypes.number.isRequired, + thumbnailPreview: PropTypes.func.isRequired, + infoModalSidebar: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, +}; + +FileTable.defaultProps = { + files: null, + handleLockFile: () => {}, +}; + +export default injectIntl(FileTable); diff --git a/src/files-and-videos/generic/InfoModal.jsx b/src/files-and-videos/generic/InfoModal.jsx new file mode 100644 index 0000000000..fd91506c37 --- /dev/null +++ b/src/files-and-videos/generic/InfoModal.jsx @@ -0,0 +1,96 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { + injectIntl, + FormattedMessage, +} from '@edx/frontend-platform/i18n'; +import { + ModalDialog, + Truncate, +} from '@edx/paragon'; + +import messages from './messages'; +import UsageMetricsMessages from './UsageMetricsMessage'; +import FileThumbnail from './ThumbnailPreview'; + +const InfoModal = ({ + file, + isOpen, + onClose, + thumbnailPreview, + usagePathStatus, + error, + sidebar, +}) => ( + + + +
    + + {file?.displayName} + +
    +
    +
    + +
    +
    +
    + +
    +
    + {sidebar(file)} +
    +
    +
    + +
    + +
    +
    +); + +InfoModal.propTypes = { + file: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + wrapperType: PropTypes.string.isRequired, + locked: PropTypes.bool, + externalUrl: PropTypes.string, + thumbnail: PropTypes.string, + id: PropTypes.string.isRequired, + portableUrl: PropTypes.string, + dateAdded: PropTypes.string.isRequired, + fileSize: PropTypes.number.isRequired, + usageLocations: PropTypes.arrayOf(PropTypes.string), + status: PropTypes.string, + }), + onClose: PropTypes.func.isRequired, + isOpen: PropTypes.bool.isRequired, + usagePathStatus: PropTypes.string.isRequired, + error: PropTypes.arrayOf(PropTypes.string).isRequired, + thumbnailPreview: PropTypes.func.isRequired, + sidebar: PropTypes.func.isRequired, +}; + +InfoModal.defaultProps = { + file: null, +}; + +export default injectIntl(InfoModal); diff --git a/src/files-and-videos/generic/ThumbnailPreview.jsx b/src/files-and-videos/generic/ThumbnailPreview.jsx new file mode 100644 index 0000000000..57461a2784 --- /dev/null +++ b/src/files-and-videos/generic/ThumbnailPreview.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const ThumbnailPreview = ({ + thumbnail, + wrapperType, + externalUrl, + displayName, + imageSize, + id, + status, + thumbnailPreview, +}) => ( + <> + {thumbnailPreview({ + thumbnail, + wrapperType, + externalUrl, + displayName, + imageSize, + id, + status, + })} + +); +ThumbnailPreview.defaultProps = { + thumbnail: null, + wrapperType: null, + externalUrl: null, + displayName: null, + id: null, + status: null, +}; +ThumbnailPreview.propTypes = { + thumbnail: PropTypes.string, + wrapperType: PropTypes.string, + externalUrl: PropTypes.string, + displayName: PropTypes.string, + id: PropTypes.string, + status: PropTypes.string, + thumbnailPreview: PropTypes.func.isRequired, + imageSize: PropTypes.shape({ + height: PropTypes.string.isRequired, + width: PropTypes.string.isRequired, + }).isRequired, +}; + +export default ThumbnailPreview; diff --git a/src/files-and-videos/generic/UsageMetricsMessage.jsx b/src/files-and-videos/generic/UsageMetricsMessage.jsx new file mode 100644 index 0000000000..84354dcd70 --- /dev/null +++ b/src/files-and-videos/generic/UsageMetricsMessage.jsx @@ -0,0 +1,64 @@ +import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n'; +import PropTypes from 'prop-types'; +import { Icon, Row, Spinner } from '@edx/paragon'; +import { ErrorOutline } from '@edx/paragon/icons'; +import isEmpty from 'lodash/isEmpty'; +import { RequestStatus } from '../../data/constants'; +import messages from './messages'; + +const UsageMetricsMessage = ({ + usagePathStatus, + usageLocations, + error, + // injected + intl, +}) => { + let usageMessage; + if (usagePathStatus === RequestStatus.SUCCESSFUL) { + usageMessage = isEmpty(usageLocations) ? ( + + ) : ( +
      + {usageLocations.map(location => ( +
    • + {location} +
    • + ))} +
    + ); + } else if (usagePathStatus === RequestStatus.FAILED) { + usageMessage = ( + + + {intl.formatMessage(messages.errorAlertMessage, { message: error })} + + ); + } else { + usageMessage = ( + <> + + + + ); + } + return usageMessage; +}; + +UsageMetricsMessage.propTypes = { + usagePathStatus: PropTypes.string.isRequired, + usageLocations: PropTypes.arrayOf(PropTypes.string).isRequired, + error: PropTypes.arrayOf(PropTypes.string).isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(UsageMetricsMessage); diff --git a/src/files-and-uploads/data/constant.js b/src/files-and-videos/generic/constants.js similarity index 98% rename from src/files-and-uploads/data/constant.js rename to src/files-and-videos/generic/constants.js index 9fe5121f37..95a95e8f1f 100644 --- a/src/files-and-uploads/data/constant.js +++ b/src/files-and-videos/generic/constants.js @@ -33,6 +33,7 @@ const FILES_AND_UPLOAD_TYPE_FILTERS = { 'application/java-vm', 'text/x-c++src', 'text/xml', 'text/x-scss', 'application/x-python-code', 'application/java-archive', 'text/x-python-script', 'application/x-ruby', 'application/mathematica', 'text/coffeescript', 'text/x-matlab', 'application/sql', 'text/php'], + video: ['.mp4', '.mov'], }; export default FILES_AND_UPLOAD_TYPE_FILTERS; diff --git a/src/files-and-videos/generic/index.js b/src/files-and-videos/generic/index.js new file mode 100644 index 0000000000..0449cc8705 --- /dev/null +++ b/src/files-and-videos/generic/index.js @@ -0,0 +1,24 @@ +import { + TableActions, + GalleryCard, + AccessColumn, + ActiveColumn, + MoreInfoColumn, + StatusColumn, + ThumbnailColumn, +} from './table-components'; +import FileInput, { useFileInput } from './FileInput'; + +export { + TableActions, + GalleryCard, + AccessColumn, + ActiveColumn, + MoreInfoColumn, + StatusColumn, + ThumbnailColumn, + FileInput, + useFileInput, +}; +export { default as FileTable } from './FileTable'; +export { default as EditFileErrors } from './EditFileErrors'; diff --git a/src/files-and-videos/generic/messages.js b/src/files-and-videos/generic/messages.js new file mode 100644 index 0000000000..c7340d3bc1 --- /dev/null +++ b/src/files-and-videos/generic/messages.js @@ -0,0 +1,138 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + rowStatusMessage: { + id: 'course-authoring.files-and-upload.rowStatus.message', + defaultMessage: 'Showing {fileCount} of {rowCount}', + }, + apiStatusToastMessage: { + id: 'course-authoring.files-and-upload.apiStatus.message', + defaultMessage: '{actionType} {selectedRowCount} file(s)', + }, + apiStatusAddingAction: { + id: 'course-authoring.files-and-upload.apiStatus.addingAction.message', + defaultMessage: 'Adding', + }, + apiStatusDeletingAction: { + id: 'course-authoring.files-and-upload.apiStatus.deletingAction.message', + defaultMessage: 'Deleting', + }, + fileSizeError: { + id: 'course-authoring.files-and-upload.addFiles.error.fileSize', + defaultMessage: 'Uploaded file(s) must be 20 MB or less. Please resize file(s) and try again.', + }, + noResultsFoundMessage: { + id: 'course-authoring.files-and-upload.table.noResultsFound.message', + defaultMessage: 'No results found', + }, + addFilesButtonLabel: { + id: 'course-authoring.files-and-upload.addFiles.button.label', + defaultMessage: 'Add files', + }, + actionsButtonLabel: { + id: 'course-authoring.files-and-upload.action.button.label', + defaultMessage: 'Actions', + }, + errorAlertMessage: { + id: 'course-authoring.files-and-upload.errorAlert.message', + defaultMessage: '{message}', + }, + usageTitle: { + id: 'course-authoring.files-and-uploads.file-info.usage.title', + defaultMessage: 'Usage', + }, + usageLoadingMessage: { + id: 'course-authoring.files-and-uploads.file-info.usage.loading.message', + defaultMessage: 'Loading', + }, + usageNotInUseMessage: { + id: 'course-authoring.files-and-uploads.file-info.usage.notInUse.message', + defaultMessage: 'Currently not in use', + }, + copyStudioUrlTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.copyStudioUrlTitle', + defaultMessage: 'Copy Studio Url', + }, + copyWebUrlTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.copyWebUrlTitle', + defaultMessage: 'Copy Web Url', + }, + downloadTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.downloadTitle', + defaultMessage: 'Download', + }, + lockMenuTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.lockTitle', + defaultMessage: 'Lock', + }, + unlockMenuTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.unlockTitle', + defaultMessage: 'Unlock', + }, + infoTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.infoTitle', + defaultMessage: 'Info', + }, + downloadEncodingsTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.downloadEncodingsTitle', + defaultMessage: 'Download video list (.csv)', + }, + deleteTitle: { + id: 'course-authoring.files-and-uploads.cardMenu.deleteTitle', + defaultMessage: 'Delete', + }, + deleteConfirmationTitle: { + id: 'course-authoring.files-and-uploads..deleteConfirmation.title', + defaultMessage: 'Delete File(s) Confirmation', + }, + deleteConfirmationMessage: { + id: 'course-authoring.files-and-uploads..deleteConfirmation.message', + defaultMessage: 'Are you sure you want to delete {fileNumber} file(s)? This action cannot be undone.', + }, + deleteFileButtonLabel: { + id: 'course-authoring.files-and-uploads.deleteConfirmation.deleteFile.label', + defaultMessage: 'Delete', + }, + cancelButtonLabel: { + id: 'course-authoring.files-and-uploads.cancelButton.label', + defaultMessage: 'Cancel', + }, + sortButtonLabel: { + id: 'course-authoring.files-and-uploads.sortButton.label', + defaultMessage: 'Sort and Filter', + }, + sortModalTitleLabel: { + id: 'course-authoring.files-and-uploads.sortModal.title', + defaultMessage: 'Sort by', + }, + sortByNameAscending: { + id: 'course-authoring.files-and-uploads.sortByNameAscendingButton.label', + defaultMessage: 'Name (A-Z)', + }, + sortByNewest: { + id: 'course-authoring.files-and-uploads.sortByNewestButton.label', + defaultMessage: 'Newest', + }, + sortBySizeDescending: { + id: 'course-authoring.files-and-uploads.sortBySizeDescendingButton.label', + defaultMessage: 'File size (High to low)', + }, + sortByNameDescending: { + id: 'course-authoring.files-and-uploads.sortByNameDescendingButton.label', + defaultMessage: 'Name (Z-A)', + }, + sortByOldest: { + id: 'course-authoring.files-and-uploads.sortByOldestButton.label', + defaultMessage: 'Oldest', + }, + sortBySizeAscending: { + id: 'course-authoring.files-and-uploads.sortBySizeAscendingButton.label', + defaultMessage: 'File size(Low to high)', + }, + applySortButton: { + id: 'course-authoring.files-and-uploads.applyySortButton.label', + defaultMessage: 'Apply', + }, +}); + +export default messages; diff --git a/src/files-and-videos/generic/table-components/FilterStatus.jsx b/src/files-and-videos/generic/table-components/FilterStatus.jsx new file mode 100644 index 0000000000..9c8f5e7c56 --- /dev/null +++ b/src/files-and-videos/generic/table-components/FilterStatus.jsx @@ -0,0 +1,79 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { + DataTableContext, Button, Row, Chip, +} from '@edx/paragon'; +import { Close } from '@edx/paragon/icons'; +import { getFilters, removeFilter } from './utils'; + +const FilterStatus = ({ + className, variant, size, clearFiltersText, buttonClassName, +}) => { + const { + state, setAllFilters, setFilter, RowStatusComponent, columns, + } = useContext(DataTableContext); + + if (!setAllFilters) { + return null; + } + + const filters = getFilters(state, columns); + + return ( +
    + + + Filters applied + {filters.map(({ name, value }) => ( + removeFilter(value, setFilter, setAllFilters, state)} + > + {name} + + ))} + + +
    + ); +}; + +FilterStatus.defaultProps = { + /** Specifies class name to append to the base element. */ + className: null, + /** Specifies class name to append to the button. */ + buttonClassName: 'pgn__smart-status-button', + /** The visual style of the `FilterStatus`. */ + variant: 'link', + /** The size of the `FilterStatus`. */ + size: 'inline', + /** A text that appears on the `Clear filters` button, defaults to 'Clear filters'. */ + clearFiltersText: undefined, +}; + +FilterStatus.propTypes = { + className: PropTypes.string, + buttonClassName: PropTypes.string, + variant: PropTypes.string, + size: PropTypes.string, + clearFiltersText: PropTypes.oneOfType([PropTypes.element, PropTypes.string]), +}; + +export default FilterStatus; diff --git a/src/files-and-videos/generic/table-components/GalleryCard.jsx b/src/files-and-videos/generic/table-components/GalleryCard.jsx new file mode 100644 index 0000000000..0ad792464a --- /dev/null +++ b/src/files-and-videos/generic/table-components/GalleryCard.jsx @@ -0,0 +1,108 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + ActionRow, + Icon, + Card, + Chip, + Truncate, +} from '@edx/paragon'; +import { ClosedCaption } from '@edx/paragon/icons'; +import FileMenu from '../FileMenu'; +import FileThumbnail from '../ThumbnailPreview'; + +const GalleryCard = ({ + className, + original, + handleBulkDownload, + handleLockFile, + handleOpenDeleteConfirmation, + handleOpenFileInfo, + thumbnailPreview, +}) => { + const lockFile = () => { + const { locked, id } = original; + handleLockFile(id, !locked); + }; + + return ( + + + handleOpenFileInfo(original)} + portableUrl={original.portableUrl} + id={original.id} + wrapperType={original.wrapperType} + onDownload={() => handleBulkDownload([{ + original: { + id: original.id, + displayName: + original.displayName, + downloadLink: original?.downloadLink, + }, + }])} + openDeleteConfirmation={() => handleOpenDeleteConfirmation([{ original }])} + /> + + )} + /> + +
    + +
    +
    + + {original.displayName} + +
    +
    + + + {original.wrapperType} + + {original.transcripts?.length > 0 && } + +
    + ); +}; + +GalleryCard.defaultProps = { + className: null, +}; +GalleryCard.propTypes = { + className: PropTypes.string, + original: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + wrapperType: PropTypes.string.isRequired, + locked: PropTypes.bool, + externalUrl: PropTypes.string, + thumbnail: PropTypes.string, + id: PropTypes.string.isRequired, + portableUrl: PropTypes.string, + status: PropTypes.string, + transcripts: PropTypes.arrayOf(PropTypes.string), + downloadLink: PropTypes.string, + }).isRequired, + handleBulkDownload: PropTypes.func.isRequired, + handleLockFile: PropTypes.func.isRequired, + handleOpenDeleteConfirmation: PropTypes.func.isRequired, + handleOpenFileInfo: PropTypes.func.isRequired, + thumbnailPreview: PropTypes.func.isRequired, +}; + +export default GalleryCard; diff --git a/src/files-and-videos/generic/table-components/GalleryCard.scss b/src/files-and-videos/generic/table-components/GalleryCard.scss new file mode 100644 index 0000000000..318659b799 --- /dev/null +++ b/src/files-and-videos/generic/table-components/GalleryCard.scss @@ -0,0 +1,23 @@ +.gallery-card { + .thumbnail-container { + aspect-ratio: 16 / 9; + + .thumbnail-image { + width: 100%; + height: 100%; + object-fit: contain; + } + } + + &.pgn__card { + .pgn__card-header { + .pgn__card-header-actions { + margin-top: 0; + } + } + } + + .picture-title { + font-size: 12px; + } +} diff --git a/src/files-and-videos/generic/table-components/RowStatus.jsx b/src/files-and-videos/generic/table-components/RowStatus.jsx new file mode 100644 index 0000000000..0733e87573 --- /dev/null +++ b/src/files-and-videos/generic/table-components/RowStatus.jsx @@ -0,0 +1,30 @@ +import React, { useContext } from 'react'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { DataTableContext } from '@edx/paragon'; +import { getCurrentViewRange } from './utils'; + +const RowStatus = ({ + // injected + intl, +}) => { + const { filteredRows, page, initialRows } = useContext(DataTableContext); + + return ( +
    + + {getCurrentViewRange({ + filterRowCount: filteredRows.length, + initialRowCount: initialRows.length, + fileCount: page.length, + intl, + })} + +
    + ); +}; + +RowStatus.propTypes = { + intl: intlShape.isRequired, +}; + +export default injectIntl(RowStatus); diff --git a/src/files-and-videos/generic/table-components/TableActions.jsx b/src/files-and-videos/generic/table-components/TableActions.jsx new file mode 100644 index 0000000000..d36f0606c8 --- /dev/null +++ b/src/files-and-videos/generic/table-components/TableActions.jsx @@ -0,0 +1,100 @@ +import React from 'react'; +import _ from 'lodash'; +import { PropTypes } from 'prop-types'; +import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { getConfig } from '@edx/frontend-platform'; +import { + Button, + Dropdown, + useToggle, +} from '@edx/paragon'; +import { Add, Tune } from '@edx/paragon/icons'; +import messages from '../messages'; +import SortAndFilterModal from './sort-and-filter-modal'; + +const TableActions = ({ + selectedFlatRows, + fileInputControl, + handleSort, + handleBulkDownload, + handleOpenDeleteConfirmation, + encodingsDownloadUrl, +}) => { + const [isSortOpen, openSort, closeSort] = useToggle(false); + return ( + <> + + + + + + + {encodingsDownloadUrl ? ( + + + + ) : null} + handleBulkDownload(selectedFlatRows)} + disabled={_.isEmpty(selectedFlatRows)} + > + + + + handleOpenDeleteConfirmation(selectedFlatRows)} + disabled={_.isEmpty(selectedFlatRows)} + > + + + + + + + + ); +}; + +TableActions.defaultProps = { + selectedFlatRows: null, +}; +TableActions.propTypes = { + selectedFlatRows: PropTypes.arrayOf( + PropTypes.shape({ + original: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + wrapperType: PropTypes.string.isRequired, + locked: PropTypes.bool, + externalUrl: PropTypes.string, + thumbnail: PropTypes.string, + id: PropTypes.string.isRequired, + portableUrl: PropTypes.string, + }).isRequired, + }), + ), + fileInputControl: PropTypes.shape({ + click: PropTypes.func.isRequired, + }).isRequired, + handleOpenDeleteConfirmation: PropTypes.func.isRequired, + handleBulkDownload: PropTypes.func.isRequired, + encodingsDownloadUrl: PropTypes.string, + handleSort: PropTypes.func.isRequired, +}; + +TableActions.defaultProps = { + encodingsDownloadUrl: null, +}; + +export default injectIntl(TableActions); diff --git a/src/files-and-videos/generic/table-components/index.js b/src/files-and-videos/generic/table-components/index.js new file mode 100644 index 0000000000..f81bce1cce --- /dev/null +++ b/src/files-and-videos/generic/table-components/index.js @@ -0,0 +1,23 @@ +import GalleryCard from './GalleryCard'; +import TableActions from './TableActions'; +import FilterStatus from './FilterStatus'; +import RowStatus from './RowStatus'; +import { + AccessColumn, + ActiveColumn, + MoreInfoColumn, + StatusColumn, + ThumbnailColumn, +} from './table-custom-columns'; + +export { + TableActions, + GalleryCard, + FilterStatus, + RowStatus, + AccessColumn, + ActiveColumn, + MoreInfoColumn, + StatusColumn, + ThumbnailColumn, +}; diff --git a/src/files-and-videos/generic/table-components/sort-and-filter-modal/SortAndFilterModal.jsx b/src/files-and-videos/generic/table-components/sort-and-filter-modal/SortAndFilterModal.jsx new file mode 100644 index 0000000000..1249a8373e --- /dev/null +++ b/src/files-and-videos/generic/table-components/sort-and-filter-modal/SortAndFilterModal.jsx @@ -0,0 +1,180 @@ +import React, { useContext, useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { + ActionRow, + Button, + DataTableContext, + Form, + ModalDialog, + SelectableBox, + useCheckboxSetValues, +} from '@edx/paragon'; +import messages from './messages'; +import { getCheckedFilters, getFilterOptions, processFilters } from './utils'; + +const SortAndFilterModal = ({ + isSortOpen, + closeSort, + handleSort, + // injected + intl, +}) => { + const { state, setAllFilters, columns } = useContext(DataTableContext); + const filterOptions = getFilterOptions(columns); + const currentFilters = getCheckedFilters(state); + const [sortBy, setSortBy] = useState('dateAdded,desc'); + const [filterBy, { + add, remove, set, clear, + }] = useCheckboxSetValues(currentFilters); + + useEffect(() => { + const updatedFilters = getCheckedFilters(state); + set(updatedFilters); + }, [state]); + + const handleChange = (e) => { + setSortBy(e.target.value); + }; + + const handleFilterUpdate = (e) => { + if (e.target.checked) { + add(e.target.value); + } else { + remove(e.target.value); + } + }; + + const handleApply = () => { + closeSort(); + handleSort(sortBy); + processFilters(filterBy, columns, setAllFilters); + }; + + const handleClearAll = () => { + setSortBy('dateAdded,desc'); + clear(); + }; + + return ( + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + + + {filterOptions.map(({ name, value }) => ( + {name} + ))} + + + +
    +
    + + + + + + + + +
    + ); +}; + +SortAndFilterModal.propTypes = { + handleSort: PropTypes.func.isRequired, + isSortOpen: PropTypes.bool.isRequired, + closeSort: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(SortAndFilterModal); diff --git a/src/files-and-videos/generic/table-components/sort-and-filter-modal/index.js b/src/files-and-videos/generic/table-components/sort-and-filter-modal/index.js new file mode 100644 index 0000000000..08166f3e06 --- /dev/null +++ b/src/files-and-videos/generic/table-components/sort-and-filter-modal/index.js @@ -0,0 +1,3 @@ +import SortAndFilterModal from './SortAndFilterModal'; + +export default SortAndFilterModal; diff --git a/src/files-and-videos/generic/table-components/sort-and-filter-modal/messages.js b/src/files-and-videos/generic/table-components/sort-and-filter-modal/messages.js new file mode 100644 index 0000000000..13165bde50 --- /dev/null +++ b/src/files-and-videos/generic/table-components/sort-and-filter-modal/messages.js @@ -0,0 +1,54 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + modalTitle: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.title', + defaultMessage: 'Sort and Filter', + }, + sortByHeader: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.sortBySection.header', + defaultMessage: 'Sort by', + }, + filterByHeader: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filterBySection.header', + defaultMessage: 'Filter by', + }, + clearAllButtonLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.clearAllButton.label', + defaultMessage: 'Clear all', + }, + cancelButtonLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.cancelButton.label', + defaultMessage: 'Cancel', + }, + sortByNameAscending: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByNameAscendingButton.label', + defaultMessage: 'Name (A-Z)', + }, + sortByNewest: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByNewestButton.label', + defaultMessage: 'Newest', + }, + sortBySizeDescending: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortBySizeDescendingButton.label', + defaultMessage: 'File size (High to low)', + }, + sortByNameDescending: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByNameDescendingButton.label', + defaultMessage: 'Name (Z-A)', + }, + sortByOldest: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortByOldestButton.label', + defaultMessage: 'Oldest', + }, + sortBySizeAscending: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.sortBySizeAscendingButton.label', + defaultMessage: 'File size (Low to high)', + }, + applySortButton: { + id: 'course-authoring..files-and-videos.sort-and-filter.modal.applyySortButton.label', + defaultMessage: 'Apply', + }, +}); + +export default messages; diff --git a/src/files-and-videos/generic/table-components/sort-and-filter-modal/utils.js b/src/files-and-videos/generic/table-components/sort-and-filter-modal/utils.js new file mode 100644 index 0000000000..149aed54ce --- /dev/null +++ b/src/files-and-videos/generic/table-components/sort-and-filter-modal/utils.js @@ -0,0 +1,128 @@ +import { isArray, isEmpty } from 'lodash'; + +export const getFilterOptions = (columns) => { + const allOptions = []; + const filterableColumns = columns.filter(column => column?.filterChoices); + + filterableColumns.forEach(column => { + const { id, filterChoices } = column; + let updatedChoices = filterChoices; + + switch (id) { + case 'locked': + updatedChoices = filterChoices.map(choice => ( + { ...choice, value: choice.value ? 'locked' : 'public' } + )); + break; + case 'usageLocations': + updatedChoices = filterChoices.map(choice => ( + { ...choice, value: choice.value ? 'active' : 'inactive' } + )); + break; + case 'transcripts': + updatedChoices = filterChoices.map(choice => ( + { ...choice, value: choice.value ? 'transcribed' : 'notTranscribed' } + )); + break; + default: + break; + } + + allOptions.push(...updatedChoices); + }); + + return allOptions; +}; + +export const getCheckedFilters = (state) => { + const { filters } = state; + const allFilters = []; + filters.forEach(filter => { + const { id, value } = filter; + let updatedValues = value; + + switch (id) { + case 'locked': + updatedValues = value.map(val => (val ? 'locked' : 'public')); + break; + case 'usageLocations': + updatedValues = value.map(val => (val ? 'active' : 'inactive')); + break; + case 'transcripts': + updatedValues = value.map(val => (val ? 'transcribed' : 'notTranscribed')); + break; + default: + break; + } + + if (isArray(updatedValues)) { + allFilters.push(...updatedValues); + } else { + allFilters.push([id, updatedValues]); + } + }); + + return allFilters; +}; + +export const processFilters = (filters, columns, setAllFilters) => { + const filterableColumns = columns.filter(column => column?.filterChoices); + const allFilters = []; + + const [displayNameFilter] = filters.filter(filter => isArray(filter)); + if (displayNameFilter) { + const [id, filterValue] = displayNameFilter; + allFilters.push({ id, value: [filterValue] }); + } + + filterableColumns.forEach(({ id, filterChoices }) => { + const filterValues = filterChoices.map(choice => choice.value); + let processedFilters = filters; + + switch (id) { + case 'locked': + processedFilters = filters.map(match => { + if (match === 'locked') { + return true; + } + if (match === 'public') { + return false; + } + return match; + }); + break; + case 'usageLocations': + processedFilters = filters.map(match => { + if (match === 'active') { + return true; + } + if (match === 'inactive') { + return false; + } + return match; + }); + break; + case 'transcripts': + processedFilters = filters.map(match => { + if (match === 'transcribed') { + return true; + } + if (match === 'notTranscribed') { + return false; + } + return match; + }); + break; + default: + break; + } + + const matchingFilters = filterValues.filter(value => processedFilters.includes(value)); + + if (!isEmpty(matchingFilters)) { + allFilters.push({ id, value: matchingFilters }); + } + }); + + setAllFilters(allFilters); +}; diff --git a/src/files-and-videos/generic/table-components/sort-and-filter-modal/utils.test.js b/src/files-and-videos/generic/table-components/sort-and-filter-modal/utils.test.js new file mode 100644 index 0000000000..55fdb3a245 --- /dev/null +++ b/src/files-and-videos/generic/table-components/sort-and-filter-modal/utils.test.js @@ -0,0 +1,329 @@ +import { getCheckedFilters, getFilterOptions, processFilters } from './utils'; + +describe('getCheckboxFilters', () => { + describe('switch case locked', () => { + it('should equal array with string locked', () => { + const state = { + filters: [ + { id: 'locked', value: [true] }, + ], + }; + const expected = ['locked']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + + it('value attribute should equal public', () => { + const state = { + filters: [ + { id: 'locked', value: [false] }, + ], + }; + const expected = ['public']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + }); + + describe('switch case usageLocations', () => { + it('value attribute should equal active', () => { + const state = { + filters: [ + { id: 'usageLocations', value: [true] }, + ], + }; + const expected = ['active']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + + it('value attribute should equal inactive', () => { + const state = { + filters: [ + { id: 'usageLocations', value: [false] }, + ], + }; + const expected = ['inactive']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + }); + + describe('switch case transcripts', () => { + it('should equal array with string transcribed', () => { + const state = { + filters: [ + { id: 'transcripts', value: [true] }, + ], + }; + const expected = ['transcribed']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + + it('should equal array with string notTranscribed', () => { + const state = { + filters: [ + { id: 'transcripts', value: [false] }, + ], + }; + const expected = ['notTranscribed']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + }); + + describe('switch case default', () => { + it('should equal array with string test', () => { + const state = { + filters: [ + { id: 'testId', value: ['testValue'] }, + ], + }; + const expected = ['testValue']; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + }); + + describe('filter with serach bar', () => { + it('should equal array in array with displayName and value', () => { + const state = { + filters: [{ id: 'displayName', value: 'filter' }], + }; + const expected = [['displayName', 'filter']]; + const actual = getCheckedFilters(state); + + expect(actual).toEqual(expected); + }); + }); +}); + +describe('getFilterOptions', () => { + describe('switch case locked', () => { + it('value attribute should equal locked', () => { + const columns = [ + { id: 'locked', filterChoices: [{ name: 'Locked', value: true }] }, + ]; + const expected = [ + { name: 'Locked', value: 'locked' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + + it('value attribute should equal public', () => { + const columns = [ + { id: 'locked', filterChoices: [{ name: 'Public', value: false }] }, + ]; + const expected = [ + { name: 'Public', value: 'public' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + }); + + describe('switch case usageLocation', () => { + it('value attribute should equal active', () => { + const columns = [ + { id: 'usageLocations', filterChoices: [{ name: 'Active', value: true }] }, + ]; + const expected = [ + { name: 'Active', value: 'active' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + + it('value attribute should equal inactive', () => { + const columns = [ + { id: 'usageLocations', filterChoices: [{ name: 'Inactive', value: false }] }, + ]; + const expected = [ + { name: 'Inactive', value: 'inactive' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + }); + + describe('switch case transcripts', () => { + it('value attribute should equal transcribed', () => { + const columns = [ + { id: 'transcripts', filterChoices: [{ name: 'Transcribed', value: true }] }, + ]; + const expected = [ + { name: 'Transcribed', value: 'transcribed' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + + it('value attribute should equal notTranscribed', () => { + const columns = [ + { id: 'transcripts', filterChoices: [{ name: 'Not transcribed', value: false }] }, + ]; + const expected = [ + { name: 'Not transcribed', value: 'notTranscribed' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + }); + + describe('switch case default', () => { + it('value attribute should equal test', () => { + const columns = [ + { id: 'other', filterChoices: [{ name: 'Test', value: 'test' }] }, + ]; + const expected = [ + { name: 'Test', value: 'test' }, + ]; + const actual = getFilterOptions(columns); + + expect(actual).toEqual(expected); + }); + }); +}); + +describe('processFilters', () => { + const setAllFilters = jest.fn(); + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should call setAllFilters with an empty array', () => { + const filters = []; + const columns = [ + { id: 'locked', filterChoices: [{ name: 'Locked', value: true }] }, + ]; + const expectedParameter = []; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + + describe('switch case locked', () => { + it('should call setAllFilters with locked filter', () => { + const filters = ['locked']; + const columns = [ + { id: 'locked', filterChoices: [{ name: 'Locked', value: true }, { name: 'Public', value: false }] }, + ]; + const expectedParameter = [{ id: 'locked', value: [true] }]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + + it('should call setAllFilters with public filter', () => { + const filters = ['public', 'filter']; + const columns = [ + { id: 'locked', filterChoices: [{ name: 'Public', value: false }] }, + { id: 'test', filterChoices: [{ name: 'Filter', value: 'filter' }] }, + ]; + const expectedParameter = [ + { id: 'locked', value: [false] }, + { id: 'test', value: ['filter'] }, + ]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + }); + + describe('switch case usageLocations', () => { + it('should call setAllFilters with active filter', () => { + const filters = ['active']; + const columns = [ + { id: 'usageLocations', filterChoices: [{ name: 'Active', value: true }] }, + ]; + const expectedParameter = [{ id: 'usageLocations', value: [true] }]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + + it('should call setAllFilters with inactive filter', () => { + const filters = ['inactive', 'filter']; + const columns = [ + { id: 'usageLocations', filterChoices: [{ name: 'Inactive', value: false }] }, + { id: 'test', filterChoices: [{ name: 'Filter', value: 'filter' }] }, + ]; + const expectedParameter = [ + { id: 'usageLocations', value: [false] }, + { id: 'test', value: ['filter'] }, + ]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + }); + + describe('switch case transcripts', () => { + it('should call setAllFilters with transcribed filter', () => { + const filters = ['transcribed', 'filter']; + const columns = [ + { id: 'transcripts', filterChoices: [{ name: 'Transcribed', value: true }] }, + { id: 'test', filterChoices: [{ name: 'Filter', value: 'filter' }] }, + ]; + const expectedParameter = [ + { id: 'transcripts', value: [true] }, + { id: 'test', value: ['filter'] }, + ]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + + it('should call setAllFilters with notTranscribed filter', () => { + const filters = ['notTranscribed']; + const columns = [ + { id: 'transcripts', filterChoices: [{ name: 'Not transcribed', value: false }] }, + ]; + const expectedParameter = [{ id: 'transcripts', value: [false] }]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + }); + + describe('switch case default', () => { + it('should call setAllFilters with test filter', () => { + const filters = ['filter']; + const columns = [ + { id: 'test', filterChoices: [{ name: 'Filter', value: 'filter' }] }, + ]; + const expectedParameter = [{ id: 'test', value: ['filter'] }]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + }); + + describe('filter with serach bar', () => { + it('should call setAllFitlers with displayName filter', () => { + const filters = [['displayName', 'search']]; + const columns = [ + { id: 'test', filterChoices: [{ name: 'Filter', value: 'filter' }] }, + ]; + const expectedParameter = [{ id: 'displayName', value: ['search'] }]; + processFilters(filters, columns, setAllFilters); + + expect(setAllFilters).toHaveBeenCalledWith(expectedParameter); + }); + }); +}); diff --git a/src/files-and-videos/generic/table-components/table-custom-columns/AccessColumn.jsx b/src/files-and-videos/generic/table-components/table-custom-columns/AccessColumn.jsx new file mode 100644 index 0000000000..b1cde1e03d --- /dev/null +++ b/src/files-and-videos/generic/table-components/table-custom-columns/AccessColumn.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { PropTypes } from 'prop-types'; +import { Icon, OverlayTrigger, Tooltip } from '@edx/paragon'; +import { Locked, LockOpen } from '@edx/paragon/icons'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import messages from '../../messages'; + +const AccessColumn = ({ + row, + // injected + intl, +}) => { + const { locked } = row.original; + return ( + + {intl.formatMessage(messages.lockFileTooltipContent)} + + )} + > + {locked ? ( + + ) : ( + + )} + + ); +}; + +AccessColumn.propTypes = { + row: { + original: { + locked: PropTypes.bool.isRequired, + }.isRequired, + }.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(AccessColumn); diff --git a/src/files-and-videos/generic/table-components/table-custom-columns/ActiveColumn.jsx b/src/files-and-videos/generic/table-components/table-custom-columns/ActiveColumn.jsx new file mode 100644 index 0000000000..149c0736ef --- /dev/null +++ b/src/files-and-videos/generic/table-components/table-custom-columns/ActiveColumn.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { PropTypes } from 'prop-types'; +import { Icon } from '@edx/paragon'; +import { Check } from '@edx/paragon/icons'; + +const ActiveColumn = ({ row }) => { + const { usageLocations } = row.original; + const numOfUsageLocations = usageLocations?.length; + return numOfUsageLocations > 0 ? : null; +}; + +ActiveColumn.propTypes = { + row: { + original: { + usageLocations: PropTypes.arrayOf(PropTypes.string).isRequired, + }.isRequired, + }.isRequired, +}; + +export default ActiveColumn; diff --git a/src/files-and-videos/generic/table-components/table-custom-columns/MoreInfoColumn.jsx b/src/files-and-videos/generic/table-components/table-custom-columns/MoreInfoColumn.jsx new file mode 100644 index 0000000000..0dfd12880e --- /dev/null +++ b/src/files-and-videos/generic/table-components/table-custom-columns/MoreInfoColumn.jsx @@ -0,0 +1,165 @@ +import React, { useState } from 'react'; +import { PropTypes } from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + Button, + Icon, + IconButton, + ModalPopup, + Menu, + MenuItem, + useToggle, +} from '@edx/paragon'; +import { MoreHoriz } from '@edx/paragon/icons'; + +import messages from '../../messages'; + +const MoreInfoColumn = ({ + row, + handleLock, + handleBulkDownload, + handleOpenFileInfo, + handleOpenDeleteConfirmation, + // injected + intl, +}) => { + const [isOpen, , close, toggle] = useToggle(); + const [target, setTarget] = useState(null); + + const { + externalUrl, + locked, + portableUrl, + id, + wrapperType, + displayName, + } = row.original; + return ( + <> + + + + {wrapperType === 'video' ? ( + { + navigator.clipboard.writeText(id); + close(); + }} + > + Copy video ID + + ) : ( + <> + { + navigator.clipboard.writeText(portableUrl); + close(); + }} + > + {intl.formatMessage(messages.copyStudioUrlTitle)} + + { + navigator.clipboard.writeText(externalUrl); + close(); + }} + > + {intl.formatMessage(messages.copyWebUrlTitle)} + + handleLock(id, !locked)} + > + {locked ? intl.formatMessage(messages.unlockMenuTitle) : intl.formatMessage(messages.lockMenuTitle)} + + + )} + handleBulkDownload( + [{ original: { id, displayName } }], + )} + > + {intl.formatMessage(messages.downloadTitle)} + + handleOpenFileInfo(row.original)} + > + {intl.formatMessage(messages.infoTitle)} + +
    + { + handleOpenDeleteConfirmation([{ original: row.original }]); + close(); + }} + > + {intl.formatMessage(messages.deleteTitle)} + +
    +
    + + ); +}; + +MoreInfoColumn.propTypes = { + row: PropTypes.shape({ + original: { + externalUrl: PropTypes.string, + locked: PropTypes.bool, + portableUrl: PropTypes.string, + id: PropTypes.string.isRequired, + wrapperType: PropTypes.string, + }.isRequired, + }).isRequired, + handleLock: PropTypes.func, + handleBulkDownload: PropTypes.func.isRequired, + handleOpenFileInfo: PropTypes.func.isRequired, + handleOpenDeleteConfirmation: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, +}; + +MoreInfoColumn.defaultProps = { + handleLock: null, +}; + +export default injectIntl(MoreInfoColumn); diff --git a/src/files-and-videos/generic/table-components/table-custom-columns/StatusColumn.jsx b/src/files-and-videos/generic/table-components/table-custom-columns/StatusColumn.jsx new file mode 100644 index 0000000000..d28f4ad906 --- /dev/null +++ b/src/files-and-videos/generic/table-components/table-custom-columns/StatusColumn.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { PropTypes } from 'prop-types'; +import { Badge } from '@edx/paragon'; + +const StatusColumn = ({ row }) => { + const { status } = row.original; + const isUploaded = status === 'Success'; + + if (isUploaded) { + return null; + } + + return ( + + {status} + + ); +}; + +StatusColumn.propTypes = { + row: { + original: { + status: PropTypes.string.isRequired, + }.isRequired, + }.isRequired, +}; + +export default StatusColumn; diff --git a/src/files-and-videos/generic/table-components/table-custom-columns/ThumbnailColumn.jsx b/src/files-and-videos/generic/table-components/table-custom-columns/ThumbnailColumn.jsx new file mode 100644 index 0000000000..ea0248ba72 --- /dev/null +++ b/src/files-and-videos/generic/table-components/table-custom-columns/ThumbnailColumn.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { PropTypes } from 'prop-types'; +import ThumbnailPreview from '../../ThumbnailPreview'; + +const ThumbnailColumn = ({ row, thumbnailPreview }) => { + const { + thumbnail, + wrapperType, + externalUrl, + displayName, + id, + status, + } = row.original; + return ( + + ); +}; + +ThumbnailColumn.propTypes = { + row: { + original: { + thumbnail: PropTypes.string, + wrapperType: PropTypes.string.isRequired, + }.isRequired, + }.isRequired, + thumbnailPreview: PropTypes.func.isRequired, +}; + +export default ThumbnailColumn; diff --git a/src/files-and-videos/generic/table-components/table-custom-columns/index.js b/src/files-and-videos/generic/table-components/table-custom-columns/index.js new file mode 100644 index 0000000000..78284945fc --- /dev/null +++ b/src/files-and-videos/generic/table-components/table-custom-columns/index.js @@ -0,0 +1,13 @@ +import AccessColumn from './AccessColumn'; +import ActiveColumn from './ActiveColumn'; +import MoreInfoColumn from './MoreInfoColumn'; +import StatusColumn from './StatusColumn'; +import ThumbnailColumn from './ThumbnailColumn'; + +export { + AccessColumn, + ActiveColumn, + MoreInfoColumn, + StatusColumn, + ThumbnailColumn, +}; diff --git a/src/files-and-videos/generic/table-components/utils.js b/src/files-and-videos/generic/table-components/utils.js new file mode 100644 index 0000000000..15dc4ea86f --- /dev/null +++ b/src/files-and-videos/generic/table-components/utils.js @@ -0,0 +1,71 @@ +import { isEmpty, isArray } from 'lodash'; +import messages from '../messages'; + +const getFilterDisplayName = (column, values) => { + const displayNames = []; + const { filterChoices } = column; + values.forEach(value => { + const [displayName] = filterChoices.filter(choice => choice.value === value); + displayNames.push(displayName); + }); + return displayNames; +}; + +export const getFilters = (state, columns) => { + const { filters } = state; + const filterableColumns = columns.filter(column => column?.filterChoices); + const allFilters = []; + + filters.forEach(filter => { + const { id, value } = filter; + const [filterColumn] = filterableColumns.filter(column => column.id === id); + let currentFilters; + + if (filterColumn) { + currentFilters = getFilterDisplayName(filterColumn, value); + } else { + const [serachValue] = value; + currentFilters = [{ name: serachValue, value: serachValue }]; + } + allFilters.push(...currentFilters); + }); + + return allFilters; +}; + +export const removeFilter = (filter, setFilter, setAllFilters, state) => { + const { filters } = state; + const [editedFilter] = filters.filter(currentFilter => currentFilter.value.includes(filter)); + + let updatedFilterValue; + if (isArray(editedFilter?.value)) { + updatedFilterValue = editedFilter.value.filter(value => value !== filter); + } else { + updatedFilterValue = filter.includes(editedFilter?.value) ? [] : editedFilter.value; + } + + if (isEmpty(updatedFilterValue)) { + const updatedFilters = filters.filter(currentFilter => currentFilter.id !== editedFilter.id); + setAllFilters(updatedFilters); + } else { + setFilter(editedFilter.id, updatedFilterValue); + } +}; + +export const getCurrentViewRange = ({ + filterRowCount, + initialRowCount, + fileCount, + intl, +}) => { + if (filterRowCount === initialRowCount) { + return intl.formatMessage( + messages.rowStatusMessage, + { fileCount, rowCount: initialRowCount }, + ); + } + return intl.formatMessage( + messages.rowStatusMessage, + { fileCount, rowCount: filterRowCount }, + ); +}; diff --git a/src/files-and-videos/generic/table-components/utils.test.js b/src/files-and-videos/generic/table-components/utils.test.js new file mode 100644 index 0000000000..cd9fd10632 --- /dev/null +++ b/src/files-and-videos/generic/table-components/utils.test.js @@ -0,0 +1,109 @@ +import { getCurrentViewRange, getFilters, removeFilter } from './utils'; + +describe('getCurrentViewRange', () => { + const intl = { + formatMessage: (name, { fileCount, rowCount }) => ( + `Showing ${fileCount} of ${rowCount}` + ), + }; + + it('should return with intials row count', () => { + const data = { + filterRowCount: 25, + initialRowCount: 25, + fileCount: 12, + intl, + }; + const expected = 'Showing 12 of 25'; + const actual = getCurrentViewRange(data); + + expect(actual).toEqual(expected); + }); + + it('should return with filter row count', () => { + const data = { + filterRowCount: 12, + initialRowCount: 25, + fileCount: 12, + intl, + }; + const expected = 'Showing 12 of 12'; + const actual = getCurrentViewRange(data); + + expect(actual).toEqual(expected); + }); +}); + +describe('getFilters', () => { + it('should return filter when columns is empty', () => { + const state = { filters: [{ id: 'test', value: ['unknown'] }] }; + const columns = []; + const expected = [{ name: 'unknown', value: 'unknown' }]; + const actual = getFilters(state, columns); + + expect(actual).toEqual(expected); + }); + + it('should return filtern for specific column', () => { + const state = { filters: [{ id: 'validColumn', value: ['filter1'] }] }; + const columns = [{ + id: 'validColumn', + filterChoices: [ + { name: 'Filter 1', value: 'filter1' }, + { name: 'Filter 2', value: 'filter2' }, + ], + }]; + const expected = [{ name: 'Filter 1', value: 'filter1' }]; + const acutal = getFilters(state, columns); + + expect(acutal).toEqual(expected); + }); +}); + +describe('removeFilter', () => { + const setAllFilters = jest.fn(); + const setFilter = jest.fn(); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('state filter.value is an array', () => { + it('should call setAllFilters', () => { + const state = { + filters: [ + { id: 'test', value: ['filter1'] }, + ], + }; + const filter = 'filter1'; + removeFilter(filter, setFilter, setAllFilters, state); + + expect(setAllFilters).toHaveBeenCalled(); + }); + + it('should call setFilter', () => { + const state = { + filters: [ + { id: 'test', value: ['filter1', 'filter2'] }, + ], + }; + const filter = 'filter1'; + removeFilter(filter, setFilter, setAllFilters, state); + + expect(setFilter).toHaveBeenCalled(); + }); + }); + describe('state filter.value is not an array', () => { + it('should call setAllFilters', () => { + const state = { + filters: [ + { id: 'test', value: 'filter1' }, + ], + }; + const filter = 'filter1'; + removeFilter(filter, setFilter, setAllFilters, state); + + expect(setAllFilters).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/files-and-videos/generic/utils.js b/src/files-and-videos/generic/utils.js new file mode 100644 index 0000000000..7cbcc07d4c --- /dev/null +++ b/src/files-and-videos/generic/utils.js @@ -0,0 +1,51 @@ +export const getFileSizeToClosestByte = (fileSize, numberOfDivides = 0) => { + if (fileSize > 1000) { + const updatedSize = fileSize / 1000; + const incrementNumberOfDivides = numberOfDivides + 1; + return getFileSizeToClosestByte(updatedSize, incrementNumberOfDivides); + } + const fileSizeFixedDecimal = Number.parseFloat(fileSize).toFixed(2); + switch (numberOfDivides) { + case 1: + return `${fileSizeFixedDecimal} KB`; + case 2: + return `${fileSizeFixedDecimal} MB`; + case 3: + return `${fileSizeFixedDecimal} GB`; + default: + return `${fileSizeFixedDecimal} B`; + } +}; + +export const sortFiles = (files, sortType) => { + const [sort, direction] = sortType.split(','); + let sortedFiles; + if (sort === 'displayName') { + sortedFiles = files.sort((f1, f2) => { + const lowerCaseF1 = f1[sort].toLowerCase(); + const lowerCaseF2 = f2[sort].toLowerCase(); + if (lowerCaseF1 < lowerCaseF2) { + return 1; + } + if (lowerCaseF1 > lowerCaseF2) { + return -1; + } + return 0; + }); + } else { + sortedFiles = files.sort((f1, f2) => { + if (f1[sort] < f2[sort]) { + return 1; + } + if (f1[sort] > f2[sort]) { + return -1; + } + return 0; + }); + } + const sortedIds = sortedFiles.map(file => file.id); + if (direction === 'asc') { + return sortedIds.reverse(); + } + return sortedIds; +}; diff --git a/src/files-and-videos/generic/utils.test.js b/src/files-and-videos/generic/utils.test.js new file mode 100644 index 0000000000..f2e9995dd9 --- /dev/null +++ b/src/files-and-videos/generic/utils.test.js @@ -0,0 +1,26 @@ +import { getFileSizeToClosestByte } from './utils'; + +describe('FilesAndUploads utils', () => { + describe('getFileSizeToClosestByte', () => { + it('should return file size with B for bytes', () => { + const expectedSize = '219.00 B'; + const actualSize = getFileSizeToClosestByte(219); + expect(expectedSize).toEqual(actualSize); + }); + it('should return file size with KB for kilobytes', () => { + const expectedSize = '21.90 KB'; + const actualSize = getFileSizeToClosestByte(21900); + expect(expectedSize).toEqual(actualSize); + }); + it('should return file size with MB for megabytes', () => { + const expectedSize = '2.19 MB'; + const actualSize = getFileSizeToClosestByte(2190000); + expect(expectedSize).toEqual(actualSize); + }); + it('should return file size with GB for gigabytes', () => { + const expectedSize = '2.03 GB'; + const actualSize = getFileSizeToClosestByte(2034190000); + expect(expectedSize).toEqual(actualSize); + }); + }); +}); diff --git a/src/files-and-videos/index.js b/src/files-and-videos/index.js new file mode 100644 index 0000000000..aff054a680 --- /dev/null +++ b/src/files-and-videos/index.js @@ -0,0 +1,3 @@ +/* eslint-disable import/prefer-default-export */ +export { default as FilesPage } from './files-page'; +export { default as VideosPage } from './videos-page'; diff --git a/src/files-and-videos/index.scss b/src/files-and-videos/index.scss new file mode 100644 index 0000000000..32c5d08f94 --- /dev/null +++ b/src/files-and-videos/index.scss @@ -0,0 +1,21 @@ +@import "files-and-videos/videos-page/transcript-settings/TranscriptSettings"; +@import "files-and-videos/videos-page/VideoThumbnail"; +@import "files-and-videos/generic/table-components/GalleryCard"; + +.files-table { + #table-filters-dropdown { + visibility: hidden; + } +} + +.pgn__form-control-set-inline { + .pgn__form-checkbox { + margin: 0; + } + + width: 90%; + display: inline-grid; + grid-auto-flow: row; + gap: 24px 16px; + grid-template-columns: repeat(3, 33%); +} diff --git a/src/files-and-videos/videos-page/VideoThumbnail.jsx b/src/files-and-videos/videos-page/VideoThumbnail.jsx new file mode 100644 index 0000000000..f86b3e00de --- /dev/null +++ b/src/files-and-videos/videos-page/VideoThumbnail.jsx @@ -0,0 +1,121 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { VideoFile } from '@edx/paragon/icons'; +import { + Badge, + Button, + Icon, + Image, +} from '@edx/paragon'; +import { FileInput, useFileInput } from '../generic'; +import messages from './messages'; + +const VideoThumbnail = ({ + thumbnail, + displayName, + id, + imageSize, + handleAddThumbnail, + videoImageSettings, + status, + // injected + intl, +}) => { + const fileInputControl = useFileInput({ + onAddFile: (file) => handleAddThumbnail(file, id), + setSelectedRows: () => {}, + setAddOpen: () => false, + }); + const [thumbnailError, setThumbnailError] = useState(false); + const allowThumbnailUpload = videoImageSettings?.videoImageUploadEnabled; + + let addThumbnailMessage = 'Add thumbnail'; + if (allowThumbnailUpload) { + if (thumbnail) { + addThumbnailMessage = 'Edit thumbnail'; + } + } + const supportedFiles = videoImageSettings?.supportedFileFormats + ? Object.values(videoImageSettings.supportedFileFormats) : null; + const isUploaded = status === 'Success'; + + const showThumbnail = allowThumbnailUpload && thumbnail && isUploaded; + + return ( +
    + {allowThumbnailUpload &&
    } + {showThumbnail && !thumbnailError ? ( +
    + {intl.formatMessage(messages.thumbnailAltMessage, setThumbnailError(true)} + /> +
    + ) : ( + <> +
    + +
    +
    + {!isUploaded && ( + + {status} + + )} +
    + + )} + {allowThumbnailUpload && ( + <> +
    + +
    + + + )} +
    + ); +}; + +VideoThumbnail.propTypes = { + thumbnail: PropTypes.string, + displayName: PropTypes.string.isRequired, + id: PropTypes.string.isRequired, + imageSize: PropTypes.shape({ + width: PropTypes.string, + height: PropTypes.string, + }).isRequired, + handleAddThumbnail: PropTypes.func.isRequired, + videoImageSettings: PropTypes.shape({ + videoImageUploadEnabled: PropTypes.bool.isRequired, + supportedFileFormats: PropTypes.shape({}), + }).isRequired, + status: PropTypes.string.isRequired, + // injected + intl: intlShape.isRequired, +}; + +VideoThumbnail.defaultProps = { + thumbnail: null, +}; + +export default injectIntl(VideoThumbnail); diff --git a/src/files-and-videos/videos-page/VideoThumbnail.scss b/src/files-and-videos/videos-page/VideoThumbnail.scss new file mode 100644 index 0000000000..e97c75b246 --- /dev/null +++ b/src/files-and-videos/videos-page/VideoThumbnail.scss @@ -0,0 +1,61 @@ +.video-thumbnail { + position: relative; + width: 90%; + max-width: 400px; + margin: auto; + overflow: hidden; +} + +.video-thumbnail .thumbnail-overlay { + background: rgba(0 0 0 / .7); + position: absolute; + height: 99%; + width: 100%; + left: 0; + top: 0; + bottom: 0; + right: 0; + opacity: 0; + -webkit-transition: all .4s ease-in-out 0s; + -moz-transition: all .4s ease-in-out 0s; + transition: all .4s ease-in-out 0s; +} + +.status-badge { + position: absolute; + text-align: center; + padding-left: 1em; + padding-right: 1em; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} + +.video-thumbnail:hover .thumbnail-overlay { + opacity: 1; +} + +.add-thumbnail { + position: absolute; + text-align: center; + padding-left: 1em; + padding-right: 1em; + width: 100%; + top: 50%; + left: 50%; + opacity: 0; + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + -webkit-transition: all .3s ease-in-out 0s; + -moz-transition: all .3s ease-in-out 0s; + transition: all .3s ease-in-out 0s; +} + +.video-thumbnail:hover .add-thumbnail { + top: 50%; + left: 50%; + opacity: 1; +} diff --git a/src/files-and-videos/videos-page/VideosPage.jsx b/src/files-and-videos/videos-page/VideosPage.jsx new file mode 100644 index 0000000000..448f3ccec3 --- /dev/null +++ b/src/files-and-videos/videos-page/VideosPage.jsx @@ -0,0 +1,247 @@ +import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { isEmpty } from 'lodash'; +import { useDispatch, useSelector } from 'react-redux'; +import { + injectIntl, + FormattedMessage, + intlShape, +} from '@edx/frontend-platform/i18n'; +import { + useToggle, + ActionRow, + Button, + CheckboxFilter, +} from '@edx/paragon'; +import Placeholder from '@edx/frontend-lib-content-components'; + +import { RequestStatus } from '../../data/constants'; +import { useModels, useModel } from '../../generic/model-store'; +import { + addVideoFile, + addVideoThumbnail, + deleteVideoFile, + fetchVideoDownload, + fetchVideos, + getUsagePaths, + resetErrors, + updateVideoOrder, +} from './data/thunks'; +import messages from './messages'; +import VideosPageProvider from './VideosPageProvider'; +import getPageHeadTitle from '../../generic/utils'; +import { + ActiveColumn, + EditFileErrors, + FileTable, + StatusColumn, + ThumbnailColumn, +} from '../generic'; +import TranscriptSettings from './transcript-settings'; +import VideoThumbnail from './VideoThumbnail'; +import { getFormattedDuration, resampleFile } from './data/utils'; +import FILES_AND_UPLOAD_TYPE_FILTERS from '../generic/constants'; +import VideoInfoModalSidebar from './info-sidebar'; + +const VideosPage = ({ + courseId, + // injected + intl, +}) => { + const dispatch = useDispatch(); + const [isTranscriptSettingsOpen, openTranscriptSettings, closeTranscriptSettings] = useToggle(false); + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.heading)); + + useEffect(() => { + dispatch(fetchVideos(courseId)); + }, [courseId]); + + const { + videoIds, + loadingStatus, + transcriptStatus, + addingStatus: addVideoStatus, + deletingStatus: deleteVideoStatus, + updatingStatus: updateVideoStatus, + usageStatus: usagePathStatus, + errors: errorMessages, + pageSettings, + } = useSelector(state => state.videos); + + const { + isVideoTranscriptEnabled, + encodingsDownloadUrl, + videoUploadMaxFileSize, + videoSupportedFileFormats, + videoImageSettings, + } = pageSettings; + + const supportedFileFormats = { 'video/*': videoSupportedFileFormats || FILES_AND_UPLOAD_TYPE_FILTERS.video }; + + const handleAddFile = (file) => dispatch(addVideoFile(courseId, file)); + const handleDeleteFile = (id) => dispatch(deleteVideoFile(courseId, id)); + const handleDownloadFile = (selectedRows) => dispatch(fetchVideoDownload({ selectedRows })); + const handleUsagePaths = (video) => dispatch(getUsagePaths({ video, courseId })); + const handleErrorReset = (error) => dispatch(resetErrors(error)); + const handleFileOrder = ({ newFileIdOrder, sortType }) => { + dispatch(updateVideoOrder(courseId, newFileIdOrder, sortType)); + }; + const handleAddThumbnail = (file, videoId) => resampleFile({ + file, + dispatch, + courseId, + videoId, + addVideoThumbnail, + }); + + const videos = useModels('videos', videoIds); + + const data = { + supportedFileFormats, + encodingsDownloadUrl, + fileIds: videoIds, + loadingStatus, + usagePathStatus, + usageErrorMessages: errorMessages.usageMetrics, + }; + const thumbnailPreview = (props) => VideoThumbnail({ ...props, handleAddThumbnail, videoImageSettings }); + const infoModalSidebar = (video) => VideoInfoModalSidebar({ video }); + const maxFileSize = videoUploadMaxFileSize * 1073741824; + const transcriptColumn = { + id: 'transcripts', + Header: 'Transcript', + accessor: (({ transcripts }) => !isEmpty(transcripts)), + Cell: ({ row }) => { + const { transcripts } = row.original; + const numOfTranscripts = transcripts?.length; + return numOfTranscripts > 0 ? `(${numOfTranscripts}) available` : null; + }, + Filter: CheckboxFilter, + filterChoices: [ + { name: intl.formatMessage(messages.transcribedCheckboxLabel), value: true }, + { name: intl.formatMessage(messages.notTranscribedCheckboxLabel), value: false }, + ], + }; + const activeColumn = { + id: 'usageLocations', + Header: 'Active', + accessor: (({ usageLocations }) => !isEmpty(usageLocations)), + Cell: ({ row }) => ActiveColumn({ row }), + Filter: CheckboxFilter, + filterChoices: [ + { name: intl.formatMessage(messages.activeCheckboxLabel), value: true }, + { name: intl.formatMessage(messages.inactiveCheckboxLabel), value: false }, + ], + }; + const durationColumn = { + id: 'duration', + Header: 'Video length', + accessor: 'duration', + Cell: ({ row }) => { + const { duration } = row.original; + return getFormattedDuration(duration); + }, + }; + const processingStatusColumn = { + id: 'status', + Header: '', + Cell: ({ row }) => StatusColumn({ row }), + Filter: CheckboxFilter, + filterChoices: [{ name: intl.formatMessage(messages.processingCheckboxLabel), value: 'Processing' }], + }; + const videoThumbnailColumn = { + id: 'courseVideoImageUrl', + Header: '', + Cell: ({ row }) => ThumbnailColumn({ row, thumbnailPreview }), + }; + const tableColumns = [ + { ...videoThumbnailColumn }, + { + Header: 'File name', + accessor: 'clientVideoId', + }, + { ...durationColumn }, + { ...transcriptColumn }, + { ...activeColumn }, + { ...processingStatusColumn }, + ]; + + if (loadingStatus === RequestStatus.DENIED) { + return ( +
    + +
    + ); + } + return ( + +
    +
    + + +
    + +
    + + {isVideoTranscriptEnabled ? ( + + ) : null} +
    +
    + {isVideoTranscriptEnabled ? ( + + ) : null} + +
    +
    + ); +}; + +VideosPage.propTypes = { + courseId: PropTypes.string.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(VideosPage); diff --git a/src/files-and-videos/videos-page/VideosPage.test.jsx b/src/files-and-videos/videos-page/VideosPage.test.jsx new file mode 100644 index 0000000000..ad16c30cf4 --- /dev/null +++ b/src/files-and-videos/videos-page/VideosPage.test.jsx @@ -0,0 +1,678 @@ +import { + render, + act, + fireEvent, + screen, + waitFor, + within, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { initializeMockApp } from '@edx/frontend-platform'; +import MockAdapter from 'axios-mock-adapter'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import initializeStore from '../../store'; +import { executeThunk } from '../../utils'; +import { RequestStatus } from '../../data/constants'; +import VideosPage from './VideosPage'; +import { + generateFetchVideosApiResponse, + generateEmptyApiResponse, + generateNewVideoApiResponse, + generateAddVideoApiResponse, + getStatusValue, + courseId, + initialState, +} from './factories/mockApiResponses'; + +import { + fetchVideos, + addVideoFile, + deleteVideoFile, + getUsagePaths, + addVideoThumbnail, + fetchVideoDownload, +} from './data/thunks'; +import { getVideosUrl, getCoursVideosApiUrl, getApiBaseUrl } from './data/api'; +import videoMessages from './messages'; +import messages from '../generic/messages'; + +let axiosMock; +let store; +let file; +jest.mock('file-saver'); + +const renderComponent = () => { + render( + + + + + , + ); +}; + +const mockStore = async ( + status, +) => { + const fetchVideosUrl = getVideosUrl(courseId); + axiosMock.onGet(fetchVideosUrl).reply(getStatusValue(status), generateFetchVideosApiResponse()); + await executeThunk(fetchVideos(courseId), store.dispatch); +}; + +const emptyMockStore = async (status) => { + const fetchVideosUrl = getVideosUrl(courseId); + axiosMock.onGet(fetchVideosUrl).reply(getStatusValue(status), generateEmptyApiResponse()); + await executeThunk(fetchVideos(courseId), store.dispatch); +}; + +describe('FilesAndUploads', () => { + describe('empty state', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore({ + ...initialState, + videos: { + ...initialState.videos, + videoIds: [], + }, + models: {}, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + file = new File(['(⌐□_□)'], 'download.mp4', { type: 'video/mp4' }); + }); + + it('should return placeholder component', async () => { + renderComponent(); + await mockStore(RequestStatus.DENIED); + expect(screen.getByTestId('under-construction-placeholder')).toBeVisible(); + }); + + it('should not render transcript settings button', async () => { + renderComponent(); + await emptyMockStore(RequestStatus.SUCCESSFUL); + expect(screen.queryByText(videoMessages.transcriptSettingsButtonLabel.defaultMessage)); + }); + + it('should have Video uploads title', async () => { + renderComponent(); + await emptyMockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByText(videoMessages.heading.defaultMessage)).toBeVisible(); + }); + + it('should render dropzone', async () => { + renderComponent(); + await emptyMockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('files-dropzone')).toBeVisible(); + + expect(screen.queryByTestId('files-data-table')).toBeNull(); + }); + + it('should upload a single file', async () => { + renderComponent(); + await emptyMockStore(RequestStatus.SUCCESSFUL); + const dropzone = screen.getByTestId('files-dropzone'); + await act(async () => { + const mockResponseData = { status: '200', ok: true, blob: () => 'Data' }; + const mockFetchResponse = Promise.resolve(mockResponseData); + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + + axiosMock.onPost(getCoursVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse()); + axiosMock.onGet(getCoursVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse()); + + Object.defineProperty(dropzone, 'files', { + value: [file], + }); + fireEvent.drop(dropzone); + await executeThunk(addVideoFile(courseId, file), store.dispatch); + }); + const addStatus = store.getState().videos.addingStatus; + expect(addStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.queryByTestId('files-dropzone')).toBeNull(); + + expect(screen.getByTestId('files-data-table')).toBeVisible(); + }); + }); + + describe('valid videos', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore(initialState); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + file = new File(['(⌐□_□)'], 'download.png', { type: 'image/png' }); + }); + + describe('table view', () => { + it('should render transcript settings button', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const transcriptSettingsButton = screen.getByText(videoMessages.transcriptSettingsButtonLabel.defaultMessage); + expect(transcriptSettingsButton).toBeVisible(); + + await act(async () => { + fireEvent.click(transcriptSettingsButton); + }); + + expect(screen.getByLabelText('close settings')).toBeVisible(); + }); + + it('should render table with gallery card', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('files-data-table')).toBeVisible(); + + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + }); + + it('should switch table to list view', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('files-data-table')).toBeVisible(); + + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + expect(screen.queryByRole('table')).toBeNull(); + + const listButton = screen.getByLabelText('List'); + await act(async () => { + fireEvent.click(listButton); + }); + expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull(); + + expect(screen.getByRole('table')).toBeVisible(); + }); + + it('should update video thumbnail', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + axiosMock.onPost(`${getApiBaseUrl()}/video_images/${courseId}/mOckID1`).reply(200, { image_url: 'url' }); + const addThumbnailButton = screen.getByTestId('video-thumbnail-mOckID1'); + const thumbnail = new File(['test'], 'sOMEUrl.jpg', { type: 'image/jpg' }); + await act(async () => { + fireEvent.click(addThumbnailButton); + await executeThunk(addVideoThumbnail({ file: thumbnail, videoId: 'mOckID1', courseId }), store.dispatch); + }); + const updateStatus = store.getState().videos.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + }); + + describe('table actions', () => { + it('should upload a single file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const mockResponseData = { status: '200', ok: true, blob: () => 'Data' }; + const mockFetchResponse = Promise.resolve(mockResponseData); + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + + axiosMock.onPost(getCoursVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse()); + axiosMock.onGet(getCoursVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse()); + + const addFilesButton = screen.getAllByLabelText('file-input')[3]; + await act(async () => { + userEvent.upload(addFilesButton, file); + await executeThunk(addVideoFile(courseId, file), store.dispatch); + }); + const addStatus = store.getState().videos.addingStatus; + expect(addStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('should have disabled action buttons', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + expect(screen.getByText(messages.downloadTitle.defaultMessage).closest('a')).toHaveClass('disabled'); + + expect(screen.getByText(messages.deleteTitle.defaultMessage).closest('a')).toHaveClass('disabled'); + }); + + it('delete button should be enabled and delete selected file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButton = screen.getAllByTestId('datatable-select-column-checkbox-cell')[0]; + fireEvent.click(selectCardButton); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + const deleteButton = screen.getByText(messages.deleteTitle.defaultMessage).closest('a'); + expect(deleteButton).not.toHaveClass('disabled'); + + axiosMock.onDelete(`${getCoursVideosApiUrl(courseId)}/mOckID1`).reply(204); + + fireEvent.click(deleteButton); + expect(screen.getByText(messages.deleteConfirmationTitle.defaultMessage)).toBeVisible(); + await act(async () => { + userEvent.click(deleteButton); + }); + + // Wait for the delete confirmation button to appear + const confirmDeleteButton = await screen.findByRole('button', { + name: messages.deleteFileButtonLabel.defaultMessage, + }); + + await act(async () => { + userEvent.click(confirmDeleteButton); + }); + + expect(screen.queryByText(messages.deleteConfirmationTitle.defaultMessage)).toBeNull(); + + // Check if the video is deleted in the store and UI + const deleteStatus = store.getState().videos.deletingStatus; + expect(deleteStatus).toEqual(RequestStatus.SUCCESSFUL); + expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull(); + }); + + it('download button should be enabled and download single selected file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButton = screen.getAllByTestId('datatable-select-column-checkbox-cell')[0]; + fireEvent.click(selectCardButton); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + const downloadButton = screen.getByText(messages.downloadTitle.defaultMessage).closest('a'); + expect(downloadButton).not.toHaveClass('disabled'); + + await act(async () => { + fireEvent.click(downloadButton); + }); + + const updateStatus = store.getState().videos.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('download button should be enabled and download multiple selected files', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButtons = screen.getAllByTestId('datatable-select-column-checkbox-cell'); + fireEvent.click(selectCardButtons[0]); + fireEvent.click(selectCardButtons[1]); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1`).reply(200, { download_link: 'http://download.org' }); + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID5`).reply(200, { download_link: 'http://download.org' }); + + const downloadButton = screen.getByText(messages.downloadTitle.defaultMessage).closest('a'); + expect(downloadButton).not.toHaveClass('disabled'); + + await act(async () => { + fireEvent.click(downloadButton); + }); + + const updateStatus = store.getState().videos.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + describe('Sort and filter button', () => { + beforeEach(async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const sortAndFilterButton = screen.getByText(messages.sortButtonLabel.defaultMessage); + + await waitFor(() => { + fireEvent.click(sortAndFilterButton); + }); + }); + + describe('sort function', () => { + it('should be enabled and sort files by name', async () => { + const sortNameAscendingButton = screen.getByText(messages.sortByNameAscending.defaultMessage); + fireEvent.click(sortNameAscendingButton); + fireEvent.click(screen.getByText(messages.applySortButton.defaultMessage)); + + expect(screen.queryByText(messages.sortModalTitleLabel.defaultMessage)).toBeNull(); + }); + + it('sort button should be enabled and sort files by file size', async () => { + const sortBySizeDescendingButton = screen.getByText(messages.sortBySizeDescending.defaultMessage); + fireEvent.click(sortBySizeDescendingButton); + fireEvent.click(screen.getByText(messages.applySortButton.defaultMessage)); + + expect(screen.queryByText(messages.sortModalTitleLabel.defaultMessage)).toBeNull(); + }); + }); + + describe('filter function', () => { + it('should filter videos with transcripts', async () => { + const notTranscribedCheckboxFilter = screen.getByText( + videoMessages.notTranscribedCheckboxLabel.defaultMessage, + ); + const transcribedCheckboxFilter = screen.getByText(videoMessages.transcribedCheckboxLabel.defaultMessage); + fireEvent.click(transcribedCheckboxFilter); + fireEvent.click(notTranscribedCheckboxFilter); + fireEvent.click(transcribedCheckboxFilter); + fireEvent.click(screen.getByText(messages.applySortButton.defaultMessage)); + + const galleryCards = screen.getAllByTestId('grid-card', { exact: false }); + + expect(galleryCards).toHaveLength(1); + }); + + it('should clearAll selections', async () => { + const sortByNewest = screen.getByText(messages.sortByNewest.defaultMessage); + const sortBySizeDescendingButton = screen.getByText(messages.sortBySizeDescending.defaultMessage); + const transcribedCheckboxFilter = screen.getByLabelText( + videoMessages.transcribedCheckboxLabel.defaultMessage, + ); + + fireEvent.click(sortBySizeDescendingButton); + fireEvent.click(transcribedCheckboxFilter); + + const clearAllButton = screen.getByText('Clear all'); + await waitFor(() => fireEvent.click(clearAllButton)); + + expect(transcribedCheckboxFilter).toHaveProperty('checked', false); + + expect(within(sortBySizeDescendingButton).getByLabelText('file size descending radio')) + .toHaveProperty('checked', false); + + expect(within(sortByNewest).getByLabelText('date added descending radio')) + .toHaveProperty('checked', true); + }); + + it('should remove Transcribed filter chip', async () => { + const transcribedCheckboxFilter = screen.getByText(videoMessages.transcribedCheckboxLabel.defaultMessage); + fireEvent.click(transcribedCheckboxFilter); + fireEvent.click(screen.getByText(messages.applySortButton.defaultMessage)); + + const imageFilterChip = screen.getByTestId('icon-after'); + fireEvent.click(imageFilterChip); + + expect(screen.queryByText(videoMessages.transcribedCheckboxLabel.defaultMessage)).toBeNull(); + }); + }); + }); + }); + + describe('card menu actions', () => { + it('should open video info', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(videoMenuButton).toBeVisible(); + + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1/usage`) + .reply(201, { usageLocations: ['subsection - unit / block'] }); + await waitFor(() => { + fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Info')); + }); + + expect(screen.getByText(messages.infoTitle.defaultMessage)).toBeVisible(); + + const { usageStatus } = store.getState().videos; + + expect(usageStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.getByText('subsection - unit / block')).toBeVisible(); + }); + + it('should open video info modal and show info tab', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(videoMenuButton).toBeVisible(); + + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1/usage`).reply(201, { usageLocations: [] }); + await waitFor(() => { + fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Info')); + }); + + expect(screen.getByText(messages.usageNotInUseMessage.defaultMessage)).toBeVisible(); + + const infoTab = screen.getAllByRole('tab')[0]; + expect(infoTab).toBeVisible(); + + expect(infoTab).toHaveClass('active'); + }); + + it('should open video info modal and show transcript tab', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(videoMenuButton).toBeVisible(); + + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1/usage`).reply(201, { usageLocations: [] }); + await waitFor(() => { + fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Info')); + }); + + expect(screen.getByText(messages.usageNotInUseMessage.defaultMessage)).toBeVisible(); + + const transcriptTab = screen.getAllByRole('tab')[1]; + await act(async () => { + fireEvent.click(transcriptTab); + }); + expect(transcriptTab).toBeVisible(); + + expect(transcriptTab).toHaveClass('active'); + }); + + it('download button should download file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(videoMenuButton).toBeVisible(); + + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1`).reply(200, { download_link: 'test' }); + await waitFor(() => { + fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Download')); + }); + + const updateStatus = store.getState().videos.updatingStatus; + + expect(updateStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('delete button should delete file', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + const fileMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(fileMenuButton).toBeVisible(); + + await waitFor(() => { + axiosMock.onDelete(`${getCoursVideosApiUrl(courseId)}/mOckID1`).reply(204); + fireEvent.click(within(fileMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByTestId('open-delete-confirmation-button')); + expect(screen.getByText(messages.deleteConfirmationTitle.defaultMessage)).toBeVisible(); + + fireEvent.click(screen.getByText(messages.deleteFileButtonLabel.defaultMessage)); + expect(screen.queryByText(messages.deleteConfirmationTitle.defaultMessage)).toBeNull(); + + executeThunk(deleteVideoFile(courseId, 'mOckID1', 5), store.dispatch); + }); + const deleteStatus = store.getState().videos.deletingStatus; + expect(deleteStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull(); + }); + }); + + describe('api errors', () => { + it('invalid file size should show error', async () => { + const errorMessage = 'File download.png exceeds maximum size of 5 GB.'; + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + axiosMock.onPost(getCoursVideosApiUrl(courseId)).reply(413, { error: errorMessage }); + const addFilesButton = screen.getAllByLabelText('file-input')[3]; + await act(async () => { + userEvent.upload(addFilesButton, file); + await executeThunk(addVideoFile(courseId, file), store.dispatch); + }); + const addStatus = store.getState().videos.addingStatus; + expect(addStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Error')).toBeVisible(); + }); + + it('404 add file should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + axiosMock.onPost(getCoursVideosApiUrl(courseId)).reply(404); + const addFilesButton = screen.getAllByLabelText('file-input')[3]; + await act(async () => { + userEvent.upload(addFilesButton, file); + await executeThunk(addVideoFile(courseId, file), store.dispatch); + }); + const addStatus = store.getState().videos.addingStatus; + expect(addStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Error')).toBeVisible(); + }); + + it('404 add thumbnail should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + axiosMock.onPost(`${getApiBaseUrl()}/video_images/${courseId}/mOckID1`).reply(404); + const addThumbnailButton = screen.getByTestId('video-thumbnail-mOckID1'); + const thumbnail = new File(['test'], 'sOMEUrl.jpg', { type: 'image/jpg' }); + await act(async () => { + fireEvent.click(addThumbnailButton); + await executeThunk(addVideoThumbnail({ file: thumbnail, videoId: 'mOckID1', courseId }), store.dispatch); + }); + const updateStatus = store.getState().videos.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Error')).toBeVisible(); + }); + + it('404 upload file to server should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const mockResponseData = { status: '404', ok: false, blob: () => 'Data' }; + const mockFetchResponse = Promise.reject(mockResponseData); + global.fetch = jest.fn().mockImplementation(() => mockFetchResponse); + + axiosMock.onPost(getCoursVideosApiUrl(courseId)).reply(204, generateNewVideoApiResponse()); + axiosMock.onGet(getCoursVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse()); + const addFilesButton = screen.getAllByLabelText('file-input')[3]; + await act(async () => { + userEvent.upload(addFilesButton, file); + await executeThunk(addVideoFile(courseId, file), store.dispatch); + }); + const addStatus = store.getState().videos.addingStatus; + expect(addStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Error')).toBeVisible(); + }); + + it('404 delete should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1'); + expect(videoMenuButton).toBeVisible(); + + await waitFor(() => { + axiosMock.onDelete(`${getCoursVideosApiUrl(courseId)}/mOckID1`).reply(404); + fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByTestId('open-delete-confirmation-button')); + expect(screen.getByText(messages.deleteConfirmationTitle.defaultMessage)).toBeVisible(); + + fireEvent.click(screen.getByText(messages.deleteFileButtonLabel.defaultMessage)); + expect(screen.queryByText(messages.deleteConfirmationTitle.defaultMessage)).toBeNull(); + + executeThunk(deleteVideoFile(courseId, 'mOckID1', 5), store.dispatch); + }); + const deleteStatus = store.getState().videos.deletingStatus; + expect(deleteStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible(); + + expect(screen.getByText('Error')).toBeVisible(); + }); + + it('404 usage path fetch should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + expect(screen.getByTestId('grid-card-mOckID3')).toBeVisible(); + + const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID3'); + expect(videoMenuButton).toBeVisible(); + + axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID3/usage`).reply(404); + await waitFor(() => { + fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle')); + fireEvent.click(screen.getByText('Info')); + executeThunk(getUsagePaths({ + courseId, + video: { id: 'mOckID3', displayName: 'mOckID3' }, + }), store.dispatch); + }); + const { usageStatus } = store.getState().videos; + expect(usageStatus).toEqual(RequestStatus.FAILED); + }); + + it('multiple video files fetch failure should show error', async () => { + renderComponent(); + await mockStore(RequestStatus.SUCCESSFUL); + const selectCardButtons = screen.getAllByTestId('datatable-select-column-checkbox-cell'); + fireEvent.click(selectCardButtons[0]); + fireEvent.click(selectCardButtons[2]); + const actionsButton = screen.getByText(messages.actionsButtonLabel.defaultMessage); + expect(actionsButton).toBeVisible(); + + await waitFor(() => { + fireEvent.click(actionsButton); + }); + const downloadButton = screen.getByText(messages.downloadTitle.defaultMessage).closest('a'); + expect(downloadButton).not.toHaveClass('disabled'); + + await waitFor(() => { + fireEvent.click(downloadButton); + executeThunk(fetchVideoDownload([{ original: { displayName: 'mOckID1', id: '2' } }]), store.dispatch); + }); + + const updateStatus = store.getState().videos.updatingStatus; + expect(updateStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Error')).toBeVisible(); + }); + }); + }); +}); diff --git a/src/files-and-videos/videos-page/VideosPageProvider.jsx b/src/files-and-videos/videos-page/VideosPageProvider.jsx new file mode 100644 index 0000000000..cbce832565 --- /dev/null +++ b/src/files-and-videos/videos-page/VideosPageProvider.jsx @@ -0,0 +1,25 @@ +import React, { useMemo } from 'react'; +import PropTypes from 'prop-types'; + +export const VideosPageContext = React.createContext({}); + +const VideosPageProvider = ({ courseId, children }) => { + const contextValue = useMemo(() => ({ + courseId, + path: `/course/${courseId}/videos`, + }), []); + return ( + + {children} + + ); +}; + +VideosPageProvider.propTypes = { + courseId: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, +}; + +export default VideosPageProvider; diff --git a/src/files-and-videos/videos-page/data/api.js b/src/files-and-videos/videos-page/data/api.js new file mode 100644 index 0000000000..3cdd3e433b --- /dev/null +++ b/src/files-and-videos/videos-page/data/api.js @@ -0,0 +1,238 @@ +/* eslint-disable import/prefer-default-export */ +import { camelCaseObject, ensureConfig, getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import saveAs from 'file-saver'; +import { isEmpty } from 'lodash'; + +ensureConfig([ + 'STUDIO_BASE_URL', +], 'Course Apps API service'); + +export const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; +export const getVideosUrl = (courseId) => `${getApiBaseUrl()}/api/contentstore/v1/videos/${courseId}`; +export const getCoursVideosApiUrl = (courseId) => `${getApiBaseUrl()}/videos/${courseId}`; + +/** + * Fetches the course custom pages for provided course + * @param {string} courseId + * @returns {Promise<[{}]>} + */ +export async function getVideos(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(getVideosUrl(courseId)); + const { video_transcript_settings: videoTranscriptSettings } = data; + const { transcription_plans: transcriptionPlans } = videoTranscriptSettings; + return { + ...camelCaseObject(data), + videoTranscriptSettings: { + ...camelCaseObject(videoTranscriptSettings), + transcriptionPlans, + }, + }; +} + +/** + * Fetches the course custom pages for provided course + * @param {string} courseId + * @returns {Promise<[{}]>} + */ +export async function fetchVideoList(courseId) { + const { data } = await getAuthenticatedHttpClient() + .get(getCoursVideosApiUrl(courseId)); + return camelCaseObject(data); +} + +export async function deleteTranscript({ videoId, language, apiUrl }) { + await getAuthenticatedHttpClient() + .delete(`${getApiBaseUrl()}${apiUrl}/${videoId}/${language}`); +} + +export async function downloadTranscript({ + videoId, + language, + apiUrl, + filename, +}) { + const { data } = await getAuthenticatedHttpClient() + .get(`${getApiBaseUrl()}${apiUrl}?edx_video_id=${videoId}&language_code=${language}`); + const file = new Blob([data], { type: 'text/plain;charset=utf-8' }); + saveAs(file, filename); +} + +export async function uploadTranscript({ + videoId, + newLanguage, + apiUrl, + file, + language, +}) { + const formData = new FormData(); + formData.append('file', file); + formData.append('edx_video_id', videoId); + formData.append('language_code', language); + formData.append('new_language_code', newLanguage); + await getAuthenticatedHttpClient().post(`${getApiBaseUrl()}${apiUrl}`, formData); +} + +export async function getDownload(selectedRows) { + const downloadErrors = []; + if (selectedRows?.length > 0) { + await Promise.allSettled( + selectedRows.map(async row => { + try { + const video = row.original; + const { downloadLink } = video; + if (!isEmpty(downloadLink)) { + saveAs(downloadLink, video.displayName); + } else { + downloadErrors.push(`Cannot find download file for ${video?.displayName}.`); + } + } catch (error) { + downloadErrors.push('Failed to download video.'); + } + }), + ); + } else { + downloadErrors.push('No files were selected to download.'); + } + return downloadErrors; +} + +/** + * Fetch where a video is used in a course. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function getVideoUsagePaths({ courseId, videoId }) { + const { data } = await getAuthenticatedHttpClient() + .get(`${getVideosUrl(courseId)}/${videoId}/usage`); + return camelCaseObject(data); +} + +/** + * Delete video from course. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function deleteVideo(courseId, videoId) { + await getAuthenticatedHttpClient() + .delete(`${getCoursVideosApiUrl(courseId)}/${videoId}`); +} + +/** + * Add thumbnail to video. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function addThumbnail({ courseId, videoId, file }) { + const formData = new FormData(); + formData.append('file', file); + const { data } = await getAuthenticatedHttpClient() + .post(`${getApiBaseUrl()}/video_images/${courseId}/${videoId}`, formData); + return camelCaseObject(data); +} + +/** + * Add video to course. + * @param {blockId} courseId Course ID for the course to operate on + + */ +export async function addVideo(courseId, file) { + const postJson = { + files: [{ file_name: file.name, content_type: file.type }], + }; + + const { data } = await getAuthenticatedHttpClient() + .post(getCoursVideosApiUrl(courseId), postJson); + return camelCaseObject(data); +} + +export async function uploadVideo( + courseId, + uploadUrl, + uploadFile, + edxVideoId, +) { + const formData = new FormData(); + formData.append('uploaded-file', uploadFile); + const uploadErrors = []; + await fetch(uploadUrl, { + method: 'PUT', + body: formData, + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) + .then(async () => { + await getAuthenticatedHttpClient() + .post(getCoursVideosApiUrl(courseId), [{ + edxVideoId, + message: 'Upload completed', + status: 'upload_completed', + }]); + }) + .catch(async () => { + uploadErrors.push(`Failed to upload ${uploadFile.name} to server.`); + await getAuthenticatedHttpClient() + .post(getCoursVideosApiUrl(courseId), [{ + edxVideoId, + message: 'Upload failed', + status: 'upload_failed', + }]); + }); + return uploadErrors; +} + +export async function deleteTranscriptPreferences(courseId) { + await getAuthenticatedHttpClient().delete(`${getApiBaseUrl()}/transcript_preferences/${courseId}`); +} + +export async function setTranscriptPreferences(courseId, preferences) { + const { + cielo24Fidelity, + cielo24Turnaround, + global, + preferredLanguages, + provider, + threePlayTurnaround, + videoSourceLanguage, + } = preferences; + const postJson = { + cielo24_fidelity: cielo24Fidelity?.toUpperCase(), + cielo24_turnaround: cielo24Turnaround, + global, + preferred_languages: preferredLanguages, + provider, + video_source_language: videoSourceLanguage, + three_play_turnaround: threePlayTurnaround, + }; + + const { data } = await getAuthenticatedHttpClient() + .post(`${getApiBaseUrl()}/transcript_preferences/${courseId}`, postJson); + return camelCaseObject(data); +} + +export async function setTranscriptCredentials(courseId, formFields) { + const { + apiKey, + global, + provider, + ...otherFields + } = formFields; + const postJson = { + api_key: apiKey, + global, + provider, + }; + + if (provider === '3PlayMedia') { + const { apiSecretKey } = otherFields; + postJson.api_secret_key = apiSecretKey; + } else { + const { username } = otherFields; + postJson.username = username; + } + await getAuthenticatedHttpClient() + .post(`${getApiBaseUrl()}/transcript_credentials/${courseId}`, postJson); +} diff --git a/src/files-and-videos/videos-page/data/api.test.js b/src/files-and-videos/videos-page/data/api.test.js new file mode 100644 index 0000000000..7604a7a08a --- /dev/null +++ b/src/files-and-videos/videos-page/data/api.test.js @@ -0,0 +1,55 @@ +import { getDownload } from './api'; +import 'file-saver'; + +jest.mock('file-saver'); + +describe('api.js', () => { + describe('getDownload', () => { + describe('selectedRows length is undefined or less than zero', () => { + it('should return with no files selected error if selectedRows is empty', async () => { + const expected = ['No files were selected to download.']; + const actual = await getDownload([], 'courseId'); + expect(actual).toEqual(expected); + }); + it('should return with no files selected error if selectedRows is null', async () => { + const expected = ['No files were selected to download.']; + const actual = await getDownload(null, 'courseId'); + expect(actual).toEqual(expected); + }); + }); + describe('selectedRows length is greater than one', () => { + it('should not throw error when blob returns null', async () => { + const expected = []; + const actual = await getDownload([ + { original: { displayName: 'test1', downloadLink: 'test1.com' } }, + { original: { displayName: 'test2', id: '2', downloadLink: 'test2.com' } }, + ]); + expect(actual).toEqual(expected); + }); + it('should return error if row does not contain .original attribute', async () => { + const expected = ['Failed to download video.']; + const actual = await getDownload([ + { asset: { displayName: 'test1', id: '1' } }, + { original: { displayName: 'test2', id: '2', downloadLink: 'test1.com' } }, + ]); + expect(actual).toEqual(expected); + }); + it('should return error if original does not contain .downloadLink attribute', async () => { + const expected = ['Cannot find download file for test2.']; + const actual = await getDownload([ + { original: { displayName: 'test2', id: '2' } }, + ]); + expect(actual).toEqual(expected); + }); + }); + describe('selectedRows length equals one', () => { + it('should return error if row does not contain .original ancestor', async () => { + const expected = ['Failed to download video.']; + const actual = await getDownload([ + { asset: { displayName: 'test1', id: '1', download_link: 'test1.com' } }, + ]); + expect(actual).toEqual(expected); + }); + }); + }); +}); diff --git a/src/files-and-videos/videos-page/data/constants.js b/src/files-and-videos/videos-page/data/constants.js new file mode 100644 index 0000000000..b534e7eb73 --- /dev/null +++ b/src/files-and-videos/videos-page/data/constants.js @@ -0,0 +1,8 @@ +export const MAX_FILE_SIZE_MB = 2000000; +export const MIN_FILE_SIZE_KB = 2000; +export const MAX_WIDTH = 1280; +export const MAX_HEIGHT = 720; +export const MIN_WIDTH = 640; +export const MIN_HEIGHT = 360; +export const ASPECT_RATIO = 16 / 9; +export const ASPECT_RATIO_ERROR_MARGIN = 0.1; diff --git a/src/files-and-videos/videos-page/data/slice.js b/src/files-and-videos/videos-page/data/slice.js new file mode 100644 index 0000000000..6a6410fcd4 --- /dev/null +++ b/src/files-and-videos/videos-page/data/slice.js @@ -0,0 +1,104 @@ +/* eslint-disable no-param-reassign */ +import { createSlice } from '@reduxjs/toolkit'; + +import { RequestStatus } from '../../../data/constants'; + +const slice = createSlice({ + name: 'videos', + initialState: { + videoIds: [], + pageSettings: {}, + loadingStatus: RequestStatus.IN_PROGRESS, + updatingStatus: '', + addingStatus: '', + deletingStatus: '', + usageStatus: '', + transcriptStatus: '', + errors: { + add: [], + delete: [], + thumbnail: [], + download: [], + usageMetrics: [], + transcript: [], + }, + }, + reducers: { + setVideoIds: (state, { payload }) => { + state.videoIds = payload.videoIds; + }, + setPageSettings: (state, { payload }) => { + state.pageSettings = payload; + }, + updateLoadingStatus: (state, { payload }) => { + state.loadingStatus = payload.status; + }, + updateEditStatus: (state, { payload }) => { + const { editType, status } = payload; + switch (editType) { + case 'delete': + state.deletingStatus = status; + break; + case 'add': + state.addingStatus = status; + break; + case 'thumbnail': + state.updatingStatus = status; + break; + case 'download': + state.updatingStatus = status; + break; + case 'usageMetrics': + state.usageStatus = status; + break; + case 'transcript': + state.transcriptStatus = status; + break; + default: + break; + } + }, + deleteVideoSuccess: (state, { payload }) => { + state.videoIds = state.videoIds.filter(id => id !== payload.videoId); + }, + addVideoSuccess: (state, { payload }) => { + state.videoIds = [payload.videoId, ...state.videoIds]; + }, + updateTranscriptCredentialsSuccess: (state, { payload }) => { + const { provider } = payload; + state.pageSettings.transcriptCredentials = { + ...state.pageSettings.transcriptCredentials, + [provider]: true, + }; + }, + updateTranscriptPreferenceSuccess: (state, { payload }) => { + state.pageSettings.activeTranscriptPreferences = payload; + }, + updateErrors: (state, { payload }) => { + const { error, message } = payload; + const currentErrorState = state.errors[error]; + state.errors[error] = [...currentErrorState, message]; + }, + clearErrors: (state, { payload }) => { + const { error } = payload; + state.errors[error] = []; + }, + }, +}); + +export const { + setVideoIds, + setPageSettings, + updateLoadingStatus, + deleteVideoSuccess, + addVideoSuccess, + updateErrors, + clearErrors, + updateEditStatus, + updateTranscriptCredentialsSuccess, + updateTranscriptPreferenceSuccess, +} = slice.actions; + +export const { + reducer, +} = slice; diff --git a/src/files-and-videos/videos-page/data/thunks.js b/src/files-and-videos/videos-page/data/thunks.js new file mode 100644 index 0000000000..42547a4719 --- /dev/null +++ b/src/files-and-videos/videos-page/data/thunks.js @@ -0,0 +1,352 @@ +import { camelCase, isEmpty } from 'lodash'; +import { getConfig } from '@edx/frontend-platform'; +import { RequestStatus } from '../../../data/constants'; +import { + addModels, + removeModel, + updateModel, + updateModels, +} from '../../../generic/model-store'; +import { + addThumbnail, + addVideo, + deleteVideo, + fetchVideoList, + getVideos, + uploadVideo, + getDownload, + deleteTranscript, + downloadTranscript, + uploadTranscript, + getVideoUsagePaths, + deleteTranscriptPreferences, + setTranscriptCredentials, + setTranscriptPreferences, +} from './api'; +import { + setVideoIds, + setPageSettings, + updateLoadingStatus, + deleteVideoSuccess, + addVideoSuccess, + updateErrors, + clearErrors, + updateEditStatus, + updateTranscriptCredentialsSuccess, + updateTranscriptPreferenceSuccess, +} from './slice'; + +import { updateFileValues } from './utils'; + +export function fetchVideos(courseId) { + return async (dispatch) => { + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.IN_PROGRESS })); + + try { + const { previousUploads, ...data } = await getVideos(courseId); + const parsedVideos = updateFileValues(previousUploads); + dispatch(addModels({ modelType: 'videos', models: parsedVideos })); + dispatch(setVideoIds({ + videoIds: parsedVideos.map(video => video.id), + })); + dispatch(setPageSettings({ ...data })); + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.SUCCESSFUL })); + } catch (error) { + if (error.response && error.response.status === 403) { + dispatch(updateLoadingStatus({ status: RequestStatus.DENIED })); + } else { + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.FAILED })); + } + } + }; +} + +export function resetErrors({ errorType }) { + return (dispatch) => { dispatch(clearErrors({ error: errorType })); }; +} + +export function updateVideoOrder(courseId, videoIds) { + return async (dispatch) => { + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.IN_PROGRESS })); + dispatch(setVideoIds({ videoIds })); + dispatch(updateLoadingStatus({ courseId, status: RequestStatus.SUCCESSFUL })); + }; +} + +export function deleteVideoFile(courseId, id) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'delete', status: RequestStatus.IN_PROGRESS })); + + try { + await deleteVideo(courseId, id); + dispatch(deleteVideoSuccess({ videoId: id })); + dispatch(removeModel({ modelType: 'videos', id })); + dispatch(updateEditStatus({ editType: 'delete', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'delete', message: `Failed to delete file id ${id}.` })); + dispatch(updateEditStatus({ editType: 'delete', status: RequestStatus.FAILED })); + } + }; +} + +export function addVideoFile(courseId, file) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.IN_PROGRESS })); + + try { + const { files } = await addVideo(courseId, file); + const { edxVideoId, uploadUrl } = files[0]; + const errors = await uploadVideo( + courseId, + uploadUrl, + file, + edxVideoId, + ); + const { videos } = await fetchVideoList(courseId); + const parsedVideos = updateFileValues(videos); + dispatch(updateModels({ + modelType: 'videos', + models: parsedVideos, + })); + dispatch(addVideoSuccess({ + videoId: edxVideoId, + })); + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.SUCCESSFUL })); + if (!isEmpty(errors)) { + errors.forEach(error => { + dispatch(updateErrors({ error: 'add', message: error })); + }); + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.FAILED })); + } + } catch (error) { + if (error.response && error.response.status === 413) { + const message = error.response.data.error; + dispatch(updateErrors({ error: 'add', message })); + } else { + dispatch(updateErrors({ error: 'add', message: `Failed to add ${file.name}.` })); + } + dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.FAILED })); + } + }; +} + +export function addVideoThumbnail({ file, videoId, courseId }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'thumbnail', status: RequestStatus.IN_PROGRESS })); + dispatch(resetErrors({ errorType: 'thumbnail' })); + try { + const { imageUrl } = await addThumbnail({ courseId, videoId, file }); + let thumbnail = imageUrl; + if (thumbnail.startsWith('/')) { + thumbnail = `${getConfig().STUDIO_BASE_URL}${imageUrl}`; + } + dispatch(updateModel({ + modelType: 'videos', + model: { + id: videoId, + thumbnail, + }, + })); + dispatch(updateEditStatus({ editType: 'thumbnail', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + if (error.response?.data?.error) { + const message = error.response.data.error; + dispatch(updateErrors({ error: 'thumbnail', message })); + } else { + dispatch(updateErrors({ error: 'thumbnail', message: `Failed to add thumbnail for video id ${videoId}.` })); + } + dispatch(updateEditStatus({ editType: 'thumbnail', status: RequestStatus.FAILED })); + } + }; +} + +export function deleteVideoTranscript({ + language, + videoId, + transcripts, + apiUrl, +}) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.IN_PROGRESS })); + + try { + await deleteTranscript({ + videoId, + language, + apiUrl, + }); + const updatedTranscripts = transcripts.filter(transcript => transcript !== language); + dispatch(updateModel({ + modelType: 'videos', + model: { + id: videoId, + transcripts: updatedTranscripts, + }, + })); + + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'transcript', message: `Failed to delete ${language} transcript.` })); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.FAILED })); + } + }; +} + +export function downloadVideoTranscript({ + language, + videoId, + filename, + apiUrl, +}) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.IN_PROGRESS })); + + try { + await downloadTranscript({ + videoId, + language, + apiUrl, + filename, + }); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'transcript', message: `Failed to download ${filename}.` })); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.FAILED })); + } + }; +} + +export function uploadVideoTranscript({ + language, + newLanguage, + videoId, + file, + apiUrl, + transcripts, +}) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.IN_PROGRESS })); + const isReplacement = !isEmpty(language); + + try { + await uploadTranscript({ + videoId, + language, + apiUrl, + file, + newLanguage, + }); + let updatedTranscripts = transcripts; + if (isReplacement) { + const removeTranscript = transcripts.filter(transcript => transcript !== language); + updatedTranscripts = [...removeTranscript, newLanguage]; + } else { + updatedTranscripts = [...transcripts, newLanguage]; + } + + dispatch(updateModel({ + modelType: 'videos', + model: { + id: videoId, + transcripts: updatedTranscripts, + }, + })); + + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + if (error.response?.data?.error) { + const message = error.response.data.error; + dispatch(updateErrors({ error: 'transcript', message })); + } else { + const message = isReplacement ? `Failed to replace ${language} with ${newLanguage}.` : `Failed to add ${newLanguage}.`; + dispatch(updateErrors({ error: 'transcript', message })); + } + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.FAILED })); + } + }; +} + +export function getUsagePaths({ video, courseId }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'usageMetrics', status: RequestStatus.IN_PROGRESS })); + + try { + const { usageLocations } = await getVideoUsagePaths({ videoId: video.id, courseId }); + dispatch(updateModel({ + modelType: 'videos', + model: { + id: video.id, + usageLocations, + }, + })); + dispatch(updateEditStatus({ editType: 'usageMetrics', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'usageMetrics', message: `Failed to get usage metrics for ${video.displayName}.` })); + dispatch(updateEditStatus({ editType: 'usageMetrics', status: RequestStatus.FAILED })); + } + }; +} + +export function fetchVideoDownload({ selectedRows }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'download', status: RequestStatus.IN_PROGRESS })); + const errors = await getDownload(selectedRows); + if (isEmpty(errors)) { + dispatch(updateEditStatus({ editType: 'download', status: RequestStatus.SUCCESSFUL })); + } else { + errors.forEach(error => { + dispatch(updateErrors({ error: 'download', message: error })); + }); + dispatch(updateEditStatus({ editType: 'download', status: RequestStatus.FAILED })); + } + }; +} + +export function clearAutomatedTranscript({ courseId }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.IN_PROGRESS })); + + try { + await deleteTranscriptPreferences(courseId); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'transcript', message: 'Failed to update order transcripts settings.' })); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.FAILED })); + } + }; +} + +export function updateTranscriptCredentials({ courseId, data }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.IN_PROGRESS })); + + try { + await setTranscriptCredentials(courseId, data); + dispatch(updateTranscriptCredentialsSuccess({ provider: camelCase(data.provider) })); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateErrors({ error: 'transcript', message: `Failed to update ${data.provider} credentials.` })); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.FAILED })); + } + }; +} + +export function updateTranscriptPreference({ courseId, data }) { + return async (dispatch) => { + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.IN_PROGRESS })); + + try { + const preferences = await setTranscriptPreferences(courseId, data); + dispatch(updateTranscriptPreferenceSuccess(preferences)); + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.SUCCESSFUL })); + } catch (error) { + if (error.response?.data?.error) { + const message = error.response.data.error; + dispatch(updateErrors({ error: 'transcript', message })); + } else { + dispatch(updateErrors({ error: 'transcript', message: `Failed to update ${data.provider} transcripts settings.` })); + } + dispatch(updateEditStatus({ editType: 'transcript', status: RequestStatus.FAILED })); + } + }; +} diff --git a/src/files-and-videos/videos-page/data/utils.js b/src/files-and-videos/videos-page/data/utils.js new file mode 100644 index 0000000000..f75fc93e01 --- /dev/null +++ b/src/files-and-videos/videos-page/data/utils.js @@ -0,0 +1,261 @@ +import { ensureConfig, getConfig } from '@edx/frontend-platform'; +import { isArray, isEmpty } from 'lodash'; +import { + ASPECT_RATIO, + ASPECT_RATIO_ERROR_MARGIN, + MAX_HEIGHT, + MAX_WIDTH, + MIN_HEIGHT, + MIN_WIDTH, +} from './constants'; + +ensureConfig([ + 'STUDIO_BASE_URL', +], 'Course Apps API service'); + +export const updateFileValues = (files) => { + const updatedFiles = []; + files.forEach(file => { + const { + edxVideoId, + clientVideoId, + created, + courseVideoImageUrl, + status, + } = file; + const wrapperType = 'video'; + + let thumbnail = courseVideoImageUrl; + if (thumbnail && thumbnail.startsWith('/')) { + thumbnail = `${getConfig().STUDIO_BASE_URL}${thumbnail}`; + } + + let uploadStatus = status; + if (status === 'Ready' || status === 'Imported') { + uploadStatus = 'Success'; + } else if (status === 'In Progress' || status === 'Uploaded') { + uploadStatus = 'Processing'; + } + + updatedFiles.push({ + ...file, + displayName: clientVideoId, + id: edxVideoId, + wrapperType, + dateAdded: created.toString(), + usageLocations: [], + status: uploadStatus, + thumbnail, + }); + }); + + return updatedFiles; +}; + +export const getFormattedDuration = (value) => { + if (!value || typeof value !== 'number' || value <= 0) { + return '00:00:00'; + } + const seconds = Math.floor(value % 60); + const minutes = Math.floor((value / 60) % 60); + const hours = Math.floor((value / 360) % 60); + const zeroPad = (num) => String(num).padStart(2, '0'); + return [hours, minutes, seconds].map(zeroPad).join(':'); +}; + +export const getLanguages = (availableLanguages) => { + const languages = {}; + availableLanguages?.forEach(language => { + const { languageCode, languageText } = language; + languages[languageCode] = languageText; + }); + return languages; +}; + +export const getSupportedFormats = (supportedFileFormats) => { + if (isEmpty(supportedFileFormats)) { + return null; + } + if (isArray(supportedFileFormats)) { + return supportedFileFormats; + } + const supportedFormats = []; + Object.entries(supportedFileFormats).forEach(([key, value]) => { + let format; + if (isArray(value)) { + value.forEach(val => { + format = key.replace('*', val.substring(1)); + supportedFormats.push(format); + }); + } else { + format = key.replace('*', value?.substring(1)); + supportedFormats.push(format); + } + }); + return supportedFormats; +}; + +/** createResampledFile({ canvasUrl, filename, mimeType }) + * createResampledFile takes a canvasUrl, filename, and a valid mimeType. The + * canvasUrl is parsed and written to an 8-bit array of unsigned integers. The + * new array is saved to a new file with the same filename as the original image. + * @param {string} canvasUrl - string of base64 URL for new image canvas + * @param {string} filename - string of the original image's filename + * @param {string} mimeType - string of mimeType for the canvas + * @return {File} new File object + */ +export const createResampledFile = ({ canvasUrl, filename, mimeType }) => { + const arr = canvasUrl.split(','); + const bstr = atob(arr[1]); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new File([u8arr], filename, { type: mimeType }); +}; + +/** resampleImage({ image, filename }) + * resampledImage takes a canvasUrl, filename, and a valid mimeType. The + * canvasUrl is parsed and written to an 8-bit array of unsigned integers. The + * new array is saved to a new file with the same filename as the original image. + * @param {File} canvasUrl - string of base64 URL for new image canvas + * @param {string} filename - string of the image's filename + * @return {array} array containing the base64 URL for the resampled image and the file containing the resampled image + */ +export const resampleImage = ({ image, filename }) => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + // Determine new dimensions for image + if (image.naturalWidth > MAX_WIDTH) { + // Set dimensions to the maximum size + canvas.width = MAX_WIDTH; + canvas.height = MAX_HEIGHT; + } else if (image.naturalWidth < MIN_WIDTH) { + // Set dimensions to the minimum size + canvas.width = MIN_WIDTH; + canvas.height = MIN_HEIGHT; + } else { + // Set dimensions to the closest 16:9 ratio + const heightRatio = 9 / 16; + canvas.width = image.naturalWidth; + canvas.height = image.naturalWidth * heightRatio; + } + const cropLeft = (image.naturalWidth - canvas.width) / 2; + const cropTop = (image.naturalHeight - canvas.height) / 2; + + ctx.drawImage(image, cropLeft, cropTop, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height); + const resampledFile = createResampledFile({ canvasUrl: canvas.toDataURL(), filename, mimeType: 'image/png' }); + return resampledFile; +}; + +export const hasValidDimensions = ({ width, height }) => { + const imageAspectRatio = Math.abs((width / height) - ASPECT_RATIO); + + if (width < MIN_WIDTH || height < MIN_HEIGHT) { + return false; + } + if (imageAspectRatio >= ASPECT_RATIO_ERROR_MARGIN) { + return false; + } + return true; +}; + +export const resampleFile = ({ + file, + dispatch, + videoId, + courseId, + addVideoThumbnail, +}) => { + const reader = new FileReader(); + const image = new Image(); + reader.onload = () => { + image.src = reader.result; + image.onload = () => { + const width = image.naturalWidth; + const height = image.naturalHeight; + if (!hasValidDimensions({ width, height })) { + const resampledFile = resampleImage({ image, filename: file.name }); + dispatch(addVideoThumbnail({ courseId, videoId, file: resampledFile })); + } else { + dispatch(addVideoThumbnail({ courseId, videoId, file })); + } + }; + }; + reader.readAsDataURL(file); +}; + +export const getLanguageOptions = (keys, languages) => { + const options = {}; + if (keys) { + keys.forEach(key => { + options[key] = languages[key]; + }); + } + return options; +}; + +export const getFidelityOptions = (fidelities) => { + const options = {}; + Object.entries(fidelities).forEach(([key, value]) => { + const { display_name: displayName } = value; + options[key] = displayName; + }); + return options; +}; + +export const checkCredentials = (transcriptCredentials) => { + const cieloHasCredentials = transcriptCredentials.cielo24; + const threePlayHasCredentials = transcriptCredentials['3PlayMedia']; + return [cieloHasCredentials, threePlayHasCredentials]; +}; + +export const checkTranscriptionPlans = (transcriptionPlans) => { + let cieloIsValid = !isEmpty(transcriptionPlans.Cielo24); + let threePlayIsValid = !isEmpty(transcriptionPlans['3PlayMedia']); + + if (cieloIsValid) { + const { fidelity, turnaround } = transcriptionPlans.Cielo24; + cieloIsValid = !isEmpty(fidelity) && !isEmpty(turnaround); + } + + if (threePlayIsValid) { + const { languages, turnaround, translations } = transcriptionPlans['3PlayMedia']; + threePlayIsValid = !isEmpty(turnaround) && !isEmpty(languages) && !isEmpty(translations); + } + + return [cieloIsValid, threePlayIsValid]; +}; + +export const validateForm = (cieloHasCredentials, threePlayHasCredentials, provider, data) => { + const { + apiKey, + apiSecretKey, + username, + cielo24Fidelity, + cielo24Turnaround, + preferredLanguages, + threePlayTurnaround, + videoSourceLanguage, + } = data; + switch (provider) { + case 'Cielo24': + if (cieloHasCredentials) { + return !isEmpty(cielo24Fidelity) && !isEmpty(cielo24Turnaround) + && !isEmpty(preferredLanguages) && !isEmpty(videoSourceLanguage); + } + return !isEmpty(apiKey) && !isEmpty(username); + case '3PlayMedia': + if (threePlayHasCredentials) { + return !isEmpty(threePlayTurnaround) && !isEmpty(preferredLanguages) && !isEmpty(videoSourceLanguage); + } + return !isEmpty(apiKey) && !isEmpty(apiSecretKey); + case 'order': + return true; + default: + break; + } + return false; +}; diff --git a/src/files-and-videos/videos-page/data/utils.test.js b/src/files-and-videos/videos-page/data/utils.test.js new file mode 100644 index 0000000000..2d3708a99d --- /dev/null +++ b/src/files-and-videos/videos-page/data/utils.test.js @@ -0,0 +1,259 @@ +import 'jest-canvas-mock'; +import { + hasValidDimensions, + getSupportedFormats, + resampleImage, + createResampledFile, + validateForm, + checkTranscriptionPlans, +} from './utils'; + +describe('getSupportedFormats', () => { + it('should return null', () => { + const supportedFileFormats = getSupportedFormats(''); + expect(supportedFileFormats).toBeNull(); + }); + it('should return provided supportedFileFormats', () => { + const expected = ['image/png', 'video/mp4']; + const actual = getSupportedFormats(expected); + expect(expected).toEqual(actual); + }); + it('should return array of valid file types', () => { + const expected = ['image/png']; + const actual = getSupportedFormats({ 'image/*': '.png' }); + expect(expected).toEqual(actual); + }); + it('should return array of valid file types', () => { + const expected = ['video/mp4', 'video/mov']; + const actual = getSupportedFormats({ 'video/*': ['.mp4', '.mov'] }); + expect(expected).toEqual(actual); + }); +}); + +describe('createResampledFile', () => { + it('should return resampled file object', () => { + const expected = new File([{ name: 'imageName', size: 20000 }], 'testVALUEVALIDIMAGE'); + const actual = createResampledFile({ + canvasUrl: 'data:MimETYpe,sOMEUrl', + filename: 'imageName', + mimeType: 'sOmEuiMAge', + }); + + expect(expected).toEqual(actual); + }); +}); + +describe('resampleImage', () => { + it('should return filename and file', () => { + const resampledFile = new File([{ name: 'testVALUEVALIDIMAGE', size: 20000 }], 'testVALUEVALIDIMAGE'); + const image = document.createElement('img'); + image.height = '800'; + image.width = '800'; + const actualImage = resampleImage({ image, filename: 'testVALUEVALIDIMAGE' }); + + expect(actualImage).toEqual(resampledFile); + }); +}); + +describe('checkValidDimensions', () => { + it('returns false for images less than min width and min height', () => { + const image = { width: 500, height: 281 }; + const actual = hasValidDimensions(image); + expect(actual).toBeFalsy(); + }); + it('returns false for images that do not have a 16:9 aspect ratio', () => { + const image = { width: 800, height: 800 }; + const actual = hasValidDimensions(image); + expect(actual).toBeFalsy(); + }); + it('returns true for images that have a 16:9 aspect ratio and larger than min width/height', () => { + const image = { width: 1280, height: 720 }; + const actual = hasValidDimensions(image); + expect(actual).toBeTruthy(); + }); +}); + +describe('validateForm', () => { + describe('provider equals Cielo24', () => { + describe('with credentials', () => { + it('should return false', () => { + const isValid = validateForm( + true, + false, + 'Cielo24', + { + cielo24Fidelity: 'test-fidelity', + cielo24Turnaround: 'test-turnaround', + preferredLanguages: [], + videoSourceLanguage: 'test-source', + }, + ); + expect(isValid).toBeFalsy(); + }); + it('should return true', () => { + const isValid = validateForm( + true, + false, + 'Cielo24', + { + cielo24Fidelity: 'test-fidelity', + cielo24Turnaround: 'test-turnaround', + preferredLanguages: ['test-language'], + videoSourceLanguage: 'test-source', + }, + ); + expect(isValid).toBeTruthy(); + }); + }); + describe('with no credentials', () => { + it('should return false', () => { + const isValid = validateForm( + false, + false, + 'Cielo24', + { + apiKey: 'test-key', + username: '', + }, + ); + expect(isValid).toBeFalsy(); + }); + it('should return true', () => { + const isValid = validateForm( + false, + false, + 'Cielo24', + { + apiKey: 'test-key', + username: 'test-username', + }, + ); + expect(isValid).toBeTruthy(); + }); + }); + }); + describe('provider equals 3PlayMedia', () => { + describe('with credentials', () => { + it('should return false', () => { + const isValid = validateForm( + false, + true, + '3PlayMedia', + { + threePlayTurnaround: 'test-turnaround', + preferredLanguages: ['test-language'], + videoSourceLanguage: '', + }, + ); + expect(isValid).toBeFalsy(); + }); + it('should return true', () => { + const isValid = validateForm( + true, + true, + '3PlayMedia', + { + threePlayTurnaround: 'test-turnaround', + preferredLanguages: ['test-language'], + videoSourceLanguage: 'test-source', + }, + ); + expect(isValid).toBeTruthy(); + }); + }); + describe('with no credentials', () => { + it('should return false', () => { + const isValid = validateForm( + true, + false, + '3PlayMedia', + { + apiKey: 'test-key', + username: '', + }, + ); + expect(isValid).toBeFalsy(); + }); + it('should return true', () => { + const isValid = validateForm( + false, + false, + '3PlayMedia', + { + apiKey: 'test-key', + apiSecretKey: 'test-username', + }, + ); + expect(isValid).toBeTruthy(); + }); + }); + }); + describe('provider equals order', () => { + it('should return true', () => { + const isValid = validateForm( + false, + false, + 'order', + {}, + ); + expect(isValid).toBeTruthy(); + }); + }); + describe('provider equals null', () => { + it('should return false', () => { + const isValid = validateForm( + false, + false, + null, + {}, + ); + expect(isValid).toBeFalsy(); + }); + }); +}); + +describe('checkTranscriptionPlans', () => { + describe('invalid Cielo24 plan', () => { + it('Cielo24 is empty should return [false, false]', () => { + const expected = [false, false]; + const actual = checkTranscriptionPlans({ '3PlayMedia': {} }); + expect(actual).toEqual(expected); + }); + it('Cielo24 is missing required atrribute fidelity should return [false, true]', () => { + const expected = [false, true]; + const actual = checkTranscriptionPlans({ + '3PlayMedia': { + languages: ['en'], + turnaround: 'test', + translations: { en: 'English' }, + }, + Cielo24: { + turnaround: ['tomorrow'], + }, + }); + expect(actual).toEqual(expected); + }); + }); + describe('invalid 3PlayMedia plan', () => { + it('3PlayMedia is empty should return [false, false]', () => { + const expected = [false, false]; + const actual = checkTranscriptionPlans({ Cielo24: {} }); + expect(actual).toEqual(expected); + }); + it('3PlayMedia atrribute languages is empty should return [true, false]', () => { + const expected = [true, false]; + const actual = checkTranscriptionPlans({ + Cielo24: { + turnaround: ['tomorrow'], + fidelity: 'test', + }, + '3PlayMedia': { + languages: [], + turnaround: 'test', + translations: { en: 'English' }, + }, + }); + expect(actual).toEqual(expected); + }); + }); +}); diff --git a/src/files-and-videos/videos-page/factories/mockApiResponses.jsx b/src/files-and-videos/videos-page/factories/mockApiResponses.jsx new file mode 100644 index 0000000000..fc0610319d --- /dev/null +++ b/src/files-and-videos/videos-page/factories/mockApiResponses.jsx @@ -0,0 +1,243 @@ +import { RequestStatus } from '../../../data/constants'; + +export const courseId = 'course'; + +export const initialState = { + courseDetail: { + courseId, + status: 'sucessful', + }, + videos: { + videoIds: ['mOckID0'], + pageSettings: { + transcriptAvailableLanguages: [ + { languageCode: 'ar', languageText: 'Arabic' }, + { languageCode: 'en', languageText: 'English' }, + { languageCode: 'fr', languageText: 'French' }, + ], + videoImageSettings: { + videoImageUploadEnabled: false, + maxSize: 2097152, + minSize: 2048, + maxWidth: 1280, + maxHeight: 720, + supportedFileFormats: { + '.bmp': 'image/bmp', + '.bmp2': 'image/x-ms-bmp', + '.gif': 'image/gif', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.png': 'image/png', + }, + }, + isVideoTranscriptEnabled: false, + activeTranscriptPreferences: null, + videoTranscriptSettings: { + transcriptDownloadHandlerUrl: '/transcript_download/', + transcriptUploadHandlerUrl: '/transcript_upload/', + transcriptDeleteHandlerUrl: `/transcript_delete/${courseId}`, + transcriptionPlans: { + Cielo24: { + turnaround: { PRIORITY: 'Priority (24 hours)' }, + fidelity: { + PREMIUM: { display_name: 'Premium (95% accuracy)', languages: { en: 'English' } }, + PROFESSIONAL: { + display_name: 'Professional (99% accuracy)', + languages: { + ar: 'Arabic', + en: 'English', + fr: 'French', + es: 'Spanish', + }, + }, + }, + }, + '3PlayMedia': { + turnaround: { two_hour: '2 hours' }, + translations: { + es: ['en'], + en: ['ar', 'en', 'es', 'fr'], + }, + languages: { + ar: 'Arabic', + en: 'English', + fr: 'French', + es: 'Spanish', + }, + }, + }, + }, + transcriptCredentials: { cielo24: false, '3PlayMedia': false }, + }, + loadingStatus: RequestStatus.SUCCESSFUL, + updatingStatus: '', + addingStatus: '', + deletingStatus: '', + usageStatus: '', + transcriptStatus: '', + errors: { + add: [], + delete: [], + thumbnail: [], + download: [], + usageMetrics: [], + transcript: [], + }, + }, + models: { + videos: { + mOckID0: { + id: 'mOckID0', + displayName: 'mOckID0.mp4', + wrapperType: 'video', + dateAdded: '', + thumbnail: '/video', + fileSize: null, + edx_video_id: 'mOckID0', + clientVideoId: 'mOckID0.mp4', + created: '', + courseVideoImageUrl: '/video', + transcripts: [], + status: 'In Progress', + downloadLink: 'http://mOckID0.mp4', + }, + }, + }, +}; + +export const generateFetchVideosApiResponse = () => ({ + image_upload_url: '/video_images/course', + video_handler_url: '/videos/course', + encodings_download_url: '/video_encodings_download/course', + default_video_image_url: '/static/studio/images/video-images/default_video_image.png', + previous_uploads: [ + { + edx_video_id: 'mOckID1', + clientVideoId: 'mOckID1.mp4', + created: '', + courseVideoImageUrl: '/video', + transcripts: [], + status: 'Imported', + duration: 12333, + downloadLink: 'http://mOckID1.mp4', + }, + { + edx_video_id: 'mOckID5', + clientVideoId: 'mOckID5.mp4', + created: '', + courseVideoImageUrl: 'http:/video', + transcripts: ['en'], + status: 'Failed', + duration: 12, + downloadLink: 'http://mOckID5.mp4', + }, + { + edx_video_id: 'mOckID3', + clientVideoId: 'mOckID3.mp4', + created: '', + courseVideoImageUrl: null, + transcripts: ['en'], + status: 'Ready', + duration: null, + downloadLink: '', + }, + ], + concurrent_upload_limit: 4, + video_supported_file_formats: ['.mp4', '.mov'], + video_upload_max_file_size: '5', + video_image_settings: { + video_image_upload_enabled: true, + max_size: 2097152, + min_size: 2048, + max_width: 1280, + max_height: 720, + supported_file_formats: { + '.bmp': 'image/bmp', + '.bmp2': 'image/x-ms-bmp', + '.gif': 'image/gif', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.png': 'image/png', + }, + }, + is_video_transcript_enabled: true, + active_transcript_preferences: null, + transcript_credentials: {}, + transcript_available_languages: [{ language_code: 'ab', language_text: 'Abkhazian' }], + video_transcript_settings: { + transcript_download_handler_url: '/transcript_download/', + transcript_upload_handler_url: '/transcript_upload/', + transcript_delete_handler_url: '/transcript_delete/course', + trancript_download_file_format: 'srt', + transcript_preferences_handler_url: '/transcript_preferences/course', + transcript_credentials_handler_url: '/transcript_credentials/course', + transcription_plans: { + Cielo24: { + display_name: 'Cielo24', + turnaround: { PRIORITY: 'Priority (24 hours)', STANDARD: 'Standard (48 hours)' }, + fidelity: { + MECHANICAL: { + display_name: 'Mechanical (75% accuracy)', + languages: { nl: 'Dutch', en: 'English', fr: 'French' }, + }, + PREMIUM: { display_name: 'Premium (95% accuracy)', languages: { en: 'English' } }, + PROFESSIONAL: { + display_name: 'Professional (99% accuracy)', + languages: { ar: 'Arabic', 'zh-tw': 'Chinese - Mandarin (Traditional)' }, + }, + }, + }, + '3PlayMedia': { + display_name: '3Play Media', + turnaround: { + two_hour: '2 hours', + same_day: 'Same day', + rush: '24 hours (rush)', + expedited: '2 days (expedited)', + standard: '4 days (standard)', + extended: '10 days (extended)', + }, + languages: { en: 'English', el: 'Greek', zh: 'Chinese' }, + translations: { + es: ['en'], + en: ['el', 'en', 'zh'], + }, + }, + }, + }, + pagination_context: {}, +}); + +export const generateAddVideoApiResponse = () => ({ + videos: [ + { + edx_video_id: 'mOckID4', + clientVideoId: 'mOckID4.mov', + created: '', + courseVideoImageUrl: null, + transcripts: ['en'], + status: 'Uploaded', + duration: 168.001, + }, + ], +}); + +export const generateEmptyApiResponse = () => ([{ + previousUploads: [], +}]); + +export const generateNewVideoApiResponse = () => ({ + files: [{ + edx_video_id: 'mOckID4', + upload_url: 'http://testing.org', + }], +}); + +export const getStatusValue = (status) => { + switch (status) { + case RequestStatus.DENIED: + return 403; + default: + return 200; + } +}; diff --git a/src/files-and-videos/videos-page/index.js b/src/files-and-videos/videos-page/index.js new file mode 100644 index 0000000000..01caa2ac1c --- /dev/null +++ b/src/files-and-videos/videos-page/index.js @@ -0,0 +1,7 @@ +import TranscriptSettings from './transcript-settings'; +import VideosPage from './VideosPage'; +import VideoThumbnail from './VideoThumbnail'; +import VideoInfoModalSidebar from './info-sidebar'; + +export default VideosPage; +export { TranscriptSettings, VideoThumbnail, VideoInfoModalSidebar }; diff --git a/src/files-and-videos/videos-page/info-sidebar/InfoTab.jsx b/src/files-and-videos/videos-page/info-sidebar/InfoTab.jsx new file mode 100644 index 0000000000..cdc5ab2bd6 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/InfoTab.jsx @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Stack } from '@edx/paragon'; +import { injectIntl, FormattedDate, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { getFileSizeToClosestByte } from '../../generic/utils'; +import { getFormattedDuration } from '../data/utils'; +import messages from './messages'; + +const InfoTab = ({ video }) => { + const fileSize = getFileSizeToClosestByte(video?.fileSize); + const duration = getFormattedDuration(video?.duration); + + return ( + +
    + +
    + +
    + +
    + {fileSize} +
    + +
    + {duration} +
    + ); +}; + +InfoTab.propTypes = { + video: PropTypes.shape({ + duration: PropTypes.number.isRequired, + dateAdded: PropTypes.string.isRequired, + fileSize: PropTypes.number.isRequired, + }), +}; + +InfoTab.defaultProps = { + video: {}, +}; + +export default injectIntl(InfoTab); diff --git a/src/files-and-videos/videos-page/info-sidebar/TranscriptTab.jsx b/src/files-and-videos/videos-page/info-sidebar/TranscriptTab.jsx new file mode 100644 index 0000000000..c0e947d8a4 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/TranscriptTab.jsx @@ -0,0 +1,136 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { useDispatch, useSelector } from 'react-redux'; +import { isEmpty } from 'lodash'; +import { ErrorAlert } from '@edx/frontend-lib-content-components'; +import { Button, Stack } from '@edx/paragon'; +import { Add } from '@edx/paragon/icons'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { getLanguages } from '../data/utils'; +import Transcript from './transcript-item'; +import { + deleteVideoTranscript, + downloadVideoTranscript, + resetErrors, + uploadVideoTranscript, +} from '../data/thunks'; +import { RequestStatus } from '../../../data/constants'; +import messages from './messages'; + +const TranscriptTab = ({ + video, + // injected + intl, +}) => { + const dispatch = useDispatch(); + const { transcriptStatus, errors } = useSelector(state => state.videos); + const { + transcriptAvailableLanguages, + videoTranscriptSettings, + } = useSelector(state => state.videos.pageSettings); + const { + transcriptDeleteHandlerUrl, + transcriptUploadHandlerUrl, + transcriptDownloadHandlerUrl, + } = videoTranscriptSettings; + const { transcripts, id, displayName } = video; + const languages = getLanguages(transcriptAvailableLanguages); + + const [previousSelection, setPreviousSelection] = useState(transcripts); + useEffect(() => { + dispatch(resetErrors({ errorType: 'transcript' })); + setPreviousSelection(transcripts); + }, [transcripts]); + + const handleTranscript = (data, actionType) => { + const { + language, + newLanguage, + file, + } = data; + dispatch(resetErrors({ errorType: 'transcript' })); + switch (actionType) { + case 'delete': + if (isEmpty(language)) { + const updatedSelection = previousSelection.filter(selection => selection !== ''); + setPreviousSelection(updatedSelection); + } else { + dispatch(deleteVideoTranscript({ + language, + videoId: id, + apiUrl: transcriptDeleteHandlerUrl, + transcripts, + })); + } + break; + case 'download': + dispatch(downloadVideoTranscript({ + filename: `${displayName}-${language}.srt`, + language, + videoId: id, + apiUrl: transcriptDownloadHandlerUrl, + })); + break; + case 'upload': + dispatch(uploadVideoTranscript({ + language, + videoId: id, + apiUrl: transcriptUploadHandlerUrl, + newLanguage, + file, + transcripts, + })); + break; + default: + break; + } + }; + + return ( + + +
      + {errors.transcript.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} +
    +
    + {previousSelection.map(transcript => ( + + ))} + +
    + ); +}; + +TranscriptTab.propTypes = { + video: PropTypes.shape({ + transcripts: PropTypes.arrayOf(PropTypes.string).isRequired, + id: PropTypes.string.isRequired, + displayName: PropTypes.string.isRequired, + }).isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(TranscriptTab); diff --git a/src/files-and-videos/videos-page/info-sidebar/TranscriptTab.test.jsx b/src/files-and-videos/videos-page/info-sidebar/TranscriptTab.test.jsx new file mode 100644 index 0000000000..f02d0c710a --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/TranscriptTab.test.jsx @@ -0,0 +1,336 @@ +import { + render, + act, + fireEvent, + screen, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ReactDOM from 'react-dom'; + +import { + initializeMockApp, +} from '@edx/frontend-platform'; +import MockAdapter from 'axios-mock-adapter'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import initializeStore from '../../../store'; +import { executeThunk } from '../../../utils'; +import { RequestStatus } from '../../../data/constants'; +import TranscriptTab from './TranscriptTab'; +import { + courseId, + initialState, +} from '../factories/mockApiResponses'; + +import { getApiBaseUrl } from '../data/api'; +import messages from './messages'; +import transcriptRowMessages from './transcript-item/messages'; +import VideosPageProvider from '../VideosPageProvider'; +import { deleteVideoTranscript } from '../data/thunks'; + +ReactDOM.createPortal = jest.fn(node => node); + +const defaultProps = { + id: 'mOckID0', + displayName: 'mOckID0.mp4', + wrapperType: 'video', + dateAdded: '', + thumbnail: '/video', + fileSize: null, + edx_video_id: 'mOckID0', + clientVideoId: 'mOckID0.mp4', + created: '', + courseVideoImageUrl: '/video', + transcripts: [], + status: 'Imported', +}; + +let axiosMock; +let store; +jest.mock('file-saver'); + +const renderComponent = (props) => { + render( + + + + + + + , + ); +}; + +describe('TranscriptTab', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore(initialState); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + describe('with no transcripts preloaded', () => { + it('should have add transcript button', async () => { + renderComponent(defaultProps); + const addButton = screen.getByText(messages.uploadButtonLabel.defaultMessage); + const transcriptRow = screen.queryByTestId('transcript', { exact: false }); + expect(addButton).toBeInTheDocument(); + expect(transcriptRow).toBeNull(); + }); + + it('should delete empty transcript row', async () => { + renderComponent(defaultProps); + const addButton = screen.getByText(messages.uploadButtonLabel.defaultMessage); + await act(async () => { fireEvent.click(addButton); }); + + const deleteButton = screen.getByLabelText('delete empty transcript'); + await act(async () => { fireEvent.click(deleteButton); }); + + expect(screen.getByText(transcriptRowMessages.deleteConfirmationHeader.defaultMessage)).toBeVisible(); + + const confirmButton = screen.getByText(transcriptRowMessages.confirmDeleteLabel.defaultMessage); + await act(async () => { fireEvent.click(confirmButton); }); + + expect(screen.queryByTestId('transcript-')).toBeNull(); + }); + + describe('uploadVideoTranscript as add function', () => { + let addButton; + const file = new File(['(⌐□_□)'], 'download.srt', { type: 'text/srt' }); + beforeEach(async () => { + renderComponent(defaultProps); + addButton = screen.getByText(messages.uploadButtonLabel.defaultMessage); + + await act(async () => { fireEvent.click(addButton); }); + }); + + it('should upload new transcript', async () => { + axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(204); + await act(async () => { + const addFileInput = screen.getByLabelText('file-input'); + expect(addFileInput).toBeInTheDocument(); + + userEvent.upload(addFileInput, file); + }); + const addStatus = store.getState().videos.transcriptStatus; + + expect(addStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('should show default error message', async () => { + axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404); + await act(async () => { + const addFileInput = screen.getByLabelText('file-input'); + userEvent.upload(addFileInput, file); + }); + const addStatus = store.getState().videos.transcriptStatus; + + expect(addStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getAllByText('Failed to add .')[0]).toBeVisible(); + }); + + it('should show api provided error message', async () => { + axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404, { error: 'api error' }); + await act(async () => { + const addFileInput = screen.getByLabelText('file-input'); + userEvent.upload(addFileInput, file); + }); + const addStatus = store.getState().videos.transcriptStatus; + + expect(addStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getAllByText('api error')[0]).toBeVisible(); + }); + }); + }); + + describe('with one transcripts preloaded', () => { + const updatedProps = { ...defaultProps, transcripts: ['ar'] }; + beforeEach(() => { + renderComponent(updatedProps); + }); + + it('should contain transcript row', () => { + const addButton = screen.getByText(messages.uploadButtonLabel.defaultMessage); + const transcriptRow = screen.getByTestId('transcript-ar'); + expect(addButton).toBeInTheDocument(); + expect(transcriptRow).toBeInTheDocument(); + }); + + describe('deleteVideoTranscript', () => { + beforeEach(async () => { + const menuButton = screen.getByTestId('ar-transcript-menu'); + await waitFor(() => { + fireEvent.click(menuButton); + }); + + const deleteButton = screen.getByText(transcriptRowMessages.deleteTranscript.defaultMessage).closest('a'); + fireEvent.click(deleteButton); + }); + + it('should open delete confirmation modal and cancel delete', async () => { + const cancelButton = screen.getByText(transcriptRowMessages.cancelDeleteLabel.defaultMessage); + await waitFor(() => { + fireEvent.click(cancelButton); + }); + + expect(screen.queryByText(transcriptRowMessages.deleteConfirmationHeader.defaultMessage)).toBeNull(); + }); + + it('should open delete confirmation modal and handle delete', async () => { + const confirmButton = screen.getByText(transcriptRowMessages.confirmDeleteLabel.defaultMessage); + axiosMock.onDelete(`${getApiBaseUrl()}/transcript_delete/${courseId}/mOckID0/ar`).reply(204); + await act(async () => { + fireEvent.click(confirmButton); + executeThunk(deleteVideoTranscript({ + language: 'ar', + videoId: updatedProps.id, + transcripts: updatedProps.transcripts, + apiUrl: `/transcript_delete/${courseId}`, + }), store.dispatch); + }); + const deleteStatus = store.getState().videos.transcriptStatus; + + expect(deleteStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.queryByText(transcriptRowMessages.deleteConfirmationHeader.defaultMessage)).toBeNull(); + }); + + it('should show error message', async () => { + const confirmButton = screen.getByText(transcriptRowMessages.confirmDeleteLabel.defaultMessage); + axiosMock.onDelete(`${getApiBaseUrl()}/transcript_delete/${courseId}/mOckID0/ar`).reply(404); + await act(async () => { + fireEvent.click(confirmButton); + executeThunk(deleteVideoTranscript({ + language: 'ar', + videoId: updatedProps.id, + transcripts: updatedProps.transcripts, + apiUrl: `/transcript_delete/${courseId}`, + }), store.dispatch); + }); + const deleteStatus = store.getState().videos.transcriptStatus; + + expect(deleteStatus).toEqual(RequestStatus.FAILED); + + expect(screen.queryByText(transcriptRowMessages.deleteConfirmationHeader.defaultMessage)).toBeNull(); + + expect(screen.getAllByText('Failed to delete ar transcript.')[0]).toBeVisible(); + }); + }); + + describe('downloadVideoTranscript', () => { + let downloadButton; + beforeEach(async () => { + const menuButton = screen.getByTestId('ar-transcript-menu'); + await waitFor(() => { + fireEvent.click(menuButton); + }); + downloadButton = screen.getByText( + transcriptRowMessages.downloadTranscript.defaultMessage, + ).closest('a'); + }); + + it('should download transcript', async () => { + axiosMock.onGet( + `${getApiBaseUrl()}/transcript_download/?edx_video_id=${updatedProps.id}&language_code=ar`, + ).reply(200, 'string of transcript'); + await act(async () => { + fireEvent.click(downloadButton); + }); + const downloadStatus = store.getState().videos.transcriptStatus; + + expect(downloadStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('should show error message', async () => { + const filename = 'mOckID0.mp4-ar.srt'; + axiosMock.onGet( + `${getApiBaseUrl()}/transcript_download/?edx_video_id=${updatedProps.id}&language_code=ar`, + ).reply(404); + await act(async () => { + fireEvent.click(downloadButton); + }); + const downloadStatus = store.getState().videos.transcriptStatus; + + expect(downloadStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getAllByText(`Failed to download ${filename}.`)[0]).toBeVisible(); + }); + }); + }); + + describe('with multiple transcripts preloaded', () => { + describe('uploadVideoTranscript as replace function', () => { + const file = new File(['(⌐□_□)'], 'download.srt', { type: 'text/srt' }); + beforeEach(async () => { + const updatedProps = { ...defaultProps, transcripts: ['fr', 'ar'] }; + renderComponent(updatedProps); + const dropdownButton = screen.getAllByTestId('language-select-dropdown')[0]; + await waitFor(() => { + fireEvent.click(dropdownButton); + }); + + const englishOption = screen.getByText('English'); + const arabicOption = screen.getAllByRole('button', { name: 'Arabic' })[0]; + await act(async () => { + expect(arabicOption).toHaveClass('disabled'); + fireEvent.click(englishOption); + }); + + const menuButton = screen.getByTestId('fr-transcript-menu'); + await waitFor(() => { + fireEvent.click(menuButton); + }); + const replaceButton = screen.getByText( + transcriptRowMessages.replaceTranscript.defaultMessage, + ).closest('a'); + fireEvent.click(replaceButton); + }); + + it('should replace transcript', async () => { + axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(204); + + await act(async () => { + const addFileInput = screen.getAllByLabelText('file-input')[0]; + expect(addFileInput).toBeInTheDocument(); + + userEvent.upload(addFileInput, file); + }); + const addStatus = store.getState().videos.transcriptStatus; + + expect(addStatus).toEqual(RequestStatus.SUCCESSFUL); + + const updatedTranscripts = store.getState().models.videos[defaultProps.id].transcripts; + + expect(updatedTranscripts).toEqual(['ar', 'en']); + }); + + it('should show error message', async () => { + axiosMock.onPost(`${getApiBaseUrl()}/transcript_upload/`).reply(404); + + await act(async () => { + const addFileInput = screen.getAllByLabelText('file-input')[0]; + expect(addFileInput).toBeInTheDocument(); + + userEvent.upload(addFileInput, file); + }); + + const addStatus = store.getState().videos.transcriptStatus; + + expect(addStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getAllByText('Failed to replace fr with en.')[0]).toBeVisible(); + }); + }); + }); +}); diff --git a/src/files-and-videos/videos-page/info-sidebar/VideoInfoModalSidebar.jsx b/src/files-and-videos/videos-page/info-sidebar/VideoInfoModalSidebar.jsx new file mode 100644 index 0000000000..2c240fb006 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/VideoInfoModalSidebar.jsx @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + Tabs, + Tab, +} from '@edx/paragon'; +import InfoTab from './InfoTab'; +import TranscriptTab from './TranscriptTab'; +import messages from './messages'; + +const VideoInfoModalSidebar = ({ + video, + // injected + intl, +}) => ( + + + + + + + + +); + +VideoInfoModalSidebar.propTypes = { + video: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + wrapperType: PropTypes.string.isRequired, + id: PropTypes.string.isRequired, + dateAdded: PropTypes.string.isRequired, + fileSize: PropTypes.number.isRequired, + transcripts: PropTypes.arrayOf(PropTypes.string), + }), + // injected + intl: intlShape.isRequired, +}; + +VideoInfoModalSidebar.defaultProps = { + video: null, +}; + +export default injectIntl(VideoInfoModalSidebar); diff --git a/src/files-and-videos/videos-page/info-sidebar/index.js b/src/files-and-videos/videos-page/info-sidebar/index.js new file mode 100644 index 0000000000..78ef7160fe --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/index.js @@ -0,0 +1,3 @@ +import VideoInfoModalSidebar from './VideoInfoModalSidebar'; + +export default VideoInfoModalSidebar; diff --git a/src/files-and-videos/videos-page/info-sidebar/messages.js b/src/files-and-videos/videos-page/info-sidebar/messages.js new file mode 100644 index 0000000000..3beb245c61 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/messages.js @@ -0,0 +1,40 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + infoTabTitle: { + id: 'course-authoring.video-uploads.file-info.infoTab.title', + defaultMessage: 'Info', + description: 'Title for info tab', + }, + transcriptTabTitle: { + id: 'course-authoring.video-uploads.file-info.transcriptTab.title', + defaultMessage: 'Transcript ({transcriptCount})', + description: 'Title for info tab', + }, + dateAddedTitle: { + id: 'course-authoring.video-uploads.file-info.infoTab.dateAdded.title', + defaultMessage: 'Date added', + description: 'Title for date added section', + }, + fileSizeTitle: { + id: 'course-authoring.video-uploads.file-info.infoTab.fileSize.title', + defaultMessage: 'File size', + description: 'Title for file size section', + }, + videoLengthTitle: { + id: 'course-authoring.video-uploads.file-info.infoTab.videoLength.title', + defaultMessage: 'Video length', + description: 'Title for video length section', + }, + errorAlertMessage: { + id: 'course-authoring.files-and-upload.file-info.transcriptTab.errorAlert.message', + defaultMessage: '{message}', + }, + uploadButtonLabel: { + id: 'course-authoriong.video-uploads.file-info.transcriptTab.upload.label', + defaultMessage: 'Add a transcript', + description: 'Label for upload button', + }, +}); + +export default messages; diff --git a/src/files-and-videos/videos-page/info-sidebar/transcript-item/LanguageSelect.jsx b/src/files-and-videos/videos-page/info-sidebar/transcript-item/LanguageSelect.jsx new file mode 100644 index 0000000000..12ed61c6b7 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/transcript-item/LanguageSelect.jsx @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Dropdown, Icon } from '@edx/paragon'; +import { Check } from '@edx/paragon/icons'; +import { isEmpty } from 'lodash'; + +const LanguageSelect = ({ + value, + previousSelection, + options, + handleSelect, + placeholderText, +}) => { + const currentSelection = isEmpty(value) ? placeholderText : options[value]; + return ( + + + {currentSelection} + + + {Object.entries(options).map(([valueKey, text]) => { + if (valueKey === value) { + return ( + + {text} + + ); + } + if (!previousSelection.includes(valueKey)) { + return ( + handleSelect(valueKey)} key={`${valueKey}-item`}> + {text} + + ); + } + return ( + + {text} + + ); + })} + + + ); +}; + +LanguageSelect.propTypes = { + value: PropTypes.string.isRequired, + options: PropTypes.shape({}).isRequired, + handleSelect: PropTypes.func.isRequired, + placeholderText: PropTypes.string.isRequired, + previousSelection: PropTypes.arrayOf(PropTypes.string).isRequired, +}; + +export default LanguageSelect; diff --git a/src/files-and-videos/videos-page/info-sidebar/transcript-item/Transcript.jsx b/src/files-and-videos/videos-page/info-sidebar/transcript-item/Transcript.jsx new file mode 100644 index 0000000000..abceab2773 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/transcript-item/Transcript.jsx @@ -0,0 +1,125 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { + Card, + Button, + Icon, + IconButton, + useToggle, +} from '@edx/paragon'; +import { DeleteOutline } from '@edx/paragon/icons'; +import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; +import { isEmpty } from 'lodash'; +import LanguageSelect from './LanguageSelect'; +import TranscriptMenu from './TranscriptMenu'; +import messages from './messages'; +import { FileInput, useFileInput } from '../../../generic'; + +const Transcript = ({ + languages, + transcript, + previousSelection, + handleTranscript, + // injected + intl, +}) => { + const [isConfirmationOpen, openConfirmation, closeConfirmation] = useToggle(); + const [newLanguage, setNewLanguage] = useState(transcript); + const language = transcript; + + const input = useFileInput({ + onAddFile: (file) => { + handleTranscript({ + file, + language, + newLanguage, + }, 'upload'); + }, + setSelectedRows: () => {}, + setAddOpen: () => {}, + }); + + const updateLangauge = (selected) => { + setNewLanguage(selected); + if (isEmpty(language)) { + input.click(); + } + }; + + return ( + <> + {isConfirmationOpen ? ( + + )} /> + + + + + + + + + + + ) : ( +
    +
    + +
    + { transcript === '' ? ( + + ) : ( + + )} +
    + )} + + + ); +}; + +Transcript.propTypes = { + languages: PropTypes.shape({}).isRequired, + transcript: PropTypes.string.isRequired, + previousSelection: PropTypes.arrayOf(PropTypes.string).isRequired, + handleTranscript: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(Transcript); diff --git a/src/files-and-videos/videos-page/info-sidebar/transcript-item/TranscriptMenu.jsx b/src/files-and-videos/videos-page/info-sidebar/transcript-item/TranscriptMenu.jsx new file mode 100644 index 0000000000..ee97f0f8af --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/transcript-item/TranscriptMenu.jsx @@ -0,0 +1,54 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n'; +import { Dropdown, Icon, IconButton } from '@edx/paragon'; +import { MoreHoriz } from '@edx/paragon/icons'; + +import messages from './messages'; + +export const TranscriptActionMenu = ({ + language, + launchDeleteConfirmation, + handleTranscript, + input, +}) => ( + + + + + + + handleTranscript({ language }, 'download')} + > + + + + + + + +); + +TranscriptActionMenu.propTypes = { + language: PropTypes.string.isRequired, + handleTranscript: PropTypes.func.isRequired, + launchDeleteConfirmation: PropTypes.func.isRequired, + input: PropTypes.shape({ + click: PropTypes.func.isRequired, + }).isRequired, +}; + +export default injectIntl(TranscriptActionMenu); diff --git a/src/files-and-videos/videos-page/info-sidebar/transcript-item/index.js b/src/files-and-videos/videos-page/info-sidebar/transcript-item/index.js new file mode 100644 index 0000000000..9f14ebaa24 --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/transcript-item/index.js @@ -0,0 +1,3 @@ +import Transcript from './Transcript'; + +export default Transcript; diff --git a/src/files-and-videos/videos-page/info-sidebar/transcript-item/messages.js b/src/files-and-videos/videos-page/info-sidebar/transcript-item/messages.js new file mode 100644 index 0000000000..b8b53f11ee --- /dev/null +++ b/src/files-and-videos/videos-page/info-sidebar/transcript-item/messages.js @@ -0,0 +1,51 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + fileSizeError: { + id: 'course-authoriong.video-uploads.file-info.transcript.error.fileSizeError', + defaultMessage: 'Transcript file size exeeds the maximum. Please try again.', + description: 'Message presented to user when transcript file size is too large', + }, + deleteTranscript: { + id: 'course-authoriong.video-uploads.file-info.transcript.deleteTranscript', + defaultMessage: 'Delete', + description: 'Message Presented To user for action to delete transcript', + }, + replaceTranscript: { + id: 'course-authoriong.video-uploads.file-info.transcript.replaceTranscript', + defaultMessage: 'Replace', + description: 'Message Presented To user for action to replace transcript', + }, + downloadTranscript: { + id: 'course-authoriong.video-uploads.file-info.transcript.downloadTranscript', + defaultMessage: 'Download', + description: 'Message Presented To user for action to download transcript', + }, + languageSelectPlaceholder: { + id: 'course-authoriong.video-uploads.file-info.transcripts.languageSelectPlaceholder', + defaultMessage: 'Select language', + description: 'Placeholder For Dropdown, which allows users to set the language associtated with a transcript', + }, + cancelDeleteLabel: { + id: 'course-authoriong.video-uploads.file-info.transcripts.cancelDeleteLabel', + defaultMessage: 'Cancel', + description: 'Label For Button, which allows users to stop the process of deleting a transcript', + }, + confirmDeleteLabel: { + id: 'course-authoriong.video-uploads.file-info.transcripts.confirmDeleteLabel', + defaultMessage: 'Delete', + description: 'Label For Button, which allows users to confirm the process of deleting a transcript', + }, + deleteConfirmationMessage: { + id: 'course-authoriong.video-uploads.file-info.transcripts.deleteConfirmationMessage', + defaultMessage: 'Are you sure you want to delete this transcript?', + description: 'Warning which allows users to select next step in the process of deleting a transcript', + }, + deleteConfirmationHeader: { + id: 'course-authoriong.video-uploads.file-info.transcripts.deleteConfirmationTitle', + defaultMessage: 'Delete this transcript?', + description: 'Title for Warning which allows users to select next step in the process of deleting a transcript', + }, +}); + +export default messages; diff --git a/src/files-and-videos/videos-page/messages.js b/src/files-and-videos/videos-page/messages.js new file mode 100644 index 0000000000..27c5a5ef6f --- /dev/null +++ b/src/files-and-videos/videos-page/messages.js @@ -0,0 +1,38 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + heading: { + id: 'course-authoring.video-uploads.heading', + defaultMessage: 'Videos', + }, + transcriptSettingsButtonLabel: { + id: 'course-authoring.video-uploads.transcript-settings.button.toggle', + defaultMessage: 'Transcript settings', + }, + thumbnailAltMessage: { + id: 'course-authoring.video-uploads.thumbnail.alt', + defaultMessage: '{displayName} video thumbnail', + }, + activeCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.activeCheckbox.label', + defaultMessage: 'Active', + }, + inactiveCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.inactiveCheckbox.label', + defaultMessage: 'Inactive', + }, + transcribedCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.transcribedCheckbox.label', + defaultMessage: 'Transcribed', + }, + notTranscribedCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.notTranscribedCheckbox.label', + defaultMessage: 'Not transcribed', + }, + processingCheckboxLabel: { + id: 'course-authoring.files-and-videos.sort-and-filter.modal.filter.processingCheckbox.label', + defaultMessage: 'Processing', + }, +}); + +export default messages; diff --git a/src/files-and-videos/videos-page/transcript-settings/Cielo24Form.jsx b/src/files-and-videos/videos-page/transcript-settings/Cielo24Form.jsx new file mode 100644 index 0000000000..76dad30e44 --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/Cielo24Form.jsx @@ -0,0 +1,125 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { isEmpty } from 'lodash'; +import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { Form, Stack, TransitionReplace } from '@edx/paragon'; +import FormDropdown from './FormDropdown'; +import { getFidelityOptions } from '../data/utils'; +import messages from './messages'; + +const Cielo24Form = ({ + hasTranscriptCredentials, + data, + setData, + transcriptionPlan, + // injected + intl, +}) => { + if (hasTranscriptCredentials) { + const { fidelity } = transcriptionPlan; + const selectedLanguage = data.preferredLanguages ? data.preferredLanguages : ''; + const turnaroundOptions = transcriptionPlan.turnaround; + const fidelityOptions = getFidelityOptions(fidelity); + const sourceLanguageOptions = data.cielo24Fidelity ? fidelity[data.cielo24Fidelity]?.languages : {}; + const languages = data.cielo24Fidelity === 'PROFESSIONAL' ? sourceLanguageOptions : { + [data.videoSourceLanguage]: sourceLanguageOptions[data.videoSourceLanguage], + }; + return ( + + + + + + setData({ ...data, cielo24Turnaround: value })} + placeholderText={intl.formatMessage(messages.cieloTurnaroundPlaceholder)} + /> + + + + + + setData({ ...data, cielo24Fidelity: value, videoSourceLanguage: '' })} + placeholderText={intl.formatMessage(messages.cieloFidelityPlaceholder)} + /> + + + {isEmpty(data.cielo24Fidelity) ? null : ( + + + + + setData({ ...data, videoSourceLanguage: value, preferredLanguages: [] })} + placeholderText={intl.formatMessage(messages.cieloSourceLanguagePlaceholder)} + /> + + )} + + + {isEmpty(data.videoSourceLanguage) ? null : ( + + + + + setData({ ...data, preferredLanguages: [value] })} + placeholderText={intl.formatMessage(messages.cieloTranscriptLanguagePlaceholder)} + /> + + )} + + + ); + } + + return ( + +
    + +
    + + + + + setData({ ...data, apiKey: e.target.value })} /> + + + + + + setData({ ...data, username: e.target.value })} /> + +
    + ); +}; + +Cielo24Form.propTypes = { + hasTranscriptCredentials: PropTypes.bool.isRequired, + data: PropTypes.shape({ + apiKey: PropTypes.string, + apiSecretKey: PropTypes.string, + cielo24Turnaround: PropTypes.string, + cielo24Fidelity: PropTypes.string, + preferredLanguages: PropTypes.arrayOf(PropTypes.string), + videoSourceLanguage: PropTypes.string, + }).isRequired, + setData: PropTypes.func.isRequired, + transcriptionPlan: PropTypes.shape({ + turnaround: PropTypes.shape({}), + fidelity: PropTypes.shape({}), + }).isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(Cielo24Form); diff --git a/src/files-and-videos/videos-page/transcript-settings/FormDropdown.jsx b/src/files-and-videos/videos-page/transcript-settings/FormDropdown.jsx new file mode 100644 index 0000000000..99c03556e2 --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/FormDropdown.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Dropdown, Form, Icon } from '@edx/paragon'; +import PropTypes from 'prop-types'; +import { Check } from '@edx/paragon/icons'; +import { isArray, isEmpty } from 'lodash'; + +const FormDropdown = ({ + value, + allowMultiple, + options, + handleSelect, + placeholderText, +}) => { + let currentSelection; + if (isEmpty(value)) { + currentSelection = placeholderText; + } else { + currentSelection = isArray(value) && value.length > 1 ? 'Multiple' : options[value]; + } + + return ( + + + + {currentSelection} + + + + {Object.entries(options).map(([valueKey, text]) => { + if (allowMultiple) { + return ( + handleSelect([valueKey, e.target.checked])} key={`${valueKey}-item`}> + {text} + + ); + } + if (valueKey === value) { + return ( + + {text} + + ); + } + return ( + handleSelect(valueKey)} key={`${valueKey}-item`}> + {text} + + ); + })} + + + ); +}; + +FormDropdown.propTypes = { + value: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).isRequired, + allowMultiple: PropTypes.bool, + options: PropTypes.shape({}).isRequired, + handleSelect: PropTypes.func.isRequired, + placeholderText: PropTypes.string.isRequired, +}; + +FormDropdown.defaultProps = { + allowMultiple: false, +}; + +export default FormDropdown; diff --git a/src/files-and-videos/videos-page/transcript-settings/OrderTranscriptForm.jsx b/src/files-and-videos/videos-page/transcript-settings/OrderTranscriptForm.jsx new file mode 100644 index 0000000000..a55a0483b2 --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/OrderTranscriptForm.jsx @@ -0,0 +1,188 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { Button, SelectableBox, Stack } from '@edx/paragon'; +import { ErrorAlert } from '@edx/frontend-lib-content-components'; +import Cielo24Form from './Cielo24Form'; +import ThreePlayMediaForm from './ThreePlayMediaForm'; +import { RequestStatus } from '../../../data/constants'; +import messages from './messages'; +import { checkCredentials, checkTranscriptionPlans, validateForm } from '../data/utils'; + +const OrderTranscriptForm = ({ + setTranscriptType, + activeTranscriptPreferences, + transcriptType, + transcriptCredentials, + closeTranscriptSettings, + handleOrderTranscripts, + transcriptionPlans, + errorMessages, + transcriptStatus, + // injected + intl, +}) => { + const [data, setData] = useState(activeTranscriptPreferences || { videoSourceLanguage: '' }); + + const [validCieloTranscriptionPlan, validThreePlayTranscriptionPlan] = checkTranscriptionPlans(transcriptionPlans); + + let [cieloHasCredentials, threePlayHasCredentials] = checkCredentials(transcriptCredentials); + useEffect(() => { + [cieloHasCredentials, threePlayHasCredentials] = checkCredentials(transcriptCredentials); + }, [transcriptCredentials]); + + let isFormValid = validateForm(cieloHasCredentials, threePlayHasCredentials, transcriptType, data); + useEffect(() => { + isFormValid = validateForm(cieloHasCredentials, threePlayHasCredentials, transcriptType, data); + }, [data]); + + const handleDiscard = () => { + setTranscriptType(activeTranscriptPreferences?.provider); + closeTranscriptSettings(); + }; + + const handleUpdate = () => handleOrderTranscripts(data, transcriptType); + + let form; + switch (transcriptType) { + case 'Cielo24': + form = ( + + ); + break; + case '3PlayMedia': + form = ( + + ); + break; + default: + break; + } + return ( + <> + + + + + + + +
      + {errorMessages.transcript.map(message => ( +
    • + {intl.formatMessage(messages.errorAlertMessage, { message })} +
    • + ))} +
    +
    + { + setTranscriptType(e.target.value); + }} + > + + + + + + + + + + + {form} + + + + + + ); +}; + +OrderTranscriptForm.propTypes = { + setTranscriptType: PropTypes.func.isRequired, + activeTranscriptPreferences: PropTypes.shape({ + provider: PropTypes.string.isRequired, + cielo24Turnaround: PropTypes.string, + cielo24Fidelity: PropTypes.string, + preferredLanguages: PropTypes.arrayOf(PropTypes.string), + turnaround: PropTypes.string, + videoSourceLanguage: PropTypes.string, + }), + transcriptType: PropTypes.string.isRequired, + transcriptCredentials: PropTypes.shape({ + cielo24: PropTypes.bool.isRequired, + '3PlayMedia': PropTypes.bool.isRequired, + }).isRequired, + closeTranscriptSettings: PropTypes.func.isRequired, + transcriptStatus: PropTypes.string.isRequired, + errorMessages: PropTypes.shape({ + transcript: PropTypes.arrayOf(PropTypes.string).isRequired, + }).isRequired, + handleOrderTranscripts: PropTypes.func.isRequired, + transcriptionPlans: PropTypes.shape({ + Cielo24: PropTypes.shape({ + turnaround: PropTypes.shape({}), + fidelity: PropTypes.shape({}), + }).isRequired, + '3PlayMedia': PropTypes.shape({ + turnaround: PropTypes.shape({}), + translations: PropTypes.shape({}), + languages: PropTypes.shape({}), + }).isRequired, + }).isRequired, + // injected + intl: intlShape.isRequired, +}; + +OrderTranscriptForm.defaultProps = { + activeTranscriptPreferences: null, +}; + +export default injectIntl(OrderTranscriptForm); diff --git a/src/files-and-videos/videos-page/transcript-settings/ThreePlayMediaForm.jsx b/src/files-and-videos/videos-page/transcript-settings/ThreePlayMediaForm.jsx new file mode 100644 index 0000000000..fdde6f1c25 --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/ThreePlayMediaForm.jsx @@ -0,0 +1,140 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { isEmpty } from 'lodash'; +import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; +import { + Form, + Icon, + Stack, + TransitionReplace, +} from '@edx/paragon'; +import { Check } from '@edx/paragon/icons'; +import FormDropdown from './FormDropdown'; +import { getLanguageOptions } from '../data/utils'; +import messages from './messages'; + +const ThreePlayMediaForm = ({ + hasTranscriptCredentials, + data, + setData, + transcriptionPlan, + // injected + intl, +}) => { + if (hasTranscriptCredentials) { + const selectedLanguages = data.preferredLanguages ? data.preferredLanguages : []; + const turnaroundOptions = transcriptionPlan.turnaround; + const sourceLangaugeOptions = getLanguageOptions( + Object.keys(transcriptionPlan.translations), + transcriptionPlan.languages, + ); + const languages = getLanguageOptions( + transcriptionPlan.translations[data.videoSourceLanguage], + transcriptionPlan.languages, + ); + const allowMultiple = Object.keys(languages).length > 1; + return ( + + + + + + setData({ ...data, threePlayTurnaround: value })} + placeholderText={intl.formatMessage(messages.threePlayMediaTurnaroundPlaceholder)} + /> + + + + + + setData({ ...data, videoSourceLanguage: value, preferredLanguages: [] })} + placeholderText={intl.formatMessage(messages.threePlayMediaSourceLanguagePlaceholder)} + /> + + + {!isEmpty(data.videoSourceLanguage) ? ( + + + + + { + if (!allowMultiple) { + setData({ ...data, preferredLanguages: [value] }); + } else { + const [lang, checked] = value; + if (checked) { + setData({ ...data, preferredLanguages: [...selectedLanguages, lang] }); + } else { + const updatedLangList = selectedLanguages.filter((selected) => selected !== lang); + setData({ ...data, preferredLanguages: updatedLangList }); + } + } + }} + placeholderText={intl.formatMessage(messages.threePlayMediaTranscriptLanguagePlaceholder)} + /> + +
      + {selectedLanguages.map(language => ( +
    • + {languages[language]} +
    • + ))} +
    +
    +
    + ) : null } +
    +
    + ); + } + return ( + +
    + +
    + + + + + setData({ ...data, apiKey: e.target.value })} /> + + + + + + setData({ ...data, apiSecretKey: e.target.value })} /> + +
    + ); +}; + +ThreePlayMediaForm.propTypes = { + hasTranscriptCredentials: PropTypes.bool.isRequired, + data: PropTypes.shape({ + apiKey: PropTypes.string, + apiSecretKey: PropTypes.string, + threePlayTurnaround: PropTypes.string, + preferredLanguages: PropTypes.arrayOf(PropTypes.string), + videoSourceLanguage: PropTypes.string, + }).isRequired, + setData: PropTypes.func.isRequired, + transcriptionPlan: PropTypes.shape({ + turnaround: PropTypes.shape({}), + translations: PropTypes.shape({}), + languages: PropTypes.shape({}), + }).isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(ThreePlayMediaForm); diff --git a/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.jsx b/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.jsx new file mode 100644 index 0000000000..0c94ee0a03 --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.jsx @@ -0,0 +1,121 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { isEmpty } from 'lodash'; +import { useDispatch, useSelector } from 'react-redux'; +import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { + ActionRow, + Collapsible, + Icon, IconButton, + Sheet, + TransitionReplace, +} from '@edx/paragon'; +import { ChevronLeft, ChevronRight, Close } from '@edx/paragon/icons'; +import OrderTranscriptForm from './OrderTranscriptForm'; +import messages from './messages'; +import { + clearAutomatedTranscript, + resetErrors, + updateTranscriptCredentials, + updateTranscriptPreference, +} from '../data/thunks'; + +const TranscriptSettings = ({ + isTranscriptSettingsOpen, + closeTranscriptSettings, + courseId, +}) => { + const dispatch = useDispatch(); + const { errors: errorMessages, pageSettings, transcriptStatus } = useSelector(state => state.videos); + const { + activeTranscriptPreferences, + transcriptCredentials, + videoTranscriptSettings, + } = pageSettings; + const { transcriptionPlans } = videoTranscriptSettings || {}; + const [transcriptType, setTranscriptType] = useState(activeTranscriptPreferences?.provider); + + const handleOrderTranscripts = (data, provider) => { + const noCredentials = isEmpty(transcriptCredentials) || data.apiKey; + dispatch(resetErrors({ errorType: 'transcript' })); + if (provider === 'order') { + dispatch(clearAutomatedTranscript({ courseId })); + } else if (noCredentials) { + dispatch(updateTranscriptCredentials({ courseId, data: { ...data, provider, global: false } })); + } else { + dispatch(updateTranscriptPreference({ courseId, data: { ...data, provider, global: false } })); + } + }; + + return ( + +
    + + + {transcriptType ? ( + setTranscriptType(null)} + alt="back button to main transcript settings view" + /> + ) : ( +
    + +
    + )} +
    + + +
    + + {transcriptType ? ( +
    + +
    + ) : ( +
    + setTranscriptType('order')} + > + + + + + +
    + )} +
    +
    +
    + ); +}; + +TranscriptSettings.propTypes = { + closeTranscriptSettings: PropTypes.func.isRequired, + isTranscriptSettingsOpen: PropTypes.bool.isRequired, + courseId: PropTypes.string.isRequired, +}; + +export default injectIntl(TranscriptSettings); diff --git a/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.scss b/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.scss new file mode 100644 index 0000000000..465d640e2b --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.scss @@ -0,0 +1,4 @@ +.pgn__selectable_box:disabled, +.pgn__selectable_box[disabled] { + opacity: .5; +} diff --git a/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.test.jsx b/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.test.jsx new file mode 100644 index 0000000000..4af40670fd --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/TranscriptSettings.test.jsx @@ -0,0 +1,660 @@ +import { + render, + act, + screen, + waitFor, + within, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { + initializeMockApp, +} from '@edx/frontend-platform'; +import MockAdapter from 'axios-mock-adapter'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import initializeStore from '../../../store'; +import { RequestStatus } from '../../../data/constants'; +import TranscriptSettings from './TranscriptSettings'; +import { + courseId, + initialState, +} from '../factories/mockApiResponses'; +import { getApiBaseUrl } from '../data/api'; +import messages from './messages'; +import VideosProvider from '../VideosPageProvider'; + +const defaultProps = { + isTranscriptSettingsOpen: true, + closeTranscriptSettings: jest.fn(), + courseId, +}; + +let axiosMock; +let store; + +const renderComponent = () => { + render( + + + + + + + , + ); +}; + +describe('TranscriptSettings', () => { + describe('default behaviors', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore(initialState); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + it('should have Transcript settings title', async () => { + renderComponent(); + const header = screen.getByText(messages.transcriptSettingsTitle.defaultMessage); + + expect(header).toBeVisible(); + }); + + it('should change view to order form', async () => { + renderComponent(defaultProps); + const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage); + await act(async () => { + userEvent.click(orderButton); + }); + const selectableButtons = screen.getAllByLabelText('none radio')[0]; + + expect(selectableButtons).toBeVisible(); + }); + + it('should return to order transcript collapsible', async () => { + renderComponent(defaultProps); + const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage); + await act(async () => { + userEvent.click(orderButton); + }); + const selectableButtons = screen.getAllByLabelText('none radio')[0]; + + expect(selectableButtons).toBeVisible(); + + const backButton = screen.getByLabelText('back button to main transcript settings view'); + await waitFor(() => { + userEvent.click(backButton); + + expect(screen.queryByLabelText('back button to main transcript settings view')).toBeNull(); + }); + }); + + it('discard changes should call closeTranscriptSettings', async () => { + renderComponent(defaultProps); + const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage); + await act(async () => { + userEvent.click(orderButton); + }); + const discardButton = screen.getByText(messages.discardSettingsLabel.defaultMessage); + await act(async () => { + userEvent.click(discardButton); + }); + + expect(defaultProps.closeTranscriptSettings).toHaveBeenCalled(); + }); + }); + + describe('loading saved preference', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore({ + ...initialState, + videos: { + ...initialState.videos, + pageSettings: { + ...initialState.videos.pageSettings, + activeTranscriptPreferences: { + provider: 'Cielo24', + cielo24Fidelity: '', + cielo24Turnaround: '', + preferredLanguages: [], + threePlayTurnaround: '', + videoSourceLanguage: '', + }, + }, + }, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + + renderComponent(defaultProps); + }); + + it('should load page with Cielo24 selected', async () => { + const cielo24Button = screen.getByText(messages.cieloLabel.defaultMessage); + + expect(within(cielo24Button).getByLabelText('Cielo24 radio')).toHaveProperty('checked', true); + }); + }); + + describe('delete transcript preferences', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore({ + ...initialState, + videos: { + ...initialState.videos, + pageSettings: { + ...initialState.videos.pageSettings, + activeTranscriptPreferences: { + provider: 'Cielo24', + cielo24Fidelity: '', + cielo24Turnaround: '', + preferredLanguages: [], + threePlayTurnaround: '', + videoSourceLanguage: '', + }, + }, + }, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + + renderComponent(defaultProps); + const noneButton = screen.getAllByLabelText('none radio')[0]; + + await act(async () => { + userEvent.click(noneButton); + }); + }); + + it('api should succeed', async () => { + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + + axiosMock.onDelete(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(204); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('should show error alert', async () => { + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + + axiosMock.onDelete(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(404); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Failed to update order transcripts settings.')).toBeVisible(); + }); + }); + + describe('with no credentials set', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore(initialState); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + + renderComponent(defaultProps); + const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage); + await act(async () => { + userEvent.click(orderButton); + }); + }); + + it('should ask for Cielo24 or 3Play Media credentials', async () => { + const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0]; + await act(async () => { + userEvent.click(cielo24Button); + }); + const cieloCredentialMessage = screen.getByTestId('cieloCredentialMessage'); + + expect(cieloCredentialMessage).toBeVisible(); + + const threePlayMediaButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayMediaButton); + }); + const threePlayMediaCredentialMessage = screen.getByTestId('threePlayMediaCredentialMessage'); + + expect(threePlayMediaCredentialMessage).toBeVisible(); + }); + + describe('api succeeds', () => { + it('should update cielo24 credentials ', async () => { + const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0]; + await act(async () => { + userEvent.click(cielo24Button); + }); + + const firstInput = screen.getByLabelText(messages.cieloApiKeyLabel.defaultMessage); + const secondInput = screen.getByLabelText(messages.cieloUsernameLabel.defaultMessage); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + + await waitFor(() => { + userEvent.type(firstInput, 'apiKey'); + userEvent.type(secondInput, 'username'); + + expect(updateButton).not.toHaveAttribute('disabled'); + }); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_credentials/${courseId}`).reply(200); + await waitFor(() => { + userEvent.click(updateButton); + }); + + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.queryByTestId('cieloCredentialMessage')).toBeNull(); + + expect(screen.getByText(messages.cieloFidelityLabel.defaultMessage)).toBeVisible(); + }); + + it('should update 3Play Media credentials', async () => { + const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayButton); + }); + + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const firstInput = screen.getByLabelText(messages.threePlayMediaApiKeyLabel.defaultMessage); + const secondInput = screen.getByLabelText(messages.threePlayMediaApiSecretLabel.defaultMessage); + + await waitFor(() => { + userEvent.type(firstInput, 'apiKey'); + userEvent.type(secondInput, 'secretKey'); + + expect(updateButton).not.toHaveAttribute('disabled'); + }); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_credentials/${courseId}`).reply(200); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.queryByTestId('threePlayCredentialMessage')).toBeNull(); + + expect(screen.getByText(messages.threePlayMediaTurnaroundLabel.defaultMessage)).toBeVisible(); + }); + }); + + describe('api fails', () => { + it('should show error alert on Cielo24 credentials update', async () => { + const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0]; + await act(async () => { + userEvent.click(cielo24Button); + }); + + const firstInput = screen.getByLabelText(messages.cieloApiKeyLabel.defaultMessage); + const secondInput = screen.getByLabelText(messages.cieloUsernameLabel.defaultMessage); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + + await waitFor(() => { + userEvent.type(firstInput, 'apiKey'); + userEvent.type(secondInput, 'username'); + + expect(updateButton).not.toHaveAttribute('disabled'); + }); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(503); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Failed to update Cielo24 credentials.')).toBeVisible(); + }); + + it('should show error alert on 3PlayMedia credentials update', async () => { + const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayButton); + }); + + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const firstInput = screen.getByLabelText(messages.threePlayMediaApiKeyLabel.defaultMessage); + const secondInput = screen.getByLabelText(messages.threePlayMediaApiSecretLabel.defaultMessage); + + await waitFor(() => { + userEvent.type(firstInput, 'apiKey'); + userEvent.type(secondInput, 'secretKey'); + + expect(updateButton).not.toHaveAttribute('disabled'); + }); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(404); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Failed to update 3PlayMedia credentials.')).toBeVisible(); + }); + }); + }); + + describe('with credentials set', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: false, + roles: [], + }, + }); + store = initializeStore({ + ...initialState, + videos: { + ...initialState.videos, + pageSettings: { + ...initialState.videos.pageSettings, + transcriptCredentials: { + cielo24: true, + '3PlayMedia': true, + }, + }, + }, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + renderComponent(defaultProps); + const orderButton = screen.getByText(messages.orderTranscriptsTitle.defaultMessage); + await act(async () => { + userEvent.click(orderButton); + }); + }); + + it('should not show credentials request for Cielo24 and 3Play Media', async () => { + const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0]; + await act(async () => { + userEvent.click(cielo24Button); + }); + const cieloCredentialMessage = screen.queryByTestId('cieloCredentialMessage'); + + expect(cieloCredentialMessage).toBeNull(); + + const threePlayMediaButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayMediaButton); + }); + const threePlayMediaCredentialMessage = screen.queryByTestId('threePlayMediaCredentialMessage'); + + expect(threePlayMediaCredentialMessage).toBeNull(); + }); + + describe('api succeeds', () => { + it('should update cielo24 preferences', async () => { + const apiResponse = { + videoSourceLanguage: 'en', + cielo24Turnaround: 'PRIORITY', + cielo24FidelityTypee: 'PREMIUM', + preferredLanguages: ['en'], + provider: 'cielo24', + global: false, + }; + + const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0]; + await act(async () => { + userEvent.click(cielo24Button); + }); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const turnaround = screen.getByText(messages.cieloTurnaroundPlaceholder.defaultMessage); + const fidelity = screen.getByText(messages.cieloFidelityPlaceholder.defaultMessage); + + await waitFor(() => { + userEvent.click(turnaround); + userEvent.click(screen.getByText('Priority (24 hours)')); + + userEvent.click(fidelity); + userEvent.click(screen.getByText('Premium (95% accuracy)')); + + const source = screen.getAllByText(messages.cieloSourceLanguagePlaceholder.defaultMessage)[0]; + userEvent.click(source); + userEvent.click(screen.getByText('English')); + + const language = screen.getByText(messages.cieloTranscriptLanguagePlaceholder.defaultMessage); + userEvent.click(language); + userEvent.click(screen.getAllByText('English')[2]); + }); + + expect(updateButton).not.toHaveAttribute('disabled'); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(200, apiResponse); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.SUCCESSFUL); + + expect(screen.getByText(messages.cieloFidelityLabel.defaultMessage)).toBeVisible(); + }); + + it('should update 3Play Media preferences with english as source language', async () => { + const apiResponse = { + videoSourceLanguage: 'en', + threePlayTurnaround: 'two_hour', + preferredLanguages: ['ar', 'fr'], + provider: '3PlayMedia', + global: false, + }; + const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayButton); + }); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage); + const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage); + + await waitFor(() => { + userEvent.click(turnaround); + userEvent.click(screen.getByText('2 hours')); + + userEvent.click(source); + userEvent.click(screen.getByText('English')); + + const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage); + userEvent.click(language); + userEvent.click(screen.getByText('Arabic')); + userEvent.click(screen.getByText('French')); + userEvent.click(screen.getAllByText('Arabic')[0]); + + expect(updateButton).not.toHaveAttribute('disabled'); + }); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(200, apiResponse); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + + it('should update 3Play Media preferences with spanish as source language', async () => { + const apiResponse = { + videoSourceLanguage: 'en', + threePlayTurnaround: 'two_hour', + preferredLanguages: ['ar', 'fr'], + provider: '3PlayMedia', + global: false, + }; + const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayButton); + }); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage); + const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage); + + await waitFor(() => { + userEvent.click(turnaround); + userEvent.click(screen.getByText('2 hours')); + + userEvent.click(source); + userEvent.click(screen.getByText('Spanish')); + + const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage); + userEvent.click(language); + userEvent.click(screen.getAllByText('English')[1]); + }); + expect(updateButton).not.toHaveAttribute('disabled'); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(200, apiResponse); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.SUCCESSFUL); + }); + }); + + describe('api fails', () => { + it('should show error alert on Cielo24 preferences update', async () => { + const cielo24Button = screen.getAllByLabelText('Cielo24 radio')[0]; + await act(async () => { + userEvent.click(cielo24Button); + }); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const turnaround = screen.getByText(messages.cieloTurnaroundPlaceholder.defaultMessage); + const fidelity = screen.getByText(messages.cieloFidelityPlaceholder.defaultMessage); + + await waitFor(() => { + userEvent.click(turnaround); + userEvent.click(screen.getByText('Priority (24 hours)')); + + userEvent.click(fidelity); + userEvent.click(screen.getByText('Premium (95% accuracy)')); + + const source = screen.getAllByText(messages.cieloSourceLanguagePlaceholder.defaultMessage)[0]; + userEvent.click(source); + userEvent.click(screen.getByText('English')); + + const language = screen.getByText(messages.cieloTranscriptLanguagePlaceholder.defaultMessage); + userEvent.click(language); + userEvent.click(screen.getAllByText('English')[2]); + }); + + expect(updateButton).not.toHaveAttribute('disabled'); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(503); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Failed to update Cielo24 transcripts settings.')).toBeVisible(); + }); + + it('should show error alert with default message on 3PlayMedia preferences update', async () => { + const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayButton); + }); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage); + const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage); + + await waitFor(() => { + userEvent.click(turnaround); + userEvent.click(screen.getByText('2 hours')); + + userEvent.click(source); + userEvent.click(screen.getByText('Spanish')); + + const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage); + userEvent.click(language); + userEvent.click(screen.getAllByText('English')[1]); + }); + expect(updateButton).not.toHaveAttribute('disabled'); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(404); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Failed to update 3PlayMedia transcripts settings.')).toBeVisible(); + }); + + it('should show error alert with default message on 3PlayMedia preferences update', async () => { + const threePlayButton = screen.getAllByLabelText('3PlayMedia radio')[0]; + await act(async () => { + userEvent.click(threePlayButton); + }); + const updateButton = screen.getByText(messages.updateSettingsLabel.defaultMessage); + const turnaround = screen.getByText(messages.threePlayMediaTurnaroundPlaceholder.defaultMessage); + const source = screen.getByText(messages.threePlayMediaSourceLanguagePlaceholder.defaultMessage); + + await waitFor(() => { + userEvent.click(turnaround); + userEvent.click(screen.getByText('2 hours')); + + userEvent.click(source); + userEvent.click(screen.getByText('Spanish')); + + const language = screen.getByText(messages.threePlayMediaTranscriptLanguagePlaceholder.defaultMessage); + userEvent.click(language); + userEvent.click(screen.getAllByText('English')[1]); + }); + expect(updateButton).not.toHaveAttribute('disabled'); + + axiosMock.onPost(`${getApiBaseUrl()}/transcript_preferences/${courseId}`).reply(404, { error: 'Invalid turnaround.' }); + await waitFor(() => { + userEvent.click(updateButton); + }); + const { transcriptStatus } = store.getState().videos; + + expect(transcriptStatus).toEqual(RequestStatus.FAILED); + + expect(screen.getByText('Invalid turnaround.')).toBeVisible(); + }); + }); + }); +}); diff --git a/src/files-and-videos/videos-page/transcript-settings/index.js b/src/files-and-videos/videos-page/transcript-settings/index.js new file mode 100644 index 0000000000..00661e5b6d --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/index.js @@ -0,0 +1,3 @@ +import TranscriptSettings from './TranscriptSettings'; + +export default TranscriptSettings; diff --git a/src/files-and-videos/videos-page/transcript-settings/messages.js b/src/files-and-videos/videos-page/transcript-settings/messages.js new file mode 100644 index 0000000000..ef8817a7e2 --- /dev/null +++ b/src/files-and-videos/videos-page/transcript-settings/messages.js @@ -0,0 +1,153 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + transcriptSettingsTitle: { + id: 'course-authoring.video-uploads.transcriptSettings.title', + defaultMessage: 'Transcript settings', + description: 'Title for transcript settings sheet', + }, + invalidCielo24TranscriptionPlanMessage: { + id: 'course-authoring.video-uploads.transcriptSettings.cielo24.errorAlert.message', + defaultMessage: 'No transcription plans found for Cielo24.', + }, + invalid3PlayMediaTranscriptionPlanMessage: { + id: 'course-authoring.video-uploads.transcriptSettings.3PlayMedia.errorAlert.message', + defaultMessage: 'No transcription plans found for 3PlayMedia.', + }, + errorAlertMessage: { + id: 'course-authoring.video-uploads.transcriptSettings.errorAlert.message', + defaultMessage: '{message}', + }, + orderTranscriptsTitle: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.title', + defaultMessage: 'Order transcripts', + description: 'Title for order transcript collapsible', + }, + noneLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.none.label', + defaultMessage: 'None', + description: 'Label for order transcript None option', + }, + cieloLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.label', + defaultMessage: 'Cielo24', + description: 'Label for order transcript Cieol24 option', + }, + threePlayMediaLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.label', + defaultMessage: '3Play Media', + description: 'Label for order transcript 3Play Media option', + }, + updateSettingsLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.updateSettings.label', + defaultMessage: 'Update settings', + description: 'Label for order transcript update settings button', + }, + discardSettingsLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.discardSettings.label', + defaultMessage: 'Discard settings', + description: 'Label for order transcript discard settings button', + }, + threePlayMediaTurnaroundLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.turnaround.label', + defaultMessage: 'Transcript turnaround', + description: 'Label for 3Play Media transcript turnaround dropdown', + }, + threePlayMediaTurnaroundPlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.turnaround.dropdown.placeholder', + defaultMessage: 'Select turnaround', + description: 'Label for 3Play Media transcript turnaround dropdown placeholder', + }, + threePlayMediaSourceLanguageLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.sourceLanguage.label', + defaultMessage: 'Video source language', + description: 'Label for 3Play Media video source language dropdown', + }, + threePlayMediaSourceLanguagePlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.sourceLanguage.dropdown.placeholder', + defaultMessage: 'Select language', + description: 'Label for 3Play Media video source language dropdown placeholder', + }, + threePlayMediaTranscriptLanguageLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.transcriptLanguage.label', + defaultMessage: 'Transcript language', + description: 'Label for 3Play Media video source language dropdown', + }, + threePlayMediaTranscriptLanguagePlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.transcriptLanguage.dropdown.placeholder', + defaultMessage: 'Select language(s)', + description: 'Label for 3Play Media transcript language dropdown placeholder', + }, + threePlayMediaCredentialMessage: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.credential.message', + defaultMessage: 'Enter the account information for your organization.', + description: 'Message for 3Play Media credential view', + }, + threePlayMediaApiKeyLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.apiKey.label', + defaultMessage: 'API key', + description: 'Label for 3Play Media API key input', + }, + threePlayMediaApiSecretLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.3PlayMedia.apiSecret.label', + defaultMessage: 'API secret', + description: 'Label for 3Play Media API secret input', + }, + cieloTurnaroundLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.turnaround.label', + defaultMessage: 'Transcript turnaround', + description: 'Label for Cielo24 transcript turnaround dropdown', + }, + cieloTurnaroundPlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.turnaround.dropdown.placeholder', + defaultMessage: 'Select turnaround', + description: 'Label for Cielo24 transcript turnaround dropdown placeholder', + }, + cieloFidelityLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.fidelity.label', + defaultMessage: 'Transcript fidelity', + description: 'Label for Cielo24 transcript fidelity dropdown', + }, + cieloFidelityPlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.fidelity.dropdown.placeholder', + defaultMessage: 'Select fidelity', + description: 'Label for Cielo24 transcript fidelity dropdown placeholder', + }, + cieloSourceLanguageLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.sourceLanguage.label', + defaultMessage: 'Video source language', + description: 'Label for Cielo24 video source language dropdown', + }, + cieloSourceLanguagePlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.sourceLanguage.dropdown.placeholder', + defaultMessage: 'Select language', + description: 'Label for Cielo24 video source language dropdown placeholder', + }, + cieloTranscriptLanguageLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.transcriptLanguage.label', + defaultMessage: 'Transcript language', + description: 'Label for Cielo24 video source language dropdown', + }, + cieloTranscriptLanguagePlaceholder: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.transcriptLanguage.dropdown.placeholder', + defaultMessage: 'Select language', + description: 'Label for Cielo24 transcript language dropdown placeholder', + }, + cieloCredentialMessage: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.credential.message', + defaultMessage: 'Enter the account information for your organization.', + description: 'Message for Cielo24 credential view', + }, + cieloApiKeyLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.apiKey.label', + defaultMessage: 'API key', + description: 'Label for Cielo24 API key input', + }, + cieloUsernameLabel: { + id: 'course-authoring.video-uploads.transcriptSettings.orderTranscripts.cielo24.username.label', + defaultMessage: 'Username', + description: 'Label for Cielo24 username input', + }, +}); + +export default messages; diff --git a/src/generic/FormikControl.jsx b/src/generic/FormikControl.jsx index 2d2ab5e7d0..981e3be025 100644 --- a/src/generic/FormikControl.jsx +++ b/src/generic/FormikControl.jsx @@ -39,7 +39,7 @@ const FormikControl = ({ }; FormikControl.propTypes = { - name: PropTypes.element.isRequired, + name: PropTypes.string.isRequired, label: PropTypes.element, help: PropTypes.element, className: PropTypes.string, diff --git a/src/generic/WysiwygEditor.jsx b/src/generic/WysiwygEditor.jsx index 0f6c7d087f..e89b3b6859 100644 --- a/src/generic/WysiwygEditor.jsx +++ b/src/generic/WysiwygEditor.jsx @@ -73,7 +73,7 @@ export const WysiwygEditor = ({ minHeight={minHeight} editorContentHtml={initialValue} setEditorRef={setEditorRef} - updateContent={handleUpdate} + onChange={handleUpdate} initializeEditor={() => ({})} /> diff --git a/src/generic/WysiwygEditor.scss b/src/generic/WysiwygEditor.scss new file mode 100644 index 0000000000..06a1226583 --- /dev/null +++ b/src/generic/WysiwygEditor.scss @@ -0,0 +1,5 @@ +.tox-dialog-wrap__backdrop { + background-color: $black !important; + opacity: .5; + z-index: $zindex-modal-backdrop; +} diff --git a/src/generic/course-stepper/CourseStepper.test.jsx b/src/generic/course-stepper/CourseStepper.test.jsx new file mode 100644 index 0000000000..5a1c8dbe75 --- /dev/null +++ b/src/generic/course-stepper/CourseStepper.test.jsx @@ -0,0 +1,107 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; + +import CourseStepper from '.'; + +const stepsMock = [ + { + title: 'Preparing', + description: 'Preparing to start the export', + }, + { + title: 'Exporting', + description: 'Creating the export data files (You can now leave this page safely, but avoid making drastic changes to content until this export is complete', + }, + { + title: 'Compressing', + description: 'Compressing the exported data and preparing it for download', + }, + { + title: 'Success', + description: 'Your exported course can now be downloaded', + }, +]; + +const renderComponent = (props) => render( + + + , +); + +describe('', () => { + it('renders CourseStepper correctly', () => { + const { + getByText, getByTestId, getAllByTestId, queryByTestId, + } = renderComponent({ activeKey: 0 }); + + const steps = getAllByTestId('course-stepper__step'); + expect(steps.length).toBe(stepsMock.length); + + stepsMock.forEach((step) => { + expect(getByText(step.title)).toBeInTheDocument(); + expect(getByText(step.description)).toBeInTheDocument(); + expect(getByTestId(`${step.title}-icon`)).toBeInTheDocument(); + }); + + const percentElement = queryByTestId('course-stepper__step-percent'); + expect(percentElement).toBeNull(); + }); + + it('marks the active and done steps correctly', () => { + const activeKey = 1; + const { getAllByTestId } = renderComponent({ activeKey }); + + const steps = getAllByTestId('course-stepper__step'); + stepsMock.forEach((_, index) => { + const stepElement = steps[index]; + if (index === activeKey) { + expect(stepElement).toHaveClass('active'); + expect(stepElement).not.toHaveClass('done'); + } + if (index < activeKey) { + expect(stepElement).not.toHaveClass('active'); + expect(stepElement).toHaveClass('done'); + } + if (index > activeKey) { + expect(stepElement).not.toHaveClass('active'); + expect(stepElement).not.toHaveClass('done'); + } + }); + }); + + it('mark the error step correctly', () => { + const { getAllByTestId } = renderComponent({ activeKey: 1, hasError: true }); + + const errorStep = getAllByTestId('course-stepper__step')[1]; + expect(errorStep).toHaveClass('error'); + }); + + it('shows error message for error step', () => { + const errorMessage = 'Some error text'; + const { getAllByTestId } = renderComponent({ activeKey: 1, hasError: true, errorMessage }); + + const errorStep = getAllByTestId('course-stepper__step')[1]; + expect(errorStep).toHaveClass('error'); + }); + + it('shows percentage for active step', () => { + const percent = 50; + const { getByTestId } = renderComponent({ activeKey: 1, percent }); + + const percentElement = getByTestId('course-stepper__step-percent'); + expect(percentElement).toBeInTheDocument(); + expect(percentElement).toHaveTextContent(`${percent}%`); + }); + + it('shows null when steps length equal to zero', () => { + const { queryByTestId } = render( + + + , + ); + + const steps = queryByTestId('[data-testid="course-stepper__step"]'); + expect(steps).toBe(null); + }); +}); diff --git a/src/generic/course-stepper/CouseStepper.scss b/src/generic/course-stepper/CouseStepper.scss new file mode 100644 index 0000000000..868f1c6f89 --- /dev/null +++ b/src/generic/course-stepper/CouseStepper.scss @@ -0,0 +1,68 @@ +.course-stepper { + .course-stepper__step { + display: flex; + gap: $spacer; + padding: 1.25rem 0; + opacity: .5; + + &:not(:last-child) { + border-bottom: 1px solid $gray-200; + } + + .course-stepper__step-icon { + position: relative; + + & svg { + position: absolute; + top: .875rem; + left: 1.25rem; + } + } + + .course-stepper__step-info { + margin-left: 1.875rem; + } + + .course-stepper__step-title { + margin-bottom: .25rem; + } + + .course-stepper__step-percent { + margin: 0; + font-size: 1rem; + } + + .course-stepper__step-description { + margin: 0; + font-size: 1rem; + color: $gray-400; + } + } + + .course-stepper__step.active { + opacity: 1; + + & svg { + animation: rotate 2s infinite linear; + } + } + + .course-stepper__step.done { + opacity: 1; + + & svg, + .course-stepper__step-title { + color: $success-500; + } + } + + .course-stepper__step.error { + opacity: 1; + + .course-stepper__step-title, + .course-stepper__step-description, + & svg { + color: $danger-300; + } + } +} diff --git a/src/generic/course-stepper/index.jsx b/src/generic/course-stepper/index.jsx new file mode 100644 index 0000000000..e984a71e38 --- /dev/null +++ b/src/generic/course-stepper/index.jsx @@ -0,0 +1,118 @@ +import React from 'react'; +import { injectIntl } from '@edx/frontend-platform/i18n'; +import { + Settings as SettingsIcon, + ManageHistory as SuccessIcon, + Warning as ErrorIcon, + CheckCircle, +} from '@edx/paragon/icons'; +import { Icon } from '@edx/paragon'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +const CourseStepper = ({ + steps, + activeKey, + percent, + hasError, + errorMessage, +}) => { + const getStepperSettings = (index) => { + const lastStepIndex = steps.length - 1; + const isActiveStep = index === activeKey; + const isLastStep = index === lastStepIndex; + const isErrorStep = isActiveStep && hasError; + const isLastStepDone = isLastStep && isActiveStep; + const completedStep = index < activeKey && !hasError; + + const getStepIcon = () => { + if (completedStep) { + return CheckCircle; + } + if (hasError && isActiveStep) { + return ErrorIcon; + } + if (isLastStep && !isActiveStep) { + return SuccessIcon; + } + if (isLastStepDone) { + return CheckCircle; + } + + return SettingsIcon; + }; + + return { + stepIcon: getStepIcon(index), + isPercentShow: Boolean(percent) && percent !== 100 && isActiveStep && !hasError, + isErrorMessageShow: isErrorStep && errorMessage, + isActiveClass: isActiveStep && !isLastStep && !hasError, + isDoneClass: index < activeKey || isLastStepDone, + isErrorClass: isErrorStep, + }; + }; + + return ( +
    + {steps.length ? steps.map(({ title, description }, index) => { + const { + stepIcon, + isPercentShow, + isErrorMessageShow, + isActiveClass, + isDoneClass, + isErrorClass, + } = getStepperSettings(index); + + return ( +
    +
    + +
    +
    +

    {title}

    + {isPercentShow && ( +

    + {percent}% +

    + )} +

    + {isErrorMessageShow ? errorMessage : description} +

    +
    +
    + ); + }) : null} +
    + ); +}; + +CourseStepper.defaultProps = { + percent: false, + hasError: false, + errorMessage: '', +}; + +CourseStepper.propTypes = { + steps: PropTypes.arrayOf(PropTypes.shape({ + title: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + })).isRequired, + activeKey: PropTypes.number.isRequired, + percent: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), + errorMessage: PropTypes.string, + hasError: PropTypes.bool, +}; + +export default injectIntl(CourseStepper); diff --git a/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.jsx b/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.jsx new file mode 100644 index 0000000000..0ea7741783 --- /dev/null +++ b/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.jsx @@ -0,0 +1,296 @@ +import React, { useRef, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { useParams } from 'react-router-dom'; +import classNames from 'classnames'; +import { useSelector } from 'react-redux'; +import { + Form, + Button, + Dropdown, + ActionRow, + StatefulButton, + TransitionReplace, +} from '@edx/paragon'; +import { Info as InfoIcon } from '@edx/paragon/icons'; +import { TypeaheadDropdown } from '@edx/frontend-lib-content-components'; + +import AlertMessage from '../alert-message'; +import { STATEFUL_BUTTON_STATES } from '../../constants'; +import { RequestStatus } from '../../data/constants'; +import { getSavingStatus } from '../data/selectors'; +import { getStudioHomeData } from '../../studio-home/data/selectors'; +import { updatePostErrors } from '../data/slice'; +import { updateCreateOrRerunCourseQuery } from '../data/thunks'; +import { useCreateOrRerunCourse } from './hooks'; +import messages from './messages'; + +const CreateOrRerunCourseForm = ({ + title, + isCreateNewCourse, + initialValues, + onClickCancel, +}) => { + const { courseId } = useParams(); + const savingStatus = useSelector(getSavingStatus); + const { allowToCreateNewOrg } = useSelector(getStudioHomeData); + const runFieldReference = useRef(null); + const displayNameFieldReference = useRef(null); + + const { + intl, + errors, + values, + postErrors, + isFormFilled, + isFormInvalid, + organizations, + showErrorBanner, + dispatch, + handleBlur, + handleChange, + hasErrorField, + setFieldValue, + } = useCreateOrRerunCourse(initialValues); + + const newCourseFields = [ + { + label: intl.formatMessage(messages.courseDisplayNameLabel), + helpText: intl.formatMessage( + isCreateNewCourse + ? messages.courseDisplayNameCreateHelpText + : messages.courseDisplayNameRerunHelpText, + ), + name: 'displayName', + value: values.displayName, + placeholder: intl.formatMessage(messages.courseDisplayNamePlaceholder), + disabled: false, + ref: displayNameFieldReference, + }, + { + label: intl.formatMessage(messages.courseOrgLabel), + helpText: isCreateNewCourse + ? intl.formatMessage(messages.courseOrgCreateHelpText, { + strong: {intl.formatMessage(messages.courseNoteOrgNameIsPartStrong)}, + }) + : intl.formatMessage(messages.courseOrgRerunHelpText, { + strong: ( + <> +
    + + {intl.formatMessage(messages.courseNoteNoSpaceAllowedStrong)} + + + ), + }), + name: 'org', + value: values.org, + options: organizations, + placeholder: intl.formatMessage(messages.courseOrgPlaceholder), + disabled: false, + }, + { + label: intl.formatMessage(messages.courseNumberLabel), + helpText: isCreateNewCourse + ? intl.formatMessage(messages.courseNumberCreateHelpText, { + strong: ( + + {intl.formatMessage(messages.courseNotePartCourseURLRequireStrong)} + + ), + }) + : intl.formatMessage(messages.courseNumberRerunHelpText), + name: 'number', + value: values.number, + placeholder: intl.formatMessage(messages.courseNumberPlaceholder), + disabled: !isCreateNewCourse, + }, + { + label: intl.formatMessage(messages.courseRunLabel), + helpText: isCreateNewCourse + ? intl.formatMessage(messages.courseRunCreateHelpText, { + strong: ( + + {intl.formatMessage(messages.courseNotePartCourseURLRequireStrong)} + + ), + }) + : intl.formatMessage(messages.courseRunRerunHelpText, { + strong: ( + <> +
    + + {intl.formatMessage(messages.courseNoteNoSpaceAllowedStrong)} + + + ), + }), + name: 'run', + value: values.run, + placeholder: intl.formatMessage(messages.courseRunPlaceholder), + disabled: false, + ref: runFieldReference, + }, + ]; + + const createButtonState = { + labels: { + default: intl.formatMessage(isCreateNewCourse ? messages.createButton : messages.rerunCreateButton), + pending: intl.formatMessage(isCreateNewCourse ? messages.creatingButton : messages.rerunningCreateButton), + }, + disabledStates: [STATEFUL_BUTTON_STATES.pending], + }; + + const handleOnClickCreate = () => { + const courseData = isCreateNewCourse ? values : { ...values, sourceCourseKey: courseId }; + dispatch(updateCreateOrRerunCourseQuery(courseData)); + }; + + const handleOnClickCancel = () => { + dispatch(updatePostErrors({})); + onClickCancel(); + }; + + const handleCustomBlurForDropdown = (e) => { + // it needs to correct handleOnChange Form.Autosuggest + const { value, name } = e.target; + setFieldValue(name, value); + handleBlur(e); + }; + + const renderOrgField = (field) => (allowToCreateNewOrg ? ( + setFieldValue(field.name, value)} + noOptionsMessage={intl.formatMessage(messages.courseOrgNoOptions)} + helpMessage="" + errorMessage="" + floatingLabel="" + /> + ) : ( + + + {field.value || intl.formatMessage(messages.courseOrgNoOptions)} + + + {field.options?.map((value) => ( + setFieldValue(field.name, value)} + > + {value} + + ))} + + + )); + + useEffect(() => { + // it needs to display the initial focus for the field depending on the current page + if (!isCreateNewCourse) { + runFieldReference?.current?.focus(); + } else { + displayNameFieldReference?.current?.focus(); + } + }, []); + + return ( +
    + + {showErrorBanner ? ( + +

    {title}

    +
    + {newCourseFields.map((field) => ( + + {field.label} + {field.name !== 'org' ? ( + + ) : renderOrgField(field)} + {field.helpText} + {hasErrorField(field.name) && ( + + {errors[field.name]} + + )} + + ))} + + + + +
    +
    + ); +}; + +CreateOrRerunCourseForm.defaultProps = { + title: '', + isCreateNewCourse: false, +}; + +CreateOrRerunCourseForm.propTypes = { + title: PropTypes.string, + initialValues: PropTypes.shape({ + displayName: PropTypes.string.isRequired, + org: PropTypes.string.isRequired, + number: PropTypes.string.isRequired, + run: PropTypes.string.isRequired, + }).isRequired, + isCreateNewCourse: PropTypes.bool, + onClickCancel: PropTypes.func.isRequired, +}; + +export default CreateOrRerunCourseForm; diff --git a/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.scss b/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.scss new file mode 100644 index 0000000000..5894c96ad2 --- /dev/null +++ b/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.scss @@ -0,0 +1,18 @@ +.create-or-rerun-course-form { + .form-group-custom { + &:not(:last-child) { + margin-bottom: $spacer; + } + + .pgn__form-label { + font: normal 1.125rem/1.75rem $font-family-base; + color: $gray-700; + margin-bottom: .25rem; + } + + .pgn__form-control-description, + .pgn__form-text { + margin-top: .62rem; + } + } +} diff --git a/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.test.jsx b/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.test.jsx new file mode 100644 index 0000000000..52a2580ce0 --- /dev/null +++ b/src/generic/create-or-rerun-course/CreateOrRerunCourseForm.test.jsx @@ -0,0 +1,272 @@ +import React from 'react'; +import { + act, + fireEvent, + screen, + render, + waitFor, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ReactDOM from 'react-dom'; + +import { initializeMockApp } from '@edx/frontend-platform'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; +import { AppProvider } from '@edx/frontend-platform/react'; +import MockAdapter from 'axios-mock-adapter'; + +import { studioHomeMock } from '../../studio-home/__mocks__'; +import { getStudioHomeApiUrl } from '../../studio-home/data/api'; +import { fetchStudioHomeData } from '../../studio-home/data/thunks'; +import { RequestStatus } from '../../data/constants'; +import initializeStore from '../../store'; +import { executeThunk } from '../../utils'; +import { updateCreateOrRerunCourseQuery } from '../data/thunks'; +import { getCreateOrRerunCourseUrl } from '../data/api'; +import messages from './messages'; +import { CreateOrRerunCourseForm } from '.'; +import { initialState } from './factories/mockApiResponses'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ + courseId: 'course-id-mock', + }), +})); + +let axiosMock; +let store; +ReactDOM.createPortal = jest.fn(node => node); + +const onClickCancelMock = jest.fn(); + +const RootWrapper = (props) => ( + + + + + +); + +const props = { + title: 'Mocked title', + isCreateNewCourse: true, + initialValues: { + displayName: '', + org: '', + number: '', + run: '', + }, + onClickCancel: onClickCancelMock, +}; + +const mockStore = async () => { + axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock); + + await executeThunk(fetchStudioHomeData, store.dispatch); +}; + +describe('', () => { + afterEach(() => jest.clearAllMocks()); + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(initialState); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + it('renders form successfully', async () => { + render(); + await mockStore(); + + expect(screen.getByText(props.title)).toBeInTheDocument(); + expect(screen.getByText(messages.courseDisplayNameLabel.defaultMessage)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(messages.courseDisplayNamePlaceholder.defaultMessage)).toBeInTheDocument(); + + expect(screen.getByText(messages.courseOrgLabel.defaultMessage)).toBeInTheDocument(); + expect(screen.getByText(messages.courseOrgNoOptions.defaultMessage)).toBeInTheDocument(); + + expect(screen.getByText(messages.courseNumberLabel.defaultMessage)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(messages.courseNumberPlaceholder.defaultMessage)).toBeInTheDocument(); + + expect(screen.getByText(messages.courseRunLabel.defaultMessage)).toBeInTheDocument(); + expect(screen.getByPlaceholderText(messages.courseRunPlaceholder.defaultMessage)).toBeInTheDocument(); + }); + + it('renders create course form with help text successfully', async () => { + render(); + await mockStore(); + expect(screen.getByText(messages.courseDisplayNameCreateHelpText.defaultMessage)).toBeInTheDocument(); + expect(screen.getByText('The name of the organization sponsoring the course.', { exact: false })).toBeInTheDocument(); + expect(screen.getByText('The unique number that identifies your course within your organization.', { exact: false })).toBeInTheDocument(); + expect(screen.getByText('The term in which your course will run.', { exact: false })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: messages.createButton.defaultMessage })).toBeInTheDocument(); + }); + + it('renders rerun course form with help text successfully', async () => { + const initialProps = { ...props, isCreateNewCourse: false }; + render(); + await mockStore(); + + expect(screen.getByText(messages.courseDisplayNameRerunHelpText.defaultMessage)).toBeInTheDocument(); + expect(screen.getByText('The name of the organization sponsoring the new course. (This name is often the same as the original organization name.)', { exact: false })).toBeInTheDocument(); + expect(screen.getByText(messages.courseNumberRerunHelpText.defaultMessage)).toBeInTheDocument(); + expect(screen.getByText('The term in which the new course will run. (This value is often different than the original course run value.)', { exact: false })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: messages.rerunCreateButton.defaultMessage })).toBeInTheDocument(); + }); + + it('should call handleOnClickCancel if button cancel clicked', async () => { + render(); + await mockStore(); + const cancelBtn = screen.getByRole('button', { name: messages.cancelButton.defaultMessage }); + await act(async () => { + fireEvent.click(cancelBtn); + }); + + expect(onClickCancelMock).toHaveBeenCalled(); + }); + + describe('handleOnClickCreate', () => { + delete window.location; + window.location = { assign: jest.fn() }; + it('should call window.location.assign with url', async () => { + render(); + await mockStore(); + const url = '/course/courseId'; + const displayNameInput = screen.getByPlaceholderText(messages.courseDisplayNamePlaceholder.defaultMessage); + const orgInput = screen.getByText(messages.courseOrgNoOptions.defaultMessage); + const numberInput = screen.getByPlaceholderText(messages.courseNumberPlaceholder.defaultMessage); + const runInput = screen.getByPlaceholderText(messages.courseRunPlaceholder.defaultMessage); + const createBtn = screen.getByRole('button', { name: messages.createButton.defaultMessage }); + + await act(async () => { + userEvent.type(displayNameInput, 'foo course name'); + fireEvent.click(orgInput); + userEvent.type(numberInput, '777'); + userEvent.type(runInput, '1'); + userEvent.click(createBtn); + }); + await axiosMock.onPost(getCreateOrRerunCourseUrl).reply(200, { url }); + await executeThunk(updateCreateOrRerunCourseQuery({ org: 'testX', run: 'some' }), store.dispatch); + + expect(window.location.assign).toHaveBeenCalledWith(`${process.env.STUDIO_BASE_URL}${url}`); + }); + it('should call window.location.assign with url and destinationCourseKey', async () => { + render(); + await mockStore(); + const url = '/course/'; + const destinationCourseKey = 'courseKey'; + const displayNameInput = screen.getByPlaceholderText(messages.courseDisplayNamePlaceholder.defaultMessage); + const orgInput = screen.getByText(messages.courseOrgNoOptions.defaultMessage); + const numberInput = screen.getByPlaceholderText(messages.courseNumberPlaceholder.defaultMessage); + const runInput = screen.getByPlaceholderText(messages.courseRunPlaceholder.defaultMessage); + const createBtn = screen.getByRole('button', { name: messages.createButton.defaultMessage }); + await axiosMock.onPost(getCreateOrRerunCourseUrl).reply(200, { url, destinationCourseKey }); + + await act(async () => { + userEvent.type(displayNameInput, 'foo course name'); + fireEvent.click(orgInput); + userEvent.type(numberInput, '777'); + userEvent.type(runInput, '1'); + userEvent.click(createBtn); + }); + await executeThunk(updateCreateOrRerunCourseQuery({ org: 'testX', run: 'some' }), store.dispatch); + + expect(window.location.assign).toHaveBeenCalledWith(`${process.env.STUDIO_BASE_URL}${url}${destinationCourseKey}`); + }); + }); + + it('should be disabled create button if form not filled', async () => { + render(); + await mockStore(); + const createBtn = screen.getByRole('button', { name: messages.createButton.defaultMessage }); + expect(createBtn).toBeDisabled(); + }); + + it('should be disabled rerun button if form not filled', async () => { + const initialProps = { ...props, isCreateNewCourse: false }; + render(); + await mockStore(); + const rerunBtn = screen.getByRole('button', { name: messages.rerunCreateButton.defaultMessage }); + expect(rerunBtn).toBeDisabled(); + }); + + it('should be disabled create button if form has error', async () => { + render(); + await mockStore(); + const createBtn = screen.getByRole('button', { name: messages.createButton.defaultMessage }); + const displayNameInput = screen.getByPlaceholderText(messages.courseDisplayNamePlaceholder.defaultMessage); + const orgInput = screen.getByText(messages.courseOrgNoOptions.defaultMessage); + const numberInput = screen.getByPlaceholderText(messages.courseNumberPlaceholder.defaultMessage); + const runInput = screen.getByPlaceholderText(messages.courseRunPlaceholder.defaultMessage); + + await act(async () => { + fireEvent.change(displayNameInput, { target: { value: 'foo course name' } }); + fireEvent.click(orgInput); + fireEvent.change(numberInput, { target: { value: 'number with invalid (+) symbol' } }); + fireEvent.change(runInput, { target: { value: 'number with invalid (=) symbol' } }); + }); + + waitFor(() => { + expect(createBtn).toBeDisabled(); + }); + }); + + it('shows typeahead dropdown with allowed to create org permissions', async () => { + const updatedStudioData = { ...studioHomeMock, allowToCreateNewOrg: true }; + store = initializeStore({ + ...initialState, + studioHome: { + ...initialState.studioHome, + studioHomeData: updatedStudioData, + }, + }); + render(); + await mockStore(); + + expect(screen.getByPlaceholderText(messages.courseOrgPlaceholder.defaultMessage)); + }); + + it('shows button pending state', async () => { + store = initializeStore({ + ...initialState, + generic: { + ...initialState.generic, + savingStatus: RequestStatus.PENDING, + }, + }); + render(); + await mockStore(); + expect(screen.getByRole('button', { name: messages.creatingButton.defaultMessage })).toBeInTheDocument(); + }); + + it('shows alert error if postErrors presents', async () => { + render(); + await mockStore(); + await axiosMock.onPost(getCreateOrRerunCourseUrl).reply(200, { errMsg: 'aaa' }); + await executeThunk(updateCreateOrRerunCourseQuery({ org: 'testX', run: 'some' }), store.dispatch); + + expect(screen.getByText('aaa')).toBeInTheDocument(); + }); + + it('shows error on field', async () => { + render(); + await mockStore(); + const numberInput = screen.getByPlaceholderText(messages.courseNumberPlaceholder.defaultMessage); + + await act(async () => { + fireEvent.change(numberInput, { target: { value: 'number with invalid (+) symbol' } }); + }); + + waitFor(() => { + expect(screen.getByText(messages.noSpaceError)).toBeInTheDocument(); + }); + }); +}); diff --git a/src/generic/create-or-rerun-course/factories/mockApiResponses.jsx b/src/generic/create-or-rerun-course/factories/mockApiResponses.jsx new file mode 100644 index 0000000000..ca3e0b3476 --- /dev/null +++ b/src/generic/create-or-rerun-course/factories/mockApiResponses.jsx @@ -0,0 +1,31 @@ +import { RequestStatus } from '../../../data/constants'; +import { studioHomeMock } from '../../../studio-home/__mocks__'; + +export const courseId = 'course-v1:edX+DemoX+Demo_Course'; + +export const initialState = { + generic: { + createOrRerunCourse: { + courseData: {}, + courseRerunData: {}, + redirectUrlObj: {}, + postErrors: {}, + }, + loadingStatuses: { + organizationLoadingStatus: 'successful', courseRerunLoadingStatus: 'successful', + }, + organizations: ['krisEdx', 'krisEd', 'DeveloperInc', 'importMit', 'testX', 'edX', 'developerInb'], + savingStatus: '', + }, + studioHome: { + loadingStatuses: { + studioHomeLoadingStatus: RequestStatus.SUCCESSFUL, + courseNotificationLoadingStatus: RequestStatus.IN_PROGRESS, + }, + savingStatuses: { + courseCreatorSavingStatus: '', + deleteNotificationSavingStatus: '', + }, + studioHomeData: studioHomeMock, + }, +}; diff --git a/src/generic/create-or-rerun-course/hooks.jsx b/src/generic/create-or-rerun-course/hooks.jsx new file mode 100644 index 0000000000..c328fdd440 --- /dev/null +++ b/src/generic/create-or-rerun-course/hooks.jsx @@ -0,0 +1,128 @@ +import { useEffect, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { getConfig } from '@edx/frontend-platform'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; + +import { RequestStatus } from '../../data/constants'; +import { getStudioHomeData } from '../../studio-home/data/selectors'; +import { + getRedirectUrlObj, + getOrganizations, + getPostErrors, + getSavingStatus, +} from '../data/selectors'; +import { updateSavingStatus, updatePostErrors } from '../data/slice'; +import { fetchOrganizationsQuery } from '../data/thunks'; +import messages from './messages'; + +const useCreateOrRerunCourse = (initialValues) => { + const intl = useIntl(); + const dispatch = useDispatch(); + const redirectUrlObj = useSelector(getRedirectUrlObj); + const createOrRerunCourseSavingStatus = useSelector(getSavingStatus); + const allOrganizations = useSelector(getOrganizations); + const postErrors = useSelector(getPostErrors); + const { + allowToCreateNewOrg, + allowedOrganizations, + } = useSelector(getStudioHomeData); + const [isFormFilled, setFormFilled] = useState(false); + const [showErrorBanner, setShowErrorBanner] = useState(false); + const organizations = allowToCreateNewOrg ? allOrganizations : allowedOrganizations; + const specialCharsRule = /^[a-zA-Z0-9_\-.'*~\s]+$/; + const noSpaceRule = /^\S*$/; + const validationSchema = Yup.object().shape({ + displayName: Yup.string().required( + intl.formatMessage(messages.requiredFieldError), + ), + org: Yup.string() + .required(intl.formatMessage(messages.requiredFieldError)) + .matches( + specialCharsRule, + intl.formatMessage(messages.disallowedCharsError), + ) + .matches(noSpaceRule, intl.formatMessage(messages.noSpaceError)), + number: Yup.string() + .required(intl.formatMessage(messages.requiredFieldError)) + .matches( + specialCharsRule, + intl.formatMessage(messages.disallowedCharsError), + ) + .matches(noSpaceRule, intl.formatMessage(messages.noSpaceError)), + run: Yup.string() + .required(intl.formatMessage(messages.requiredFieldError)) + .matches( + specialCharsRule, + intl.formatMessage(messages.disallowedCharsError), + ) + .matches(noSpaceRule, intl.formatMessage(messages.noSpaceError)), + }); + + const { + values, errors, touched, handleChange, handleBlur, setFieldValue, + } = useFormik({ + initialValues, + enableReinitialize: true, + validateOnBlur: false, + validationSchema, + }); + + useEffect(() => { + if (allowToCreateNewOrg) { + dispatch(fetchOrganizationsQuery()); + } + }, []); + + useEffect(() => { + setFormFilled(Object.values(values).every((i) => i)); + dispatch(updatePostErrors({})); + }, [values]); + + useEffect(() => { + setShowErrorBanner(!!postErrors.errMsg); + }, [postErrors]); + + useEffect(() => { + if (createOrRerunCourseSavingStatus === RequestStatus.SUCCESSFUL) { + dispatch(updateSavingStatus({ status: '' })); + const { url, destinationCourseKey } = redirectUrlObj; + // New courses' url to the outline page is provided in the url. However, for course + // re-runs the url is /course/. The actual destination for the rer-run's outline + // is in the destionationCourseKey attribute from the api. + if (url) { + if (destinationCourseKey) { + window.location.assign(`${getConfig().STUDIO_BASE_URL}${url}${destinationCourseKey}`); + } else { + window.location.assign(`${getConfig().STUDIO_BASE_URL}${url}`); + } + } + } else if (createOrRerunCourseSavingStatus === RequestStatus.FAILED) { + dispatch(updateSavingStatus({ status: '' })); + } + }, [createOrRerunCourseSavingStatus]); + + const hasErrorField = (fieldName) => !!errors[fieldName] && !!touched[fieldName]; + const isFormInvalid = Object.keys(errors).length; + + return { + intl, + errors, + values, + postErrors, + isFormFilled, + isFormInvalid, + organizations, + showErrorBanner, + dispatch, + handleBlur, + handleChange, + hasErrorField, + setFieldValue, + setShowErrorBanner, + }; +}; + +// eslint-disable-next-line import/prefer-default-export +export { useCreateOrRerunCourse }; diff --git a/src/generic/create-or-rerun-course/index.js b/src/generic/create-or-rerun-course/index.js new file mode 100644 index 0000000000..83b3965919 --- /dev/null +++ b/src/generic/create-or-rerun-course/index.js @@ -0,0 +1,2 @@ +export { default as CreateOrRerunCourseForm } from './CreateOrRerunCourseForm'; +export { useCreateOrRerunCourse } from './hooks'; diff --git a/src/generic/create-or-rerun-course/messages.js b/src/generic/create-or-rerun-course/messages.js new file mode 100644 index 0000000000..16a07af20e --- /dev/null +++ b/src/generic/create-or-rerun-course/messages.js @@ -0,0 +1,130 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + courseDisplayNameLabel: { + id: 'course-authoring.create-or-rerun-course.display-name.label', + defaultMessage: 'Course name', + }, + courseDisplayNamePlaceholder: { + id: 'course-authoring.create-or-rerun-course.display-name.placeholder', + defaultMessage: 'e.g. Introduction to Computer Science', + }, + courseDisplayNameCreateHelpText: { + id: 'course-authoring.create-or-rerun-course.create.display-name.help-text', + defaultMessage: 'The public display name for your course. This cannot be changed, but you can set a different display name in advanced settings later.', + }, + courseDisplayNameRerunHelpText: { + id: 'course-authoring.create-or-rerun-course.rerun.display-name.help-text', + defaultMessage: 'The public display name for the new course. (This name is often the same as the original course name.)', + }, + courseOrgLabel: { + id: 'course-authoring.create-or-rerun-course.org.label', + defaultMessage: 'Organization', + }, + courseOrgPlaceholder: { + id: 'course-authoring.create-or-rerun-course.org.placeholder', + defaultMessage: 'e.g. UniversityX or OrganizationX', + }, + courseOrgNoOptions: { + id: 'course-authoring.create-or-rerun-course.org.no-options', + defaultMessage: 'No options', + }, + courseOrgCreateHelpText: { + id: 'course-authoring.create-or-rerun-course.create.org.help-text', + defaultMessage: 'The name of the organization sponsoring the course. {strong} This cannot be changed, but you can set a different display name in advanced settings later.', + }, + courseOrgRerunHelpText: { + id: 'course-authoring.create-or-rerun-course.rerun.org.help-text', + defaultMessage: 'The name of the organization sponsoring the new course. (This name is often the same as the original organization name.) {strong}', + }, + courseNoteNoSpaceAllowedStrong: { + id: 'course-authoring.create-or-rerun-course.no-space-allowed.strong', + defaultMessage: 'Note: No spaces or special characters are allowed.', + }, + courseNoteOrgNameIsPartStrong: { + id: 'course-authoring.create-or-rerun-course.org.help-text.strong', + defaultMessage: 'Note: The organization name is part of the course URL.', + }, + courseNumberLabel: { + id: 'course-authoring.create-or-rerun-course.number.label', + defaultMessage: 'Course number', + }, + courseNumberPlaceholder: { + id: 'course-authoring.create-or-rerun-course.number.placeholder', + defaultMessage: 'e.g. CS101', + }, + courseNumberCreateHelpText: { + id: 'course-authoring.create-or-rerun-course.create.number.help-text', + defaultMessage: 'The unique number that identifies your course within your organization. {strong}', + }, + courseNumberRerunHelpText: { + id: 'course-authoring.create-or-rerun-course.rerun.number.help-text', + defaultMessage: 'The unique number that identifies the new course within the organization. (This number will be the same as the original course number and cannot be changed.)', + }, + courseNotePartCourseURLRequireStrong: { + id: 'course-authoring.create-or-rerun-course.number.help-text.strong', + defaultMessage: 'Note: This is part of your course URL, so no spaces or special characters are allowed and it cannot be changed.', + }, + courseRunLabel: { + id: 'course-authoring.create-or-rerun-course.run.label', + defaultMessage: 'Course run', + }, + courseRunPlaceholder: { + id: 'course-authoring.create-or-rerun-course.run.placeholder', + defaultMessage: 'e.g. 2014_T1', + }, + courseRunCreateHelpText: { + id: 'course-authoring.create-or-rerun-course.create.run.help-text', + defaultMessage: 'The term in which your course will run. {strong}', + }, + courseRunRerunHelpText: { + id: 'course-authoring.create-or-rerun-course.create.rerun.help-text', + defaultMessage: 'The term in which the new course will run. (This value is often different than the original course run value.){strong}', + }, + defaultPlaceholder: { + id: 'course-authoring.create-or-rerun-course.default-placeholder', + defaultMessage: 'Label', + }, + createButton: { + id: 'course-authoring.create-or-rerun-course.create.button.create', + defaultMessage: 'Create', + }, + rerunCreateButton: { + id: 'course-authoring.create-or-rerun-course.rerun.button.create', + defaultMessage: 'Create re-run', + }, + creatingButton: { + id: 'course-authoring.create-or-rerun-course.button.creating', + defaultMessage: 'Creating', + }, + rerunningCreateButton: { + id: 'course-authoring.create-or-rerun-course.rerun.button.rerunning', + defaultMessage: 'Processing re-run request', + }, + cancelButton: { + id: 'course-authoring.create-or-rerun-course.button.cancel', + defaultMessage: 'Cancel', + }, + requiredFieldError: { + id: 'course-authoring.create-or-rerun-course.required.error', + defaultMessage: 'Required field.', + }, + disallowedCharsError: { + id: 'course-authoring.create-or-rerun-course.disallowed-chars.error', + defaultMessage: 'Please do not use any spaces or special characters in this field.', + }, + noSpaceError: { + id: 'course-authoring.create-or-rerun-course.no-space.error', + defaultMessage: 'Please do not use any spaces in this field.', + }, + alertErrorExistsAriaLabelledBy: { + id: 'course-authoring.create-or-rerun-course.error.already-exists.labelledBy', + defaultMessage: 'alert-already-exists-title', + }, + alertErrorExistsAriaDescribedBy: { + id: 'course-authoring.create-or-rerun-course.error.already-exists.aria.describedBy', + defaultMessage: 'alert-confirmation-description', + }, +}); + +export default messages; diff --git a/src/generic/data/api.js b/src/generic/data/api.js new file mode 100644 index 0000000000..36dce24bd8 --- /dev/null +++ b/src/generic/data/api.js @@ -0,0 +1,44 @@ +import { camelCaseObject, getConfig } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { convertObjectToSnakeCase } from '../../utils'; + +export const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL; +export const getCreateOrRerunCourseUrl = new URL('course/', getApiBaseUrl()).href; +export const getCourseRerunUrl = (courseId) => new URL(`/api/contentstore/v1/course_rerun/${courseId}`, getApiBaseUrl()).href; +export const getOrganizationsUrl = new URL('organizations', getApiBaseUrl()).href; + +/** + * Get's organizations data. + * @returns {Promise} + */ +export async function getOrganizations() { + const { data } = await getAuthenticatedHttpClient().get( + getOrganizationsUrl, + ); + return camelCaseObject(data); +} + +/** + * Get's course rerun data. + * @returns {Promise} + */ +export async function getCourseRerun(courseId) { + const { data } = await getAuthenticatedHttpClient().get( + getCourseRerunUrl(courseId), + ); + return camelCaseObject(data); +} + +/** + * Create or rerun course with data. + * @param {object} data + * @returns {Promise} + */ +export async function createOrRerunCourse(courseData) { + const { data } = await getAuthenticatedHttpClient().post( + getCreateOrRerunCourseUrl, + convertObjectToSnakeCase(courseData, true), + ); + return camelCaseObject(data); +} diff --git a/src/generic/data/api.test.js b/src/generic/data/api.test.js new file mode 100644 index 0000000000..fd9d561c33 --- /dev/null +++ b/src/generic/data/api.test.js @@ -0,0 +1,75 @@ +import MockAdapter from 'axios-mock-adapter'; +import { initializeMockApp } from '@edx/frontend-platform'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import { + createOrRerunCourse, + getApiBaseUrl, + getOrganizations, + getCreateOrRerunCourseUrl, + getCourseRerunUrl, + getCourseRerun, +} from './api'; + +let axiosMock; + +describe('generic api calls', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should get organizations', async () => { + const organizationsData = ['edX', 'org']; + const queryUrl = new URL('organizations', getApiBaseUrl()).href; + axiosMock.onGet(queryUrl).reply(200, organizationsData); + const result = await getOrganizations(); + + expect(axiosMock.history.get[0].url).toEqual(queryUrl); + expect(result).toEqual(organizationsData); + }); + + it('should get course rerun', async () => { + const courseId = 'course-mock-id'; + const courseRerunData = { + allowUnicodeCourseId: false, + courseCreatorStatus: 'granted', + displayName: 'Demonstration Course', + number: 'DemoX', + org: 'edX', + run: 'Demo_Course', + }; + axiosMock.onGet(getCourseRerunUrl(courseId)).reply(200, courseRerunData); + const result = await getCourseRerun(courseId); + + expect(axiosMock.history.get[0].url).toEqual(getCourseRerunUrl(courseId)); + expect(result).toEqual(courseRerunData); + }); + + it('should post create or rerun course', async () => { + const courseRerunData = { + allowUnicodeCourseId: false, + courseCreatorStatus: 'granted', + displayName: 'Demonstration Course', + number: 'DemoX', + org: 'edX', + run: 'Demo_Course', + }; + axiosMock.onPost(getCreateOrRerunCourseUrl).reply(200, courseRerunData); + const result = await createOrRerunCourse(courseRerunData); + + expect(axiosMock.history.post[0].url).toEqual(getCreateOrRerunCourseUrl); + expect(result).toEqual(courseRerunData); + }); +}); diff --git a/src/generic/data/selectors.js b/src/generic/data/selectors.js new file mode 100644 index 0000000000..461e09fe98 --- /dev/null +++ b/src/generic/data/selectors.js @@ -0,0 +1,7 @@ +export const getLoadingStatuses = (state) => state.generic.loadingStatuses; +export const getSavingStatus = (state) => state.generic.savingStatus; +export const getOrganizations = (state) => state.generic.organizations; +export const getCourseData = (state) => state.generic.createOrRerunCourse.courseData; +export const getCourseRerunData = (state) => state.generic.createOrRerunCourse.courseRerunData; +export const getRedirectUrlObj = (state) => state.generic.createOrRerunCourse.redirectUrlObj; +export const getPostErrors = (state) => state.generic.createOrRerunCourse.postErrors; diff --git a/src/generic/data/slice.js b/src/generic/data/slice.js new file mode 100644 index 0000000000..a25112704e --- /dev/null +++ b/src/generic/data/slice.js @@ -0,0 +1,59 @@ +/* eslint-disable no-param-reassign */ +import { createSlice } from '@reduxjs/toolkit'; + +import { RequestStatus } from '../../data/constants'; + +const slice = createSlice({ + name: 'generic', + initialState: { + loadingStatuses: { + organizationLoadingStatus: RequestStatus.IN_PROGRESS, + courseRerunLoadingStatus: RequestStatus.IN_PROGRESS, + }, + savingStatus: '', + organizations: [], + createOrRerunCourse: { + courseData: {}, + courseRerunData: {}, + redirectUrlObj: {}, + postErrors: {}, + }, + }, + reducers: { + fetchOrganizations: (state, { payload }) => { + state.organizations = payload; + }, + updateLoadingStatuses: (state, { payload }) => { + state.loadingStatuses = { ...state.loadingStatuses, ...payload }; + }, + updateSavingStatus: (state, { payload }) => { + state.savingStatus = payload.status; + }, + updateCourseData: (state, { payload }) => { + state.createOrRerunCourse.courseData = payload; + }, + updateCourseRerunData: (state, { payload }) => { + state.createOrRerunCourse.courseRerunData = payload; + }, + updateRedirectUrlObj: (state, { payload }) => { + state.createOrRerunCourse.redirectUrlObj = payload; + }, + updatePostErrors: (state, { payload }) => { + state.createOrRerunCourse.postErrors = payload; + }, + }, +}); + +export const { + fetchOrganizations, + updatePostErrors, + updateCourseRerunData, + updateLoadingStatuses, + updateSavingStatus, + updateCourseData, + updateRedirectUrlObj, +} = slice.actions; + +export const { + reducer, +} = slice; diff --git a/src/generic/data/thunks.js b/src/generic/data/thunks.js new file mode 100644 index 0000000000..0008a187f4 --- /dev/null +++ b/src/generic/data/thunks.js @@ -0,0 +1,51 @@ +import { RequestStatus } from '../../data/constants'; +import { createOrRerunCourse, getOrganizations, getCourseRerun } from './api'; +import { + fetchOrganizations, + updatePostErrors, + updateLoadingStatuses, + updateRedirectUrlObj, + updateCourseRerunData, + updateSavingStatus, +} from './slice'; + +export function fetchOrganizationsQuery() { + return async (dispatch) => { + try { + const organizations = await getOrganizations(); + dispatch(fetchOrganizations(organizations)); + dispatch(updateLoadingStatuses({ organizationLoadingStatus: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateLoadingStatuses({ organizationLoadingStatus: RequestStatus.FAILED })); + } + }; +} + +export function fetchCourseRerunQuery(courseId) { + return async (dispatch) => { + try { + const courseRerun = await getCourseRerun(courseId); + dispatch(updateCourseRerunData(courseRerun)); + dispatch(updateLoadingStatuses({ courseRerunLoadingStatus: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(updateLoadingStatuses({ courseRerunLoadingStatus: RequestStatus.FAILED })); + } + }; +} + +export function updateCreateOrRerunCourseQuery(courseData) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); + + try { + const response = await createOrRerunCourse(courseData); + dispatch(updateRedirectUrlObj('url' in response ? response : {})); + dispatch(updatePostErrors('errMsg' in response ? response : {})); + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + return true; + } catch (error) { + dispatch(updateSavingStatus({ status: RequestStatus.FAILED })); + return false; + } + }; +} diff --git a/src/generic/help-sidebar/HelpSidebar.jsx b/src/generic/help-sidebar/HelpSidebar.jsx new file mode 100644 index 0000000000..0b9cf96bba --- /dev/null +++ b/src/generic/help-sidebar/HelpSidebar.jsx @@ -0,0 +1,123 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useLocation } from 'react-router-dom'; +import classNames from 'classnames'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { getConfig } from '@edx/frontend-platform'; + +import { otherLinkURLParams } from './constants'; +import messages from './messages'; +import HelpSidebarLink from './HelpSidebarLink'; + +const HelpSidebar = ({ + intl, + courseId, + showOtherSettings, + proctoredExamSettingsUrl, + children, + className, +}) => { + const { pathname } = useLocation(); + const { + grading, + courseTeam, + advancedSettings, + scheduleAndDetails, + groupConfigurations, + } = otherLinkURLParams; + + const showOtherLink = (params) => !pathname.includes(params); + const generateLegacyURL = (urlParameter) => { + const referObj = new URL(`${urlParameter}/${courseId}`, getConfig().STUDIO_BASE_URL); + return referObj.href; + }; + + const scheduleAndDetailsDestination = generateLegacyURL(scheduleAndDetails); + const gradingDestination = generateLegacyURL(grading); + const courseTeamDestination = generateLegacyURL(courseTeam); + const advancedSettingsDestination = generateLegacyURL(advancedSettings); + const groupConfigurationsDestination = generateLegacyURL(groupConfigurations); + + return ( + + ); +}; + +HelpSidebar.defaultProps = { + proctoredExamSettingsUrl: '', + className: undefined, + courseId: undefined, + showOtherSettings: false, +}; + +HelpSidebar.propTypes = { + intl: intlShape.isRequired, + courseId: PropTypes.string, + showOtherSettings: PropTypes.bool, + proctoredExamSettingsUrl: PropTypes.string, + children: PropTypes.node.isRequired, + className: PropTypes.string, +}; + +export default injectIntl(HelpSidebar); diff --git a/src/generic/help-sidebar/HelpSidebar.scss b/src/generic/help-sidebar/HelpSidebar.scss index cf37013305..26f08f2e9a 100644 --- a/src/generic/help-sidebar/HelpSidebar.scss +++ b/src/generic/help-sidebar/HelpSidebar.scss @@ -1,6 +1,4 @@ .help-sidebar { - margin-top: 8.563rem; - .help-sidebar-about { .help-sidebar-about-title { color: $black; diff --git a/src/generic/help-sidebar/HelpSidebar.test.jsx b/src/generic/help-sidebar/HelpSidebar.test.jsx index 410ae631b1..fe8b03db26 100644 --- a/src/generic/help-sidebar/HelpSidebar.test.jsx +++ b/src/generic/help-sidebar/HelpSidebar.test.jsx @@ -1,12 +1,15 @@ import React from 'react'; import { render } from '@testing-library/react'; import { IntlProvider } from '@edx/frontend-platform/i18n'; - -import HelpSidebar from '.'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { initializeMockApp } from '@edx/frontend-platform'; +import initializeStore from '../../store'; import messages from './messages'; +import { HelpSidebar } from '.'; const mockPathname = '/foo-bar'; +let store; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: () => ({ @@ -15,11 +18,15 @@ jest.mock('react-router-dom', () => ({ })); const RootWrapper = (props) => ( - - -

    Test children

    -
    -
    + + + +

    Test children

    +
    +
    +
    ); const props = { @@ -29,6 +36,19 @@ const props = { }; describe('HelpSidebar', () => { + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + }); + it('renders children correctly', () => { const { getByText } = render(); expect(getByText('Test children')).toBeTruthy(); @@ -57,7 +77,7 @@ describe('HelpSidebar', () => { }); it('should render proctored mfe url only if passed not empty value', () => { - const initialProps = { ...props, proctoredExamSettingsUrl: 'http:/link-to' }; + const initialProps = { ...props, showOtherSettings: true, proctoredExamSettingsUrl: 'http:/link-to' }; const { getByText } = render(); expect(getByText(messages.sidebarLinkToProctoredExamSettings.defaultMessage)).toBeTruthy(); }); diff --git a/src/generic/help-sidebar/HelpSidebarLink.jsx b/src/generic/help-sidebar/HelpSidebarLink.jsx index 709ef175e7..115e6d85ec 100644 --- a/src/generic/help-sidebar/HelpSidebarLink.jsx +++ b/src/generic/help-sidebar/HelpSidebarLink.jsx @@ -6,7 +6,11 @@ const HelpSidebarLink = ({ as, pathToPage, title }) => { const TagElement = as; return ( - + {title} diff --git a/src/generic/help-sidebar/constants.js b/src/generic/help-sidebar/constants.js index 68ce38a19d..6cc930689d 100644 --- a/src/generic/help-sidebar/constants.js +++ b/src/generic/help-sidebar/constants.js @@ -6,4 +6,5 @@ export const otherLinkURLParams = { advancedSettings: 'settings/advanced', groupConfigurations: 'group_configurations', proctoredExamSettings: 'proctored-exam-settings', + studioHome: 'home', }; diff --git a/src/generic/help-sidebar/index.js b/src/generic/help-sidebar/index.js new file mode 100644 index 0000000000..7f0fc8374a --- /dev/null +++ b/src/generic/help-sidebar/index.js @@ -0,0 +1,2 @@ +export { default as HelpSidebar } from './HelpSidebar'; +export { default as HelpSidebarLink } from './HelpSidebarLink'; diff --git a/src/generic/help-sidebar/index.jsx b/src/generic/help-sidebar/index.jsx deleted file mode 100644 index 5337bb509f..0000000000 --- a/src/generic/help-sidebar/index.jsx +++ /dev/null @@ -1,119 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { useLocation } from 'react-router-dom'; -import classNames from 'classnames'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { getConfig } from '@edx/frontend-platform'; - -import HelpSidebarLink from './HelpSidebarLink'; -import { otherLinkURLParams } from './constants'; -import messages from './messages'; - -const HelpSidebar = ({ - intl, - courseId, - showOtherSettings, - proctoredExamSettingsUrl, - children, - className, -}) => { - const { pathname } = useLocation(); - const { - grading, - courseTeam, - advancedSettings, - scheduleAndDetails, - groupConfigurations, - } = otherLinkURLParams; - - const showOtherLink = (params) => !pathname.includes(params); - const generateLegacyURL = (urlParameter) => { - const referObj = new URL(`${urlParameter}/${courseId}`, getConfig().STUDIO_BASE_URL); - return referObj.href; - }; - - const scheduleAndDetailsDestination = generateLegacyURL(scheduleAndDetails); - const gradingDestination = generateLegacyURL(grading); - const courseTeamDestination = generateLegacyURL(courseTeam); - const advancedSettingsDestination = generateLegacyURL(advancedSettings); - const groupConfigurationsDestination = generateLegacyURL(groupConfigurations); - - return ( - - ); -}; - -HelpSidebar.defaultProps = { - proctoredExamSettingsUrl: '', - className: undefined, -}; - -HelpSidebar.propTypes = { - intl: intlShape.isRequired, - courseId: PropTypes.string.isRequired, - showOtherSettings: PropTypes.bool.isRequired, - proctoredExamSettingsUrl: PropTypes.string, - children: PropTypes.node.isRequired, - className: PropTypes.string, -}; - -export default injectIntl(HelpSidebar); diff --git a/src/generic/help-sidebar/messages.js b/src/generic/help-sidebar/messages.js index 70c7be782c..a8c8db3efd 100644 --- a/src/generic/help-sidebar/messages.js +++ b/src/generic/help-sidebar/messages.js @@ -7,7 +7,7 @@ const messages = defineMessages({ }, sidebarLinkToScheduleAndDetails: { id: 'course-authoring.help-sidebar.links.schedule-and-details', - defaultMessage: 'Details & schedule', + defaultMessage: 'Schedule & details', description: 'Link to Studio Schedule & Details page', }, sidebarLinkToGrading: { diff --git a/src/generic/internet-connection-alert/index.jsx b/src/generic/internet-connection-alert/index.jsx index fbf8be5484..23a7ba9157 100644 --- a/src/generic/internet-connection-alert/index.jsx +++ b/src/generic/internet-connection-alert/index.jsx @@ -30,7 +30,10 @@ const InternetConnectionAlert = ({ useEffect(() => { if (isQueryPending) { - onQueryProcessing(); + if (onQueryProcessing) { + onQueryProcessing(); + } + setShowAlert(!isOnline); if (!isOnline) { @@ -63,14 +66,15 @@ const InternetConnectionAlert = ({ InternetConnectionAlert.defaultProps = { isQueryPending: false, - + onQueryProcessing: () => ({}), + onInternetConnectionFailed: () => ({}), }; InternetConnectionAlert.propTypes = { isFailed: PropTypes.bool.isRequired, isQueryPending: PropTypes.bool, - onQueryProcessing: PropTypes.func.isRequired, - onInternetConnectionFailed: PropTypes.func.isRequired, + onQueryProcessing: PropTypes.func, + onInternetConnectionFailed: PropTypes.func, }; export default InternetConnectionAlert; diff --git a/src/generic/modal-error/ModalError.jsx b/src/generic/modal-error/ModalError.jsx new file mode 100644 index 0000000000..132bbe165c --- /dev/null +++ b/src/generic/modal-error/ModalError.jsx @@ -0,0 +1,35 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { ActionRow, AlertModal, Button } from '@edx/paragon'; +import { Error } from '@edx/paragon/icons'; + +const ModalError = ({ + isOpen, title, message, handleCancel, handleAction, cancelButtonText, actionButtonText, +}) => ( + + + + + )} + > +

    {message}

    +
    +); + +ModalError.propTypes = { + isOpen: PropTypes.bool.isRequired, + title: PropTypes.string.isRequired, + message: PropTypes.string.isRequired, + handleCancel: PropTypes.func.isRequired, + handleAction: PropTypes.func.isRequired, + cancelButtonText: PropTypes.string.isRequired, + actionButtonText: PropTypes.string.isRequired, +}; + +export default ModalError; diff --git a/src/generic/processing-notification/ProccessingNotification.scss b/src/generic/processing-notification/ProccessingNotification.scss new file mode 100644 index 0000000000..257cbd2afc --- /dev/null +++ b/src/generic/processing-notification/ProccessingNotification.scss @@ -0,0 +1,25 @@ +.processing-notification { + display: flex; + position: fixed; + bottom: -13rem; + transition: bottom 1s; + right: 1.25rem; + padding: .625rem 1.25rem; + z-index: $zindex-popover; + + &.is-show { + bottom: .625rem; + } + + .processing-notification-icon { + margin-right: .625rem; + animation: rotate 1s linear infinite; + } + + .processing-notification-title { + font-size: 1rem; + line-height: 1.5rem; + color: $white; + margin-bottom: 0; + } +} diff --git a/src/generic/processing-notification/ProcessingNotification.test.jsx b/src/generic/processing-notification/ProcessingNotification.test.jsx new file mode 100644 index 0000000000..16b86401ea --- /dev/null +++ b/src/generic/processing-notification/ProcessingNotification.test.jsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { capitalize } from 'lodash'; +import { NOTIFICATION_MESSAGES } from '../../constants'; +import ProcessingNotification from '.'; + +const props = { + title: NOTIFICATION_MESSAGES.saving, + isShow: true, +}; + +describe('', () => { + it('renders successfully', () => { + const { getByText } = render(); + expect(getByText(capitalize(props.title))).toBeInTheDocument(); + }); +}); diff --git a/src/generic/processing-notification/data/selectors.js b/src/generic/processing-notification/data/selectors.js new file mode 100644 index 0000000000..f34ed9df55 --- /dev/null +++ b/src/generic/processing-notification/data/selectors.js @@ -0,0 +1,5 @@ +// eslint-disable-next-line import/prefer-default-export +export const getProcessingNotification = (state) => ({ + isShow: state.processingNotification.isShow, + title: state.processingNotification.title, +}); diff --git a/src/generic/processing-notification/data/slice.js b/src/generic/processing-notification/data/slice.js new file mode 100644 index 0000000000..4090524a9d --- /dev/null +++ b/src/generic/processing-notification/data/slice.js @@ -0,0 +1,28 @@ +/* eslint-disable no-param-reassign */ +import { createSlice } from '@reduxjs/toolkit'; + +const initialState = { + isShow: false, + title: '', +}; + +const slice = createSlice({ + name: 'processingNotification', + initialState, + reducers: { + showProcessingNotification: (state, { payload }) => { + state.isShow = true; + state.title = payload; + }, + hideProcessingNotification: () => initialState, + }, +}); + +export const { + showProcessingNotification, + hideProcessingNotification, +} = slice.actions; + +export const { + reducer, +} = slice; diff --git a/src/generic/processing-notification/index.jsx b/src/generic/processing-notification/index.jsx new file mode 100644 index 0000000000..c58053f457 --- /dev/null +++ b/src/generic/processing-notification/index.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { Badge, Icon } from '@edx/paragon'; +import { Settings as IconSettings } from '@edx/paragon/icons'; +import { capitalize } from 'lodash'; + +import { NOTIFICATION_MESSAGES } from '../../constants'; + +const ProcessingNotification = ({ isShow, title }) => ( + + +

    + {capitalize(title)} +

    +
    +); + +ProcessingNotification.propTypes = { + isShow: PropTypes.bool.isRequired, + title: PropTypes.oneOf(Object.values(NOTIFICATION_MESSAGES)).isRequired, +}; + +export default ProcessingNotification; diff --git a/src/generic/styles.scss b/src/generic/styles.scss index e5dca7bba5..becfb9a77a 100644 --- a/src/generic/styles.scss +++ b/src/generic/styles.scss @@ -2,3 +2,7 @@ @import "./course-upload-image/CourseUploadImage"; @import "./sub-header/SubHeader"; @import "./section-sub-header/SectionSubHeader"; +@import "./processing-notification/ProccessingNotification"; +@import "./create-or-rerun-course/CreateOrRerunCourseForm"; +@import "./WysiwygEditor"; +@import "./course-stepper/CouseStepper"; diff --git a/src/generic/sub-header/SubHeader.jsx b/src/generic/sub-header/SubHeader.jsx index f6a7608a6b..a0146fcd57 100644 --- a/src/generic/sub-header/SubHeader.jsx +++ b/src/generic/sub-header/SubHeader.jsx @@ -1,40 +1,65 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { ActionRow } from '@edx/paragon'; const SubHeader = ({ - title, subtitle, contentTitle, description, instruction, + title, + subtitle, + contentTitle, + description, + instruction, + headerActions, + titleActions, + hideBorder, }) => ( - <> +

    {subtitle} {title} + {titleActions && ( + + {titleActions} + + )}

    + {headerActions && ( + + {headerActions} + + )}
    -
    -

    {contentTitle}

    - {description} -
    + {contentTitle && ( +
    +

    {contentTitle}

    + {description} +
    + )} {instruction && (

    {instruction}

    )} - +
    ); - SubHeader.defaultProps = { instruction: '', description: '', + subtitle: '', + contentTitle: '', + headerActions: null, + titleActions: null, + hideBorder: false, }; - SubHeader.propTypes = { title: PropTypes.string.isRequired, - subtitle: PropTypes.string.isRequired, - contentTitle: PropTypes.string.isRequired, + subtitle: PropTypes.string, + contentTitle: PropTypes.string, description: PropTypes.string, instruction: PropTypes.oneOfType([ PropTypes.element, PropTypes.string, ]), + headerActions: PropTypes.node, + titleActions: PropTypes.node, + hideBorder: PropTypes.bool, }; - export default SubHeader; diff --git a/src/generic/sub-header/SubHeader.scss b/src/generic/sub-header/SubHeader.scss index 3a52f6768e..693d5603b9 100644 --- a/src/generic/sub-header/SubHeader.scss +++ b/src/generic/sub-header/SubHeader.scss @@ -1,6 +1,14 @@ +.sub-header { + display: flex; + + .sub-header-actions { + margin-bottom: 1.75rem; + align-self: flex-end; + } +} + .sub-header-title { font: normal $font-weight-bold 2rem/2.25rem $font-family-base; - margin-bottom: 1.75rem; color: $black; .sub-header-title-subtitle { @@ -25,7 +33,6 @@ display: flex; justify-content: space-between; align-items: center; - border-bottom: $border-width solid $light-400; - padding-bottom: 12px; + margin-top: 1.5rem; margin-bottom: 12px; } diff --git a/src/generic/utils.js b/src/generic/utils.js new file mode 100644 index 0000000000..27236e8aa8 --- /dev/null +++ b/src/generic/utils.js @@ -0,0 +1,10 @@ +import { isEmpty } from 'lodash'; + +const getPageHeadTitle = (courseName, pageName) => { + if (isEmpty(courseName)) { + return `${pageName} | ${process.env.SITE_NAME}`; + } + return `${pageName} | ${courseName} | ${process.env.SITE_NAME}`; +}; + +export default getPageHeadTitle; diff --git a/src/generic/utils.test.js b/src/generic/utils.test.js new file mode 100644 index 0000000000..587164d9d6 --- /dev/null +++ b/src/generic/utils.test.js @@ -0,0 +1,16 @@ +import getPageHeadTitle from './utils'; + +describe('utils', () => { + describe('getPageHeader', () => { + it('should return with page name and site name', () => { + const expected = 'pageName | edX'; + const actual = getPageHeadTitle(null, 'pageName'); + expect(expected).toEqual(actual); + }); + it('should return with page name, course name, and site name', () => { + const expected = 'pageName | courseName | edX'; + const actual = getPageHeadTitle('courseName', 'pageName'); + expect(expected).toEqual(actual); + }); + }); +}); diff --git a/src/grading-settings/GradingSettings.jsx b/src/grading-settings/GradingSettings.jsx index 9df43dc299..827486e584 100644 --- a/src/grading-settings/GradingSettings.jsx +++ b/src/grading-settings/GradingSettings.jsx @@ -7,6 +7,7 @@ import { } from '@edx/paragon'; import { CheckCircle, Warning, Add as IconAdd } from '@edx/paragon/icons'; +import { useModel } from '../generic/model-store'; import AlertMessage from '../generic/alert-message'; import { RequestStatus } from '../data/constants'; import InternetConnectionAlert from '../generic/internet-connection-alert'; @@ -28,6 +29,7 @@ import AssignmentSection from './assignment-section'; import CreditSection from './credit-section'; import DeadlineSection from './deadline-section'; import { useConvertGradeCutoffs, useUpdateGradingData } from './hooks'; +import getPageHeadTitle from '../generic/utils'; const GradingSettings = ({ intl, courseId }) => { const gradingSettingsData = useSelector(getGradingSettings); @@ -42,6 +44,9 @@ const GradingSettings = ({ intl, courseId }) => { const [showOverrideInternetConnectionAlert, setOverrideInternetConnectionAlert] = useState(false); const [eligibleGrade, setEligibleGrade] = useState(null); + const courseDetails = useModel('courseDetails', courseId); + document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.headingTitle)); + const { graders, resetDataRef, @@ -110,7 +115,7 @@ const GradingSettings = ({ intl, courseId }) => { return ( <> - +
    { />
    - +
    +

    + {intl.formatMessage(messages.assignmentTypeSectionTitle)} +

    + + {intl.formatMessage(messages.assignmentTypeSectionDescription)} + +
    { setShowSuccessAlert={setShowSuccessAlert} />