Compare commits
75 Commits
abdullahwa
...
open-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d80a68132a | ||
|
|
b66238c7c0 | ||
|
|
e4c5238f70 | ||
|
|
1bc759a1e7 | ||
|
|
5cc04f8a80 | ||
|
|
de4189b4a5 | ||
|
|
785b91d3c7 | ||
|
|
a63409eaa6 | ||
|
|
3c8e5b2501 | ||
|
|
a88066a2c5 | ||
|
|
e0fb41d8f5 | ||
|
|
55adcfe90d | ||
|
|
c884ff2882 | ||
|
|
5c1df3e16e | ||
|
|
8aea28c6e0 | ||
|
|
14245bc6ad | ||
|
|
dd9202fafe | ||
|
|
23fb68f2c3 | ||
|
|
92b7ae1b77 | ||
|
|
087c82c60c | ||
|
|
de408b5a3a | ||
|
|
2f5d4f71ec | ||
|
|
64be7e3b37 | ||
|
|
a63c808300 | ||
|
|
6d9a8a1eac | ||
|
|
65f45f72f0 | ||
|
|
a9a73efbb6 | ||
|
|
e24fb7889e | ||
|
|
9327948b61 | ||
|
|
4146fa6c6e | ||
|
|
be71668b8d | ||
|
|
5686dee43b | ||
|
|
bef6796da4 | ||
|
|
e55f031c39 | ||
|
|
98138181f7 | ||
|
|
c32462e21e | ||
|
|
34104495c5 | ||
|
|
907ce50071 | ||
|
|
7f668a6ca4 | ||
|
|
6ec44b5f41 | ||
|
|
1834655399 | ||
|
|
bfcac5c0dd | ||
|
|
422a5db6f9 | ||
|
|
08140226c3 | ||
|
|
612d1d8c63 | ||
|
|
b119671ee2 | ||
|
|
0f440c6b3a | ||
|
|
2fda48fa5f | ||
|
|
63e220ee3e | ||
|
|
2641aecc8a | ||
|
|
fc3e38f63b | ||
|
|
aaf4989610 | ||
|
|
fd6b9ae3a6 | ||
|
|
fdcda9833f | ||
|
|
74eaaa1f9e | ||
|
|
2adff6e51d | ||
|
|
5634e9e507 | ||
|
|
ced2c0e891 | ||
|
|
99a144a869 | ||
|
|
50d2577353 | ||
|
|
7f3164bbd7 | ||
|
|
3c64eb75aa | ||
|
|
3c74cd23b2 | ||
|
|
e306b62dd1 | ||
|
|
b61cb5c7cd | ||
|
|
0b1505975b | ||
|
|
a9d33f612c | ||
|
|
57d2fea5fd | ||
|
|
ffa0f14693 | ||
|
|
806591f1cc | ||
|
|
fde3872e2e | ||
|
|
5247ec5022 | ||
|
|
dd13ed49aa | ||
|
|
0a50bbc9ef | ||
|
|
d44edb84a0 |
5
.env
5
.env
@@ -30,15 +30,16 @@ USER_INFO_COOKIE_NAME=''
|
||||
ENABLE_ACCESSIBILITY_PAGE=false
|
||||
ENABLE_PROGRESS_GRAPH_SETTINGS=false
|
||||
ENABLE_TEAM_TYPE_SETTING=false
|
||||
ENABLE_NEW_EDITOR_PAGES=true
|
||||
ENABLE_UNIT_PAGE=false
|
||||
ENABLE_ASSETS_PAGE=false
|
||||
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN=false
|
||||
ENABLE_TAGGING_TAXONOMY_PAGES=false
|
||||
ENABLE_TAGGING_TAXONOMY_PAGES=true
|
||||
BBB_LEARN_MORE_URL=''
|
||||
HOTJAR_APP_ID=''
|
||||
HOTJAR_VERSION=6
|
||||
HOTJAR_DEBUG=false
|
||||
INVITE_STUDENTS_EMAIL_TO=''
|
||||
AI_TRANSLATIONS_BASE_URL=''
|
||||
ENABLE_HOME_PAGE_COURSE_API_V2=false
|
||||
ENABLE_CHECKLIST_QUALITY=''
|
||||
ENABLE_GRADING_METHOD_IN_PROBLEMS=false
|
||||
|
||||
@@ -32,10 +32,10 @@ USER_INFO_COOKIE_NAME='edx-user-info'
|
||||
ENABLE_ACCESSIBILITY_PAGE=false
|
||||
ENABLE_PROGRESS_GRAPH_SETTINGS=false
|
||||
ENABLE_TEAM_TYPE_SETTING=false
|
||||
ENABLE_NEW_EDITOR_PAGES=true
|
||||
ENABLE_UNIT_PAGE=false
|
||||
ENABLE_ASSETS_PAGE=false
|
||||
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN=false
|
||||
ENABLE_VIDEO_UPLOAD_PAGE_LINK_IN_CONTENT_DROPDOWN=true
|
||||
ENABLE_NEW_VIDEO_UPLOAD_PAGE=true
|
||||
ENABLE_TAGGING_TAXONOMY_PAGES=true
|
||||
BBB_LEARN_MORE_URL=''
|
||||
HOTJAR_APP_ID=''
|
||||
@@ -43,4 +43,6 @@ HOTJAR_VERSION=6
|
||||
HOTJAR_DEBUG=true
|
||||
INVITE_STUDENTS_EMAIL_TO="someone@domain.com"
|
||||
AI_TRANSLATIONS_BASE_URL='http://localhost:18760'
|
||||
ENABLE_HOME_PAGE_COURSE_API_V2=false
|
||||
ENABLE_CHECKLIST_QUALITY=true
|
||||
ENABLE_GRADING_METHOD_IN_PROBLEMS=false
|
||||
|
||||
@@ -28,11 +28,12 @@ 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_UNIT_PAGE=true
|
||||
ENABLE_ASSETS_PAGE=false
|
||||
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"
|
||||
ENABLE_HOME_PAGE_COURSE_API_V2=true
|
||||
ENABLE_CHECKLIST_QUALITY=true
|
||||
ENABLE_GRADING_METHOD_IN_PROBLEMS=false
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
coverage/*
|
||||
dist/
|
||||
node_modules/
|
||||
jest.config.js
|
||||
jest.config.js
|
||||
env.config.jsx
|
||||
example.env.config.jsx
|
||||
|
||||
3
.github/workflows/validate.yml
vendored
3
.github/workflows/validate.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
||||
node-version: ${{ env.NODE_VER }}
|
||||
- run: make validate.ci
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,3 +26,6 @@ temp/babel-plugin-react-intl
|
||||
|
||||
# Messages .json files fetched by atlas
|
||||
src/i18n/messages/
|
||||
|
||||
# environment js config
|
||||
env.config.jsx
|
||||
|
||||
10
README.rst
10
README.rst
@@ -140,13 +140,6 @@ Requirements
|
||||
* ``new_core_editors.use_new_video_editor``: must be enabled for the new Video Xblock editor to be used in Studio
|
||||
* ``new_core_editors.use_new_problem_editor``: must be enabled for the new Problem Xblock editor to be used in Studio
|
||||
|
||||
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 (on by default)
|
||||
|
||||
Feature Description
|
||||
-------------------
|
||||
|
||||
@@ -267,7 +260,8 @@ 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.
|
||||
* ``ENABLE_TAGGING_TAXONOMY_PAGES``: must be enabled (which it is by default) in order to actually enable/show the new
|
||||
Tagging/Taxonomy functionality.
|
||||
|
||||
|
||||
Developing
|
||||
|
||||
24
example.env.config.jsx
Normal file
24
example.env.config.jsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import WholeCourseTranslation from '@edx/course-app-translation-plugin';
|
||||
import { PLUGIN_OPERATIONS, DIRECT_PLUGIN } from '@openedx/frontend-plugin-framework';
|
||||
|
||||
// Load environment variables from .env file
|
||||
const config = {
|
||||
...process.env,
|
||||
pluginSlots: {
|
||||
additional_course_plugin: {
|
||||
plugins: [
|
||||
{
|
||||
op: PLUGIN_OPERATIONS.Insert,
|
||||
widget: {
|
||||
id: 'whole-course-translation-plugin',
|
||||
type: DIRECT_PLUGIN,
|
||||
priority: 1,
|
||||
RenderWidget: WholeCourseTranslation,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
4455
package-lock.json
generated
4455
package-lock.json
generated
@@ -16,9 +16,9 @@
|
||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||
"@edx/frontend-component-ai-translations": "^2.0.0",
|
||||
"@edx/frontend-component-footer": "^13.0.2",
|
||||
"@edx/frontend-component-header": "^5.0.2",
|
||||
"@edx/frontend-component-header": "^5.1.0",
|
||||
"@edx/frontend-enterprise-hotjar": "^2.0.0",
|
||||
"@edx/frontend-lib-content-components": "^2.1.4",
|
||||
"@edx/frontend-lib-content-components": "^2.5.1",
|
||||
"@edx/frontend-platform": "7.0.1",
|
||||
"@edx/openedx-atlas": "^0.6.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
@@ -26,6 +26,7 @@
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/react-fontawesome": "0.2.0",
|
||||
"@meilisearch/instant-meilisearch": "^0.17.0",
|
||||
"@openedx-plugins/course-app-calculator": "file:plugins/course-apps/calculator",
|
||||
"@openedx-plugins/course-app-edxnotes": "file:plugins/course-apps/edxnotes",
|
||||
"@openedx-plugins/course-app-learning_assistant": "file:plugins/course-apps/learning_assistant",
|
||||
@@ -36,10 +37,10 @@
|
||||
"@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams",
|
||||
"@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki",
|
||||
"@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary",
|
||||
"@openedx/paragon": "^21.5.7",
|
||||
"@openedx/frontend-plugin-framework": "^1.1.0",
|
||||
"@openedx/paragon": "^22.2.1",
|
||||
"@reduxjs/toolkit": "1.9.7",
|
||||
"@tanstack/react-query": "4.36.1",
|
||||
"broadcast-channel": "^7.0.0",
|
||||
"classnames": "2.2.6",
|
||||
"core-js": "3.8.1",
|
||||
"email-validator": "2.0.4",
|
||||
@@ -47,11 +48,13 @@
|
||||
"formik": "2.2.6",
|
||||
"jszip": "^3.10.1",
|
||||
"lodash": "4.17.21",
|
||||
"meilisearch": "^0.38.0",
|
||||
"moment": "2.29.4",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "17.0.2",
|
||||
"react-datepicker": "^4.13.0",
|
||||
"react-dom": "17.0.2",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-redux": "7.2.9",
|
||||
"react-responsive": "9.0.2",
|
||||
@@ -72,14 +75,15 @@
|
||||
"@edx/reactifex": "^1.0.3",
|
||||
"@edx/stylelint-config-edx": "2.3.0",
|
||||
"@edx/typescript-config": "^1.0.1",
|
||||
"@openedx/frontend-build": "13.0.27",
|
||||
"@openedx/frontend-build": "13.1.0",
|
||||
"@testing-library/jest-dom": "5.17.0",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"axios": "^0.27.2",
|
||||
"axios": "^0.28.0",
|
||||
"axios-mock-adapter": "1.22.0",
|
||||
"eslint-import-resolver-webpack": "^0.13.8",
|
||||
"fetch-mock-jest": "^1.5.1",
|
||||
"glob": "7.2.3",
|
||||
"husky": "7.0.4",
|
||||
"jest-canvas-mock": "^2.5.2",
|
||||
@@ -107,12 +111,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
||||
"integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@@ -147,85 +151,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
|
||||
"integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.23.4",
|
||||
"chalk": "^2.4.2"
|
||||
"@babel/highlight": "^7.24.2",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"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"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/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": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/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/@babel/code-frame/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
|
||||
"integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz",
|
||||
"integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -277,13 +217,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
|
||||
"integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
|
||||
"integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.23.6",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"@babel/types": "^7.24.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -328,16 +268,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.23.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz",
|
||||
"integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz",
|
||||
"integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-member-expression-to-functions": "^7.23.0",
|
||||
"@babel/helper-optimise-call-expression": "^7.22.5",
|
||||
"@babel/helper-replace-supers": "^7.22.20",
|
||||
"@babel/helper-replace-supers": "^7.24.1",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"semver": "^6.3.1"
|
||||
@@ -366,9 +306,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz",
|
||||
"integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==",
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz",
|
||||
"integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-compilation-targets": "^7.22.6",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -423,11 +363,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"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==",
|
||||
"version": "7.24.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz",
|
||||
"integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.15"
|
||||
"@babel/types": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -463,9 +403,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-plugin-utils": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
|
||||
"integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
|
||||
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -487,12 +427,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-replace-supers": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz",
|
||||
"integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz",
|
||||
"integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-member-expression-to-functions": "^7.22.15",
|
||||
"@babel/helper-member-expression-to-functions": "^7.23.0",
|
||||
"@babel/helper-optimise-call-expression": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -536,9 +476,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
|
||||
"integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
|
||||
"integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -573,26 +513,27 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz",
|
||||
"integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
|
||||
"integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.23.9",
|
||||
"@babel/traverse": "^7.23.9",
|
||||
"@babel/types": "^7.23.9"
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.1",
|
||||
"@babel/types": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
|
||||
"integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
|
||||
"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -663,9 +604,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
|
||||
"integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
|
||||
"integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -674,11 +615,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
||||
"version": "7.23.3",
|
||||
"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.23.3.tgz",
|
||||
"integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==",
|
||||
"version": "7.24.1",
|
||||
"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.24.1.tgz",
|
||||
"integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -688,13 +629,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz",
|
||||
"integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz",
|
||||
"integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.23.3"
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -835,11 +776,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-assertions": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz",
|
||||
"integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz",
|
||||
"integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -849,11 +790,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-attributes": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz",
|
||||
"integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz",
|
||||
"integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -885,11 +826,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-jsx": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
|
||||
"integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
|
||||
"integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -993,11 +934,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-typescript": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
|
||||
"integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz",
|
||||
"integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1022,11 +963,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-arrow-functions": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz",
|
||||
"integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz",
|
||||
"integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1036,12 +977,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-async-generator-functions": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz",
|
||||
"integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==",
|
||||
"version": "7.24.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz",
|
||||
"integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-remap-async-to-generator": "^7.22.20",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4"
|
||||
},
|
||||
@@ -1053,12 +994,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-async-to-generator": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz",
|
||||
"integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz",
|
||||
"integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-module-imports": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-remap-async-to-generator": "^7.22.20"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1069,11 +1010,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoped-functions": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz",
|
||||
"integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz",
|
||||
"integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1083,11 +1024,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoping": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz",
|
||||
"integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz",
|
||||
"integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1097,12 +1038,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-class-properties": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz",
|
||||
"integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz",
|
||||
"integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1112,12 +1053,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-class-static-block": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz",
|
||||
"integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz",
|
||||
"integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.4",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-class-static-block": "^7.14.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1128,16 +1069,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-classes": {
|
||||
"version": "7.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz",
|
||||
"integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz",
|
||||
"integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-replace-supers": "^7.22.20",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-replace-supers": "^7.24.1",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -1149,12 +1090,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-computed-properties": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz",
|
||||
"integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz",
|
||||
"integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/template": "^7.22.15"
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/template": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1164,11 +1105,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-destructuring": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz",
|
||||
"integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz",
|
||||
"integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1178,12 +1119,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dotall-regex": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz",
|
||||
"integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1193,11 +1134,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-duplicate-keys": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz",
|
||||
"integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz",
|
||||
"integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1207,11 +1148,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dynamic-import": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz",
|
||||
"integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz",
|
||||
"integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1222,12 +1163,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-exponentiation-operator": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz",
|
||||
"integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz",
|
||||
"integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1237,11 +1178,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-export-namespace-from": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz",
|
||||
"integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz",
|
||||
"integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1252,11 +1193,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-for-of": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz",
|
||||
"integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz",
|
||||
"integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1267,13 +1208,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-function-name": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz",
|
||||
"integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz",
|
||||
"integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-compilation-targets": "^7.22.15",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1283,11 +1224,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-json-strings": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz",
|
||||
"integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz",
|
||||
"integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-json-strings": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1298,11 +1239,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-literals": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz",
|
||||
"integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1312,11 +1253,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-logical-assignment-operators": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz",
|
||||
"integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz",
|
||||
"integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1327,11 +1268,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-member-expression-literals": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz",
|
||||
"integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1341,12 +1282,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-amd": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz",
|
||||
"integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz",
|
||||
"integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1356,12 +1297,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-commonjs": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz",
|
||||
"integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz",
|
||||
"integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-simple-access": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1372,13 +1313,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-systemjs": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz",
|
||||
"integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz",
|
||||
"integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-validator-identifier": "^7.22.20"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1389,12 +1330,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-umd": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz",
|
||||
"integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz",
|
||||
"integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1419,11 +1360,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-new-target": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz",
|
||||
"integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz",
|
||||
"integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1433,11 +1374,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz",
|
||||
"integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz",
|
||||
"integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1448,11 +1389,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-numeric-separator": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz",
|
||||
"integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz",
|
||||
"integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-numeric-separator": "^7.10.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1463,15 +1404,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-rest-spread": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz",
|
||||
"integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz",
|
||||
"integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.23.3",
|
||||
"@babel/helper-compilation-targets": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
"@babel/plugin-transform-parameters": "^7.23.3"
|
||||
"@babel/plugin-transform-parameters": "^7.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1481,12 +1421,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-super": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz",
|
||||
"integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz",
|
||||
"integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-replace-supers": "^7.22.20"
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-replace-supers": "^7.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1496,11 +1436,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-catch-binding": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz",
|
||||
"integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz",
|
||||
"integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1511,11 +1451,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-chaining": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz",
|
||||
"integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz",
|
||||
"integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
|
||||
},
|
||||
@@ -1527,11 +1467,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-parameters": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz",
|
||||
"integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz",
|
||||
"integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1541,12 +1481,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-methods": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz",
|
||||
"integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz",
|
||||
"integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1556,13 +1496,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-property-in-object": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz",
|
||||
"integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz",
|
||||
"integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==",
|
||||
"dependencies": {
|
||||
"@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/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1573,11 +1513,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-property-literals": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz",
|
||||
"integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1587,11 +1527,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-constant-elements": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.23.3.tgz",
|
||||
"integrity": "sha512-zP0QKq/p6O42OL94udMgSfKXyse4RyJ0JqbQ34zDAONWjyrEsghYEyTSK5FIpmXmCpB55SHokL1cRRKHv8L2Qw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.1.tgz",
|
||||
"integrity": "sha512-QXp1U9x0R7tkiGB0FOk8o74jhnap0FlZ5gNkRIWdG3eP+SvMFg118e1zaWewDzgABb106QSKpVsD3Wgd8t6ifA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1601,11 +1541,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-display-name": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz",
|
||||
"integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz",
|
||||
"integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1647,12 +1587,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-pure-annotations": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz",
|
||||
"integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz",
|
||||
"integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1662,11 +1602,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-regenerator": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz",
|
||||
"integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz",
|
||||
"integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"regenerator-transform": "^0.15.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1677,11 +1617,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-reserved-words": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz",
|
||||
"integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz",
|
||||
"integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1691,11 +1631,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-shorthand-properties": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz",
|
||||
"integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz",
|
||||
"integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1705,11 +1645,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-spread": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz",
|
||||
"integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz",
|
||||
"integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1720,11 +1660,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-sticky-regex": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz",
|
||||
"integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1734,11 +1674,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-template-literals": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz",
|
||||
"integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz",
|
||||
"integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1748,11 +1688,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-typeof-symbol": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz",
|
||||
"integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz",
|
||||
"integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1762,14 +1702,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-typescript": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz",
|
||||
"integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz",
|
||||
"integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-create-class-features-plugin": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-typescript": "^7.23.3"
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.4",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-typescript": "^7.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1779,11 +1719,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-escapes": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz",
|
||||
"integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz",
|
||||
"integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1793,12 +1733,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-property-regex": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz",
|
||||
"integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1808,12 +1748,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-regex": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz",
|
||||
"integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1823,12 +1763,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-sets-regex": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz",
|
||||
"integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz",
|
||||
"integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1965,15 +1905,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-typescript": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz",
|
||||
"integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz",
|
||||
"integrity": "sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-validator-option": "^7.22.15",
|
||||
"@babel/plugin-syntax-jsx": "^7.23.3",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.23.3",
|
||||
"@babel/plugin-transform-typescript": "^7.23.3"
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"@babel/plugin-syntax-jsx": "^7.24.1",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.24.1",
|
||||
"@babel/plugin-transform-typescript": "^7.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1988,9 +1928,9 @@
|
||||
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
|
||||
"integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
|
||||
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@@ -1999,9 +1939,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime-corejs3": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.9.tgz",
|
||||
"integrity": "sha512-oeOFTrYWdWXCvXGB5orvMTJ6gCZ9I6FBjR+M38iKNXCsPxr4xT0RTdg5uz1H7QP8pp74IzPtwritEr+JscqHXQ==",
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.4.tgz",
|
||||
"integrity": "sha512-VOQOexSilscN24VEY810G/PqtpFvx/z6UqDIjIWbDe2368HhDLkYN5TYwaEz/+eRCUkhJ2WaNLLmQAlxzfWj4w==",
|
||||
"dependencies": {
|
||||
"core-js-pure": "^3.30.2",
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
@@ -2021,31 +1961,31 @@
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
|
||||
"integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz",
|
||||
"integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
"@babel/parser": "^7.23.9",
|
||||
"@babel/types": "^7.23.9"
|
||||
"@babel/parser": "^7.24.0",
|
||||
"@babel/types": "^7.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
|
||||
"integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
|
||||
"integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
"@babel/generator": "^7.23.6",
|
||||
"@babel/code-frame": "^7.24.1",
|
||||
"@babel/generator": "^7.24.1",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.23.9",
|
||||
"@babel/types": "^7.23.9",
|
||||
"@babel/parser": "^7.24.1",
|
||||
"@babel/types": "^7.24.0",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -2054,9 +1994,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
|
||||
"integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
|
||||
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.23.4",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
@@ -2087,9 +2027,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/autocomplete": {
|
||||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.12.0.tgz",
|
||||
"integrity": "sha512-r4IjdYFthwbCQyvqnSlx0WBHRHi8nBvU+WjJxFUij81qsBfhNudf/XKKmmC2j3m0LaOYUQTf3qiEK1J8lO1sdg==",
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.15.0.tgz",
|
||||
"integrity": "sha512-G2Zm0mXznxz97JhaaOdoEG2cVupn4JjPaS4AcNvZzhOsnnG9YVN68VzfoUw6dYTsIxT6a/cmoFEN47KAWhXaOg==",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
@@ -2143,9 +2083,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-javascript": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.1.tgz",
|
||||
"integrity": "sha512-jlFOXTejVyiQCW3EQwvKH0m99bUYIw40oPmFjSX2VS78yzfe0HELZ+NEo9Yfo1MkGRpGlj3Gnu4rdxV1EnAs5A==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz",
|
||||
"integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/language": "^6.6.0",
|
||||
@@ -2157,13 +2097,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-xml": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.2.tgz",
|
||||
"integrity": "sha512-JQYZjHL2LAfpiZI2/qZ/qzDuSqmGKMwyApYmEUUCTxLM4MWS7sATUEfIguZQr9Zjx/7gcdnewb039smF6nC2zw==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz",
|
||||
"integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/language": "^6.4.0",
|
||||
"@codemirror/state": "^6.0.0",
|
||||
"@codemirror/view": "^6.0.0",
|
||||
"@lezer/common": "^1.0.0",
|
||||
"@lezer/xml": "^1.0.0"
|
||||
}
|
||||
@@ -2202,14 +2143,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/state": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.0.tgz",
|
||||
"integrity": "sha512-hm8XshYj5Fo30Bb922QX9hXB/bxOAVH+qaqHBzw5TKa72vOeslyGwd4X8M0c1dJ9JqxlaMceOQ8RsL9tC7gU0A=="
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
|
||||
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.24.0.tgz",
|
||||
"integrity": "sha512-zK6m5pNkdhdJl8idPP1gA4N8JKTiSsOz8U/Iw+C1ChMwyLG7+MLiNXnH/wFuAk6KeGEe33/adOiAh5jMqee03w==",
|
||||
"version": "6.26.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.1.tgz",
|
||||
"integrity": "sha512-wLw0t3R9AwOSQThdZ5Onw8QQtem5asE7+bPlnzc57eubPqiuJKIzwjMZ+C42vQett+iva+J8VgFV4RYWDBh5FA==",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"style-mod": "^4.1.0",
|
||||
@@ -2225,9 +2166,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/cascade-layer-name-parser": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.7.tgz",
|
||||
"integrity": "sha512-9J4aMRJ7A2WRjaRLvsMeWrL69FmEuijtiW1XlK/sG+V0UJiHVYUyvj9mY4WAXfU/hGIiGOgL8e0jJcRyaZTjDQ==",
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.9.tgz",
|
||||
"integrity": "sha512-RRqNjxTZDUhx7pxYOBG/AkCVmPS3zYzfE47GEhIGkFuWFTQGJBgWOUUkKNo5MfxIfjDz5/1L3F3rF1oIsYaIpw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -2242,14 +2183,14 @@
|
||||
"node": "^14 || ^16 || >=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@csstools/css-parser-algorithms": "^2.5.0",
|
||||
"@csstools/css-tokenizer": "^2.2.3"
|
||||
"@csstools/css-parser-algorithms": "^2.6.1",
|
||||
"@csstools/css-tokenizer": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/css-parser-algorithms": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.5.0.tgz",
|
||||
"integrity": "sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ==",
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.1.tgz",
|
||||
"integrity": "sha512-ubEkAaTfVZa+WwGhs5jbo5Xfqpeaybr/RvWzvFxRs4jfq16wH8l8Ty/QEEpINxll4xhuGfdMbipRyz5QZh9+FA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -2264,13 +2205,13 @@
|
||||
"node": "^14 || ^16 || >=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@csstools/css-tokenizer": "^2.2.3"
|
||||
"@csstools/css-tokenizer": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/css-tokenizer": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.3.tgz",
|
||||
"integrity": "sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==",
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.4.tgz",
|
||||
"integrity": "sha512-PuWRAewQLbDhGeTvFuq2oClaSCKPIBmHyIobCV39JHRYN0byDcUWJl5baPeNUcqrjtdMNqFooE0FGl31I3JOqw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -2286,9 +2227,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/media-query-list-parser": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.7.tgz",
|
||||
"integrity": "sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ==",
|
||||
"version": "2.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.9.tgz",
|
||||
"integrity": "sha512-qqGuFfbn4rUmyOB0u8CVISIp5FfJ5GAR3mBrZ9/TKndHakdnm6pY0L/fbLcpPnrzwCyyTEZl1nUcXAYHEWneTA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -2303,8 +2244,8 @@
|
||||
"node": "^14 || ^16 || >=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@csstools/css-parser-algorithms": "^2.5.0",
|
||||
"@csstools/css-tokenizer": "^2.2.3"
|
||||
"@csstools/css-parser-algorithms": "^2.6.1",
|
||||
"@csstools/css-tokenizer": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/selector-specificity": {
|
||||
@@ -2437,16 +2378,6 @@
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-ai-translations/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/@edx/frontend-component-ai-translations/node_modules/react-responsive": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz",
|
||||
@@ -2542,9 +2473,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.0.2.tgz",
|
||||
"integrity": "sha512-73fNNc1X/tevb3/hw7+s22T+nPGlW1yXA7zsT9eRzdH7rBxONfp0Jz7yEdeBvTax9a96PaOht45DA6GX9eG4KA==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.1.0.tgz",
|
||||
"integrity": "sha512-l+xZXDY3EjnsEN3BucFgw4gYfYh8/bCEVgY+a+Wu3xM+Kg4YQw9FwaHJM8CyPTt30JnMM6Qt6Q4vKdbgqbCOLg==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "6.5.1",
|
||||
@@ -2649,9 +2580,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-lib-content-components": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-2.1.4.tgz",
|
||||
"integrity": "sha512-5uZH0NxjLJQIpZhovC0EphdMK1sXt00bFElKs4DLWmV90ojDNNqtgQ73BIX4H9tz44QYrwCovYWUQ3NYCg5epA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-2.5.1.tgz",
|
||||
"integrity": "sha512-qxSGCF6GxDaeszW/f3ikf8V0j9yR6r1sohV15fHURrNvV0JPF860EIVgbPHR1FKjL1Iwo16Q/KWc0uY+HVwBYA==",
|
||||
"dependencies": {
|
||||
"@codemirror/lang-html": "^6.0.0",
|
||||
"@codemirror/lang-xml": "^6.0.0",
|
||||
@@ -2690,7 +2621,7 @@
|
||||
"xmlchecker": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/frontend-platform": "^7.0.1",
|
||||
"@edx/frontend-platform": "^7.0.1 || ^8.0.0",
|
||||
"@openedx/paragon": "^21.5.7 || ^22.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.14.0 || ^17.0.0",
|
||||
@@ -2873,6 +2804,15 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform/node_modules/axios": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.9",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform/node_modules/intl-messageformat": {
|
||||
"version": "10.5.8",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.8.tgz",
|
||||
@@ -2911,9 +2851,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform/node_modules/typescript": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
|
||||
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
@@ -3020,15 +2960,6 @@
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "0.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz",
|
||||
"integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
|
||||
@@ -3078,9 +3009,9 @@
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"node_modules/@emotion/react": {
|
||||
"version": "11.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.3.tgz",
|
||||
"integrity": "sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==",
|
||||
"version": "11.11.4",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz",
|
||||
"integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.11.0",
|
||||
@@ -3101,9 +3032,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/serialize": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.3.tgz",
|
||||
"integrity": "sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz",
|
||||
"integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==",
|
||||
"dependencies": {
|
||||
"@emotion/hash": "^0.9.1",
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
@@ -3237,9 +3168,10 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
|
||||
"integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
@@ -3267,9 +3199,9 @@
|
||||
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
|
||||
},
|
||||
"node_modules/@formatjs/cli": {
|
||||
"version": "6.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.7.tgz",
|
||||
"integrity": "sha512-F8sPvXsrjOXKAXpbZo3HObq3TZWNa91cimRukmy/54GRo83V0q2ybj9YXtBfcGlnFhzRFXq8ukkTtHgYeRMJaQ==",
|
||||
"version": "6.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.9.tgz",
|
||||
"integrity": "sha512-YH09kY6oufPdNDIwva/rC7wyg/ptJG6hRZ768eJEafiBR5R1VV1pKFmx106FV5WT7nzBm8Xf4Td+8+Mu+DtQsg==",
|
||||
"bin": {
|
||||
"formatjs": "bin/formatjs"
|
||||
},
|
||||
@@ -3277,7 +3209,7 @@
|
||||
"node": ">= 16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.3.4"
|
||||
"vue": "^3.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"vue": {
|
||||
@@ -3356,9 +3288,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/intl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.0.tgz",
|
||||
"integrity": "sha512-X3xT9guVkKDS86EKV80lS0KxoazUglkJTGZO66sKY7otgl0VeStPA8B3u8UkKT47PexVV98fUzjpkchYmbe9nw==",
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.1.tgz",
|
||||
"integrity": "sha512-dsLG15U7xDi8yzKf4hcAWSsCaez3XrjTO2oaRHPyHtXLm1aEzYbDw6bClo/HMHu+iwS5GbDqT3DV+hYP2ylScg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": "1.18.2",
|
||||
@@ -3554,16 +3486,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",
|
||||
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-5.0.0.tgz",
|
||||
@@ -3601,440 +3523,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw=="
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz",
|
||||
"integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-x64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz",
|
||||
"integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz",
|
||||
"integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"macos": ">=11",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz",
|
||||
"integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"macos": ">=10.13",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz",
|
||||
"integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz",
|
||||
"integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz",
|
||||
"integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz",
|
||||
"integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz",
|
||||
"integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz",
|
||||
"integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz",
|
||||
"integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz",
|
||||
"integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-s390x": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz",
|
||||
"integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-x64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz",
|
||||
"integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz",
|
||||
"integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz",
|
||||
"integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz",
|
||||
"integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^0.45.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-ia32": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz",
|
||||
"integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-x64": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz",
|
||||
"integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
@@ -4668,41 +4159,41 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"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==",
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
||||
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
@@ -4711,18 +4202,18 @@
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.22",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
|
||||
"integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"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=="
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
|
||||
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="
|
||||
},
|
||||
"node_modules/@lezer/common": {
|
||||
"version": "1.2.1",
|
||||
@@ -4730,9 +4221,9 @@
|
||||
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
|
||||
},
|
||||
"node_modules/@lezer/css": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.7.tgz",
|
||||
"integrity": "sha512-7BlFFAKNn/b39jJLrhdLSX5A2k56GIJvyLqdmm7UU+7XvequY084iuKDMAEhAmAzHnwDE8FK4OQtsIUssW91tg==",
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.8.tgz",
|
||||
"integrity": "sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.2.0",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
@@ -4748,9 +4239,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/html": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.8.tgz",
|
||||
"integrity": "sha512-EXseJ3pUzWxE6XQBQdqWHZqqlGQRSuNMBcLb6mZWS2J2v+QZhOObD+3ZIKIcm59ntTzyor4LqFTb72iJc3k23Q==",
|
||||
"version": "1.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.9.tgz",
|
||||
"integrity": "sha512-MXxeCMPyrcemSLGaTQEZx0dBUH0i+RPl8RN5GwMAzo53nTsd/Unc/t5ZxACeQoyPUM5/GkPLRUs2WliOImzkRA==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.2.0",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
@@ -4758,9 +4249,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/javascript": {
|
||||
"version": "1.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.13.tgz",
|
||||
"integrity": "sha512-5IBr8LIO3xJdJH1e9aj/ZNLE4LSbdsx25wFmGRAZsj2zSmwAYjx26JyU/BYOCpRQlu1jcv1z3vy4NB9+UkfRow==",
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.14.tgz",
|
||||
"integrity": "sha512-GEdUyspTRgc5dwIGebUk+f3BekvqEWVIYsIuAC3pA8e8wcikGwBZRWRa450L0s8noGWuULwnmi4yjxTnYz9PpA==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.2.0",
|
||||
"@lezer/highlight": "^1.1.3",
|
||||
@@ -4776,15 +4267,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/xml": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.4.tgz",
|
||||
"integrity": "sha512-WmXKb5eX8+rRfZYSNRR5TPee/ZoDgBdVS/rj1VCJGDKa5gNldIctQYibCoFVyNhvZsyL/8nHbZJZPM4gnXN2Vw==",
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.5.tgz",
|
||||
"integrity": "sha512-VFouqOzmUWfIg+tfmpcdV33ewtK+NSwd4ngSe1aG7HFb4BN0ExyY1b8msp+ndFrnlG4V4iC8yXacjFtrwERnaw==",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.2.0",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
"@lezer/lr": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@meilisearch/instant-meilisearch": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@meilisearch/instant-meilisearch/-/instant-meilisearch-0.17.0.tgz",
|
||||
"integrity": "sha512-6SDDivDWsmYjX33m2fAUCcBvatjutBbvqV8Eg+CEllz0l6piAiDK/WlukVpYrSmhYN2YGQsJSm62WbMGciPhUg==",
|
||||
"dependencies": {
|
||||
"meilisearch": "^0.38.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@newrelic/publish-sourcemap": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@newrelic/publish-sourcemap/-/publish-sourcemap-5.1.0.tgz",
|
||||
@@ -4929,9 +4428,9 @@
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@openedx/frontend-build": {
|
||||
"version": "13.0.27",
|
||||
"resolved": "https://registry.npmjs.org/@openedx/frontend-build/-/frontend-build-13.0.27.tgz",
|
||||
"integrity": "sha512-hhYd9WafApPr+QdTQsFYusDmkMRavoTghn/MJ+A/8Nk4xS7Dy/7W944FnQUOQjWrrYV3gpdenpQ7XCV88R4WEg==",
|
||||
"version": "13.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@openedx/frontend-build/-/frontend-build-13.1.0.tgz",
|
||||
"integrity": "sha512-HkIy0lVkEmOjss0RPO5Xfi2Z5zj2ksCeZS/QBx+K9nIjApL5kt+0vaj8ww54WSw2/iFfUCdPrBM8ck6PyvI8FQ==",
|
||||
"dependencies": {
|
||||
"@babel/cli": "7.22.5",
|
||||
"@babel/core": "7.22.5",
|
||||
@@ -4961,11 +4460,12 @@
|
||||
"dotenv-webpack": "8.0.1",
|
||||
"eslint": "8.44.0",
|
||||
"eslint-config-airbnb": "19.0.4",
|
||||
"eslint-plugin-formatjs": "^4.12.2",
|
||||
"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",
|
||||
"express": "^4.18.2",
|
||||
"file-loader": "6.2.0",
|
||||
"html-webpack-plugin": "5.6.0",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
@@ -4981,15 +4481,15 @@
|
||||
"resolve-url-loader": "5.0.0",
|
||||
"sass": "1.69.7",
|
||||
"sass-loader": "13.3.3",
|
||||
"sharp": "0.33.2",
|
||||
"sharp": "0.32.6",
|
||||
"source-map-loader": "4.0.2",
|
||||
"style-loader": "3.3.4",
|
||||
"url-loader": "4.1.1",
|
||||
"webpack": "5.89.0",
|
||||
"webpack-bundle-analyzer": "4.10.1",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-merge": "5.10.0"
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^4.15.1",
|
||||
"webpack-merge": "^5.10.0"
|
||||
},
|
||||
"bin": {
|
||||
"fedx-scripts": "bin/fedx-scripts.js"
|
||||
@@ -4998,64 +4498,366 @@
|
||||
"react": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-build/node_modules/webpack": {
|
||||
"version": "5.89.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz",
|
||||
"integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==",
|
||||
"node_modules/@openedx/frontend-build/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/@openedx/frontend-build/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/@openedx/frontend-build/node_modules/eslint": {
|
||||
"version": "8.44.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz",
|
||||
"integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@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.9.0",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"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",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.2.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.7",
|
||||
"watchpack": "^2.4.0",
|
||||
"webpack-sources": "^3.2.3"
|
||||
"@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": {
|
||||
"webpack": "bin/webpack.js"
|
||||
"eslint": "bin/eslint.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"webpack-cli": {
|
||||
"optional": true
|
||||
}
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-build/node_modules/webpack-sources": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||
"node_modules/@openedx/frontend-build/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",
|
||||
"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/@openedx/frontend-build/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/@openedx/frontend-build/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/@openedx/frontend-build/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": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-build/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/@openedx/frontend-build/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": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-build/node_modules/globals": {
|
||||
"version": "13.24.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
|
||||
"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
|
||||
"dependencies": {
|
||||
"type-fest": "^0.20.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-build/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/@openedx/frontend-build/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/@openedx/frontend-plugin-framework": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@openedx/frontend-plugin-framework/-/frontend-plugin-framework-1.1.0.tgz",
|
||||
"integrity": "sha512-WT2Up9UR1ctQLeN43iCwEF6BOmU3zxL+s+clDeS4zp/aPue3v5ObTbzRsuJGlFg9gA6lY1C6Yh2+QQ6w2sK2aw==",
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||
"@edx/frontend-component-footer": "13.0.3",
|
||||
"@edx/frontend-component-header": "5.0.2",
|
||||
"classnames": "^2.3.2",
|
||||
"core-js": "3.36.0",
|
||||
"react-redux": "7.2.9",
|
||||
"redux": "4.2.1",
|
||||
"regenerator-runtime": "0.14.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/frontend-platform": "^7.0.0",
|
||||
"@openedx/paragon": "^21.0.0 || ^22.0.0",
|
||||
"prop-types": "^15.8.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-error-boundary": "^4.0.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@edx/frontend-component-footer": {
|
||||
"version": "13.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-13.0.3.tgz",
|
||||
"integrity": "sha512-09vX6qC7AcDwG02qhBzKr4x58hpe9FXZrA9ui2cJnsG53pKaNL+wvOSRtDUBNexCf+y/iPg+8RgR+4alkzhZhw==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "6.5.1",
|
||||
"@fortawesome/free-regular-svg-icons": "6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "6.5.1",
|
||||
"@fortawesome/react-fontawesome": "0.2.0",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/frontend-platform": "^7.0.0",
|
||||
"@openedx/paragon": ">= 21.11.3 < 23.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@edx/frontend-component-header": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-5.0.2.tgz",
|
||||
"integrity": "sha512-73fNNc1X/tevb3/hw7+s22T+nPGlW1yXA7zsT9eRzdH7rBxONfp0Jz7yEdeBvTax9a96PaOht45DA6GX9eG4KA==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "6.5.1",
|
||||
"@fortawesome/free-regular-svg-icons": "6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "6.5.1",
|
||||
"@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": {
|
||||
"@edx/frontend-platform": "^7.0.0",
|
||||
"@openedx/paragon": ">= 21.5.7 < 23.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
|
||||
"integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
|
||||
"integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/free-brands-svg-icons": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.1.tgz",
|
||||
"integrity": "sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.1.tgz",
|
||||
"integrity": "sha512-m6ShXn+wvqEU69wSP84coxLbNl7sGVZb+Ca+XZq6k30SzuP3X4TfPqtycgUh9ASwlNh5OfQCd8pDIWxl+O+LlQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz",
|
||||
"integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/core-js": {
|
||||
"version": "3.36.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.0.tgz",
|
||||
"integrity": "sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/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/@openedx/frontend-plugin-framework/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": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/frontend-plugin-framework/node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/@openedx/paragon": {
|
||||
"version": "21.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-21.13.1.tgz",
|
||||
"integrity": "sha512-sLL+Z3ZWIRM6x+OrKZV0S7/SQpEcSeRcDm7E3FzhsnAWudsJCTELvSW+84uy/8dwV7mJhttsBPqQEtNafbCyYA==",
|
||||
"version": "22.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@openedx/paragon/-/paragon-22.2.1.tgz",
|
||||
"integrity": "sha512-Dd7PzvHwNnUokqbFkuOpugJZ9dHaUBOcYwqAA2aMoN7tgi4xEZWsfDFyP1+se2UPuR7NvNGammEesLAwGQ0Ylw==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||
@@ -5097,21 +4899,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/paragon/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
|
||||
"integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==",
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz",
|
||||
"integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/paragon/node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
|
||||
"integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz",
|
||||
"integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.5.1"
|
||||
"@fortawesome/fontawesome-common-types": "6.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -5171,16 +4973,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@openedx/paragon/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/@openedx/paragon/node_modules/react-responsive": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz",
|
||||
@@ -5260,9 +5052,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
"version": "1.0.0-next.24",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz",
|
||||
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ=="
|
||||
"version": "1.0.0-next.25",
|
||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz",
|
||||
"integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ=="
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
@@ -5321,9 +5113,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@restart/hooks": {
|
||||
"version": "0.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.15.tgz",
|
||||
"integrity": "sha512-cZFXYTxbpzYcieq/mBwSyXgqnGMHoBVh3J7MU0CCoIB4NRZxV9/TuwTBAaLMqpNhC3zTPMCgkQ5Ey07L02Xmcw==",
|
||||
"version": "0.4.16",
|
||||
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
|
||||
"integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
},
|
||||
@@ -5733,6 +5525,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/react-hooks/node_modules/react-error-boundary": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz",
|
||||
"integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/react/node_modules/@testing-library/dom": {
|
||||
"version": "8.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz",
|
||||
@@ -5888,9 +5696,9 @@
|
||||
"integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
||||
"integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==",
|
||||
"version": "8.56.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz",
|
||||
"integrity": "sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==",
|
||||
"dependencies": {
|
||||
"@types/estree": "*",
|
||||
"@types/json-schema": "*"
|
||||
@@ -5922,9 +5730,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express-serve-static-core": {
|
||||
"version": "4.17.43",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
|
||||
"integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
|
||||
"integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
@@ -6076,9 +5884,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.11.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz",
|
||||
"integrity": "sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==",
|
||||
"version": "20.12.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
|
||||
"integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
@@ -6101,20 +5909,25 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
|
||||
},
|
||||
"node_modules/@types/picomatch": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.3.tgz",
|
||||
"integrity": "sha512-Yll76ZHikRFCyz/pffKGjrCwe/le2CDwOP5F210KQo27kpRE46U2rDnzikNlVn6/ezH3Mhn46bJMTfeVTtcYMg=="
|
||||
},
|
||||
"node_modules/@types/prettier": {
|
||||
"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.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
|
||||
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
|
||||
"version": "15.7.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
|
||||
"integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ=="
|
||||
"version": "6.9.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz",
|
||||
"integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA=="
|
||||
},
|
||||
"node_modules/@types/range-parser": {
|
||||
"version": "1.2.7",
|
||||
@@ -6122,12 +5935,12 @@
|
||||
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "17.0.75",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.75.tgz",
|
||||
"integrity": "sha512-MSA+NzEzXnQKrqpO63CYqNstFjsESgvJAdAyyJ1n6ZQq/GLgf6nOfIKwk+Twuz0L1N6xPe+qz5xRCJrbhMaLsw==",
|
||||
"version": "17.0.80",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.80.tgz",
|
||||
"integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"@types/scheduler": "^0.16",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
@@ -6169,6 +5982,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
|
||||
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="
|
||||
},
|
||||
"node_modules/@types/send": {
|
||||
"version": "0.17.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
||||
@@ -6187,13 +6005,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/serve-static": {
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
|
||||
"integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
|
||||
"version": "1.15.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
|
||||
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
||||
"dependencies": {
|
||||
"@types/http-errors": "*",
|
||||
"@types/mime": "*",
|
||||
"@types/node": "*"
|
||||
"@types/node": "*",
|
||||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/sockjs": {
|
||||
@@ -6244,6 +6062,235 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
|
||||
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
|
||||
"integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.21.0",
|
||||
"@typescript-eslint/visitor-keys": "6.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
|
||||
"integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
|
||||
"integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.21.0",
|
||||
"@typescript-eslint/visitor-keys": "6.21.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "9.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/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==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/globby": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||
"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/@typescript-eslint/typescript-estree/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": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
|
||||
"integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "6.21.0",
|
||||
"@typescript-eslint/types": "6.21.0",
|
||||
"@typescript-eslint/typescript-estree": "6.21.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/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": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/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/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
|
||||
"integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.21.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys/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/@ungap/structured-clone": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@videojs/http-streaming": {
|
||||
"version": "2.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.16.2.tgz",
|
||||
@@ -6291,9 +6338,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
|
||||
"integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
|
||||
@@ -6310,9 +6357,9 @@
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
|
||||
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA=="
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
|
||||
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.6",
|
||||
@@ -6330,14 +6377,14 @@
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"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==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
|
||||
"integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6"
|
||||
"@webassemblyjs/wasm-gen": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ieee754": {
|
||||
@@ -6362,26 +6409,26 @@
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"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==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
|
||||
"integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@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"
|
||||
"@webassemblyjs/helper-wasm-section": "1.12.1",
|
||||
"@webassemblyjs/wasm-gen": "1.12.1",
|
||||
"@webassemblyjs/wasm-opt": "1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "1.12.1",
|
||||
"@webassemblyjs/wast-printer": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-gen": {
|
||||
"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==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
|
||||
"integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
@@ -6389,22 +6436,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
|
||||
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
|
||||
"integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/wasm-gen": "1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
|
||||
"integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
@@ -6413,11 +6460,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
|
||||
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
|
||||
"integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
@@ -6722,9 +6769,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz",
|
||||
"integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
|
||||
"integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
@@ -6785,14 +6832,15 @@
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"node_modules/array-includes": {
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz",
|
||||
"integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==",
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
|
||||
"integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1",
|
||||
"get-intrinsic": "^1.2.1",
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"is-string": "^1.0.7"
|
||||
},
|
||||
"engines": {
|
||||
@@ -6830,15 +6878,39 @@
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.find": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.2.tgz",
|
||||
"integrity": "sha512-DRumkfW97iZGOfn+lIXbkVrXL04sfYKX+EfOodo8XboR5sxPDVvOjZTF/rysusa9lmhmSOeD6Vp6RKQP+eP4Tg==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.3.tgz",
|
||||
"integrity": "sha512-fO/ORdOELvjbbeIfZfzrXFMhYHGofRGqd+am9zm3tZ4GlJINj/pA2eITyfd65Vg6+ZbHd/Cys7stpoRSWtQFdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1",
|
||||
"es-shim-unscopables": "^1.0.0"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-shim-unscopables": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array.prototype.findlastindex": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
|
||||
"integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-shim-unscopables": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -7016,9 +7088,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz",
|
||||
"integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
|
||||
"dependencies": {
|
||||
"possible-typed-array-names": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -7027,20 +7102,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axe-core": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.8.4.tgz",
|
||||
"integrity": "sha512-CZLSKisu/bhJ2awW4kJndluz2HLZYIHh5Uy1+ZwDRkJi69811xgIXXfdU9HSLX0Th+ILrHj8qfL/5wzamsFtQg==",
|
||||
"version": "4.9.0",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.0.tgz",
|
||||
"integrity": "sha512-H5orY+M2Fr56DWmMFpMrq5Ge93qjNdPVqzBv5gWK3aD1OvjBEJlEzxf09z93dGVQeI0LiW+aCMIx1QtShC/zUw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz",
|
||||
"integrity": "sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.9",
|
||||
"form-data": "^4.0.0"
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios-cache-interceptor": {
|
||||
@@ -7076,6 +7152,11 @@
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
|
||||
"integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg=="
|
||||
},
|
||||
"node_modules/babel-jest": {
|
||||
"version": "26.6.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
|
||||
@@ -7171,9 +7252,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-formatjs": {
|
||||
"version": "10.5.13",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.13.tgz",
|
||||
"integrity": "sha512-0dtMhoa6q0P5lUHBphLd8/y+CRlh5IG3Rq+Wk64kOEDwUVZF8xq1qMSjC3iw1wH4tmP2qTzBL+Bz1xEjyBd/ew==",
|
||||
"version": "10.5.14",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-formatjs/-/babel-plugin-formatjs-10.5.14.tgz",
|
||||
"integrity": "sha512-F++4Txa2bxrjbvspLxIXBDwcbKOftUvGgBDlz0hGe/fp7eXSPBJcu49xWj0/5VyMgSad4gKmBzWE5bfC27x19Q==",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.10.4",
|
||||
"@babel/helper-plugin-utils": "^7.10.4",
|
||||
@@ -7216,9 +7297,9 @@
|
||||
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="
|
||||
},
|
||||
"node_modules/babel-plugin-formatjs/node_modules/typescript": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
|
||||
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -7286,12 +7367,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz",
|
||||
"integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==",
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz",
|
||||
"integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.6",
|
||||
"@babel/helper-define-polyfill-provider": "^0.5.0",
|
||||
"@babel/helper-define-polyfill-provider": "^0.6.1",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -7336,6 +7417,21 @@
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz",
|
||||
"integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==",
|
||||
"dependencies": {
|
||||
"@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"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-transform-imports": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-imports/-/babel-plugin-transform-imports-2.0.0.tgz",
|
||||
@@ -7430,6 +7526,38 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/bare-events": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz",
|
||||
"integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/bare-fs": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.3.tgz",
|
||||
"integrity": "sha512-amG72llr9pstfXOBOHve1WjiuKKAMnebcmMbPWDZ7BCevAoJLpugjuAPRsDINEyjT0a6tbaVx3DctkXIRbLuJw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bare-events": "^2.0.0",
|
||||
"bare-path": "^2.0.0",
|
||||
"streamx": "^2.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-os": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz",
|
||||
"integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/bare-path": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.1.tgz",
|
||||
"integrity": "sha512-OHM+iwRDRMDBsSW7kl3dO62JyHdBKO3B25FB9vNQBPcGHMo4+eA8Yj41Lfbk3pS/seDY+siNge0LdRTulAau/A==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bare-os": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
|
||||
@@ -7491,11 +7619,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
@@ -7522,12 +7653,12 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
@@ -7535,7 +7666,7 @@
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
@@ -7610,45 +7741,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/broadcast-channel": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-7.0.0.tgz",
|
||||
"integrity": "sha512-a2tW0Ia1pajcPBOGUF2jXlDnvE9d5/dg6BG9h60OmRUcZVr/veUrU8vEQFwwQIhwG3KVzYwSk3v2nRRGFgQDXQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.23.4",
|
||||
"oblivious-set": "1.4.0",
|
||||
"p-queue": "6.6.2",
|
||||
"unload": "2.4.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/pubkey"
|
||||
}
|
||||
},
|
||||
"node_modules/broadcast-channel/node_modules/@babel/runtime": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz",
|
||||
"integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/broadcast-channel/node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"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/browserslist": {
|
||||
"version": "4.22.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz",
|
||||
"integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==",
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
|
||||
"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -7664,8 +7765,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001580",
|
||||
"electron-to-chromium": "^1.4.648",
|
||||
"caniuse-lite": "^1.0.30001587",
|
||||
"electron-to-chromium": "^1.4.668",
|
||||
"node-releases": "^2.0.14",
|
||||
"update-browserslist-db": "^1.0.13"
|
||||
},
|
||||
@@ -7745,14 +7846,15 @@
|
||||
"integrity": "sha512-O0KwuHuJnbHUrghHi2kGp0SxnWSIBXTYt7M8WVhW0kbPRUNUKoE/Of6e1rRD6AAxmfxFunKnt90yEK09D+sc5g=="
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz",
|
||||
"integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.3",
|
||||
"set-function-length": "^1.2.0"
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"set-function-length": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7827,9 +7929,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001585",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001585.tgz",
|
||||
"integrity": "sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==",
|
||||
"version": "1.0.30001606",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz",
|
||||
"integrity": "sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -7925,6 +8027,11 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"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/chrome-trace-event": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
@@ -8327,9 +8434,9 @@
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -8364,11 +8471,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.35.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.1.tgz",
|
||||
"integrity": "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==",
|
||||
"version": "3.36.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz",
|
||||
"integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2"
|
||||
"browserslist": "^4.23.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -8376,9 +8483,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/core-js-pure": {
|
||||
"version": "3.35.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.35.1.tgz",
|
||||
"integrity": "sha512-zcIdi/CL3MWbBJYo5YCeVAAx+Sy9yJE9I3/u9LkFABwbeaPhTMRWraM8mYFp9jW5Z50hOy7FVzCc8dCrpZqtIQ==",
|
||||
"version": "3.36.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.36.1.tgz",
|
||||
"integrity": "sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -8436,6 +8543,14 @@
|
||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
|
||||
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
@@ -8450,9 +8565,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/css-declaration-sorter": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.1.1.tgz",
|
||||
"integrity": "sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz",
|
||||
"integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18"
|
||||
},
|
||||
@@ -8612,39 +8727,40 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cssnano-preset-default": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.3.tgz",
|
||||
"integrity": "sha512-4y3H370aZCkT9Ev8P4SO4bZbt+AExeKhh8wTbms/X7OLDo5E7AYUUy6YPxa/uF5Grf+AJwNcCnxKhZynJ6luBA==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz",
|
||||
"integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==",
|
||||
"dependencies": {
|
||||
"css-declaration-sorter": "^7.1.1",
|
||||
"cssnano-utils": "^4.0.1",
|
||||
"browserslist": "^4.23.0",
|
||||
"css-declaration-sorter": "^7.2.0",
|
||||
"cssnano-utils": "^4.0.2",
|
||||
"postcss-calc": "^9.0.1",
|
||||
"postcss-colormin": "^6.0.2",
|
||||
"postcss-convert-values": "^6.0.2",
|
||||
"postcss-discard-comments": "^6.0.1",
|
||||
"postcss-discard-duplicates": "^6.0.1",
|
||||
"postcss-discard-empty": "^6.0.1",
|
||||
"postcss-discard-overridden": "^6.0.1",
|
||||
"postcss-merge-longhand": "^6.0.2",
|
||||
"postcss-merge-rules": "^6.0.3",
|
||||
"postcss-minify-font-values": "^6.0.1",
|
||||
"postcss-minify-gradients": "^6.0.1",
|
||||
"postcss-minify-params": "^6.0.2",
|
||||
"postcss-minify-selectors": "^6.0.2",
|
||||
"postcss-normalize-charset": "^6.0.1",
|
||||
"postcss-normalize-display-values": "^6.0.1",
|
||||
"postcss-normalize-positions": "^6.0.1",
|
||||
"postcss-normalize-repeat-style": "^6.0.1",
|
||||
"postcss-normalize-string": "^6.0.1",
|
||||
"postcss-normalize-timing-functions": "^6.0.1",
|
||||
"postcss-normalize-unicode": "^6.0.2",
|
||||
"postcss-normalize-url": "^6.0.1",
|
||||
"postcss-normalize-whitespace": "^6.0.1",
|
||||
"postcss-ordered-values": "^6.0.1",
|
||||
"postcss-reduce-initial": "^6.0.2",
|
||||
"postcss-reduce-transforms": "^6.0.1",
|
||||
"postcss-svgo": "^6.0.2",
|
||||
"postcss-unique-selectors": "^6.0.2"
|
||||
"postcss-colormin": "^6.1.0",
|
||||
"postcss-convert-values": "^6.1.0",
|
||||
"postcss-discard-comments": "^6.0.2",
|
||||
"postcss-discard-duplicates": "^6.0.3",
|
||||
"postcss-discard-empty": "^6.0.3",
|
||||
"postcss-discard-overridden": "^6.0.2",
|
||||
"postcss-merge-longhand": "^6.0.5",
|
||||
"postcss-merge-rules": "^6.1.1",
|
||||
"postcss-minify-font-values": "^6.1.0",
|
||||
"postcss-minify-gradients": "^6.0.3",
|
||||
"postcss-minify-params": "^6.1.0",
|
||||
"postcss-minify-selectors": "^6.0.4",
|
||||
"postcss-normalize-charset": "^6.0.2",
|
||||
"postcss-normalize-display-values": "^6.0.2",
|
||||
"postcss-normalize-positions": "^6.0.2",
|
||||
"postcss-normalize-repeat-style": "^6.0.2",
|
||||
"postcss-normalize-string": "^6.0.2",
|
||||
"postcss-normalize-timing-functions": "^6.0.2",
|
||||
"postcss-normalize-unicode": "^6.1.0",
|
||||
"postcss-normalize-url": "^6.0.2",
|
||||
"postcss-normalize-whitespace": "^6.0.2",
|
||||
"postcss-ordered-values": "^6.0.2",
|
||||
"postcss-reduce-initial": "^6.1.0",
|
||||
"postcss-reduce-transforms": "^6.0.2",
|
||||
"postcss-svgo": "^6.0.3",
|
||||
"postcss-unique-selectors": "^6.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
@@ -8654,9 +8770,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cssnano-utils": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.1.tgz",
|
||||
"integrity": "sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==",
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz",
|
||||
"integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
},
|
||||
@@ -8738,6 +8854,54 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/data-view-buffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
|
||||
"integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.6",
|
||||
"es-errors": "^1.3.0",
|
||||
"is-data-view": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/data-view-byte-length": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
|
||||
"integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"is-data-view": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/data-view-byte-offset": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
|
||||
"integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.6",
|
||||
"es-errors": "^1.3.0",
|
||||
"is-data-view": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
@@ -8821,6 +8985,20 @@
|
||||
"node": ">=14.16"
|
||||
}
|
||||
},
|
||||
"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/deep-diff": {
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
|
||||
@@ -8857,6 +9035,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -8934,17 +9120,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz",
|
||||
"integrity": "sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.1"
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-lazy-prop": {
|
||||
@@ -9034,9 +9222,9 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -9292,9 +9480,9 @@
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.665",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.665.tgz",
|
||||
"integrity": "sha512-UpyCWObBoD+nSZgOC2ToaIdZB0r9GhqT2WahPKiSki6ckkSuKhQNso8V2PrFcHBMleI/eqbKgVQgVC4Wni4ilw=="
|
||||
"version": "1.4.728",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.728.tgz",
|
||||
"integrity": "sha512-Ud1v7hJJYIqehlUJGqR6PF1Ek8l80zWwxA6nGxigBsGJ9f9M2fciHyrIiNMerSHSH3p+0/Ia7jIlnDkt41h5cw=="
|
||||
},
|
||||
"node_modules/email-prop-type": {
|
||||
"version": "3.0.1",
|
||||
@@ -9324,9 +9512,9 @@
|
||||
}
|
||||
},
|
||||
"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=="
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
|
||||
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
|
||||
},
|
||||
"node_modules/emojis-list": {
|
||||
"version": "3.0.0",
|
||||
@@ -9353,15 +9541,17 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
|
||||
"integrity": "sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
"graceful-fs": "^4.1.2",
|
||||
"memory-fs": "^0.2.0",
|
||||
"tapable": "^0.1.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
@@ -9403,49 +9593,56 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.22.3",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz",
|
||||
"integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==",
|
||||
"version": "1.23.3",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
|
||||
"integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
|
||||
"dependencies": {
|
||||
"array-buffer-byte-length": "^1.0.0",
|
||||
"arraybuffer.prototype.slice": "^1.0.2",
|
||||
"available-typed-arrays": "^1.0.5",
|
||||
"call-bind": "^1.0.5",
|
||||
"es-set-tostringtag": "^2.0.1",
|
||||
"array-buffer-byte-length": "^1.0.1",
|
||||
"arraybuffer.prototype.slice": "^1.0.3",
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
"call-bind": "^1.0.7",
|
||||
"data-view-buffer": "^1.0.1",
|
||||
"data-view-byte-length": "^1.0.1",
|
||||
"data-view-byte-offset": "^1.0.0",
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-set-tostringtag": "^2.0.3",
|
||||
"es-to-primitive": "^1.2.1",
|
||||
"function.prototype.name": "^1.1.6",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"get-symbol-description": "^1.0.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"get-symbol-description": "^1.0.2",
|
||||
"globalthis": "^1.0.3",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.2",
|
||||
"has-proto": "^1.0.3",
|
||||
"has-symbols": "^1.0.3",
|
||||
"hasown": "^2.0.0",
|
||||
"internal-slot": "^1.0.5",
|
||||
"is-array-buffer": "^3.0.2",
|
||||
"hasown": "^2.0.2",
|
||||
"internal-slot": "^1.0.7",
|
||||
"is-array-buffer": "^3.0.4",
|
||||
"is-callable": "^1.2.7",
|
||||
"is-negative-zero": "^2.0.2",
|
||||
"is-data-view": "^1.0.1",
|
||||
"is-negative-zero": "^2.0.3",
|
||||
"is-regex": "^1.1.4",
|
||||
"is-shared-array-buffer": "^1.0.2",
|
||||
"is-shared-array-buffer": "^1.0.3",
|
||||
"is-string": "^1.0.7",
|
||||
"is-typed-array": "^1.1.12",
|
||||
"is-typed-array": "^1.1.13",
|
||||
"is-weakref": "^1.0.2",
|
||||
"object-inspect": "^1.13.1",
|
||||
"object-keys": "^1.1.1",
|
||||
"object.assign": "^4.1.4",
|
||||
"regexp.prototype.flags": "^1.5.1",
|
||||
"safe-array-concat": "^1.0.1",
|
||||
"safe-regex-test": "^1.0.0",
|
||||
"string.prototype.trim": "^1.2.8",
|
||||
"string.prototype.trimend": "^1.0.7",
|
||||
"string.prototype.trimstart": "^1.0.7",
|
||||
"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",
|
||||
"object.assign": "^4.1.5",
|
||||
"regexp.prototype.flags": "^1.5.2",
|
||||
"safe-array-concat": "^1.1.2",
|
||||
"safe-regex-test": "^1.0.3",
|
||||
"string.prototype.trim": "^1.2.9",
|
||||
"string.prototype.trimend": "^1.0.8",
|
||||
"string.prototype.trimstart": "^1.0.8",
|
||||
"typed-array-buffer": "^1.0.2",
|
||||
"typed-array-byte-length": "^1.0.1",
|
||||
"typed-array-byte-offset": "^1.0.2",
|
||||
"typed-array-length": "^1.0.6",
|
||||
"unbox-primitive": "^1.0.2",
|
||||
"which-typed-array": "^1.1.13"
|
||||
"which-typed-array": "^1.1.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -9454,6 +9651,17 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
@@ -9482,18 +9690,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
|
||||
"integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w=="
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz",
|
||||
"integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw=="
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
|
||||
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz",
|
||||
"integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
|
||||
"integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"has-tostringtag": "^1.0.0",
|
||||
"hasown": "^2.0.0"
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -9577,26 +9796,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.44.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz",
|
||||
"integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==",
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
|
||||
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
|
||||
"peer": true,
|
||||
"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",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/js": "8.57.0",
|
||||
"@humanwhocodes/config-array": "^0.11.14",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"ajv": "^6.10.0",
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
"ajv": "^6.12.4",
|
||||
"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",
|
||||
"eslint-scope": "^7.2.2",
|
||||
"eslint-visitor-keys": "^3.4.3",
|
||||
"espree": "^9.6.1",
|
||||
"esquery": "^1.4.2",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -9606,7 +9827,6 @@
|
||||
"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",
|
||||
@@ -9618,7 +9838,6 @@
|
||||
"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": {
|
||||
@@ -9722,29 +9941,6 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-webpack/node_modules/enhanced-resolve": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
|
||||
"integrity": "sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"memory-fs": "^0.2.0",
|
||||
"tapable": "^0.1.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-webpack/node_modules/interpret": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-webpack/node_modules/resolve": {
|
||||
"version": "2.0.0-next.5",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
|
||||
@@ -9771,19 +9967,10 @@
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-webpack/node_modules/tapable": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz",
|
||||
"integrity": "sha512-jX8Et4hHg57mug1/079yitEKWGB3LCwoxByLsNim89LABq8NqgiX+6iYVOsq0vX8uJHkU+DZ5fnq95f800bEsQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
|
||||
"integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
|
||||
"dependencies": {
|
||||
"debug": "^3.2.7"
|
||||
},
|
||||
@@ -9804,26 +9991,89 @@
|
||||
"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==",
|
||||
"node_modules/eslint-plugin-formatjs": {
|
||||
"version": "4.12.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-formatjs/-/eslint-plugin-formatjs-4.12.2.tgz",
|
||||
"integrity": "sha512-b4iEsi0Y3zy7J6xjxlhrIaDFJa27OiLwardvCRBRHALoZs8rNJ0oQIW6ymUgELLEMeFuEMAd2837M+n5SHJutg==",
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.6",
|
||||
"array.prototype.flat": "^1.3.1",
|
||||
"array.prototype.flatmap": "^1.3.1",
|
||||
"@formatjs/icu-messageformat-parser": "2.7.6",
|
||||
"@formatjs/ts-transformer": "3.13.12",
|
||||
"@types/eslint": "7 || 8",
|
||||
"@types/picomatch": "^2.3.0",
|
||||
"@typescript-eslint/utils": "^6.18.1",
|
||||
"emoji-regex": "^10.2.1",
|
||||
"magic-string": "^0.30.0",
|
||||
"picomatch": "^2.3.1",
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "5",
|
||||
"unicode-emoji-utils": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "7 || 8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-formatjs/node_modules/@formatjs/ts-transformer": {
|
||||
"version": "3.13.12",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.13.12.tgz",
|
||||
"integrity": "sha512-uf1+DgbsCrzHAg7uIf0QlzpIkHYxRSRig5iJa9FaoUNIDZzNEE2oW/uLLLq7I9Z2FLIPhbmgq8hbW40FoQv+Fg==",
|
||||
"dependencies": {
|
||||
"@formatjs/icu-messageformat-parser": "2.7.6",
|
||||
"@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": "5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ts-jest": ">=27"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ts-jest": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-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/eslint-plugin-formatjs/node_modules/typescript": {
|
||||
"version": "5.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
|
||||
"integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
|
||||
"integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.7",
|
||||
"array.prototype.findlastindex": "^1.2.3",
|
||||
"array.prototype.flat": "^1.3.2",
|
||||
"array.prototype.flatmap": "^1.3.2",
|
||||
"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",
|
||||
"is-core-module": "^2.11.0",
|
||||
"eslint-import-resolver-node": "^0.3.9",
|
||||
"eslint-module-utils": "^2.8.0",
|
||||
"hasown": "^2.0.0",
|
||||
"is-core-module": "^2.13.1",
|
||||
"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"
|
||||
"object.fromentries": "^2.0.7",
|
||||
"object.groupby": "^1.0.1",
|
||||
"object.values": "^1.1.7",
|
||||
"semver": "^6.3.1",
|
||||
"tsconfig-paths": "^3.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
@@ -9836,6 +10086,7 @@
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
@@ -9844,6 +10095,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
@@ -9880,6 +10132,11 @@
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jsx-a11y/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/eslint-plugin-react": {
|
||||
"version": "7.32.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz",
|
||||
@@ -9930,16 +10187,6 @@
|
||||
"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.5",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
|
||||
@@ -9987,12 +10234,14 @@
|
||||
"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=="
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"peer": true
|
||||
},
|
||||
"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==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
@@ -10008,6 +10257,7 @@
|
||||
"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==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
@@ -10019,6 +10269,7 @@
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
@@ -10030,6 +10281,7 @@
|
||||
"version": "13.24.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
|
||||
"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"type-fest": "^0.20.2"
|
||||
},
|
||||
@@ -10044,6 +10296,7 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
@@ -10055,6 +10308,7 @@
|
||||
"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==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -10267,6 +10521,14 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"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": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/expect": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
|
||||
@@ -10342,16 +10604,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"body-parser": "1.20.2",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -10483,6 +10745,11 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.8.tgz",
|
||||
"integrity": "sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q=="
|
||||
},
|
||||
"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.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
@@ -10509,9 +10776,9 @@
|
||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.4.tgz",
|
||||
"integrity": "sha512-utnwm92SyozgA3hhH2I8qldf2lBqm6qHOICawRNRFu1qMe3+oqr+GcXjGqTmXTMGE5T4eC03kr/rlh5C1IRdZA==",
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz",
|
||||
"integrity": "sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -10564,6 +10831,95 @@
|
||||
"bser": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-mock": {
|
||||
"version": "9.11.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.11.0.tgz",
|
||||
"integrity": "sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"core-js": "^3.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"glob-to-regexp": "^0.4.0",
|
||||
"is-subset": "^0.1.1",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"path-to-regexp": "^2.2.1",
|
||||
"querystring": "^0.2.0",
|
||||
"whatwg-url": "^6.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "charity",
|
||||
"url": "https://www.justgiving.com/refugee-support-europe"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"node-fetch": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"node-fetch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-mock-jest": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/fetch-mock-jest/-/fetch-mock-jest-1.5.1.tgz",
|
||||
"integrity": "sha512-+utwzP8C+Pax1GSka3nFXILWMY3Er2L+s090FOgqVNrNCPp0fDqgXnAHAJf12PLHi0z4PhcTaZNTz8e7K3fjqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fetch-mock": "^9.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "charity",
|
||||
"url": "https://www.justgiving.com/refugee-support-europe"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"node-fetch": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"node-fetch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-mock/node_modules/path-to-regexp": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz",
|
||||
"integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fetch-mock/node_modules/tr46": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
|
||||
"integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-mock/node_modules/webidl-conversions": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
|
||||
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fetch-mock/node_modules/whatwg-url": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
|
||||
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash.sortby": "^4.7.0",
|
||||
"tr46": "^1.0.1",
|
||||
"webidl-conversions": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
@@ -10760,14 +11116,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.2.9",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
|
||||
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ=="
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
|
||||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw=="
|
||||
},
|
||||
"node_modules/focus-lock": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.0.1.tgz",
|
||||
"integrity": "sha512-4YEXPTg9tATXwaVTpzHxT7GgO+Xot+VAoBSfXakUXXvQIXID0xv43GkZNDXkzWLYW1L9hrbHZ1CQjfT/svK9zA==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.4.tgz",
|
||||
"integrity": "sha512-Gv0N3mvej3pD+HWkNryrF8sExzEHqhQ6OSFxD4DPxm9n5HGCaHme98ZMBZroNEAJcsdtHxk+skvThGKyUeoEGA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.3"
|
||||
},
|
||||
@@ -10776,9 +11132,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -11036,6 +11392,11 @@
|
||||
"tinymce": "^5.10.4"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
@@ -11065,19 +11426,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -11199,6 +11547,11 @@
|
||||
"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",
|
||||
@@ -11414,20 +11767,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.2"
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
|
||||
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -11524,9 +11877,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
@@ -11591,9 +11944,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/html-entities": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
|
||||
"integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz",
|
||||
"integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -11681,6 +12034,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/html-webpack-plugin/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/htmlparser2": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||
@@ -11986,9 +12347,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/imask": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/imask/-/imask-7.4.0.tgz",
|
||||
"integrity": "sha512-fU6mCo5YiTeDI8aVreuOKLOWxXIrRVnuQhZQXbjhwHxQb3GOQyCtlDGMyHxu2gq//LnKDxTwDBq1teRHmkzA3Q==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/imask/-/imask-7.5.0.tgz",
|
||||
"integrity": "sha512-eoTEnw67KAamB1zsiYtU35s0Fj1XYZ8mN2q3ZDGO4ot4FtPmBpw9S6kOTj0kaOILdsEA6ZhNtH2TAMXe/NChmQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime-corejs3": "^7.23.9"
|
||||
},
|
||||
@@ -12204,11 +12565,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/interpret": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
|
||||
"integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/intl-messageformat": {
|
||||
@@ -12407,6 +12769,20 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-data-view": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
|
||||
"integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
|
||||
"dependencies": {
|
||||
"is-typed-array": "^1.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-date-object": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
|
||||
@@ -12548,17 +12924,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-map": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
|
||||
"integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
|
||||
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-negative-zero": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
|
||||
"integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
|
||||
"integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -12672,19 +13051,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-set": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
|
||||
"integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
|
||||
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-shared-array-buffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
|
||||
"integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
|
||||
"integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2"
|
||||
"call-bind": "^1.0.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -12715,6 +13100,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-subset": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz",
|
||||
"integrity": "sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/is-symbol": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
|
||||
@@ -12771,9 +13162,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-weakmap": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
|
||||
"integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
|
||||
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -12790,12 +13184,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-weakset": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
|
||||
"integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
|
||||
"integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"get-intrinsic": "^1.1.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -12940,9 +13337,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/istanbul-reports": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz",
|
||||
"integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==",
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
|
||||
"integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
|
||||
"dependencies": {
|
||||
"html-escaper": "^2.0.0",
|
||||
"istanbul-lib-report": "^3.0.0"
|
||||
@@ -14551,11 +14948,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
|
||||
"integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
|
||||
"integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antonk52"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
@@ -14647,6 +15047,12 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
||||
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
@@ -14667,6 +15073,12 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
|
||||
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
|
||||
},
|
||||
"node_modules/lodash.sortby": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
||||
"integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.throttle": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||
@@ -14749,6 +15161,17 @@
|
||||
"global": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.9",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
|
||||
"integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/mailto-link": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mailto-link/-/mailto-link-2.0.0.tgz",
|
||||
@@ -14853,6 +15276,14 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/meilisearch": {
|
||||
"version": "0.38.0",
|
||||
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.38.0.tgz",
|
||||
"integrity": "sha512-bHaq8nYxSKw9/Qslq1Zes5g9tHgFkxy/I9o8942wv2PqlNOT0CzptIkh/x98N52GikoSZOXSQkgt6oMjtf5uZw==",
|
||||
"dependencies": {
|
||||
"cross-fetch": "^3.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/memfs": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
|
||||
@@ -15049,6 +15480,17 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/min-document": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
|
||||
@@ -15136,6 +15578,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"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.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
@@ -15263,6 +15710,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -15295,6 +15747,90 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.57.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.57.0.tgz",
|
||||
"integrity": "sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi/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": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"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-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
@@ -15510,12 +16046,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -15561,26 +16097,27 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object.entries": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz",
|
||||
"integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==",
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
|
||||
"integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object.fromentries": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz",
|
||||
"integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==",
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
|
||||
"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -15589,13 +16126,31 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object.hasown": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz",
|
||||
"integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==",
|
||||
"node_modules/object.groupby": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
|
||||
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object.hasown": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz",
|
||||
"integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==",
|
||||
"dependencies": {
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -15613,13 +16168,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object.values": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz",
|
||||
"integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
|
||||
"integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -15628,14 +16183,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/oblivious-set": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.4.0.tgz",
|
||||
"integrity": "sha512-szyd0ou0T8nsAqHtprRcP3WidfsN1TnAR5yWXf2mFCEr5ek3LEOkT6EZ/92Xfs74HIdyhG5WkGxIssMU0jBaeg==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/obuf": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
|
||||
@@ -15807,21 +16354,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/p-queue": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
|
||||
"integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^4.0.4",
|
||||
"p-timeout": "^3.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-retry": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
|
||||
@@ -15834,17 +16366,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/p-timeout": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
|
||||
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
|
||||
"dependencies": {
|
||||
"p-finally": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
@@ -16210,6 +16731,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/possible-typed-array-names": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.33",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||
@@ -16253,13 +16782,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-colormin": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.2.tgz",
|
||||
"integrity": "sha512-TXKOxs9LWcdYo5cgmcSHPkyrLAh86hX1ijmyy6J8SbOhyv6ua053M3ZAM/0j44UsnQNIWdl8gb5L7xX2htKeLw==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz",
|
||||
"integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"browserslist": "^4.23.0",
|
||||
"caniuse-api": "^3.0.0",
|
||||
"colord": "^2.9.1",
|
||||
"colord": "^2.9.3",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16270,11 +16799,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-convert-values": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.2.tgz",
|
||||
"integrity": "sha512-aeBmaTnGQ+NUSVQT8aY0sKyAD/BaLJenEKZ03YK0JnDE1w1Rr8XShoxdal2V2H26xTJKr3v5haByOhJuyT4UYw==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz",
|
||||
"integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"browserslist": "^4.23.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16312,9 +16841,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-discard-comments": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.1.tgz",
|
||||
"integrity": "sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz",
|
||||
"integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
},
|
||||
@@ -16323,9 +16852,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-discard-duplicates": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.1.tgz",
|
||||
"integrity": "sha512-1hvUs76HLYR8zkScbwyJ8oJEugfPV+WchpnA+26fpJ7Smzs51CzGBHC32RS03psuX/2l0l0UKh2StzNxOrKCYg==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz",
|
||||
"integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
},
|
||||
@@ -16334,9 +16863,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-discard-empty": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.1.tgz",
|
||||
"integrity": "sha512-yitcmKwmVWtNsrrRqGJ7/C0YRy53i0mjexBDQ9zYxDwTWVBgbU4+C9jIZLmQlTDT9zhml+u0OMFJh8+31krmOg==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz",
|
||||
"integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
},
|
||||
@@ -16345,9 +16874,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-discard-overridden": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.1.tgz",
|
||||
"integrity": "sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz",
|
||||
"integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
},
|
||||
@@ -16413,12 +16942,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/postcss-merge-longhand": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.2.tgz",
|
||||
"integrity": "sha512-+yfVB7gEM8SrCo9w2lCApKIEzrTKl5yS1F4yGhV3kSim6JzbfLGJyhR1B6X+6vOT0U33Mgx7iv4X9MVWuaSAfw==",
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz",
|
||||
"integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"stylehacks": "^6.0.2"
|
||||
"stylehacks": "^6.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
@@ -16428,14 +16957,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-merge-rules": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.3.tgz",
|
||||
"integrity": "sha512-yfkDqSHGohy8sGYIJwBmIGDv4K4/WrJPX355XrxQb/CSsT4Kc/RxDi6akqn5s9bap85AWgv21ArcUWwWdGNSHA==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz",
|
||||
"integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"browserslist": "^4.23.0",
|
||||
"caniuse-api": "^3.0.0",
|
||||
"cssnano-utils": "^4.0.1",
|
||||
"postcss-selector-parser": "^6.0.15"
|
||||
"cssnano-utils": "^4.0.2",
|
||||
"postcss-selector-parser": "^6.0.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
@@ -16445,9 +16974,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-minify-font-values": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.1.tgz",
|
||||
"integrity": "sha512-tIwmF1zUPoN6xOtA/2FgVk1ZKrLcCvE0dpZLtzyyte0j9zUeB8RTbCqrHZGjJlxOvNWKMYtunLrrl7HPOiR46w==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz",
|
||||
"integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16459,12 +16988,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-minify-gradients": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.1.tgz",
|
||||
"integrity": "sha512-M1RJWVjd6IOLPl1hYiOd5HQHgpp6cvJVLrieQYS9y07Yo8itAr6jaekzJphaJFR0tcg4kRewCk3kna9uHBxn/w==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz",
|
||||
"integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==",
|
||||
"dependencies": {
|
||||
"colord": "^2.9.1",
|
||||
"cssnano-utils": "^4.0.1",
|
||||
"colord": "^2.9.3",
|
||||
"cssnano-utils": "^4.0.2",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16475,12 +17004,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-minify-params": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.2.tgz",
|
||||
"integrity": "sha512-zwQtbrPEBDj+ApELZ6QylLf2/c5zmASoOuA4DzolyVGdV38iR2I5QRMsZcHkcdkZzxpN8RS4cN7LPskOkTwTZw==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz",
|
||||
"integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"cssnano-utils": "^4.0.1",
|
||||
"browserslist": "^4.23.0",
|
||||
"cssnano-utils": "^4.0.2",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16491,11 +17020,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-minify-selectors": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.2.tgz",
|
||||
"integrity": "sha512-0b+m+w7OAvZejPQdN2GjsXLv5o0jqYHX3aoV0e7RBKPCsB7TYG5KKWBFhGnB/iP3213Ts8c5H4wLPLMm7z28Sg==",
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz",
|
||||
"integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.0.15"
|
||||
"postcss-selector-parser": "^6.0.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
@@ -16505,9 +17034,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-extract-imports": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
|
||||
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
|
||||
"integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >= 14"
|
||||
},
|
||||
@@ -16516,9 +17045,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-local-by-default": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz",
|
||||
"integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz",
|
||||
"integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==",
|
||||
"dependencies": {
|
||||
"icss-utils": "^5.0.0",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
@@ -16532,9 +17061,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-scope": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz",
|
||||
"integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz",
|
||||
"integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
},
|
||||
@@ -16560,9 +17089,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-charset": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.1.tgz",
|
||||
"integrity": "sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz",
|
||||
"integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==",
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
},
|
||||
@@ -16571,9 +17100,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-display-values": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.1.tgz",
|
||||
"integrity": "sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz",
|
||||
"integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16585,9 +17114,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-positions": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.1.tgz",
|
||||
"integrity": "sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz",
|
||||
"integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16599,9 +17128,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-repeat-style": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.1.tgz",
|
||||
"integrity": "sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz",
|
||||
"integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16613,9 +17142,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-string": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.1.tgz",
|
||||
"integrity": "sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz",
|
||||
"integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16627,9 +17156,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-timing-functions": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.1.tgz",
|
||||
"integrity": "sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz",
|
||||
"integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16641,11 +17170,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-unicode": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.2.tgz",
|
||||
"integrity": "sha512-Ff2VdAYCTGyMUwpevTZPZ4w0+mPjbZzLLyoLh/RMpqUqeQKZ+xMm31hkxBavDcGKcxm6ACzGk0nBfZ8LZkStKA==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz",
|
||||
"integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"browserslist": "^4.23.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16656,9 +17185,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-url": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.1.tgz",
|
||||
"integrity": "sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz",
|
||||
"integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16670,9 +17199,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-whitespace": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.1.tgz",
|
||||
"integrity": "sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz",
|
||||
"integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16684,11 +17213,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-ordered-values": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.1.tgz",
|
||||
"integrity": "sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz",
|
||||
"integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==",
|
||||
"dependencies": {
|
||||
"cssnano-utils": "^4.0.1",
|
||||
"cssnano-utils": "^4.0.2",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16699,11 +17228,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-reduce-initial": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.2.tgz",
|
||||
"integrity": "sha512-YGKalhNlCLcjcLvjU5nF8FyeCTkCO5UtvJEt0hrPZVCTtRLSOH4z00T1UntQPj4dUmIYZgMj8qK77JbSX95hSw==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz",
|
||||
"integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"browserslist": "^4.23.0",
|
||||
"caniuse-api": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -16714,9 +17243,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-reduce-transforms": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.1.tgz",
|
||||
"integrity": "sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz",
|
||||
"integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
@@ -16790,9 +17319,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-selector-parser": {
|
||||
"version": "6.0.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
|
||||
"integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
|
||||
"version": "6.0.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
|
||||
"integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -16802,9 +17331,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-svgo": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.2.tgz",
|
||||
"integrity": "sha512-IH5R9SjkTkh0kfFOQDImyy1+mTCb+E830+9SV1O+AaDcoHTvfsvt6WwJeo7KwcHbFnevZVCsXhDmjFiGVuwqFQ==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz",
|
||||
"integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"svgo": "^3.2.0"
|
||||
@@ -16817,11 +17346,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-unique-selectors": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.2.tgz",
|
||||
"integrity": "sha512-8IZGQ94nechdG7Y9Sh9FlIY2b4uS8/k8kdKRX040XHsS3B6d1HrJAkXrBSsSu4SuARruSsUjW3nlSw8BHkaAYQ==",
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz",
|
||||
"integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.0.15"
|
||||
"postcss-selector-parser": "^6.0.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
@@ -16835,6 +17364,70 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz",
|
||||
"integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^1.0.1",
|
||||
"node-abi": "^3.3.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"simple-get": "^4.0.0",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuild-install": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"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",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -16910,13 +17503,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"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.8.1"
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types-extra": {
|
||||
@@ -16948,6 +17541,11 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/psl": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
@@ -17073,6 +17671,16 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/querystring": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
|
||||
"integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==",
|
||||
"deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
@@ -17097,6 +17705,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"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",
|
||||
@@ -17123,9 +17736,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
@@ -17136,6 +17749,28 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"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",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-json-comments": "~2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"rc": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/rc/node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"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": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
@@ -17324,28 +17959,13 @@
|
||||
"react": ">= 16.8 || 18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dropzone/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/react-error-boundary": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz",
|
||||
"integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==",
|
||||
"dev": true,
|
||||
"version": "4.0.13",
|
||||
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz",
|
||||
"integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.13.1"
|
||||
}
|
||||
@@ -17361,12 +17981,12 @@
|
||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||
},
|
||||
"node_modules/react-focus-lock": {
|
||||
"version": "2.9.8",
|
||||
"resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.9.8.tgz",
|
||||
"integrity": "sha512-nLrUCTF8/BWGaWV00wvmIOPe56HTLWtqjqwWebHE80jB0fCMsm/Cl2zbp8ulbCoe5BOU7bWSCg5YhkYhDxykWw==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.11.2.tgz",
|
||||
"integrity": "sha512-DDTbEiov0+RthESPVSTIdAWPPKic+op3sCcP+icbMRobvQNt7LuAlJ3KoarqQv5sCgKArru3kXmlmFTa27/CdQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"focus-lock": "^1.0.1",
|
||||
"focus-lock": "^1.3.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-clientside-effect": "^1.2.6",
|
||||
"use-callback-ref": "^1.3.0",
|
||||
@@ -17383,14 +18003,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-focus-on": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.9.1.tgz",
|
||||
"integrity": "sha512-IYo2j4mgNpZEJNv+/XzZs3S3xhJbR+AFop092h4OMW7sbFpIMVWxp/Z61V/gfpsgOi7VnoSFXP2bfOWWkjjtOw==",
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.9.2.tgz",
|
||||
"integrity": "sha512-3UZ9PjA+pe8ZK3B+rz7zcgJUIRJVzJEddYe6R5WVUAsSXW8awHw9nXJqK0UU5MenGEUh/tMUBWMqN633+d2eCA==",
|
||||
"dependencies": {
|
||||
"aria-hidden": "^1.2.2",
|
||||
"react-focus-lock": "^2.9.4",
|
||||
"react-remove-scroll": "^2.5.6",
|
||||
"react-style-singleton": "^2.2.0",
|
||||
"react-focus-lock": "^2.11.2",
|
||||
"react-remove-scroll": "^2.5.7",
|
||||
"react-style-singleton": "^2.2.1",
|
||||
"tslib": "^2.3.1",
|
||||
"use-callback-ref": "^1.3.0",
|
||||
"use-sidecar": "^1.1.2"
|
||||
@@ -17428,11 +18048,11 @@
|
||||
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
|
||||
},
|
||||
"node_modules/react-imask": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-imask/-/react-imask-7.4.0.tgz",
|
||||
"integrity": "sha512-U7O2IhIKIGF0ch16xBinwbWGfsgeDyM3KcftD8/bWLuES+KQOjv8wCjX2QZNiAqsZ3FgSembaJmqAN8XlB5LbA==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-imask/-/react-imask-7.5.0.tgz",
|
||||
"integrity": "sha512-yWExhHphDmNaHvmOsYR+5QcludeBdYk6bXyo8kouIJFAub5sF+O0kLPVupg2yhd7EfTqjLswFZ/tqY1AhKnd9Q==",
|
||||
"dependencies": {
|
||||
"imask": "^7.4.0",
|
||||
"imask": "^7.5.0",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -17442,25 +18062,15 @@
|
||||
"react": ">=0.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-imask/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/react-intl": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.2.tgz",
|
||||
"integrity": "sha512-IpW2IkLtGENSFlX3vfH11rjuCIsW0VyjT0Q1pPKMZPtT2z1FxLt4weFT5Ezti2TScT1xiyb3aQBFth9EB7jzAg==",
|
||||
"version": "6.6.4",
|
||||
"resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.4.tgz",
|
||||
"integrity": "sha512-bD+7hVTX3zBFI3z/ffIVZrNkCVK0/sQguQ/DqW5uZ6JFWsuiwOieVcLnmtFiUgMQZLdmwNl2Ur5c10RaO7NWBQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@formatjs/ecma402-abstract": "1.18.2",
|
||||
"@formatjs/icu-messageformat-parser": "2.7.6",
|
||||
"@formatjs/intl": "2.10.0",
|
||||
"@formatjs/intl": "2.10.1",
|
||||
"@formatjs/intl-displaynames": "6.6.6",
|
||||
"@formatjs/intl-listformat": "7.5.5",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
@@ -17610,11 +18220,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
|
||||
"integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
|
||||
"version": "2.5.9",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.9.tgz",
|
||||
"integrity": "sha512-bvHCLBrFfM2OgcrpPY2YW84sPdS2o2HKWJUf1xGyGLnSoEnOTOBpahIarjRuYtN0ryahCeP242yf+5TrBX/pZA==",
|
||||
"dependencies": {
|
||||
"react-remove-scroll-bar": "^2.3.4",
|
||||
"react-remove-scroll-bar": "^2.3.6",
|
||||
"react-style-singleton": "^2.2.1",
|
||||
"tslib": "^2.1.0",
|
||||
"use-callback-ref": "^1.3.0",
|
||||
@@ -17634,9 +18244,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll-bar": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz",
|
||||
"integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==",
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
|
||||
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
|
||||
"dependencies": {
|
||||
"react-style-singleton": "^2.2.1",
|
||||
"tslib": "^2.0.0"
|
||||
@@ -18090,13 +18700,14 @@
|
||||
"integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg=="
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
|
||||
"integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==",
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
|
||||
"integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"set-function-name": "^2.0.0"
|
||||
"call-bind": "^1.0.6",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"set-function-name": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -18401,12 +19012,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/safe-array-concat": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz",
|
||||
"integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
|
||||
"integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.5",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"call-bind": "^1.0.7",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"has-symbols": "^1.0.3",
|
||||
"isarray": "^2.0.5"
|
||||
},
|
||||
@@ -19003,29 +19614,30 @@
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
|
||||
"integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.2",
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.3",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.1"
|
||||
"has-property-descriptors": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-name": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz",
|
||||
"integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
|
||||
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
"functions-have-names": "^1.2.3",
|
||||
"has-property-descriptors": "^1.0.0"
|
||||
"has-property-descriptors": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -19102,42 +19714,25 @@
|
||||
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
|
||||
},
|
||||
"node_modules/sharp": {
|
||||
"version": "0.33.2",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz",
|
||||
"integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==",
|
||||
"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,
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"detect-libc": "^2.0.2",
|
||||
"semver": "^7.5.4"
|
||||
"node-addon-api": "^6.1.0",
|
||||
"prebuild-install": "^7.1.1",
|
||||
"semver": "^7.5.4",
|
||||
"simple-get": "^4.0.1",
|
||||
"tar-fs": "^3.0.4",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"libvips": ">=8.15.1",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
"node": ">=14.15.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.33.2",
|
||||
"@img/sharp-darwin-x64": "0.33.2",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.1",
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.1",
|
||||
"@img/sharp-libvips-linux-arm": "1.0.1",
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.1",
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.1",
|
||||
"@img/sharp-libvips-linux-x64": "1.0.1",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.1",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.1",
|
||||
"@img/sharp-linux-arm": "0.33.2",
|
||||
"@img/sharp-linux-arm64": "0.33.2",
|
||||
"@img/sharp-linux-s390x": "0.33.2",
|
||||
"@img/sharp-linux-x64": "0.33.2",
|
||||
"@img/sharp-linuxmusl-arm64": "0.33.2",
|
||||
"@img/sharp-linuxmusl-x64": "0.33.2",
|
||||
"@img/sharp-wasm32": "0.33.2",
|
||||
"@img/sharp-win32-ia32": "0.33.2",
|
||||
"@img/sharp-win32-x64": "0.33.2"
|
||||
}
|
||||
},
|
||||
"node_modules/sharp/node_modules/lru-cache": {
|
||||
@@ -19204,11 +19799,11 @@
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
|
||||
"integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.6",
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
@@ -19225,6 +19820,49 @@
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"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/simple-get": {
|
||||
"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": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
@@ -19454,9 +20092,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -19545,9 +20183,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/spdx-exceptions": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz",
|
||||
"integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw=="
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
|
||||
"integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="
|
||||
},
|
||||
"node_modules/spdx-expression-parse": {
|
||||
"version": "3.0.1",
|
||||
@@ -19706,6 +20344,18 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/streamx": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz",
|
||||
"integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==",
|
||||
"dependencies": {
|
||||
"fast-fifo": "^1.1.0",
|
||||
"queue-tick": "^1.0.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bare-events": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
@@ -19758,32 +20408,39 @@
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/string.prototype.matchall": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz",
|
||||
"integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==",
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
|
||||
"integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1",
|
||||
"get-intrinsic": "^1.2.1",
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"gopd": "^1.0.1",
|
||||
"has-symbols": "^1.0.3",
|
||||
"internal-slot": "^1.0.5",
|
||||
"regexp.prototype.flags": "^1.5.0",
|
||||
"set-function-name": "^2.0.0",
|
||||
"side-channel": "^1.0.4"
|
||||
"internal-slot": "^1.0.7",
|
||||
"regexp.prototype.flags": "^1.5.2",
|
||||
"set-function-name": "^2.0.2",
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.trim": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz",
|
||||
"integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==",
|
||||
"version": "1.2.9",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
|
||||
"integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.0",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -19793,26 +20450,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.trimend": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz",
|
||||
"integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==",
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
|
||||
"integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.trimstart": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz",
|
||||
"integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==",
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
|
||||
"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"es-abstract": "^1.22.1"
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -19897,9 +20557,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/style-mod": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz",
|
||||
"integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA=="
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
||||
},
|
||||
"node_modules/style-search": {
|
||||
"version": "0.1.0",
|
||||
@@ -19908,12 +20568,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/stylehacks": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.2.tgz",
|
||||
"integrity": "sha512-00zvJGnCu64EpMjX8b5iCZ3us2Ptyw8+toEkb92VdmkEaRaSGBNKAoK6aWZckhXxmQP8zWiTaFaiMGIU8Ve8sg==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz",
|
||||
"integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.22.2",
|
||||
"postcss-selector-parser": "^6.0.15"
|
||||
"browserslist": "^4.23.0",
|
||||
"postcss-selector-parser": "^6.0.16"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14 || ^16 || >=18.0"
|
||||
@@ -20308,9 +20968,9 @@
|
||||
"integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
|
||||
},
|
||||
"node_modules/table": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
|
||||
"integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
|
||||
"version": "6.8.2",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
|
||||
"integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.1",
|
||||
@@ -20346,11 +21006,35 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz",
|
||||
"integrity": "sha512-jX8Et4hHg57mug1/079yitEKWGB3LCwoxByLsNim89LABq8NqgiX+6iYVOsq0vX8uJHkU+DZ5fnq95f800bEsQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz",
|
||||
"integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^3.1.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bare-fs": "^2.1.1",
|
||||
"bare-path": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
|
||||
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4",
|
||||
"fast-fifo": "^1.2.0",
|
||||
"streamx": "^2.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/terminal-link": {
|
||||
@@ -20369,9 +21053,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.27.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz",
|
||||
"integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==",
|
||||
"version": "5.30.3",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz",
|
||||
"integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
@@ -20484,9 +21168,9 @@
|
||||
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz",
|
||||
"integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw=="
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
|
||||
},
|
||||
"node_modules/tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
@@ -20637,6 +21321,17 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader": {
|
||||
"version": "9.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
|
||||
@@ -20657,6 +21352,19 @@
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/enhanced-resolve": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
|
||||
"integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
@@ -20684,6 +21392,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-loader/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
@@ -20725,6 +21442,17 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.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"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -20768,11 +21496,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typed-array-buffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz",
|
||||
"integrity": "sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
|
||||
"integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.6",
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"is-typed-array": "^1.1.13"
|
||||
},
|
||||
@@ -20781,14 +21509,15 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
|
||||
"integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"call-bind": "^1.0.7",
|
||||
"for-each": "^0.3.3",
|
||||
"has-proto": "^1.0.1",
|
||||
"is-typed-array": "^1.1.10"
|
||||
"gopd": "^1.0.1",
|
||||
"has-proto": "^1.0.3",
|
||||
"is-typed-array": "^1.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -20798,15 +21527,16 @@
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
|
||||
"integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.5",
|
||||
"call-bind": "^1.0.2",
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
"call-bind": "^1.0.7",
|
||||
"for-each": "^0.3.3",
|
||||
"has-proto": "^1.0.1",
|
||||
"is-typed-array": "^1.1.10"
|
||||
"gopd": "^1.0.1",
|
||||
"has-proto": "^1.0.3",
|
||||
"is-typed-array": "^1.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -20816,13 +21546,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typed-array-length": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
|
||||
"integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
|
||||
"integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"call-bind": "^1.0.7",
|
||||
"for-each": "^0.3.3",
|
||||
"is-typed-array": "^1.1.9"
|
||||
"gopd": "^1.0.1",
|
||||
"has-proto": "^1.0.3",
|
||||
"is-typed-array": "^1.1.13",
|
||||
"possible-typed-array-names": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -20890,6 +21626,14 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-emoji-utils": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-emoji-utils/-/unicode-emoji-utils-1.2.0.tgz",
|
||||
"integrity": "sha512-djUB91p/6oYpgps4W5K/MAvM+UspoAANHSUW495BrxeLRoned3iNPEDQgrKx9LbLq93VhNz0NWvI61vcfrwYoA==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "10.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-match-property-ecmascript": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
|
||||
@@ -20965,14 +21709,6 @@
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unload": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unload/-/unload-2.4.1.tgz",
|
||||
"integrity": "sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/pubkey"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
@@ -21122,9 +21858,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/use-callback-ref": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.1.tgz",
|
||||
"integrity": "sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
|
||||
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
@@ -21366,9 +22102,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
|
||||
"integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==",
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.2"
|
||||
@@ -21402,26 +22138,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.90.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz",
|
||||
"integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==",
|
||||
"peer": true,
|
||||
"version": "5.91.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz",
|
||||
"integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.5",
|
||||
"@webassemblyjs/ast": "^1.11.5",
|
||||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"@webassemblyjs/ast": "^1.12.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.12.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"browserslist": "^4.21.10",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.15.0",
|
||||
"enhanced-resolve": "^5.16.0",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
@@ -21429,7 +22164,7 @@
|
||||
"schema-utils": "^3.2.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"watchpack": "^2.4.0",
|
||||
"watchpack": "^2.4.1",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"bin": {
|
||||
@@ -21542,10 +22277,18 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-cli/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/webpack-dev-middleware": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
|
||||
"integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
|
||||
"integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
|
||||
"dependencies": {
|
||||
"colorette": "^2.0.10",
|
||||
"memfs": "^3.4.3",
|
||||
@@ -21614,9 +22357,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server": {
|
||||
"version": "4.15.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz",
|
||||
"integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==",
|
||||
"version": "4.15.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
||||
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
||||
"dependencies": {
|
||||
"@types/bonjour": "^3.5.9",
|
||||
"@types/connect-history-api-fallback": "^1.3.5",
|
||||
@@ -21646,7 +22389,7 @@
|
||||
"serve-index": "^1.9.1",
|
||||
"sockjs": "^0.3.24",
|
||||
"spdy": "^4.0.2",
|
||||
"webpack-dev-middleware": "^5.3.1",
|
||||
"webpack-dev-middleware": "^5.3.4",
|
||||
"ws": "^8.13.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -21792,11 +22535,30 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/enhanced-resolve": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
|
||||
"integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/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/webpack/node_modules/webpack-sources": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
@@ -21878,14 +22640,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/which-collection": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
|
||||
"integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
|
||||
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
|
||||
"dependencies": {
|
||||
"is-map": "^2.0.1",
|
||||
"is-set": "^2.0.1",
|
||||
"is-weakmap": "^2.0.1",
|
||||
"is-weakset": "^2.0.1"
|
||||
"is-map": "^2.0.3",
|
||||
"is-set": "^2.0.3",
|
||||
"is-weakmap": "^2.0.2",
|
||||
"is-weakset": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -21897,15 +22662,15 @@
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||
},
|
||||
"node_modules/which-typed-array": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
|
||||
"integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
|
||||
"integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.6",
|
||||
"call-bind": "^1.0.5",
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
"call-bind": "^1.0.7",
|
||||
"for-each": "^0.3.3",
|
||||
"gopd": "^1.0.1",
|
||||
"has-tostringtag": "^1.0.1"
|
||||
"has-tostringtag": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
||||
20
package.json
20
package.json
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "fedx-scripts webpack",
|
||||
"i18n_extract": "fedx-scripts formatjs extract",
|
||||
"stylelint": "stylelint \"src/**/*.scss\" \"scss/**/*.scss\" --config .stylelintrc.json",
|
||||
"stylelint": "stylelint \"plugins/**/*.scss\" \"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": "TZ=UTC fedx-scripts jest --updateSnapshot",
|
||||
@@ -43,9 +43,9 @@
|
||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||
"@edx/frontend-component-ai-translations": "^2.0.0",
|
||||
"@edx/frontend-component-footer": "^13.0.2",
|
||||
"@edx/frontend-component-header": "^5.0.2",
|
||||
"@edx/frontend-component-header": "^5.1.0",
|
||||
"@edx/frontend-enterprise-hotjar": "^2.0.0",
|
||||
"@edx/frontend-lib-content-components": "^2.1.4",
|
||||
"@edx/frontend-lib-content-components": "^2.5.1",
|
||||
"@edx/frontend-platform": "7.0.1",
|
||||
"@edx/openedx-atlas": "^0.6.0",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
@@ -53,6 +53,7 @@
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/react-fontawesome": "0.2.0",
|
||||
"@meilisearch/instant-meilisearch": "^0.17.0",
|
||||
"@openedx-plugins/course-app-calculator": "file:plugins/course-apps/calculator",
|
||||
"@openedx-plugins/course-app-edxnotes": "file:plugins/course-apps/edxnotes",
|
||||
"@openedx-plugins/course-app-learning_assistant": "file:plugins/course-apps/learning_assistant",
|
||||
@@ -63,10 +64,10 @@
|
||||
"@openedx-plugins/course-app-teams": "file:plugins/course-apps/teams",
|
||||
"@openedx-plugins/course-app-wiki": "file:plugins/course-apps/wiki",
|
||||
"@openedx-plugins/course-app-xpert_unit_summary": "file:plugins/course-apps/xpert_unit_summary",
|
||||
"@openedx/paragon": "^21.5.7",
|
||||
"@openedx/frontend-plugin-framework": "^1.1.0",
|
||||
"@openedx/paragon": "^22.2.1",
|
||||
"@reduxjs/toolkit": "1.9.7",
|
||||
"@tanstack/react-query": "4.36.1",
|
||||
"broadcast-channel": "^7.0.0",
|
||||
"classnames": "2.2.6",
|
||||
"core-js": "3.8.1",
|
||||
"email-validator": "2.0.4",
|
||||
@@ -74,11 +75,13 @@
|
||||
"formik": "2.2.6",
|
||||
"jszip": "^3.10.1",
|
||||
"lodash": "4.17.21",
|
||||
"meilisearch": "^0.38.0",
|
||||
"moment": "2.29.4",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "17.0.2",
|
||||
"react-datepicker": "^4.13.0",
|
||||
"react-dom": "17.0.2",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-redux": "7.2.9",
|
||||
"react-responsive": "9.0.2",
|
||||
@@ -99,14 +102,15 @@
|
||||
"@edx/reactifex": "^1.0.3",
|
||||
"@edx/stylelint-config-edx": "2.3.0",
|
||||
"@edx/typescript-config": "^1.0.1",
|
||||
"@openedx/frontend-build": "13.0.27",
|
||||
"@openedx/frontend-build": "13.1.0",
|
||||
"@testing-library/jest-dom": "5.17.0",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"axios": "^0.27.2",
|
||||
"axios": "^0.28.0",
|
||||
"axios-mock-adapter": "1.22.0",
|
||||
"eslint-import-resolver-webpack": "^0.13.8",
|
||||
"fetch-mock-jest": "^1.5.1",
|
||||
"glob": "7.2.3",
|
||||
"husky": "7.0.4",
|
||||
"jest-canvas-mock": "^2.5.2",
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
} from 'react-router-dom';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { PageWrap } from '@edx/frontend-platform/react';
|
||||
import { Textbooks } from 'CourseAuthoring/textbooks';
|
||||
import CourseAuthoringPage from './CourseAuthoringPage';
|
||||
import { PagesAndResources } from './pages-and-resources';
|
||||
import EditorContainer from './editors/EditorContainer';
|
||||
@@ -17,10 +18,12 @@ import { GradingSettings } from './grading-settings';
|
||||
import CourseTeam from './course-team/CourseTeam';
|
||||
import { CourseUpdates } from './course-updates';
|
||||
import { CourseUnit } from './course-unit';
|
||||
import { Certificates } from './certificates';
|
||||
import CourseExportPage from './export-page/CourseExportPage';
|
||||
import CourseImportPage from './import-page/CourseImportPage';
|
||||
import { DECODED_ROUTES } from './constants';
|
||||
import CourseChecklist from './course-checklist';
|
||||
import GroupConfigurations from './group-configurations';
|
||||
|
||||
/**
|
||||
* As of this writing, these routes are mounted at a path prefixed with the following:
|
||||
@@ -81,11 +84,11 @@ const CourseAuthoringRoutes = () => {
|
||||
))}
|
||||
<Route
|
||||
path="editor/course-videos/:blockId"
|
||||
element={getConfig().ENABLE_NEW_EDITOR_PAGES === 'true' ? <PageWrap><VideoSelectorContainer courseId={courseId} /></PageWrap> : null}
|
||||
element={<PageWrap><VideoSelectorContainer courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
<Route
|
||||
path="editor/:blockType/:blockId?"
|
||||
element={getConfig().ENABLE_NEW_EDITOR_PAGES === 'true' ? <PageWrap><EditorContainer courseId={courseId} /></PageWrap> : null}
|
||||
element={<PageWrap><EditorContainer courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
<Route
|
||||
path="settings/details"
|
||||
@@ -99,6 +102,10 @@ const CourseAuthoringRoutes = () => {
|
||||
path="course_team"
|
||||
element={<PageWrap><CourseTeam courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
<Route
|
||||
path="group_configurations"
|
||||
element={<PageWrap><GroupConfigurations courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
<Route
|
||||
path="settings/advanced"
|
||||
element={<PageWrap><AdvancedSettings courseId={courseId} /></PageWrap>}
|
||||
@@ -115,6 +122,14 @@ const CourseAuthoringRoutes = () => {
|
||||
path="checklists"
|
||||
element={<PageWrap><CourseChecklist courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
<Route
|
||||
path="certificates"
|
||||
element={<PageWrap><Certificates courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
<Route
|
||||
path="textbooks"
|
||||
element={<PageWrap><Textbooks courseId={courseId} /></PageWrap>}
|
||||
/>
|
||||
</Routes>
|
||||
</CourseAuthoringPage>
|
||||
);
|
||||
|
||||
16
src/__mocks__/clipboardUnit.js
Normal file
16
src/__mocks__/clipboardUnit.js
Normal file
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
content: {
|
||||
id: 67,
|
||||
userId: 3,
|
||||
created: '2024-01-16T13:09:11.540615Z',
|
||||
purpose: 'clipboard',
|
||||
status: 'ready',
|
||||
blockType: 'vertical',
|
||||
blockTypeDisplay: 'Unit',
|
||||
olxUrl: 'http://localhost:18010/api/content-staging/v1/staged-content/67/olx',
|
||||
displayName: 'Introduction: Video and Sequences',
|
||||
},
|
||||
sourceUsageKey: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0270f6de40fc',
|
||||
sourceContextTitle: 'Demonstration Course',
|
||||
sourceEditUrl: 'http://localhost:18010/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0270f6de40fc',
|
||||
};
|
||||
16
src/__mocks__/clipboardXBlock.js
Normal file
16
src/__mocks__/clipboardXBlock.js
Normal file
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
content: {
|
||||
id: 69,
|
||||
userId: 3,
|
||||
created: '2024-01-16T13:33:21.314439Z',
|
||||
purpose: 'clipboard',
|
||||
status: 'ready',
|
||||
blockType: 'html',
|
||||
blockTypeDisplay: 'Text',
|
||||
olxUrl: 'http://localhost:18010/api/content-staging/v1/staged-content/69/olx',
|
||||
displayName: 'Blank HTML Page',
|
||||
},
|
||||
sourceUsageKey: 'block-v1:edX+DemoX+Demo_Course+type@html+block@html1',
|
||||
sourceContextTitle: 'Demonstration Course',
|
||||
sourceEditUrl: 'http://localhost:18010/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical1',
|
||||
};
|
||||
2
src/__mocks__/index.js
Normal file
2
src/__mocks__/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as clipboardUnit } from './clipboardUnit';
|
||||
export { default as clipboardXBlock } from './clipboardXBlock';
|
||||
@@ -71,7 +71,7 @@ const SettingCard = ({
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(messages.helpButtonText)}
|
||||
variant="primary"
|
||||
className=" ml-1 mr-2"
|
||||
className="flex-shrink-0 ml-1 mr-2"
|
||||
/>
|
||||
<ModalPopup
|
||||
hasArrow
|
||||
|
||||
57
src/certificates/Certificates.jsx
Normal file
57
src/certificates/Certificates.jsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Helmet } from 'react-helmet';
|
||||
import PropTypes from 'prop-types';
|
||||
import Placeholder from '@edx/frontend-lib-content-components';
|
||||
|
||||
import { RequestStatus } from '../data/constants';
|
||||
import Loading from '../generic/Loading';
|
||||
import useCertificates from './hooks/useCertificates';
|
||||
import CertificateWithoutModes from './certificate-without-modes/CertificateWithoutModes';
|
||||
import EmptyCertificatesWithModes from './empty-certificates-with-modes/EmptyCertificatesWithModes';
|
||||
import CertificatesList from './certificates-list/CertificatesList';
|
||||
import CertificateCreateForm from './certificate-create-form/CertificateCreateForm';
|
||||
import CertificateEditForm from './certificate-edit-form/CertificateEditForm';
|
||||
import { MODE_STATES } from './data/constants';
|
||||
import MainLayout from './layout/MainLayout';
|
||||
|
||||
const MODE_COMPONENTS = {
|
||||
[MODE_STATES.noModes]: CertificateWithoutModes,
|
||||
[MODE_STATES.noCertificates]: EmptyCertificatesWithModes,
|
||||
[MODE_STATES.create]: CertificateCreateForm,
|
||||
[MODE_STATES.view]: CertificatesList,
|
||||
[MODE_STATES.editAll]: CertificateEditForm,
|
||||
};
|
||||
|
||||
const Certificates = ({ courseId }) => {
|
||||
const {
|
||||
certificates, componentMode, isLoading, loadingStatus, pageHeadTitle, hasCertificateModes,
|
||||
} = useCertificates({ courseId });
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
if (loadingStatus === RequestStatus.DENIED) {
|
||||
return (
|
||||
<div className="row justify-content-center m-6" data-testid="request-denied-placeholder">
|
||||
<Placeholder />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const ModeComponent = MODE_COMPONENTS[componentMode] || MODE_COMPONENTS[MODE_STATES.noModes];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet><title>{pageHeadTitle}</title></Helmet>
|
||||
<MainLayout courseId={courseId} showHeaderButtons={hasCertificateModes && certificates?.length > 0}>
|
||||
<ModeComponent courseId={courseId} />
|
||||
</MainLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Certificates.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Certificates;
|
||||
189
src/certificates/Certificates.test.jsx
Normal file
189
src/certificates/Certificates.test.jsx
Normal file
@@ -0,0 +1,189 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { RequestStatus } from '../data/constants';
|
||||
import { executeThunk } from '../utils';
|
||||
import initializeStore from '../store';
|
||||
import { getCertificatesApiUrl } from './data/api';
|
||||
import { fetchCertificates } from './data/thunks';
|
||||
import { certificatesDataMock } from './__mocks__';
|
||||
import Certificates from './Certificates';
|
||||
import messages from './messages';
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
const courseId = 'course-123';
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<AppProvider store={store} messages={{}}>
|
||||
<IntlProvider locale="en">
|
||||
<Certificates courseId={courseId} {...props} />
|
||||
</IntlProvider>
|
||||
</AppProvider>,
|
||||
);
|
||||
|
||||
describe('Certificates', () => {
|
||||
beforeEach(async () => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
});
|
||||
|
||||
it('renders WithoutModes when there are certificates but no certificate modes', async () => {
|
||||
const noModesMock = {
|
||||
...certificatesDataMock,
|
||||
courseModes: [],
|
||||
hasCertificateModes: false,
|
||||
};
|
||||
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, noModesMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const { getByText, queryByRole } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.withoutModesText.defaultMessage)).toBeInTheDocument();
|
||||
expect(queryByRole('button', { name: messages.headingActionsPreview.defaultMessage })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders WithoutModes when there are no certificate modes', async () => {
|
||||
const noModesMock = {
|
||||
...certificatesDataMock,
|
||||
certificates: [],
|
||||
courseModes: [],
|
||||
hasCertificateModes: false,
|
||||
};
|
||||
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, noModesMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const { getByText, queryByText } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.withoutModesText.defaultMessage)).toBeInTheDocument();
|
||||
expect(queryByText(messages.noCertificatesText.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders WithModesWithoutCertificates when there are modes but no certificates', async () => {
|
||||
const noCertificatesMock = {
|
||||
...certificatesDataMock,
|
||||
certificates: [],
|
||||
};
|
||||
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, noCertificatesMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const { getByText, queryByText } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.noCertificatesText.defaultMessage)).toBeInTheDocument();
|
||||
expect(queryByText(messages.withoutModesText.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders CertificatesList when there are modes and certificates', async () => {
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, certificatesDataMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const { getByText, queryByText, getByTestId } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByTestId('certificates-list')).toBeInTheDocument();
|
||||
expect(getByText(certificatesDataMock.courseTitle)).toBeInTheDocument();
|
||||
expect(getByText(certificatesDataMock.certificates[0].signatories[0].name)).toBeInTheDocument();
|
||||
expect(queryByText(messages.noCertificatesText.defaultMessage)).not.toBeInTheDocument();
|
||||
expect(queryByText(messages.withoutModesText.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders CertificateCreateForm when there is componentMode = MODE_STATES.create', async () => {
|
||||
const noCertificatesMock = {
|
||||
...certificatesDataMock,
|
||||
certificates: [],
|
||||
};
|
||||
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, noCertificatesMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const { queryByTestId, getByTestId, getByRole } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
const addCertificateButton = getByRole('button', { name: messages.setupCertificateBtn.defaultMessage });
|
||||
userEvent.click(addCertificateButton);
|
||||
});
|
||||
|
||||
expect(getByTestId('certificates-create-form')).toBeInTheDocument();
|
||||
expect(getByTestId('certificate-details-form')).toBeInTheDocument();
|
||||
expect(getByTestId('signatory-form')).toBeInTheDocument();
|
||||
expect(queryByTestId('certificate-details')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('signatory')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders CertificateEditForm when there is componentMode = MODE_STATES.editAll', async () => {
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, certificatesDataMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const { queryByTestId, getByTestId, getAllByLabelText } = renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
const editCertificateButton = getAllByLabelText(messages.editTooltip.defaultMessage)[0];
|
||||
userEvent.click(editCertificateButton);
|
||||
});
|
||||
|
||||
expect(getByTestId('certificates-edit-form')).toBeInTheDocument();
|
||||
expect(getByTestId('certificate-details-form')).toBeInTheDocument();
|
||||
expect(getByTestId('signatory-form')).toBeInTheDocument();
|
||||
expect(queryByTestId('certificate-details')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('signatory')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders placeholder if request fails', async () => {
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(403, certificatesDataMock);
|
||||
|
||||
const { getByTestId } = renderComponent();
|
||||
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
expect(getByTestId('request-denied-placeholder')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('updates loading status if request fails', async () => {
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(404, certificatesDataMock);
|
||||
|
||||
renderComponent();
|
||||
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
expect(store.getState().certificates.loadingStatus).toBe(RequestStatus.FAILED);
|
||||
});
|
||||
});
|
||||
20
src/certificates/__mocks__/certificates.js
Normal file
20
src/certificates/__mocks__/certificates.js
Normal file
@@ -0,0 +1,20 @@
|
||||
module.exports = [
|
||||
{
|
||||
id: 1,
|
||||
courseTitle: 'Course Title 1',
|
||||
signatories: [
|
||||
{
|
||||
name: 'Signatory Name 1',
|
||||
title: 'Signatory Title 1',
|
||||
organization: 'Signatory Organization 1',
|
||||
signatureImagePath: '/path/to/signature1/image.png',
|
||||
},
|
||||
{
|
||||
name: 'Signatory Name 2',
|
||||
title: 'Signatory Title 2',
|
||||
organization: 'Signatory Organization 2',
|
||||
signatureImagePath: '/path/to/signature2/image.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
32
src/certificates/__mocks__/certificatesData.js
Normal file
32
src/certificates/__mocks__/certificatesData.js
Normal file
@@ -0,0 +1,32 @@
|
||||
module.exports = {
|
||||
certificateActivationHandlerUrl: '/certificates/activation/course-v1:org+101+101/',
|
||||
certificateWebViewUrl: '//certificates/course/course-v1:org+101+101?preview=honor',
|
||||
certificates: [
|
||||
{
|
||||
courseTitle: 'Course title',
|
||||
description: 'Description of the certificate',
|
||||
editing: false,
|
||||
id: 1622146085,
|
||||
isActive: false,
|
||||
name: 'Name of the certificate',
|
||||
signatories: [
|
||||
{
|
||||
id: 268550145,
|
||||
name: 'name_sign',
|
||||
organization: 'org',
|
||||
signatureImagePath: '/asset-v1:org+101+101+type@asset+block@camera.png',
|
||||
title: 'title_sign',
|
||||
},
|
||||
],
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
courseModes: ['honor', 'audit'],
|
||||
hasCertificateModes: true,
|
||||
isActive: false,
|
||||
isGlobalStaff: true,
|
||||
mfeProctoredExamSettingsUrl: '',
|
||||
courseNumber: 'DemoX',
|
||||
courseTitle: 'Demonstration Course',
|
||||
courseNumberOverride: 'Course Number Display String',
|
||||
};
|
||||
3
src/certificates/__mocks__/index.js
Normal file
3
src/certificates/__mocks__/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as certificatesDataMock } from './certificatesData';
|
||||
export { default as signatoriesMock } from './signatories';
|
||||
export { default as certificatesMock } from './certificates';
|
||||
8
src/certificates/__mocks__/signatories.js
Normal file
8
src/certificates/__mocks__/signatories.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = [
|
||||
{
|
||||
id: '1', name: 'John Doe', title: 'CEO', organization: 'Company', signatureImagePath: '/path/to/signature1.png',
|
||||
},
|
||||
{
|
||||
id: '2', name: 'Jane Doe', title: 'CFO', organization: 'Company 2', signatureImagePath: '/path/to/signature2.png',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,70 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card, Stack, Button } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Formik, Form, FieldArray } from 'formik';
|
||||
|
||||
import CertificateDetailsForm from '../certificate-details/CertificateDetailsForm';
|
||||
import CertificateSignatories from '../certificate-signatories/CertificateSignatories';
|
||||
import { defaultCertificate } from '../constants';
|
||||
import messages from '../messages';
|
||||
import useCertificateCreateForm from './hooks/useCertificateCreateForm';
|
||||
|
||||
const CertificateCreateForm = ({ courseId }) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
courseTitle, handleCertificateSubmit, handleFormCancel,
|
||||
} = useCertificateCreateForm(courseId);
|
||||
|
||||
return (
|
||||
<Formik initialValues={defaultCertificate} onSubmit={handleCertificateSubmit}>
|
||||
{({
|
||||
values, handleChange, handleBlur, resetForm, setFieldValue,
|
||||
}) => (
|
||||
<Form className="certificates-card-form" data-testid="certificates-create-form">
|
||||
<Card>
|
||||
<Card.Section>
|
||||
<Stack gap="4">
|
||||
<CertificateDetailsForm
|
||||
courseTitleOverride={values.courseTitle}
|
||||
detailsCourseTitle={courseTitle}
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
/>
|
||||
<FieldArray
|
||||
name="signatories"
|
||||
render={arrayHelpers => (
|
||||
<CertificateSignatories
|
||||
isForm
|
||||
signatories={values.signatories}
|
||||
arrayHelpers={arrayHelpers}
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
setFieldValue={setFieldValue}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
</Card.Section>
|
||||
<Card.Footer className="justify-content-start">
|
||||
<Button type="submit">
|
||||
{intl.formatMessage(messages.cardCreate)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
onClick={() => handleFormCancel(resetForm)}
|
||||
>
|
||||
{intl.formatMessage(messages.cardCancel)}
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
CertificateCreateForm.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CertificateCreateForm;
|
||||
@@ -0,0 +1,156 @@
|
||||
import { render, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { Provider } from 'react-redux';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { executeThunk } from '../../utils';
|
||||
import initializeStore from '../../store';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import { getCertificatesApiUrl, getCertificateApiUrl } from '../data/api';
|
||||
import { fetchCertificates, createCourseCertificate } from '../data/thunks';
|
||||
import { certificatesDataMock } from '../__mocks__';
|
||||
import detailsMessages from '../certificate-details/messages';
|
||||
import signatoryMessages from '../certificate-signatories/messages';
|
||||
import messages from '../messages';
|
||||
import CertificateCreateForm from './CertificateCreateForm';
|
||||
|
||||
const courseId = 'course-123';
|
||||
let store;
|
||||
let axiosMock;
|
||||
|
||||
const renderComponent = () => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificateCreateForm courseId={courseId} />
|
||||
</IntlProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {
|
||||
certificates: [],
|
||||
hasCertificateModes: true,
|
||||
},
|
||||
componentMode: MODE_STATES.create,
|
||||
},
|
||||
};
|
||||
|
||||
describe('CertificateCreateForm', () => {
|
||||
beforeEach(async () => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, {
|
||||
...certificatesDataMock,
|
||||
certificates: [],
|
||||
});
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
});
|
||||
|
||||
it('renders with empty fields', () => {
|
||||
const { getByPlaceholderText } = renderComponent();
|
||||
|
||||
expect(getByPlaceholderText(detailsMessages.detailsCourseTitleOverride.defaultMessage).value).toBe('');
|
||||
expect(getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage).value).toBe('');
|
||||
expect(getByPlaceholderText(signatoryMessages.titlePlaceholder.defaultMessage).value).toBe('');
|
||||
expect(getByPlaceholderText(signatoryMessages.organizationPlaceholder.defaultMessage).value).toBe('');
|
||||
expect(getByPlaceholderText(signatoryMessages.imagePlaceholder.defaultMessage).value).toBe('');
|
||||
});
|
||||
|
||||
it('creates a new certificate', async () => {
|
||||
const courseTitleOverrideValue = 'Create Course Title';
|
||||
const signatoryNameValue = 'Create signatory name';
|
||||
const newCertificateData = {
|
||||
...certificatesDataMock,
|
||||
courseTitle: courseTitleOverrideValue,
|
||||
certificates: [{
|
||||
...certificatesDataMock.certificates[0],
|
||||
signatories: [{
|
||||
...certificatesDataMock.certificates[0].signatories[0],
|
||||
name: signatoryNameValue,
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
const { getByPlaceholderText, getByRole, getByDisplayValue } = renderComponent();
|
||||
|
||||
userEvent.type(
|
||||
getByPlaceholderText(detailsMessages.detailsCourseTitleOverride.defaultMessage),
|
||||
courseTitleOverrideValue,
|
||||
);
|
||||
userEvent.type(
|
||||
getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage),
|
||||
signatoryNameValue,
|
||||
);
|
||||
userEvent.click(getByRole('button', { name: messages.cardCreate.defaultMessage }));
|
||||
|
||||
axiosMock.onPost(
|
||||
getCertificateApiUrl(courseId),
|
||||
).reply(200, newCertificateData);
|
||||
await executeThunk(createCourseCertificate(courseId, newCertificateData), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByDisplayValue(courseTitleOverrideValue)).toBeInTheDocument();
|
||||
expect(getByDisplayValue(signatoryNameValue)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('cancel certificates creation', async () => {
|
||||
const { getByRole } = renderComponent();
|
||||
userEvent.click(getByRole('button', { name: messages.cardCancel.defaultMessage }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.noCertificates);
|
||||
});
|
||||
});
|
||||
|
||||
it('there is no delete signatory button if signatories length is less then 2', async () => {
|
||||
const { queryAllByRole } = renderComponent();
|
||||
const deleteIcons = queryAllByRole('button', { name: messages.deleteTooltip.defaultMessage });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(deleteIcons.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('add and delete signatory', async () => {
|
||||
const {
|
||||
getAllByRole, queryAllByRole, getByText, getByRole,
|
||||
} = renderComponent();
|
||||
|
||||
const addSignatoryBtn = getByText(signatoryMessages.addSignatoryButton.defaultMessage);
|
||||
|
||||
userEvent.click(addSignatoryBtn);
|
||||
|
||||
const deleteIcons = getAllByRole('button', { name: messages.deleteTooltip.defaultMessage });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(deleteIcons.length).toBe(2);
|
||||
});
|
||||
|
||||
userEvent.click(deleteIcons[0]);
|
||||
|
||||
const confirModal = getByRole('dialog');
|
||||
const deleteModalButton = within(confirModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage });
|
||||
|
||||
userEvent.click(deleteIcons[0]);
|
||||
userEvent.click(deleteModalButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryAllByRole('button', { name: messages.deleteTooltip.defaultMessage }).length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
|
||||
import { MODE_STATES } from '../../data/constants';
|
||||
import { getCourseTitle } from '../../data/selectors';
|
||||
import { setMode } from '../../data/slice';
|
||||
import { createCourseCertificate } from '../../data/thunks';
|
||||
|
||||
const useCertificateCreateForm = (courseId) => {
|
||||
const dispatch = useDispatch();
|
||||
const courseTitle = useSelector(getCourseTitle);
|
||||
|
||||
const handleCertificateSubmit = (values) => {
|
||||
const signatoriesWithoutIds = values.signatories.map(({ id, ...rest }) => rest);
|
||||
const newValues = { ...values, signatories: signatoriesWithoutIds };
|
||||
dispatch(createCourseCertificate(courseId, newValues));
|
||||
};
|
||||
|
||||
const handleFormCancel = (resetForm) => {
|
||||
dispatch(setMode(MODE_STATES.noCertificates));
|
||||
resetForm();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
};
|
||||
return {
|
||||
courseTitle, handleCertificateSubmit, handleFormCancel,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCertificateCreateForm;
|
||||
123
src/certificates/certificate-details/CertificateDetails.jsx
Normal file
123
src/certificates/certificate-details/CertificateDetails.jsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Icon, Stack, IconButtonWithTooltip,
|
||||
} from '@openedx/paragon';
|
||||
import {
|
||||
EditOutline as EditOutlineIcon, DeleteOutline as DeleteOutlineIcon,
|
||||
} from '@openedx/paragon/icons';
|
||||
|
||||
import CertificateSection from '../certificate-section/CertificateSection';
|
||||
import ModalNotification from '../../generic/modal-notification';
|
||||
import commonMessages from '../messages';
|
||||
import messages from './messages';
|
||||
import useCertificateDetails from './hooks/useCertificateDetails';
|
||||
|
||||
const CertificateDetails = ({
|
||||
certificateId,
|
||||
detailsCourseTitle,
|
||||
courseTitleOverride,
|
||||
detailsCourseNumber,
|
||||
courseNumberOverride,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
isConfirmOpen,
|
||||
confirmOpen,
|
||||
confirmClose,
|
||||
isEditModalOpen,
|
||||
editModalOpen,
|
||||
editModalClose,
|
||||
isCertificateActive,
|
||||
handleEditAll,
|
||||
handleDeleteCard,
|
||||
} = useCertificateDetails(certificateId);
|
||||
|
||||
return (
|
||||
<CertificateSection
|
||||
title={intl.formatMessage(messages.detailsSectionTitle)}
|
||||
className="certificate-details"
|
||||
data-testid="certificate-details"
|
||||
actions={(
|
||||
<Stack direction="horizontal" gap="2">
|
||||
<IconButtonWithTooltip
|
||||
src={EditOutlineIcon}
|
||||
iconAs={Icon}
|
||||
tooltipContent={<div>{intl.formatMessage(commonMessages.editTooltip)}</div>}
|
||||
alt={intl.formatMessage(commonMessages.editTooltip)}
|
||||
onClick={isCertificateActive ? editModalOpen : handleEditAll}
|
||||
/>
|
||||
<IconButtonWithTooltip
|
||||
src={DeleteOutlineIcon}
|
||||
iconAs={Icon}
|
||||
tooltipContent={<div>{intl.formatMessage(commonMessages.deleteTooltip)}</div>}
|
||||
alt={intl.formatMessage(commonMessages.deleteTooltip)}
|
||||
onClick={confirmOpen}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
>
|
||||
<Stack>
|
||||
<Stack direction="horizontal" gap="1.5" className="certificate-details__info">
|
||||
<p className="certificate-details__info-paragraph">
|
||||
<strong>{intl.formatMessage(messages.detailsCourseTitle)}:</strong> {detailsCourseTitle}
|
||||
</p>
|
||||
<p className="certificate-details__info-paragraph-course-number">
|
||||
<strong>{intl.formatMessage(messages.detailsCourseNumber)}:</strong> {detailsCourseNumber}
|
||||
</p>
|
||||
</Stack>
|
||||
<Stack direction="horizontal" gap="1.5" className="certificate-details__info">
|
||||
{courseTitleOverride && (
|
||||
<p className="certificate-details__info-paragraph">
|
||||
<strong>{intl.formatMessage(messages.detailsCourseTitleOverride)}:</strong> {courseTitleOverride}
|
||||
</p>
|
||||
)}
|
||||
{courseNumberOverride && (
|
||||
<p className="certificate-details__info-paragraph text-right">
|
||||
<strong>{intl.formatMessage(messages.detailsCourseNumberOverride)}:</strong> {courseNumberOverride}
|
||||
</p>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<ModalNotification
|
||||
isOpen={isEditModalOpen}
|
||||
title={intl.formatMessage(messages.editCertificateConfirmationTitle)}
|
||||
message={intl.formatMessage(messages.editCertificateMessage)}
|
||||
actionButtonText={intl.formatMessage(commonMessages.editTooltip)}
|
||||
cancelButtonText={intl.formatMessage(commonMessages.cardCancel)}
|
||||
handleCancel={editModalClose}
|
||||
handleAction={() => {
|
||||
editModalClose();
|
||||
handleEditAll();
|
||||
}}
|
||||
/>
|
||||
<ModalNotification
|
||||
isOpen={isConfirmOpen}
|
||||
title={intl.formatMessage(messages.deleteCertificateConfirmationTitle)}
|
||||
message={intl.formatMessage(messages.deleteCertificateMessage)}
|
||||
actionButtonText={intl.formatMessage(commonMessages.deleteTooltip)}
|
||||
cancelButtonText={intl.formatMessage(commonMessages.cardCancel)}
|
||||
handleCancel={confirmClose}
|
||||
handleAction={() => {
|
||||
confirmClose();
|
||||
handleDeleteCard();
|
||||
}}
|
||||
/>
|
||||
</CertificateSection>
|
||||
);
|
||||
};
|
||||
|
||||
CertificateDetails.defaultProps = {
|
||||
courseTitleOverride: '',
|
||||
courseNumberOverride: '',
|
||||
};
|
||||
|
||||
CertificateDetails.propTypes = {
|
||||
certificateId: PropTypes.number.isRequired,
|
||||
courseTitleOverride: PropTypes.string,
|
||||
courseNumberOverride: PropTypes.string,
|
||||
detailsCourseTitle: PropTypes.string.isRequired,
|
||||
detailsCourseNumber: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CertificateDetails;
|
||||
118
src/certificates/certificate-details/CertificateDetails.test.jsx
Normal file
118
src/certificates/certificate-details/CertificateDetails.test.jsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import { Provider, useDispatch } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
|
||||
import initializeStore from '../../store';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import { deleteCourseCertificate } from '../data/thunks';
|
||||
import commonMessages from '../messages';
|
||||
import messages from './messages';
|
||||
import CertificateDetails from './CertificateDetails';
|
||||
|
||||
let store;
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const certificateId = 123;
|
||||
|
||||
jest.mock('react-redux', () => ({
|
||||
...jest.requireActual('react-redux'),
|
||||
useDispatch: jest.fn(),
|
||||
useSelector: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useParams: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../data/thunks', () => ({
|
||||
deleteCourseCertificate: jest.fn(),
|
||||
}));
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificateDetails {...props} />
|
||||
</IntlProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const defaultProps = {
|
||||
componentMode: MODE_STATES.view,
|
||||
detailsCourseTitle: 'Course Title',
|
||||
detailsCourseNumber: 'Course Number',
|
||||
handleChange: jest.fn(),
|
||||
handleBlur: jest.fn(),
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {
|
||||
certificates: [],
|
||||
hasCertificateModes: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('CertificateDetails', () => {
|
||||
let mockDispatch;
|
||||
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
useParams.mockReturnValue({ courseId });
|
||||
mockDispatch = jest.fn();
|
||||
useDispatch.mockReturnValue(mockDispatch);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
useParams.mockClear();
|
||||
mockDispatch.mockClear();
|
||||
});
|
||||
|
||||
it('renders correctly in view mode', () => {
|
||||
const { getByText } = renderComponent(defaultProps);
|
||||
|
||||
expect(getByText(messages.detailsSectionTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(defaultProps.detailsCourseTitle)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens confirm modal on delete button click', () => {
|
||||
const { getByRole, getByText } = renderComponent(defaultProps);
|
||||
const deleteButton = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
|
||||
userEvent.click(deleteButton);
|
||||
|
||||
expect(getByText(messages.deleteCertificateConfirmationTitle.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('dispatches delete action on confirm modal action', async () => {
|
||||
const props = { ...defaultProps, courseId, certificateId };
|
||||
const { getByRole } = renderComponent(props);
|
||||
const deleteButton = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
|
||||
userEvent.click(deleteButton);
|
||||
|
||||
await waitFor(() => {
|
||||
const confirmActionButton = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
|
||||
userEvent.click(confirmActionButton);
|
||||
});
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledWith(deleteCourseCertificate(courseId, certificateId));
|
||||
});
|
||||
|
||||
it('shows course title override in view mode', () => {
|
||||
const courseTitleOverride = 'Overridden Title';
|
||||
const props = { ...defaultProps, courseTitleOverride };
|
||||
const { getByText } = renderComponent(props);
|
||||
|
||||
expect(getByText(courseTitleOverride)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Stack, Form } from '@openedx/paragon';
|
||||
|
||||
import CertificateSection from '../certificate-section/CertificateSection';
|
||||
import messages from './messages';
|
||||
|
||||
const CertificateDetailsForm = ({
|
||||
detailsCourseTitle,
|
||||
courseTitleOverride,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<CertificateSection
|
||||
title={intl.formatMessage(messages.detailsSectionTitle)}
|
||||
className="certificate-details"
|
||||
data-testid="certificate-details-form"
|
||||
>
|
||||
<Stack>
|
||||
<Stack direction="horizontal" gap="1.5" className="certificate-details__info">
|
||||
<p className="certificate-details__info-paragraph">
|
||||
<strong>{intl.formatMessage(messages.detailsCourseTitle)}:</strong> {detailsCourseTitle}
|
||||
</p>
|
||||
</Stack>
|
||||
<Stack direction="horizontal" gap="1.5" className="certificate-details__info">
|
||||
<Form.Group className="m-0 w-100">
|
||||
<Form.Label>{intl.formatMessage(messages.detailsCourseTitleOverride)}</Form.Label>
|
||||
<Form.Control
|
||||
name="courseTitle"
|
||||
value={courseTitleOverride}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
placeholder={intl.formatMessage(messages.detailsCourseTitleOverride)}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<span className="x-small">{intl.formatMessage(messages.detailsCourseTitleOverrideDescription)}</span>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</CertificateSection>
|
||||
);
|
||||
};
|
||||
|
||||
CertificateDetailsForm.propTypes = {
|
||||
courseTitleOverride: PropTypes.string.isRequired,
|
||||
detailsCourseTitle: PropTypes.string.isRequired,
|
||||
handleChange: PropTypes.func.isRequired,
|
||||
handleBlur: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default CertificateDetailsForm;
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Provider } from 'react-redux';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
|
||||
import initializeStore from '../../store';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import commonMessages from '../messages';
|
||||
import messages from './messages';
|
||||
import CertificateDetailsForm from './CertificateDetailsForm';
|
||||
|
||||
let store;
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificateDetailsForm {...props} />
|
||||
</IntlProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const defaultProps = {
|
||||
componentMode: MODE_STATES.view,
|
||||
detailsCourseTitle: 'Course Title',
|
||||
detailsCourseNumber: 'Course Number',
|
||||
handleChange: jest.fn(),
|
||||
handleBlur: jest.fn(),
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {
|
||||
certificates: [],
|
||||
hasCertificateModes: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('CertificateDetails', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
});
|
||||
|
||||
it('renders correctly in create mode', () => {
|
||||
const { getByText, getByPlaceholderText } = renderComponent(defaultProps);
|
||||
|
||||
expect(getByText(messages.detailsSectionTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByPlaceholderText(messages.detailsCourseTitleOverride.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles input change in create mode', async () => {
|
||||
const { getByPlaceholderText } = renderComponent(defaultProps);
|
||||
const input = getByPlaceholderText(messages.detailsCourseTitleOverride.defaultMessage);
|
||||
const newInputValue = 'New Title';
|
||||
|
||||
userEvent.type(input, newInputValue);
|
||||
|
||||
waitFor(() => {
|
||||
expect(input.value).toBe(newInputValue);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not show delete button in create mode', () => {
|
||||
const { queryByRole } = renderComponent(defaultProps);
|
||||
|
||||
expect(queryByRole('button', { name: commonMessages.deleteTooltip.defaultMessage })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useToggle } from '@openedx/paragon';
|
||||
|
||||
import { setMode } from '../../data/slice';
|
||||
import { deleteCourseCertificate } from '../../data/thunks';
|
||||
import { getIsCertificateActive } from '../../data/selectors';
|
||||
import { MODE_STATES } from '../../data/constants';
|
||||
|
||||
const useCertificateDetails = (certificateId) => {
|
||||
const dispatch = useDispatch();
|
||||
const { courseId } = useParams();
|
||||
const [isConfirmOpen, confirmOpen, confirmClose] = useToggle(false);
|
||||
const [isEditModalOpen, editModalOpen, editModalClose] = useToggle(false);
|
||||
const isCertificateActive = useSelector(getIsCertificateActive);
|
||||
|
||||
const handleEditAll = () => {
|
||||
dispatch(setMode(MODE_STATES.editAll));
|
||||
};
|
||||
|
||||
const handleDeleteCard = () => {
|
||||
if (certificateId) {
|
||||
dispatch(deleteCourseCertificate(courseId, certificateId));
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isConfirmOpen,
|
||||
confirmOpen,
|
||||
confirmClose,
|
||||
isEditModalOpen,
|
||||
editModalOpen,
|
||||
editModalClose,
|
||||
isCertificateActive,
|
||||
handleEditAll,
|
||||
handleDeleteCard,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCertificateDetails;
|
||||
56
src/certificates/certificate-details/messages.js
Normal file
56
src/certificates/certificate-details/messages.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
detailsSectionTitle: {
|
||||
id: 'course-authoring.certificates.details.section.title',
|
||||
defaultMessage: 'Certificate details',
|
||||
description: 'Title for the section',
|
||||
},
|
||||
detailsCourseTitle: {
|
||||
id: 'course-authoring.certificates.details.course.title',
|
||||
defaultMessage: 'Course title',
|
||||
description: 'Label for displaying the official course title in the certificate details section',
|
||||
},
|
||||
detailsCourseTitleOverride: {
|
||||
id: 'course-authoring.certificates.details.course.title.override',
|
||||
defaultMessage: 'Course title override',
|
||||
description: 'Label for the course title override input field',
|
||||
},
|
||||
detailsCourseTitleOverrideDescription: {
|
||||
id: 'course-authoring.certificates.details.course.title.override.description',
|
||||
defaultMessage: 'Specify an alternative to the official course title to display on certificates. Leave blank to use the official course title.',
|
||||
description: 'Helper text under the course title override input field',
|
||||
},
|
||||
detailsCourseNumber: {
|
||||
id: 'course-authoring.certificates.details.course.number',
|
||||
defaultMessage: 'Course number',
|
||||
description: 'Label for displaying the official course number in the certificate details section',
|
||||
},
|
||||
detailsCourseNumberOverride: {
|
||||
id: 'course-authoring.certificates.details.course.number.override',
|
||||
defaultMessage: 'Course number override',
|
||||
description: 'Label for the course number override input field',
|
||||
},
|
||||
deleteCertificateConfirmationTitle: {
|
||||
id: 'course-authoring.certificates.details.confirm-modal',
|
||||
defaultMessage: 'Delete this certificate?',
|
||||
description: 'Title for the confirmation modal when a user attempts to delete a certificate',
|
||||
},
|
||||
deleteCertificateMessage: {
|
||||
id: 'course-authoring.certificates.details.confirm-modal.message',
|
||||
defaultMessage: 'Deleting this certificate is permanent and cannot be undone.',
|
||||
description: 'Warning message within the delete confirmation modal, emphasizing the permanent nature of the action',
|
||||
},
|
||||
editCertificateConfirmationTitle: {
|
||||
id: 'course-authoring.certificates.details.confirm.edit',
|
||||
defaultMessage: 'Edit this certificate?',
|
||||
description: 'Title for the confirmation modal when a user attempts to edit an already activated (live) certificate',
|
||||
},
|
||||
editCertificateMessage: {
|
||||
id: 'course-authoring.certificates.details.confirm.edit.message',
|
||||
defaultMessage: 'This certificate has already been activated and is live. Are you sure you want to continue editing?',
|
||||
description: 'Message warning users about the implications of editing a certificate that is already live, prompting for confirmation',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
104
src/certificates/certificate-edit-form/CertificateEditForm.jsx
Normal file
104
src/certificates/certificate-edit-form/CertificateEditForm.jsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card, Stack, Button } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Formik, Form, FieldArray } from 'formik';
|
||||
|
||||
import ModalNotification from '../../generic/modal-notification';
|
||||
import CertificateDetailsForm from '../certificate-details/CertificateDetailsForm';
|
||||
import CertificateSignatories from '../certificate-signatories/CertificateSignatories';
|
||||
import commonMessages from '../messages';
|
||||
import messages from '../certificate-details/messages';
|
||||
import useCertificateEditForm from './hooks/useCertificateEditForm';
|
||||
|
||||
const CertificateEditForm = ({ courseId }) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
confirmOpen,
|
||||
courseTitle,
|
||||
certificates,
|
||||
confirmClose,
|
||||
initialValues,
|
||||
isConfirmOpen,
|
||||
handleCertificateDelete,
|
||||
handleCertificateSubmit,
|
||||
handleCertificateUpdateCancel,
|
||||
} = useCertificateEditForm(courseId);
|
||||
|
||||
return (
|
||||
<>
|
||||
{certificates.map((certificate, id) => (
|
||||
<Formik initialValues={initialValues[id]} onSubmit={handleCertificateSubmit} key={certificate.id}>
|
||||
{({
|
||||
values, handleChange, handleBlur, resetForm, setFieldValue,
|
||||
}) => (
|
||||
<>
|
||||
<Form className="certificates-card-form" data-testid="certificates-edit-form">
|
||||
<Card>
|
||||
<Card.Section>
|
||||
<Stack gap="4">
|
||||
<CertificateDetailsForm
|
||||
courseTitleOverride={values.courseTitle}
|
||||
detailsCourseTitle={courseTitle}
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
/>
|
||||
<FieldArray
|
||||
name="signatories"
|
||||
render={arrayHelpers => (
|
||||
<CertificateSignatories
|
||||
isForm
|
||||
signatories={values.signatories}
|
||||
arrayHelpers={arrayHelpers}
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
setFieldValue={setFieldValue}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
</Card.Section>
|
||||
<Card.Footer className="justify-content-start">
|
||||
<Button type="submit">
|
||||
{intl.formatMessage(commonMessages.saveTooltip)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
onClick={() => handleCertificateUpdateCancel(resetForm)}
|
||||
>
|
||||
{intl.formatMessage(commonMessages.cardCancel)}
|
||||
</Button>
|
||||
<Button
|
||||
className="ml-auto"
|
||||
variant="tertiary"
|
||||
onClick={() => confirmOpen(certificate.id)}
|
||||
>
|
||||
{intl.formatMessage(commonMessages.deleteTooltip)}
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
</Form>
|
||||
<ModalNotification
|
||||
isOpen={isConfirmOpen}
|
||||
title={intl.formatMessage(messages.deleteCertificateConfirmationTitle)}
|
||||
message={intl.formatMessage(messages.deleteCertificateMessage)}
|
||||
actionButtonText={intl.formatMessage(commonMessages.deleteTooltip)}
|
||||
cancelButtonText={intl.formatMessage(commonMessages.cardCancel)}
|
||||
handleCancel={() => confirmClose()}
|
||||
handleAction={() => {
|
||||
confirmClose();
|
||||
handleCertificateDelete(certificate.id);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Formik>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
CertificateEditForm.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CertificateEditForm;
|
||||
@@ -0,0 +1,140 @@
|
||||
import { Provider } from 'react-redux';
|
||||
import { render, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import { executeThunk } from '../../utils';
|
||||
import initializeStore from '../../store';
|
||||
import { getCertificatesApiUrl, getUpdateCertificateApiUrl } from '../data/api';
|
||||
import { fetchCertificates, deleteCourseCertificate, updateCourseCertificate } from '../data/thunks';
|
||||
import { certificatesDataMock } from '../__mocks__';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import messagesDetails from '../certificate-details/messages';
|
||||
import messages from '../messages';
|
||||
import CertificateEditForm from './CertificateEditForm';
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
const courseId = 'course-123';
|
||||
|
||||
const renderComponent = () => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificateEditForm courseId="course-123" />
|
||||
</IntlProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {},
|
||||
componentMode: MODE_STATES.editAll,
|
||||
},
|
||||
};
|
||||
|
||||
describe('CertificateEditForm Component', () => {
|
||||
beforeEach(async () => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, certificatesDataMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
});
|
||||
|
||||
it('submits the form with updated certificate details', async () => {
|
||||
const courseTitleOverrideValue = 'Updated Course Title';
|
||||
const signatoryNameValue = 'Updated signatory name';
|
||||
const newCertificateData = {
|
||||
...certificatesDataMock,
|
||||
courseTitle: courseTitleOverrideValue,
|
||||
certificates: [{
|
||||
...certificatesDataMock.certificates[0],
|
||||
signatories: [{
|
||||
...certificatesDataMock.certificates[0].signatories[0],
|
||||
name: signatoryNameValue,
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
const { getByDisplayValue, getByRole, getByPlaceholderText } = renderComponent();
|
||||
|
||||
userEvent.type(
|
||||
getByPlaceholderText(messagesDetails.detailsCourseTitleOverride.defaultMessage),
|
||||
courseTitleOverrideValue,
|
||||
);
|
||||
|
||||
userEvent.click(getByRole('button', { name: messages.saveTooltip.defaultMessage }));
|
||||
|
||||
axiosMock.onPost(
|
||||
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
|
||||
).reply(200, newCertificateData);
|
||||
await executeThunk(updateCourseCertificate(courseId, newCertificateData), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByDisplayValue(
|
||||
certificatesDataMock.certificates[0].courseTitle + courseTitleOverrideValue,
|
||||
)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('deletes a certificate and updates the store', async () => {
|
||||
axiosMock.onDelete(
|
||||
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
|
||||
).reply(200);
|
||||
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
userEvent.click(getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
|
||||
|
||||
const confirmDeleteModal = getByRole('dialog');
|
||||
userEvent.click(within(confirmDeleteModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
|
||||
|
||||
await executeThunk(deleteCourseCertificate(courseId, certificatesDataMock.certificates[0].id), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getState().certificates.certificatesData.certificates.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('updates loading status if delete fails', async () => {
|
||||
axiosMock.onDelete(
|
||||
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
|
||||
).reply(404);
|
||||
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
userEvent.click(getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
|
||||
|
||||
const confirmDeleteModal = getByRole('dialog');
|
||||
userEvent.click(within(confirmDeleteModal).getByRole('button', { name: messages.deleteTooltip.defaultMessage }));
|
||||
|
||||
await executeThunk(deleteCourseCertificate(courseId, certificatesDataMock.certificates[0].id), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getState().certificates.savingStatus).toBe(RequestStatus.FAILED);
|
||||
});
|
||||
});
|
||||
|
||||
it('cancel edit form', async () => {
|
||||
const { getByRole } = renderComponent();
|
||||
|
||||
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.editAll);
|
||||
|
||||
userEvent.click(getByRole('button', { name: messages.cardCancel.defaultMessage }));
|
||||
|
||||
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.view);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useToggle } from '@openedx/paragon';
|
||||
|
||||
import { MODE_STATES } from '../../data/constants';
|
||||
import { getCourseTitle, getCertificates } from '../../data/selectors';
|
||||
import { setMode } from '../../data/slice';
|
||||
import { updateCourseCertificate, deleteCourseCertificate } from '../../data/thunks';
|
||||
import { defaultCertificate } from '../../constants';
|
||||
|
||||
const useCertificateEditForm = (courseId) => {
|
||||
const dispatch = useDispatch();
|
||||
const [isConfirmOpen, confirmOpen, confirmClose] = useToggle(false);
|
||||
const courseTitle = useSelector(getCourseTitle);
|
||||
const certificates = useSelector(getCertificates);
|
||||
|
||||
const handleCertificateSubmit = (values) => {
|
||||
const signatoriesWithoutLocalIds = values.signatories.map(signatory => {
|
||||
if (signatory.id && typeof signatory.id === 'string' && signatory.id.startsWith('local-')) {
|
||||
const { id, ...rest } = signatory;
|
||||
return rest;
|
||||
}
|
||||
return signatory;
|
||||
});
|
||||
|
||||
const newValues = {
|
||||
...values,
|
||||
signatories: signatoriesWithoutLocalIds,
|
||||
};
|
||||
|
||||
dispatch(updateCourseCertificate(courseId, newValues));
|
||||
};
|
||||
|
||||
const handleCertificateUpdateCancel = (resetForm) => {
|
||||
dispatch(setMode(MODE_STATES.view));
|
||||
resetForm();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
};
|
||||
|
||||
const handleCertificateDelete = (certificateId) => {
|
||||
dispatch(deleteCourseCertificate(courseId, certificateId));
|
||||
};
|
||||
|
||||
const initialValues = certificates.map((certificate) => ({
|
||||
...certificate,
|
||||
courseTitle: certificate.courseTitle || defaultCertificate.courseTitle,
|
||||
signatories: certificate.signatories || defaultCertificate.signatories,
|
||||
}));
|
||||
|
||||
return {
|
||||
confirmOpen,
|
||||
courseTitle,
|
||||
certificates,
|
||||
confirmClose,
|
||||
initialValues,
|
||||
isConfirmOpen,
|
||||
handleCertificateDelete,
|
||||
handleCertificateSubmit,
|
||||
handleCertificateUpdateCancel,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCertificateEditForm;
|
||||
29
src/certificates/certificate-section/CertificateSection.jsx
Normal file
29
src/certificates/certificate-section/CertificateSection.jsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Stack } from '@openedx/paragon';
|
||||
|
||||
const CertificateSection = ({
|
||||
title, actions, children, ...rest
|
||||
}) => (
|
||||
<section {...rest}>
|
||||
<Stack className="justify-content-between mb-2.5" direction="horizontal">
|
||||
<h2 className="lead section-title mb-0">{title}</h2>
|
||||
{actions && actions}
|
||||
</Stack>
|
||||
<hr className="mt-0 mb-4" />
|
||||
<div>
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
CertificateSection.defaultProps = {
|
||||
children: null,
|
||||
actions: null,
|
||||
};
|
||||
CertificateSection.propTypes = {
|
||||
children: PropTypes.node,
|
||||
actions: PropTypes.node,
|
||||
title: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CertificateSection;
|
||||
@@ -0,0 +1,130 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Stack, Button, Form } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import CertificateSection from '../certificate-section/CertificateSection';
|
||||
import Signatory from './signatory/Signatory';
|
||||
import SignatoryForm from './signatory/SignatoryForm';
|
||||
import useEditSignatory from './hooks/useEditSignatory';
|
||||
import useCreateSignatory from './hooks/useCreateSignatory';
|
||||
import messages from './messages';
|
||||
|
||||
const CertificateSignatories = ({
|
||||
isForm,
|
||||
editModes,
|
||||
signatories,
|
||||
arrayHelpers,
|
||||
initialSignatoriesValues,
|
||||
setFieldValue,
|
||||
setEditModes,
|
||||
handleBlur,
|
||||
handleChange,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
toggleEditSignatory,
|
||||
handleDeleteSignatory,
|
||||
handleCancelUpdateSignatory,
|
||||
} = useEditSignatory({
|
||||
arrayHelpers, editModes, setEditModes, setFieldValue, initialSignatoriesValues,
|
||||
});
|
||||
|
||||
const { handleAddSignatory } = useCreateSignatory({ arrayHelpers });
|
||||
|
||||
return (
|
||||
<CertificateSection
|
||||
title={intl.formatMessage(messages.signatoriesSectionTitle)}
|
||||
className="certificate-signatories"
|
||||
>
|
||||
<div>
|
||||
<p className="mb-4.5">
|
||||
{intl.formatMessage(messages.signatoriesRecommendation)}
|
||||
</p>
|
||||
<Stack gap="4.5">
|
||||
{signatories.map(({
|
||||
id, name, title, organization, signatureImagePath,
|
||||
}, idx) => (
|
||||
isForm || editModes[idx] ? (
|
||||
<SignatoryForm
|
||||
key={id}
|
||||
index={idx}
|
||||
isEdit={editModes[idx]}
|
||||
name={name}
|
||||
title={title}
|
||||
organization={organization}
|
||||
signatureImagePath={signatureImagePath}
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
setFieldValue={setFieldValue}
|
||||
showDeleteButton={signatories.length > 1 && !editModes[idx]}
|
||||
handleDeleteSignatory={() => handleDeleteSignatory(idx)}
|
||||
{...(editModes[idx] && {
|
||||
handleCancelUpdateSignatory: () => handleCancelUpdateSignatory(idx),
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
<Signatory
|
||||
key={id}
|
||||
index={idx}
|
||||
name={name}
|
||||
title={title}
|
||||
organization={organization}
|
||||
signatureImagePath={signatureImagePath}
|
||||
handleEdit={() => toggleEditSignatory(idx)}
|
||||
/>
|
||||
)
|
||||
))}
|
||||
</Stack>
|
||||
{isForm && (
|
||||
<>
|
||||
<Button variant="outline-primary" onClick={handleAddSignatory} className="w-100 mt-4">
|
||||
{intl.formatMessage(messages.addSignatoryButton)}
|
||||
</Button>
|
||||
<Form.Control.Feedback>
|
||||
<span className="x-small">{intl.formatMessage(messages.addSignatoryButtonDescription)}</span>
|
||||
</Form.Control.Feedback>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CertificateSection>
|
||||
);
|
||||
};
|
||||
|
||||
CertificateSignatories.defaultProps = {
|
||||
handleChange: null,
|
||||
handleBlur: null,
|
||||
setFieldValue: null,
|
||||
arrayHelpers: null,
|
||||
isForm: false,
|
||||
editModes: {},
|
||||
setEditModes: null,
|
||||
initialSignatoriesValues: null,
|
||||
};
|
||||
|
||||
CertificateSignatories.propTypes = {
|
||||
isForm: PropTypes.bool,
|
||||
editModes: PropTypes.objectOf(PropTypes.bool),
|
||||
initialSignatoriesValues: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
organization: PropTypes.string.isRequired,
|
||||
signatureImagePath: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
})),
|
||||
handleChange: PropTypes.func,
|
||||
handleBlur: PropTypes.func,
|
||||
setFieldValue: PropTypes.func,
|
||||
setEditModes: PropTypes.func,
|
||||
arrayHelpers: PropTypes.shape({
|
||||
push: PropTypes.func,
|
||||
remove: PropTypes.func,
|
||||
}),
|
||||
signatories: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
organization: PropTypes.string.isRequired,
|
||||
signatureImagePath: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
};
|
||||
|
||||
export default CertificateSignatories;
|
||||
@@ -0,0 +1,110 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { Provider } from 'react-redux';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
|
||||
import initializeStore from '../../store';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import { signatoriesMock } from '../__mocks__';
|
||||
import commonMessages from '../messages';
|
||||
import messages from './messages';
|
||||
import useEditSignatory from './hooks/useEditSignatory';
|
||||
import useCreateSignatory from './hooks/useCreateSignatory';
|
||||
import CertificateSignatories from './CertificateSignatories';
|
||||
|
||||
let store;
|
||||
|
||||
const mockArrayHelpers = {
|
||||
push: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('./hooks/useEditSignatory');
|
||||
|
||||
jest.mock('./hooks/useCreateSignatory');
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificateSignatories {...props} />
|
||||
</IntlProvider>,
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const defaultProps = {
|
||||
signatories: signatoriesMock,
|
||||
handleChange: jest.fn(),
|
||||
handleBlur: jest.fn(),
|
||||
setFieldValue: jest.fn(),
|
||||
arrayHelpers: mockArrayHelpers,
|
||||
isForm: true,
|
||||
resetForm: jest.fn(),
|
||||
editModes: {},
|
||||
setEditModes: jest.fn(),
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {
|
||||
certificates: [],
|
||||
hasCertificateModes: true,
|
||||
},
|
||||
componentMode: MODE_STATES.create,
|
||||
},
|
||||
};
|
||||
|
||||
describe('CertificateSignatories', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
useEditSignatory.mockReturnValue({
|
||||
toggleEditSignatory: jest.fn(),
|
||||
handleDeleteSignatory: jest.fn(),
|
||||
handleCancelUpdateSignatory: jest.fn(),
|
||||
});
|
||||
|
||||
useCreateSignatory.mockReturnValue({
|
||||
handleAddSignatory: jest.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
|
||||
it('renders signatory components for each signatory', () => {
|
||||
const { getByText } = renderComponent({ ...defaultProps, isForm: false });
|
||||
|
||||
signatoriesMock.forEach(signatory => {
|
||||
expect(getByText(signatory.name)).toBeInTheDocument();
|
||||
expect(getByText(signatory.title)).toBeInTheDocument();
|
||||
expect(getByText(signatory.organization)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('adds a new signatory when add button is clicked', () => {
|
||||
const { getByText } = renderComponent({ ...defaultProps, isForm: true });
|
||||
|
||||
userEvent.click(getByText(messages.addSignatoryButton.defaultMessage));
|
||||
expect(useCreateSignatory().handleAddSignatory).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls remove for the correct signatory when delete icon is clicked', async () => {
|
||||
const { getAllByRole } = renderComponent(defaultProps);
|
||||
|
||||
const deleteIcons = getAllByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
|
||||
expect(deleteIcons.length).toBe(signatoriesMock.length);
|
||||
|
||||
userEvent.click(deleteIcons[0]);
|
||||
|
||||
waitFor(() => {
|
||||
expect(mockArrayHelpers.remove).toHaveBeenCalledWith(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
const useCreateSignatory = ({ arrayHelpers }) => {
|
||||
const handleAddSignatory = () => {
|
||||
const getNewSignatory = () => ({
|
||||
id: `local-${uuid()}`, name: '', title: '', organization: '', signatureImagePath: '',
|
||||
});
|
||||
|
||||
arrayHelpers.push(getNewSignatory());
|
||||
};
|
||||
|
||||
return { handleAddSignatory };
|
||||
};
|
||||
|
||||
export default useCreateSignatory;
|
||||
@@ -0,0 +1,33 @@
|
||||
const useEditSignatory = ({
|
||||
arrayHelpers, editModes, setEditModes, setFieldValue, initialSignatoriesValues,
|
||||
}) => {
|
||||
const handleDeleteSignatory = (id) => {
|
||||
arrayHelpers.remove(id);
|
||||
|
||||
if (editModes && setEditModes) {
|
||||
const newEditModes = { ...editModes };
|
||||
delete newEditModes[id];
|
||||
setEditModes(newEditModes);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleEditSignatory = (id) => {
|
||||
setEditModes(prev => ({
|
||||
...prev,
|
||||
[id]: !prev[id],
|
||||
}));
|
||||
};
|
||||
|
||||
const handleCancelUpdateSignatory = (id) => {
|
||||
const signatoryInitialValues = initialSignatoriesValues[id];
|
||||
Object.keys(signatoryInitialValues).forEach(fieldKey => {
|
||||
const fieldName = `signatories[${id}].${fieldKey}`;
|
||||
setFieldValue(fieldName, signatoryInitialValues[fieldKey]);
|
||||
});
|
||||
toggleEditSignatory(id);
|
||||
};
|
||||
|
||||
return { toggleEditSignatory, handleDeleteSignatory, handleCancelUpdateSignatory };
|
||||
};
|
||||
|
||||
export default useEditSignatory;
|
||||
116
src/certificates/certificate-signatories/messages.js
Normal file
116
src/certificates/certificate-signatories/messages.js
Normal file
@@ -0,0 +1,116 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
signatoryTitle: {
|
||||
id: 'course-authoring.certificates.signatories.title',
|
||||
defaultMessage: 'Signatory',
|
||||
description: 'Title for a signatory',
|
||||
},
|
||||
signatoriesRecommendation: {
|
||||
id: 'course-authoring.certificates.signatories.recommendation',
|
||||
defaultMessage: 'It is strongly recommended that you include four or fewer signatories. If you include additional signatories, preview the certificate in Print View to ensure the certificate will print correctly on one page.',
|
||||
description: 'A recommendation for the number of signatories to include on a certificate, emphasizing the importance of testing the print layout',
|
||||
},
|
||||
signatoriesSectionTitle: {
|
||||
id: 'course-authoring.certificates.signatories.section.title',
|
||||
defaultMessage: 'Certificate signatories',
|
||||
description: 'Title for the section',
|
||||
},
|
||||
addSignatoryButton: {
|
||||
id: 'course-authoring.certificates.signatories.add.signatory.button',
|
||||
defaultMessage: 'Add additional signatory',
|
||||
description: 'Button text for adding a new signatory to the certificate',
|
||||
},
|
||||
addSignatoryButtonDescription: {
|
||||
id: 'course-authoring.certificates.signatories.add.signatory.button.description',
|
||||
defaultMessage: '(Add signatories for a certificate)',
|
||||
description: 'Helper text for the button used to add signatories',
|
||||
},
|
||||
nameLabel: {
|
||||
id: 'course-authoring.certificates.signatories.name.label',
|
||||
defaultMessage: 'Name',
|
||||
description: 'Label for the input field where the signatory name is entered',
|
||||
},
|
||||
namePlaceholder: {
|
||||
id: 'course-authoring.certificates.signatories.name.placeholder',
|
||||
defaultMessage: 'Name of the signatory',
|
||||
description: 'Placeholder text for the signatory name input field',
|
||||
},
|
||||
nameDescription: {
|
||||
id: 'course-authoring.certificates.signatories.name.description',
|
||||
defaultMessage: 'The name of this signatory as it should appear on certificates.',
|
||||
description: 'Helper text under the name input field',
|
||||
},
|
||||
titleLabel: {
|
||||
id: 'course-authoring.certificates.signatories.title.label',
|
||||
defaultMessage: 'Title',
|
||||
description: 'Label for the input field where the signatory title is entered',
|
||||
},
|
||||
titlePlaceholder: {
|
||||
id: 'course-authoring.certificates.signatories.title.placeholder',
|
||||
defaultMessage: 'Title of the signatory',
|
||||
description: 'Placeholder text for the signatory title input field',
|
||||
},
|
||||
titleDescription: {
|
||||
id: 'course-authoring.certificates.signatories.title.description',
|
||||
defaultMessage: 'Titles more than 100 characters may prevent students from printing their certificate on a single page.',
|
||||
description: 'Helper text under the title input field',
|
||||
},
|
||||
organizationLabel: {
|
||||
id: 'course-authoring.certificates.signatories.organization.label',
|
||||
defaultMessage: 'Organization',
|
||||
description: 'Label for the input field where the signatory organization is entered',
|
||||
},
|
||||
organizationPlaceholder: {
|
||||
id: 'course-authoring.certificates.signatories.organization.placeholder',
|
||||
defaultMessage: 'Organization of the signatory',
|
||||
description: 'Placeholder text for the signatory organization input field',
|
||||
},
|
||||
organizationDescription: {
|
||||
id: 'course-authoring.certificates.signatories.organization.description',
|
||||
defaultMessage: 'The organization that this signatory belongs to, as it should appear on certificates.',
|
||||
description: 'Helper text under the organization input field',
|
||||
},
|
||||
imageLabel: {
|
||||
id: 'course-authoring.certificates.signatories.image.label',
|
||||
defaultMessage: 'Signature image',
|
||||
description: 'Label for the input field where the signatory image is selected',
|
||||
},
|
||||
imagePlaceholder: {
|
||||
id: 'course-authoring.certificates.signatories.image.placeholder',
|
||||
defaultMessage: 'Path to signature image',
|
||||
description: 'Placeholder text for the signatory image input field',
|
||||
},
|
||||
imageDescription: {
|
||||
id: 'course-authoring.certificates.signatories.image.description',
|
||||
defaultMessage: 'Image must be in PNG format',
|
||||
description: 'Helper text under the image input field',
|
||||
},
|
||||
uploadImageButton: {
|
||||
id: 'course-authoring.certificates.signatories.upload.image.button',
|
||||
defaultMessage: '{uploadText} signature image',
|
||||
description: 'Button text for adding or replacing a signature image',
|
||||
},
|
||||
uploadModal: {
|
||||
id: 'course-authoring.certificates.signatories.upload.modal',
|
||||
defaultMessage: 'Upload',
|
||||
description: 'Option for button text for adding a new signature image',
|
||||
},
|
||||
uploadModalReplace: {
|
||||
id: 'course-authoring.certificates.signatories.upload.modal.replace',
|
||||
defaultMessage: 'Replace',
|
||||
description: 'Option for button text for replacing an existing signature image',
|
||||
},
|
||||
deleteSignatoryConfirmation: {
|
||||
id: 'course-authoring.certificates.signatories.confirm-modal',
|
||||
defaultMessage: 'Delete "{name}" from the list of signatories?',
|
||||
description: 'Title for the confirmation modal when a user attempts to delete a signatory, where "{name}" is the name of the signatory to be deleted',
|
||||
},
|
||||
deleteSignatoryConfirmationMessage: {
|
||||
id: 'course-authoring.certificates.signatories.confirm-modal.message',
|
||||
defaultMessage: 'This action cannot be undone.',
|
||||
description: 'A warning message that emphasizes the permanence of the delete action for a signatory',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -0,0 +1,66 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Image, Icon, Stack, IconButtonWithTooltip,
|
||||
} from '@openedx/paragon';
|
||||
import {
|
||||
EditOutline as EditOutlineIcon,
|
||||
} from '@openedx/paragon/icons';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import commonMessages from '../../messages';
|
||||
import messages from '../messages';
|
||||
|
||||
const Signatory = ({
|
||||
index,
|
||||
name,
|
||||
title,
|
||||
organization,
|
||||
signatureImagePath,
|
||||
handleEdit,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<div className="bg-light-200 p-2.5 signatory" data-testid="signatory">
|
||||
<Stack className="signatory__header" gap={3}>
|
||||
<h3 className="section-title m-0">{`${intl.formatMessage(messages.signatoryTitle)} ${index + 1}`}</h3>
|
||||
<Stack className="signatory__text-fields-stack">
|
||||
<p className="signatory__text"><b>{intl.formatMessage(messages.nameLabel)}</b> {name}</p>
|
||||
<p className="signatory__text"><b>{intl.formatMessage(messages.titleLabel)}</b> {title}</p>
|
||||
<p className="signatory__text"><b>{intl.formatMessage(messages.organizationLabel)}</b> {organization}</p>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<IconButtonWithTooltip
|
||||
className="signatory__action-button"
|
||||
src={EditOutlineIcon}
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(commonMessages.editTooltip)}
|
||||
tooltipContent={<div>{intl.formatMessage(commonMessages.editTooltip)}</div>}
|
||||
onClick={handleEdit}
|
||||
/>
|
||||
<div className="signatory__image-container">
|
||||
{signatureImagePath && (
|
||||
<Image
|
||||
src={`${getConfig().STUDIO_BASE_URL}${signatureImagePath}`}
|
||||
fluid
|
||||
alt={intl.formatMessage(messages.imageLabel)}
|
||||
className="signatory__image"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Signatory.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
organization: PropTypes.string.isRequired,
|
||||
signatureImagePath: PropTypes.string.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
handleEdit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Signatory;
|
||||
@@ -0,0 +1,45 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { signatoriesMock } from '../../__mocks__';
|
||||
import commonMessages from '../../messages';
|
||||
import messages from '../messages';
|
||||
import Signatory from './Signatory';
|
||||
|
||||
const mockHandleEdit = jest.fn();
|
||||
|
||||
const renderSignatory = (props) => render(
|
||||
<IntlProvider locale="en">
|
||||
<Signatory {...props} />
|
||||
</IntlProvider>,
|
||||
);
|
||||
|
||||
const defaultProps = { ...signatoriesMock[0], handleEdit: mockHandleEdit, index: 0 };
|
||||
|
||||
describe('Signatory Component', () => {
|
||||
it('renders in MODE_STATES.view mode', () => {
|
||||
const {
|
||||
getByText, queryByText, getByAltText, getByRole,
|
||||
} = renderSignatory(defaultProps);
|
||||
const signatureImage = getByAltText(messages.imageLabel.defaultMessage);
|
||||
const sectionTitle = getByRole('heading', { level: 3, name: `${messages.signatoryTitle.defaultMessage} ${defaultProps.index + 1}` });
|
||||
|
||||
expect(sectionTitle).toBeInTheDocument();
|
||||
expect(getByText(defaultProps.name)).toBeInTheDocument();
|
||||
expect(getByText(defaultProps.title)).toBeInTheDocument();
|
||||
expect(getByText(defaultProps.organization)).toBeInTheDocument();
|
||||
expect(signatureImage).toBeInTheDocument();
|
||||
expect(signatureImage).toHaveAttribute('src', expect.stringContaining(defaultProps.signatureImagePath));
|
||||
expect(queryByText(messages.namePlaceholder.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls handleEdit when the edit button is clicked', () => {
|
||||
const { getByRole } = renderSignatory(defaultProps);
|
||||
|
||||
const editButton = getByRole('button', { name: commonMessages.editTooltip.defaultMessage });
|
||||
userEvent.click(editButton);
|
||||
|
||||
expect(mockHandleEdit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,200 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import {
|
||||
Image, Icon, Stack, IconButtonWithTooltip, FormLabel, Form, Button, useToggle,
|
||||
} from '@openedx/paragon';
|
||||
import { DeleteOutline as DeleteOutlineIcon } from '@openedx/paragon/icons';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import ModalDropzone from '../../../generic/modal-dropzone/ModalDropzone';
|
||||
import ModalNotification from '../../../generic/modal-notification';
|
||||
import { updateSavingImageStatus } from '../../data/slice';
|
||||
import commonMessages from '../../messages';
|
||||
import messages from '../messages';
|
||||
|
||||
const SignatoryForm = ({
|
||||
index,
|
||||
name,
|
||||
title,
|
||||
isEdit,
|
||||
handleBlur,
|
||||
organization,
|
||||
handleChange,
|
||||
setFieldValue,
|
||||
showDeleteButton,
|
||||
signatureImagePath,
|
||||
handleDeleteSignatory,
|
||||
handleCancelUpdateSignatory,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const [isOpen, open, close] = useToggle(false);
|
||||
const [isConfirmOpen, confirmOpen, confirmClose] = useToggle(false);
|
||||
|
||||
const handleImageUpload = (newImagePath) => {
|
||||
setFieldValue(`signatories[${index}].signatureImagePath`, newImagePath);
|
||||
};
|
||||
|
||||
const handleSavingStatusDispatch = (status) => {
|
||||
dispatch(updateSavingImageStatus(status));
|
||||
};
|
||||
|
||||
const formData = [
|
||||
{
|
||||
labelText: intl.formatMessage(messages.nameLabel),
|
||||
value: name,
|
||||
name: `signatories[${index}].name`,
|
||||
placeholder: intl.formatMessage(messages.namePlaceholder),
|
||||
feedback: intl.formatMessage(messages.nameDescription),
|
||||
onChange: handleChange,
|
||||
onBlur: handleBlur,
|
||||
},
|
||||
{
|
||||
as: 'textarea',
|
||||
labelText: intl.formatMessage(messages.titleLabel),
|
||||
value: title,
|
||||
name: `signatories[${index}].title`,
|
||||
placeholder: intl.formatMessage(messages.titlePlaceholder),
|
||||
feedback: intl.formatMessage(messages.titleDescription),
|
||||
onChange: handleChange,
|
||||
onBlur: handleBlur,
|
||||
},
|
||||
{
|
||||
labelText: intl.formatMessage(messages.organizationLabel),
|
||||
value: organization,
|
||||
name: `signatories[${index}].organization`,
|
||||
placeholder: intl.formatMessage(messages.organizationPlaceholder),
|
||||
feedback: intl.formatMessage(messages.organizationDescription),
|
||||
onChange: handleChange,
|
||||
onBlur: handleBlur,
|
||||
},
|
||||
];
|
||||
|
||||
const uploadReplaceText = intl.formatMessage(
|
||||
messages.uploadImageButton,
|
||||
{
|
||||
uploadText: signatureImagePath
|
||||
? intl.formatMessage(messages.uploadModalReplace)
|
||||
: intl.formatMessage(messages.uploadModal),
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="bg-light-200 p-2.5 signatory-form" data-testid="signatory-form">
|
||||
<Stack className="justify-content-between mb-4" direction="horizontal">
|
||||
<h3 className="section-title">{`${intl.formatMessage(messages.signatoryTitle)} ${index + 1}`}</h3>
|
||||
<Stack direction="horizontal" gap="2">
|
||||
{showDeleteButton && (
|
||||
<IconButtonWithTooltip
|
||||
src={DeleteOutlineIcon}
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(commonMessages.deleteTooltip)}
|
||||
tooltipContent={<div>{intl.formatMessage(commonMessages.deleteTooltip)}</div>}
|
||||
onClick={confirmOpen}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack gap="4">
|
||||
{formData.map(({ labelText, feedback, ...rest }) => (
|
||||
<Form.Group className="m-0" key={labelText}>
|
||||
<FormLabel>{labelText}</FormLabel>
|
||||
<Form.Control {...rest} className="m-0" />
|
||||
<Form.Control.Feedback>
|
||||
<span className="x-small">{feedback}</span>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
))}
|
||||
<Form.Group className="m-0">
|
||||
<FormLabel> {intl.formatMessage(messages.imageLabel)}</FormLabel>
|
||||
{signatureImagePath && (
|
||||
<Image
|
||||
src={`${getConfig().STUDIO_BASE_URL}${signatureImagePath}`}
|
||||
fluid
|
||||
alt={intl.formatMessage(messages.imageLabel)}
|
||||
className="signatory__image"
|
||||
/>
|
||||
)}
|
||||
<Stack direction="horizontal" className="align-items-baseline">
|
||||
<Stack>
|
||||
<Form.Control
|
||||
readOnly
|
||||
value={signatureImagePath}
|
||||
name={`signatories[${index}].signatureImagePath`}
|
||||
placeholder={intl.formatMessage(messages.imagePlaceholder)}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<span className="x-small">{intl.formatMessage(messages.imageDescription)}</span>
|
||||
</Form.Control.Feedback>
|
||||
</Stack>
|
||||
<Button onClick={open}>{uploadReplaceText}</Button>
|
||||
</Stack>
|
||||
</Form.Group>
|
||||
</Stack>
|
||||
{isEdit && (
|
||||
<Stack direction="horizontal" gap="2" className="mt-4">
|
||||
<Button type="submit">
|
||||
{intl.formatMessage(commonMessages.saveTooltip)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
onClick={() => handleCancelUpdateSignatory()}
|
||||
>
|
||||
{intl.formatMessage(commonMessages.cardCancel)}
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<ModalDropzone
|
||||
isOpen={isOpen}
|
||||
onClose={close}
|
||||
onCancel={close}
|
||||
onChange={handleImageUpload}
|
||||
fileTypes={['png']}
|
||||
onSavingStatus={handleSavingStatusDispatch}
|
||||
imageHelpText={intl.formatMessage(messages.imageDescription)}
|
||||
modalTitle={uploadReplaceText}
|
||||
/>
|
||||
<ModalNotification
|
||||
isOpen={isConfirmOpen}
|
||||
title={intl.formatMessage(messages.deleteSignatoryConfirmation, { name })}
|
||||
message={intl.formatMessage(messages.deleteSignatoryConfirmationMessage)}
|
||||
actionButtonText={intl.formatMessage(commonMessages.deleteTooltip)}
|
||||
cancelButtonText={intl.formatMessage(commonMessages.cardCancel)}
|
||||
handleCancel={confirmClose}
|
||||
handleAction={() => {
|
||||
confirmClose();
|
||||
handleDeleteSignatory();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
SignatoryForm.defaultProps = {
|
||||
isEdit: false,
|
||||
handleChange: null,
|
||||
handleBlur: null,
|
||||
handleDeleteSignatory: null,
|
||||
setFieldValue: null,
|
||||
handleCancelUpdateSignatory: null,
|
||||
};
|
||||
|
||||
SignatoryForm.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
organization: PropTypes.string.isRequired,
|
||||
showDeleteButton: PropTypes.bool.isRequired,
|
||||
signatureImagePath: PropTypes.string.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
isEdit: PropTypes.bool,
|
||||
handleChange: PropTypes.func,
|
||||
handleBlur: PropTypes.func,
|
||||
setFieldValue: PropTypes.func,
|
||||
handleDeleteSignatory: PropTypes.func,
|
||||
handleCancelUpdateSignatory: PropTypes.func,
|
||||
};
|
||||
|
||||
export default SignatoryForm;
|
||||
@@ -0,0 +1,161 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { Provider } from 'react-redux';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
|
||||
import initializeStore from '../../../store';
|
||||
import { signatoriesMock } from '../../__mocks__';
|
||||
import commonMessages from '../../messages';
|
||||
import messages from '../messages';
|
||||
import SignatoryForm from './SignatoryForm';
|
||||
|
||||
let store;
|
||||
|
||||
const renderSignatory = (props) => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<SignatoryForm {...props} />
|
||||
</IntlProvider>,
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {
|
||||
certificates: [],
|
||||
hasCertificateModes: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
...signatoriesMock[0],
|
||||
showDeleteButton: true,
|
||||
isEdit: true,
|
||||
handleChange: jest.fn(),
|
||||
handleBlur: jest.fn(),
|
||||
setFieldValue: jest.fn(),
|
||||
handleDeleteSignatory: jest.fn(),
|
||||
handleCancelUpdateSignatory: jest.fn(),
|
||||
};
|
||||
|
||||
describe('Signatory Component', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
});
|
||||
it('renders in CREATE mode', () => {
|
||||
const { queryByTestId, getByPlaceholderText } = renderSignatory(defaultProps);
|
||||
|
||||
expect(queryByTestId('signatory-view')).not.toBeInTheDocument();
|
||||
expect(getByPlaceholderText(messages.namePlaceholder.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles input change', async () => {
|
||||
const handleChange = jest.fn();
|
||||
const { getByPlaceholderText } = renderSignatory({ ...defaultProps, handleChange });
|
||||
const input = getByPlaceholderText(messages.namePlaceholder.defaultMessage);
|
||||
const newInputValue = 'Jane Doe';
|
||||
|
||||
userEvent.type(input, newInputValue, { name: 'signatories[0].name' });
|
||||
|
||||
waitFor(() => {
|
||||
expect(handleChange).toHaveBeenCalledWith(expect.anything());
|
||||
expect(input.value).toBe(newInputValue);
|
||||
});
|
||||
});
|
||||
|
||||
it('opens image upload modal on button click', () => {
|
||||
const { getByRole, queryByRole } = renderSignatory(defaultProps);
|
||||
const replaceButton = getByRole(
|
||||
'button',
|
||||
{ name: messages.uploadImageButton.defaultMessage.replace('{uploadText}', messages.uploadModalReplace.defaultMessage) },
|
||||
);
|
||||
|
||||
expect(queryByRole('presentation')).not.toBeInTheDocument();
|
||||
|
||||
userEvent.click(replaceButton);
|
||||
|
||||
expect(getByRole('presentation')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows confirm modal on delete icon click', async () => {
|
||||
const { getByLabelText, getByText } = renderSignatory(defaultProps);
|
||||
const deleteIcon = getByLabelText(commonMessages.deleteTooltip.defaultMessage);
|
||||
|
||||
userEvent.click(deleteIcon);
|
||||
|
||||
expect(getByText(messages.deleteSignatoryConfirmationMessage.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('cancels deletion of a signatory', () => {
|
||||
const { getByRole } = renderSignatory(defaultProps);
|
||||
|
||||
const deleteIcon = getByRole('button', { name: commonMessages.deleteTooltip.defaultMessage });
|
||||
userEvent.click(deleteIcon);
|
||||
|
||||
const cancelButton = getByRole('button', { name: commonMessages.cardCancel.defaultMessage });
|
||||
userEvent.click(cancelButton);
|
||||
|
||||
expect(defaultProps.handleDeleteSignatory).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders without save button with isEdit=false', () => {
|
||||
const { queryByRole } = renderSignatory({ ...defaultProps, isEdit: false });
|
||||
|
||||
const deleteIcon = queryByRole('button', { name: commonMessages.saveTooltip.defaultMessage });
|
||||
|
||||
expect(deleteIcon).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders button with Replace text if there is a signatureImagePath', () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
isEdit: false,
|
||||
};
|
||||
|
||||
const { getByRole, queryByRole } = renderSignatory(newProps);
|
||||
|
||||
const replaceButton = getByRole(
|
||||
'button',
|
||||
{ name: messages.uploadImageButton.defaultMessage.replace('{uploadText}', messages.uploadModalReplace.defaultMessage) },
|
||||
);
|
||||
const uploadButton = queryByRole(
|
||||
'button',
|
||||
{ name: messages.uploadImageButton.defaultMessage.replace('{uploadText}', messages.uploadModal.defaultMessage) },
|
||||
);
|
||||
|
||||
expect(replaceButton).toBeInTheDocument();
|
||||
expect(uploadButton).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders button with Upload text if there is no signatureImagePath', () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
signatureImagePath: '',
|
||||
isEdit: false,
|
||||
};
|
||||
|
||||
const { getByRole, queryByRole } = renderSignatory(newProps);
|
||||
|
||||
const uploadButton = getByRole(
|
||||
'button',
|
||||
{ name: messages.uploadImageButton.defaultMessage.replace('{uploadText}', messages.uploadModal.defaultMessage) },
|
||||
);
|
||||
const replaceButton = queryByRole(
|
||||
'button',
|
||||
{ name: messages.uploadImageButton.defaultMessage.replace('{uploadText}', messages.uploadModalReplace.defaultMessage) },
|
||||
);
|
||||
|
||||
expect(uploadButton).toBeInTheDocument();
|
||||
expect(replaceButton).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Card } from '@openedx/paragon';
|
||||
|
||||
import messages from '../messages';
|
||||
|
||||
const CertificateWithoutModes = () => {
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Card>
|
||||
<Card.Section className="d-flex justify-content-center">
|
||||
<span className="small">{intl.formatMessage(messages.withoutModesText)}</span>
|
||||
</Card.Section>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CertificateWithoutModes;
|
||||
@@ -0,0 +1,43 @@
|
||||
import { render, waitFor } 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 WithoutModes from './CertificateWithoutModes';
|
||||
|
||||
const courseId = 'course-123';
|
||||
let store;
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<AppProvider store={store} messages={{}}>
|
||||
<IntlProvider locale="en">
|
||||
<WithoutModes courseId={courseId} {...props} />
|
||||
</IntlProvider>
|
||||
</AppProvider>,
|
||||
);
|
||||
|
||||
describe('CertificateWithoutModes', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
});
|
||||
|
||||
it('renders correctly', async () => {
|
||||
const { getByText, queryByText } = renderComponent();
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.withoutModesText.defaultMessage)).toBeInTheDocument();
|
||||
|
||||
expect(queryByText(messages.headingActionsPreview.defaultMessage)).not.toBeInTheDocument();
|
||||
expect(queryByText(messages.headingActionsDeactivate.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
69
src/certificates/certificates-list/CertificatesList.jsx
Normal file
69
src/certificates/certificates-list/CertificatesList.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card, Stack } from '@openedx/paragon';
|
||||
import { Formik, Form, FieldArray } from 'formik';
|
||||
|
||||
import CertificateDetails from '../certificate-details/CertificateDetails';
|
||||
import CertificateSignatories from '../certificate-signatories/CertificateSignatories';
|
||||
import useCertificatesList from './hooks/useCertificatesList';
|
||||
|
||||
const CertificatesList = ({ courseId }) => {
|
||||
const {
|
||||
editModes,
|
||||
courseTitle,
|
||||
certificates,
|
||||
courseNumber,
|
||||
initialValues,
|
||||
courseNumberOverride,
|
||||
setEditModes,
|
||||
handleSubmit,
|
||||
} = useCertificatesList(courseId);
|
||||
|
||||
return (
|
||||
<>
|
||||
{certificates.map((certificate, idx) => (
|
||||
<Formik initialValues={initialValues[idx]} onSubmit={handleSubmit} key={certificate.id}>
|
||||
{({
|
||||
values, handleChange, handleBlur, setFieldValue,
|
||||
}) => (
|
||||
<Form className="certificates-card-form" data-testid="certificates-list">
|
||||
<Card>
|
||||
<Card.Section>
|
||||
<Stack gap="2">
|
||||
<CertificateDetails
|
||||
detailsCourseTitle={courseTitle}
|
||||
detailsCourseNumber={courseNumber}
|
||||
courseNumberOverride={courseNumberOverride}
|
||||
courseTitleOverride={certificate.courseTitle}
|
||||
certificateId={certificate.id}
|
||||
/>
|
||||
<FieldArray
|
||||
name="signatories"
|
||||
render={arrayHelpers => (
|
||||
<CertificateSignatories
|
||||
signatories={values.signatories}
|
||||
arrayHelpers={arrayHelpers}
|
||||
editModes={editModes}
|
||||
initialSignatoriesValues={initialValues[idx].signatories}
|
||||
handleChange={handleChange}
|
||||
handleBlur={handleBlur}
|
||||
setFieldValue={setFieldValue}
|
||||
setEditModes={setEditModes}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
</Card.Section>
|
||||
</Card>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
CertificatesList.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CertificatesList;
|
||||
133
src/certificates/certificates-list/CertificatesList.test.jsx
Normal file
133
src/certificates/certificates-list/CertificatesList.test.jsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import { Provider } from 'react-redux';
|
||||
import { render, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { executeThunk } from '../../utils';
|
||||
import initializeStore from '../../store';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import { getCertificatesApiUrl, getUpdateCertificateApiUrl } from '../data/api';
|
||||
import { fetchCertificates, updateCourseCertificate } from '../data/thunks';
|
||||
import { certificatesMock, certificatesDataMock } from '../__mocks__';
|
||||
import signatoryMessages from '../certificate-signatories/messages';
|
||||
import messages from '../messages';
|
||||
import CertificatesList from './CertificatesList';
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
const courseId = 'course-123';
|
||||
|
||||
const renderComponent = () => render(
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificatesList courseId="course-123" />
|
||||
</IntlProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
describe('CertificatesList Component', () => {
|
||||
beforeEach(async () => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, {
|
||||
...certificatesDataMock,
|
||||
certificates: certificatesMock,
|
||||
});
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
});
|
||||
|
||||
it('renders each certificate', () => {
|
||||
const { getByText } = renderComponent();
|
||||
|
||||
certificatesMock.forEach((certificate) => {
|
||||
certificate.signatories.forEach((signatory) => {
|
||||
expect(getByText(signatory.name)).toBeInTheDocument();
|
||||
expect(getByText(signatory.title)).toBeInTheDocument();
|
||||
expect(getByText(signatory.organization)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('update certificate', async () => {
|
||||
const {
|
||||
getByText, queryByText, getByPlaceholderText, getByRole, getAllByLabelText,
|
||||
} = renderComponent();
|
||||
|
||||
const signatoryNameValue = 'Updated signatory name';
|
||||
const newCertificateData = {
|
||||
...certificatesDataMock,
|
||||
certificates: [{
|
||||
...certificatesMock[0],
|
||||
signatories: [{
|
||||
...certificatesMock[0].signatories[0],
|
||||
name: signatoryNameValue,
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
const editButtons = getAllByLabelText(messages.editTooltip.defaultMessage);
|
||||
|
||||
userEvent.click(editButtons[1]);
|
||||
|
||||
const nameInput = getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage);
|
||||
userEvent.clear(nameInput);
|
||||
userEvent.type(nameInput, signatoryNameValue);
|
||||
|
||||
userEvent.click(getByRole('button', { name: messages.saveTooltip.defaultMessage }));
|
||||
|
||||
axiosMock
|
||||
.onPost(getUpdateCertificateApiUrl(courseId, certificatesMock.id))
|
||||
.reply(200, newCertificateData);
|
||||
await executeThunk(updateCourseCertificate(courseId, newCertificateData), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText(newCertificateData.certificates[0].signatories[0].name)).toBeInTheDocument();
|
||||
expect(queryByText(certificatesDataMock.certificates[0].signatories[0].name)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('toggle edit signatory', async () => {
|
||||
const {
|
||||
getAllByLabelText, queryByPlaceholderText, getByTestId, getByPlaceholderText,
|
||||
} = renderComponent();
|
||||
const editButtons = getAllByLabelText(messages.editTooltip.defaultMessage);
|
||||
|
||||
expect(editButtons.length).toBe(3);
|
||||
|
||||
userEvent.click(editButtons[1]);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
userEvent.click(within(getByTestId('signatory-form')).getByRole('button', { name: messages.cardCancel.defaultMessage }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByPlaceholderText(signatoryMessages.namePlaceholder.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('toggle certificate edit all', async () => {
|
||||
const { getByTestId } = renderComponent();
|
||||
const detailsSection = getByTestId('certificate-details');
|
||||
const editButton = within(detailsSection).getByLabelText(messages.editTooltip.defaultMessage);
|
||||
userEvent.click(editButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getState().certificates.componentMode).toBe(MODE_STATES.editAll);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useState } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
|
||||
import { MODE_STATES } from '../../data/constants';
|
||||
import {
|
||||
getCourseTitle, getCourseNumber, getCourseNumberOverride, getCertificates,
|
||||
} from '../../data/selectors';
|
||||
import { updateCourseCertificate } from '../../data/thunks';
|
||||
import { setMode } from '../../data/slice';
|
||||
import { defaultCertificate } from '../../constants';
|
||||
|
||||
const useCertificatesList = (courseId) => {
|
||||
const dispatch = useDispatch();
|
||||
const certificates = useSelector(getCertificates);
|
||||
const courseTitle = useSelector(getCourseTitle);
|
||||
const courseNumber = useSelector(getCourseNumber);
|
||||
const courseNumberOverride = useSelector(getCourseNumberOverride);
|
||||
|
||||
const [editModes, setEditModes] = useState({});
|
||||
|
||||
const initialValues = certificates.map((certificate) => ({
|
||||
...certificate,
|
||||
courseTitle: certificate.courseTitle || defaultCertificate.courseTitle,
|
||||
signatories: certificate.signatories || defaultCertificate.signatories,
|
||||
}));
|
||||
|
||||
const handleSubmit = async (values) => {
|
||||
await dispatch(updateCourseCertificate(courseId, values));
|
||||
setEditModes({});
|
||||
dispatch(setMode(MODE_STATES.view));
|
||||
};
|
||||
|
||||
return {
|
||||
editModes,
|
||||
courseTitle,
|
||||
certificates,
|
||||
courseNumber,
|
||||
initialValues,
|
||||
courseNumberOverride,
|
||||
setEditModes,
|
||||
handleSubmit,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCertificatesList;
|
||||
13
src/certificates/constants.js
Normal file
13
src/certificates/constants.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const defaultCertificate = {
|
||||
courseTitle: '',
|
||||
signatories: [{
|
||||
id: `local-${uuid()}`,
|
||||
name: '',
|
||||
title: '',
|
||||
organization: '',
|
||||
signatureImagePath: '',
|
||||
}],
|
||||
};
|
||||
89
src/certificates/data/api.js
Normal file
89
src/certificates/data/api.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { prepareCertificatePayload } from '../utils';
|
||||
|
||||
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
|
||||
|
||||
export const getCertificatesApiUrl = (courseId) => `${getApiBaseUrl()}/api/contentstore/v1/certificates/${courseId}`;
|
||||
export const getCertificateApiUrl = (courseId) => `${getApiBaseUrl()}/certificates/${courseId}`;
|
||||
export const getUpdateCertificateApiUrl = (courseId, certificateId) => `${getCertificateApiUrl(courseId)}/${certificateId}`;
|
||||
export const getUpdateCertificateActiveStatusApiUrl = (path) => `${getApiBaseUrl()}${path}`;
|
||||
|
||||
/**
|
||||
* Gets certificates for a course.
|
||||
* @param {string} courseId
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function getCertificates(courseId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(getCertificatesApiUrl(courseId));
|
||||
|
||||
return camelCaseObject(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create course certificate.
|
||||
* @param {string} courseId
|
||||
* @param {object} certificatesData
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
|
||||
export async function createCertificate(courseId, certificatesData) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(
|
||||
getCertificateApiUrl(courseId),
|
||||
prepareCertificatePayload(certificatesData),
|
||||
);
|
||||
|
||||
return camelCaseObject(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update course certificate.
|
||||
* @param {string} courseId
|
||||
* @param {object} certificateData
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function updateCertificate(courseId, certificateData) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(
|
||||
getUpdateCertificateApiUrl(courseId, certificateData.id),
|
||||
prepareCertificatePayload(certificateData),
|
||||
);
|
||||
return camelCaseObject(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete course certificate.
|
||||
* @param {string} courseId
|
||||
* @param {object} certificateId
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function deleteCertificate(courseId, certificateId) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.delete(
|
||||
getUpdateCertificateApiUrl(courseId, certificateId),
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate/deactivate course certificate.
|
||||
* @param {string} courseId
|
||||
* @param {object} activationStatus
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export async function updateActiveStatus(path, activationStatus) {
|
||||
const body = {
|
||||
is_active: activationStatus,
|
||||
};
|
||||
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(
|
||||
getUpdateCertificateActiveStatusApiUrl(path),
|
||||
body,
|
||||
);
|
||||
return camelCaseObject(data);
|
||||
}
|
||||
12
src/certificates/data/constants.js
Normal file
12
src/certificates/data/constants.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export const MODE_STATES = {
|
||||
noModes: 'no_modes',
|
||||
noCertificates: 'no_certificates',
|
||||
view: 'view',
|
||||
editAll: 'edit_all',
|
||||
create: 'create',
|
||||
};
|
||||
|
||||
export const ACTIVATION_MESSAGES = {
|
||||
activating: 'Activating',
|
||||
deactivating: 'Deactivating',
|
||||
};
|
||||
22
src/certificates/data/selectors.js
Normal file
22
src/certificates/data/selectors.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
export const getLoadingStatus = (state) => state.certificates.loadingStatus;
|
||||
export const getSavingStatus = (state) => state.certificates.savingStatus;
|
||||
export const getSavingImageStatus = (state) => state.certificates.savingImageStatus;
|
||||
export const getErrorMessage = (state) => state.certificates.errorMessage;
|
||||
export const getSendRequestErrors = (state) => state.certificates.sendRequestErrors.developer_message;
|
||||
export const getCertificates = state => state.certificates.certificatesData.certificates;
|
||||
export const getHasCertificateModes = state => state.certificates.certificatesData.hasCertificateModes;
|
||||
export const getCourseModes = state => state.certificates.certificatesData.courseModes;
|
||||
export const getCertificateActivationUrl = state => state.certificates.certificatesData.certificateActivationHandlerUrl;
|
||||
export const getCertificateWebViewUrl = state => state.certificates.certificatesData.certificateWebViewUrl;
|
||||
export const getIsCertificateActive = state => state.certificates.certificatesData.isActive;
|
||||
export const getComponentMode = state => state.certificates.componentMode;
|
||||
export const getCourseNumber = state => state.certificates.certificatesData.courseNumber;
|
||||
export const getCourseNumberOverride = state => state.certificates.certificatesData.courseNumberOverride;
|
||||
export const getCourseTitle = state => state.certificates.certificatesData.courseTitle;
|
||||
|
||||
export const getHasCertificates = createSelector(
|
||||
[getCertificates],
|
||||
(certificates) => certificates && certificates.length > 0,
|
||||
);
|
||||
62
src/certificates/data/slice.js
Normal file
62
src/certificates/data/slice.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import { MODE_STATES } from './constants';
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'certificates',
|
||||
initialState: {
|
||||
certificatesData: {},
|
||||
componentMode: MODE_STATES.noModes,
|
||||
loadingStatus: RequestStatus.PENDING,
|
||||
savingStatus: '',
|
||||
savingImageStatus: '',
|
||||
errorMessage: '',
|
||||
},
|
||||
reducers: {
|
||||
updateSavingStatus: (state, { payload }) => {
|
||||
const { status, errorMessage } = payload;
|
||||
state.savingStatus = status;
|
||||
state.errorMessage = errorMessage;
|
||||
},
|
||||
updateSavingImageStatus: (state, { payload }) => {
|
||||
state.savingImageStatus = payload.status;
|
||||
},
|
||||
updateLoadingStatus: (state, { payload }) => {
|
||||
state.loadingStatus = payload.status;
|
||||
},
|
||||
fetchCertificatesSuccess: (state, { payload }) => {
|
||||
Object.assign(state.certificatesData, payload);
|
||||
},
|
||||
createCertificateSuccess: (state, action) => {
|
||||
state.certificatesData.certificates.push(action.payload);
|
||||
},
|
||||
updateCertificateSuccess: (state, action) => {
|
||||
const index = state.certificatesData.certificates.findIndex(c => c.id === action.payload.id);
|
||||
|
||||
if (index !== -1) {
|
||||
state.certificatesData.certificates[index] = action.payload;
|
||||
}
|
||||
},
|
||||
setMode: (state, action) => {
|
||||
state.componentMode = action.payload;
|
||||
},
|
||||
deleteCertificateSuccess: (state) => {
|
||||
state.certificatesData.certificates = [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setMode,
|
||||
updateSavingStatus,
|
||||
updateLoadingStatus,
|
||||
updateSavingImageStatus,
|
||||
fetchCertificatesSuccess,
|
||||
createCertificateSuccess,
|
||||
updateCertificateSuccess,
|
||||
deleteCertificateSuccess,
|
||||
} = slice.actions;
|
||||
|
||||
export const { reducer } = slice;
|
||||
117
src/certificates/data/thunks.js
Normal file
117
src/certificates/data/thunks.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import {
|
||||
hideProcessingNotification,
|
||||
showProcessingNotification,
|
||||
} from '../../generic/processing-notification/data/slice';
|
||||
import { handleResponseErrors } from '../../generic/saving-error-alert';
|
||||
import { NOTIFICATION_MESSAGES } from '../../constants';
|
||||
import {
|
||||
getCertificates,
|
||||
createCertificate,
|
||||
updateCertificate,
|
||||
deleteCertificate,
|
||||
updateActiveStatus,
|
||||
} from './api';
|
||||
import {
|
||||
fetchCertificatesSuccess,
|
||||
updateLoadingStatus,
|
||||
updateSavingStatus,
|
||||
createCertificateSuccess,
|
||||
updateCertificateSuccess,
|
||||
deleteCertificateSuccess,
|
||||
} from './slice';
|
||||
import { ACTIVATION_MESSAGES } from './constants';
|
||||
|
||||
export function fetchCertificates(courseId) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateLoadingStatus({ status: RequestStatus.IN_PROGRESS }));
|
||||
|
||||
try {
|
||||
const certificates = await getCertificates(courseId);
|
||||
|
||||
dispatch(fetchCertificatesSuccess(certificates));
|
||||
dispatch(updateLoadingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
} catch (error) {
|
||||
if (error.response && error.response.status === 403) {
|
||||
dispatch(updateLoadingStatus({ courseId, status: RequestStatus.DENIED }));
|
||||
} else {
|
||||
dispatch(updateLoadingStatus({ courseId, status: RequestStatus.FAILED }));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createCourseCertificate(courseId, certificate) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving));
|
||||
|
||||
try {
|
||||
const certificateValues = await createCertificate(courseId, certificate);
|
||||
dispatch(createCertificateSuccess(certificateValues));
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
return true;
|
||||
} catch (error) {
|
||||
return handleResponseErrors(error, dispatch, updateSavingStatus);
|
||||
} finally {
|
||||
dispatch(hideProcessingNotification());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateCourseCertificate(courseId, certificate) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.saving));
|
||||
|
||||
try {
|
||||
const certificatesValues = await updateCertificate(courseId, certificate);
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
dispatch(updateCertificateSuccess(certificatesValues));
|
||||
return true;
|
||||
} catch (error) {
|
||||
return handleResponseErrors(error, dispatch, updateSavingStatus);
|
||||
} finally {
|
||||
dispatch(hideProcessingNotification());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteCourseCertificate(courseId, certificateId) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.PENDING }));
|
||||
dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.deleting));
|
||||
|
||||
try {
|
||||
const certificatesValues = await deleteCertificate(courseId, certificateId);
|
||||
dispatch(deleteCertificateSuccess(certificatesValues));
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
return true;
|
||||
} catch (error) {
|
||||
return handleResponseErrors(error, dispatch, updateSavingStatus);
|
||||
} finally {
|
||||
dispatch(hideProcessingNotification());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function updateCertificateActiveStatus(courseId, path, activationStatus) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.PENDING }));
|
||||
|
||||
dispatch(showProcessingNotification(
|
||||
activationStatus ? ACTIVATION_MESSAGES.activating : ACTIVATION_MESSAGES.deactivating,
|
||||
));
|
||||
|
||||
try {
|
||||
await updateActiveStatus(path, activationStatus);
|
||||
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
|
||||
dispatch(fetchCertificates(courseId));
|
||||
return true;
|
||||
} catch (error) {
|
||||
return handleResponseErrors(error, dispatch, updateSavingStatus);
|
||||
} finally {
|
||||
dispatch(hideProcessingNotification());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Button, ActionRow, Card } from '@openedx/paragon';
|
||||
import { Add as AddIcon } from '@openedx/paragon/icons';
|
||||
|
||||
import { setMode } from '../data/slice';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
import messages from '../messages';
|
||||
|
||||
const EmptyCertificatesWithModes = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleCreateMode = () => {
|
||||
dispatch(setMode(MODE_STATES.create));
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card.Section>
|
||||
<ActionRow>
|
||||
<span className="small">{intl.formatMessage(messages.noCertificatesText)}</span>
|
||||
<ActionRow.Spacer />
|
||||
<Button
|
||||
iconBefore={AddIcon}
|
||||
onClick={handleCreateMode}
|
||||
>
|
||||
{intl.formatMessage(messages.setupCertificateBtn)}
|
||||
</Button>
|
||||
</ActionRow>
|
||||
</Card.Section>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyCertificatesWithModes;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { render, waitFor } 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 WithModesWithoutCertificates from './EmptyCertificatesWithModes';
|
||||
|
||||
const courseId = 'course-123';
|
||||
let store;
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<AppProvider store={store} messages={{}}>
|
||||
<IntlProvider locale="en">
|
||||
<WithModesWithoutCertificates courseId={courseId} {...props} />
|
||||
</IntlProvider>
|
||||
</AppProvider>,
|
||||
);
|
||||
|
||||
describe('EmptyCertificatesWithModes', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
});
|
||||
|
||||
it('renders correctly', async () => {
|
||||
const { getByText, queryByText } = renderComponent();
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.noCertificatesText.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.setupCertificateBtn.defaultMessage)).toBeInTheDocument();
|
||||
|
||||
expect(queryByText(messages.headingActionsPreview.defaultMessage)).not.toBeInTheDocument();
|
||||
expect(queryByText(messages.headingActionsDeactivate.defaultMessage)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
49
src/certificates/hooks/useCertificates.jsx
Normal file
49
src/certificates/hooks/useCertificates.jsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import getPageHeadTitle from '../../generic/utils';
|
||||
import {
|
||||
getComponentMode, getLoadingStatus, getCertificates, getHasCertificateModes, getCourseTitle,
|
||||
} from '../data/selectors';
|
||||
import { setMode } from '../data/slice';
|
||||
import { fetchCertificates } from '../data/thunks';
|
||||
import { MODE_STATES } from '../data/constants';
|
||||
|
||||
import messages from '../messages';
|
||||
|
||||
const useCertificates = ({ courseId }) => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const componentMode = useSelector(getComponentMode);
|
||||
const certificates = useSelector(getCertificates);
|
||||
const loadingStatus = useSelector(getLoadingStatus);
|
||||
const hasCertificateModes = useSelector(getHasCertificateModes);
|
||||
const courseTitle = useSelector(getCourseTitle);
|
||||
|
||||
const isLoading = useMemo(() => loadingStatus === RequestStatus.IN_PROGRESS, [loadingStatus]);
|
||||
|
||||
const pageHeadTitle = getPageHeadTitle(courseTitle, intl.formatMessage(messages.headingTitleTabText));
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasCertificateModes) {
|
||||
dispatch(setMode(MODE_STATES.noModes));
|
||||
} else if (certificates.length === 0) {
|
||||
dispatch(setMode(MODE_STATES.noCertificates));
|
||||
} else {
|
||||
dispatch(setMode(MODE_STATES.view));
|
||||
}
|
||||
}, [hasCertificateModes, certificates]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchCertificates(courseId));
|
||||
}, [courseId]);
|
||||
|
||||
return {
|
||||
componentMode, isLoading, loadingStatus, certificates, pageHeadTitle, hasCertificateModes,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCertificates;
|
||||
2
src/certificates/index.js
Normal file
2
src/certificates/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
export { default as Certificates } from './Certificates';
|
||||
77
src/certificates/layout/MainLayout.jsx
Normal file
77
src/certificates/layout/MainLayout.jsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { Container, Layout } from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { SavingErrorAlert } from '../../generic/saving-error-alert';
|
||||
import ProcessingNotification from '../../generic/processing-notification';
|
||||
import SubHeader from '../../generic/sub-header/SubHeader';
|
||||
import messages from '../messages';
|
||||
import CertificatesSidebar from './certificates-sidebar/CertificatesSidebar';
|
||||
import HeaderButtons from './header-buttons/HeaderButtons';
|
||||
import useLayout from './hooks/useLayout';
|
||||
|
||||
const MainLayout = ({ courseId, showHeaderButtons, children }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
errorMessage,
|
||||
savingStatus,
|
||||
isShowProcessingNotification,
|
||||
processingNotificationTitle,
|
||||
} = useLayout();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container size="xl" className="certificates px-4">
|
||||
<div className="mt-5" />
|
||||
<SubHeader
|
||||
hideBorder
|
||||
title={intl.formatMessage(messages.headingTitle)}
|
||||
subtitle={intl.formatMessage(messages.headingSubtitle)}
|
||||
headerActions={showHeaderButtons && <HeaderButtons />}
|
||||
/>
|
||||
<section>
|
||||
<Layout
|
||||
lg={[{ span: 9 }, { span: 3 }]}
|
||||
md={[{ span: 9 }, { span: 3 }]}
|
||||
sm={[{ span: 9 }, { span: 3 }]}
|
||||
xs={[{ span: 9 }, { span: 3 }]}
|
||||
xl={[{ span: 9 }, { span: 3 }]}
|
||||
>
|
||||
<Layout.Element>
|
||||
<article role="main">
|
||||
{children}
|
||||
</article>
|
||||
</Layout.Element>
|
||||
<Layout.Element>
|
||||
<CertificatesSidebar courseId={courseId} />
|
||||
</Layout.Element>
|
||||
</Layout>
|
||||
</section>
|
||||
</Container>
|
||||
<div className="certificates alert-toast">
|
||||
<ProcessingNotification
|
||||
isShow={isShowProcessingNotification}
|
||||
title={processingNotificationTitle}
|
||||
/>
|
||||
<SavingErrorAlert
|
||||
savingStatus={savingStatus}
|
||||
errorMessage={errorMessage}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
MainLayout.defaultProps = {
|
||||
showHeaderButtons: false,
|
||||
children: null,
|
||||
};
|
||||
|
||||
MainLayout.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
showHeaderButtons: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default MainLayout;
|
||||
@@ -0,0 +1,45 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Button, Hyperlink } from '@openedx/paragon';
|
||||
|
||||
import { HelpSidebar } from '../../../generic/help-sidebar';
|
||||
import { useHelpUrls } from '../../../help-urls/hooks';
|
||||
import { getSidebarData } from './utils';
|
||||
import SidebarBlock from './sidebar-block/SidebarBlock';
|
||||
import messages from './messages';
|
||||
|
||||
const CertificatesSidebar = ({ courseId }) => {
|
||||
const intl = useIntl();
|
||||
const { certificates: learnMoreCertificates } = useHelpUrls(['certificates']);
|
||||
return (
|
||||
<HelpSidebar
|
||||
courseId={courseId}
|
||||
showOtherSettings
|
||||
>
|
||||
{getSidebarData({ messages, intl }).map(({ title, paragraphs }, id) => (
|
||||
<SidebarBlock
|
||||
key={title}
|
||||
title={title}
|
||||
paragraphs={paragraphs}
|
||||
isLast={id === getSidebarData({ messages, intl }).length - 1}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
as={Hyperlink}
|
||||
target="_blank"
|
||||
showLaunchIcon={false}
|
||||
size="sm"
|
||||
href={learnMoreCertificates}
|
||||
variant="outline-primary"
|
||||
>
|
||||
{intl.formatMessage(messages.learnMoreBtn)}
|
||||
</Button>
|
||||
</HelpSidebar>
|
||||
);
|
||||
};
|
||||
|
||||
CertificatesSidebar.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default CertificatesSidebar;
|
||||
@@ -0,0 +1,56 @@
|
||||
import { render, waitFor } 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 CertificatesSidebar from './CertificatesSidebar';
|
||||
import messages from './messages';
|
||||
|
||||
const courseId = 'course-123';
|
||||
let store;
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
...jest.requireActual('@edx/frontend-platform/i18n'),
|
||||
useIntl: () => ({
|
||||
formatMessage: (message) => message.defaultMessage,
|
||||
}),
|
||||
}));
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<AppProvider store={store} messages={{}}>
|
||||
<IntlProvider locale="en">
|
||||
<CertificatesSidebar courseId={courseId} {...props} />
|
||||
</IntlProvider>
|
||||
</AppProvider>,
|
||||
);
|
||||
|
||||
describe('CertificatesSidebar', () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore();
|
||||
});
|
||||
|
||||
it('renders correctly', async () => {
|
||||
const { getByText } = renderComponent();
|
||||
await waitFor(() => {
|
||||
expect(getByText(messages.workingWithCertificatesTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.workingWithCertificatesFirstParagraph.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.workingWithCertificatesSecondParagraph.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.workingWithCertificatesThirdParagraph.defaultMessage)).toBeInTheDocument();
|
||||
|
||||
expect(getByText(messages.issuingCertificatesTitle.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.issuingCertificatesFirstParagraph.defaultMessage)).toBeInTheDocument();
|
||||
expect(getByText(messages.issuingCertificatesSecondParagraph.defaultMessage)).toBeInTheDocument();
|
||||
|
||||
expect(getByText(messages.learnMoreBtn.defaultMessage)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
66
src/certificates/layout/certificates-sidebar/messages.js
Normal file
66
src/certificates/layout/certificates-sidebar/messages.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
workingWithCertificatesTitle: {
|
||||
id: 'course-authoring.certificates.sidebar.working-with-certificates.title',
|
||||
defaultMessage: 'Working with certificates',
|
||||
description: 'Title for the section on how to work with certificates',
|
||||
},
|
||||
workingWithCertificatesFirstParagraph: {
|
||||
id: 'course-authoring.certificates.sidebar.working-with-certificates.first-paragraph',
|
||||
defaultMessage: 'Specify a course title to use on the certificate if the course\'s official title is too long to be displayed well.',
|
||||
description: 'Instructions for specifying a course title for the certificate',
|
||||
},
|
||||
workingWithCertificatesSecondParagraph: {
|
||||
id: 'course-authoring.certificates.sidebar.working-with-certificates.second-paragraph',
|
||||
defaultMessage: 'For verified certificates, specify between one and four signatories and upload the associated images. To edit or delete a certificate before it is activated, hover over the top right corner of the form and select {strongText} or the delete icon.',
|
||||
description: 'Details on how to specify signatories for verified certificates and edit or delete certificates',
|
||||
},
|
||||
workingWithCertificatesSecondParagraph_strong: {
|
||||
id: 'course-authoring.certificates.sidebar.working-with-certificates.second-paragraph.strong',
|
||||
defaultMessage: 'Edit',
|
||||
description: 'The strong emphasis text for the edit option',
|
||||
},
|
||||
workingWithCertificatesThirdParagraph: {
|
||||
id: 'course-authoring.certificates.sidebar.working-with-certificates.third-paragraph',
|
||||
defaultMessage: 'To view a sample certificate, choose a course mode and select {strongText}.',
|
||||
description: 'Instructions on how to view a sample certificate',
|
||||
},
|
||||
workingWithCertificatesThirdParagraph_strong: {
|
||||
id: 'course-authoring.certificates.sidebar.working-with-certificates.third-paragraph.strong',
|
||||
defaultMessage: 'Preview certificate',
|
||||
description: 'The strong emphasis text for the button to preview a sample certificate',
|
||||
},
|
||||
issuingCertificatesTitle: {
|
||||
id: 'course-authoring.certificates.sidebar.issuing-certificates.title',
|
||||
defaultMessage: 'Issuing certificates to learners',
|
||||
description: 'Title for the section on issuing certificates to learners',
|
||||
},
|
||||
issuingCertificatesFirstParagraph: {
|
||||
id: 'course-authoring.certificates.sidebar.issuing-certificates.first-paragraph',
|
||||
defaultMessage: 'To begin issuing course certificates, a course team member with either the Staff or Admin role selects {strongText}. Only course team members with these roles can edit or delete an activated certificate.',
|
||||
description: 'Instructions for issuing course certificates and the roles required to edit or delete certificates',
|
||||
},
|
||||
issuingCertificatesFirstParagraph_strong: {
|
||||
id: 'course-authoring.certificates.sidebar.issuing-certificates.first-paragraph.strong',
|
||||
defaultMessage: 'Activate',
|
||||
description: 'The strong emphasis text for the activation option',
|
||||
},
|
||||
issuingCertificatesSecondParagraph: {
|
||||
id: 'course-authoring.certificates.sidebar.issuing-certificates.second-paragraph',
|
||||
defaultMessage: '{strongText} delete certificates after a course has started; learners who have already earned certificates will no longer be able to access them.',
|
||||
description: 'A warning against deleting certificates once a course has started, noting the impact on learners',
|
||||
},
|
||||
issuingCertificatesSecondParagraph_strong: {
|
||||
id: 'course-authoring.certificates.sidebar.issuing-certificates.second-paragraph.strong',
|
||||
defaultMessage: 'Do not',
|
||||
description: 'The strong emphasis text part of the warning against deleting certificates',
|
||||
},
|
||||
learnMoreBtn: {
|
||||
id: 'course-authoring.certificates.sidebar.learnmore.button',
|
||||
defaultMessage: 'Learn more about certificates',
|
||||
description: 'Text for a button that links to additional information about setting up certificates in studio',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const SidebarBlock = ({ title, paragraphs, isLast }) => (
|
||||
<React.Fragment key={title}>
|
||||
<h4 className="help-sidebar-about-title">
|
||||
{title}
|
||||
</h4>
|
||||
{paragraphs.map((text) => (
|
||||
<p key={text} className="help-sidebar-about-descriptions">
|
||||
{text}
|
||||
</p>
|
||||
))}
|
||||
{!isLast && <hr />}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
SidebarBlock.defaultProps = {
|
||||
isLast: false,
|
||||
};
|
||||
|
||||
SidebarBlock.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
paragraphs: PropTypes.arrayOf(PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.node,
|
||||
])).isRequired,
|
||||
isLast: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default SidebarBlock;
|
||||
@@ -0,0 +1,33 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import SidebarBlock from './SidebarBlock';
|
||||
|
||||
const testProps = {
|
||||
title: 'Test Title',
|
||||
paragraphs: ['Test Paragraph'],
|
||||
};
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<SidebarBlock {...props} />,
|
||||
);
|
||||
|
||||
describe('SidebarBlock', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { getByText } = renderComponent(testProps);
|
||||
|
||||
expect(getByText(testProps.title)).toBeInTheDocument();
|
||||
expect(getByText(testProps.paragraphs[0])).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders <hr> if isLast is false', () => {
|
||||
const { getByRole } = renderComponent(testProps);
|
||||
|
||||
expect(getByRole('separator')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render <hr> if isLast is true', () => {
|
||||
const { queryByRole } = renderComponent({ ...testProps, isLast: true });
|
||||
|
||||
expect(queryByRole('separator')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
30
src/certificates/layout/certificates-sidebar/utils.jsx
Normal file
30
src/certificates/layout/certificates-sidebar/utils.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const getSidebarData = ({ messages, intl }) => [
|
||||
{
|
||||
title: intl.formatMessage(messages.workingWithCertificatesTitle),
|
||||
paragraphs: [
|
||||
intl.formatMessage(messages.workingWithCertificatesFirstParagraph),
|
||||
intl.formatMessage(
|
||||
messages.workingWithCertificatesSecondParagraph,
|
||||
{ strongText: <strong>{intl.formatMessage(messages.workingWithCertificatesSecondParagraph_strong)}</strong> },
|
||||
),
|
||||
intl.formatMessage(
|
||||
messages.workingWithCertificatesThirdParagraph,
|
||||
{ strongText: <strong>{intl.formatMessage(messages.workingWithCertificatesThirdParagraph_strong)}</strong> },
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage(messages.issuingCertificatesTitle),
|
||||
paragraphs: [
|
||||
intl.formatMessage(
|
||||
messages.issuingCertificatesFirstParagraph,
|
||||
{ strongText: <strong>{intl.formatMessage(messages.issuingCertificatesFirstParagraph_strong)}</strong> },
|
||||
),
|
||||
intl.formatMessage(
|
||||
messages.issuingCertificatesSecondParagraph,
|
||||
{ strongText: <strong>{intl.formatMessage(messages.issuingCertificatesSecondParagraph_strong)}</strong> },
|
||||
),
|
||||
],
|
||||
},
|
||||
];
|
||||
46
src/certificates/layout/header-buttons/HeaderButtons.jsx
Normal file
46
src/certificates/layout/header-buttons/HeaderButtons.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Button, Dropdown, DropdownButton, Hyperlink,
|
||||
} from '@openedx/paragon';
|
||||
|
||||
import messages from '../../messages';
|
||||
import useHeaderButtons from './hooks/useHeaderButtons';
|
||||
|
||||
const HeaderButtons = () => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
previewUrl,
|
||||
courseModes,
|
||||
dropdowmItem,
|
||||
isCertificateActive,
|
||||
setDropdowmItem,
|
||||
handleActivationStatus,
|
||||
} = useHeaderButtons();
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownButton id="dropdown-basic-button" title={dropdowmItem} onSelect={(item) => setDropdowmItem(item)}>
|
||||
{courseModes.map((mode) => <Dropdown.Item key={mode} eventKey={mode}>{mode}</Dropdown.Item>)}
|
||||
</DropdownButton>
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
as={Hyperlink}
|
||||
destination={previewUrl}
|
||||
target="_blank"
|
||||
showLaunchIcon={false}
|
||||
>
|
||||
{intl.formatMessage(messages.headingActionsPreview)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
onClick={handleActivationStatus}
|
||||
>
|
||||
{isCertificateActive
|
||||
? intl.formatMessage(messages.headingActionsDeactivate)
|
||||
: intl.formatMessage(messages.headingActionsActivate)}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderButtons;
|
||||
130
src/certificates/layout/header-buttons/HeaderButtons.test.jsx
Normal file
130
src/certificates/layout/header-buttons/HeaderButtons.test.jsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Provider } from 'react-redux';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { executeThunk } from '../../../utils';
|
||||
import initializeStore from '../../../store';
|
||||
import { MODE_STATES } from '../../data/constants';
|
||||
import { getCertificatesApiUrl, getUpdateCertificateApiUrl } from '../../data/api';
|
||||
import { fetchCertificates, updateCertificateActiveStatus } from '../../data/thunks';
|
||||
import { certificatesDataMock } from '../../__mocks__';
|
||||
import messages from '../../messages';
|
||||
import HeaderButtons from './HeaderButtons';
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
const courseId = 'course-123';
|
||||
|
||||
const renderComponent = (props) => render(
|
||||
<Provider store={store} messages={{}}>
|
||||
<IntlProvider locale="en">
|
||||
<HeaderButtons {...props} />
|
||||
</IntlProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
const initialState = {
|
||||
certificates: {
|
||||
certificatesData: {},
|
||||
componentMode: MODE_STATES.editAll,
|
||||
},
|
||||
};
|
||||
|
||||
describe('HeaderButtons Component', () => {
|
||||
beforeEach(async () => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
});
|
||||
store = initializeStore(initialState);
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, certificatesDataMock);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
});
|
||||
|
||||
it('updates preview URL param based on selected dropdown item', async () => {
|
||||
const { getByRole } = renderComponent();
|
||||
const previewLink = getByRole('link', { name: messages.headingActionsPreview.defaultMessage });
|
||||
|
||||
expect(previewLink).toHaveAttribute('href', expect.stringContaining(certificatesDataMock.courseModes[0]));
|
||||
|
||||
const dropdownButton = getByRole('button', { name: certificatesDataMock.courseModes[0] });
|
||||
await userEvent.click(dropdownButton);
|
||||
|
||||
const verifiedMode = await getByRole('button', { name: certificatesDataMock.courseModes[1] });
|
||||
await userEvent.click(verifiedMode);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(previewLink).toHaveAttribute('href', expect.stringContaining(certificatesDataMock.courseModes[1]));
|
||||
});
|
||||
});
|
||||
|
||||
it('activates certificate when button is clicked', async () => {
|
||||
const newCertificateData = {
|
||||
...certificatesDataMock,
|
||||
isActive: true,
|
||||
};
|
||||
|
||||
const { getByRole, queryByRole } = renderComponent();
|
||||
|
||||
const activationButton = getByRole('button', { name: messages.headingActionsActivate.defaultMessage });
|
||||
await userEvent.click(activationButton);
|
||||
|
||||
axiosMock.onPost(
|
||||
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
|
||||
).reply(200);
|
||||
await executeThunk(updateCertificateActiveStatus(courseId), store.dispatch);
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, newCertificateData);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getState().certificates.certificatesData.isActive).toBe(true);
|
||||
expect(getByRole('button', { name: messages.headingActionsDeactivate.defaultMessage })).toBeInTheDocument();
|
||||
expect(queryByRole('button', { name: messages.headingActionsActivate.defaultMessage })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('deactivates certificate when button is clicked', async () => {
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, { ...certificatesDataMock, isActive: true });
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
const newCertificateData = {
|
||||
...certificatesDataMock,
|
||||
isActive: false,
|
||||
};
|
||||
|
||||
const { getByRole, queryByRole } = renderComponent();
|
||||
|
||||
const deactivateButton = getByRole('button', { name: messages.headingActionsDeactivate.defaultMessage });
|
||||
await userEvent.click(deactivateButton);
|
||||
|
||||
axiosMock.onPost(
|
||||
getUpdateCertificateApiUrl(courseId, certificatesDataMock.certificates[0].id),
|
||||
).reply(200);
|
||||
await executeThunk(updateCertificateActiveStatus(courseId), store.dispatch);
|
||||
axiosMock
|
||||
.onGet(getCertificatesApiUrl(courseId))
|
||||
.reply(200, newCertificateData);
|
||||
await executeThunk(fetchCertificates(courseId), store.dispatch);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getState().certificates.certificatesData.isActive).toBe(false);
|
||||
expect(getByRole('button', { name: messages.headingActionsActivate.defaultMessage })).toBeInTheDocument();
|
||||
expect(queryByRole('button', { name: messages.headingActionsDeactivate.defaultMessage })).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
getCourseModes, getCertificateActivationUrl, getCertificateWebViewUrl, getIsCertificateActive,
|
||||
} from '../../../data/selectors';
|
||||
import { updateCertificateActiveStatus } from '../../../data/thunks';
|
||||
|
||||
const useHeaderButtons = () => {
|
||||
const { courseId } = useParams();
|
||||
const dispatch = useDispatch();
|
||||
const courseModes = useSelector(getCourseModes);
|
||||
const certificateWebViewUrl = useSelector(getCertificateWebViewUrl);
|
||||
const certificateActivationHandlerUrl = useSelector(getCertificateActivationUrl);
|
||||
const isCertificateActive = useSelector(getIsCertificateActive);
|
||||
|
||||
const [dropdowmItem, setDropdowmItem] = useState(courseModes[0]);
|
||||
|
||||
const handleActivationStatus = () => {
|
||||
const status = !isCertificateActive;
|
||||
|
||||
dispatch(updateCertificateActiveStatus(courseId, certificateActivationHandlerUrl, status));
|
||||
};
|
||||
|
||||
const previewUrl = useMemo(() => {
|
||||
if (!certificateWebViewUrl) { return ''; }
|
||||
|
||||
const getUrl = () => new URL(certificateWebViewUrl, window.location.origin);
|
||||
const url = getUrl();
|
||||
|
||||
const searchParams = new URLSearchParams(url.search);
|
||||
searchParams.set('preview', dropdowmItem);
|
||||
url.search = searchParams.toString();
|
||||
|
||||
return url.toString();
|
||||
}, [certificateWebViewUrl, dropdowmItem]);
|
||||
|
||||
return {
|
||||
previewUrl,
|
||||
courseModes,
|
||||
dropdowmItem,
|
||||
isCertificateActive,
|
||||
setDropdowmItem,
|
||||
handleActivationStatus,
|
||||
};
|
||||
};
|
||||
|
||||
export default useHeaderButtons;
|
||||
31
src/certificates/layout/hooks/useLayout.jsx
Normal file
31
src/certificates/layout/hooks/useLayout.jsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { RequestStatus } from '../../../data/constants';
|
||||
import { getProcessingNotification } from '../../../generic/processing-notification/data/selectors';
|
||||
import { getSavingStatus, getErrorMessage } from '../../data/selectors';
|
||||
|
||||
const useLayout = () => {
|
||||
const savingStatus = useSelector(getSavingStatus);
|
||||
const errorMessage = useSelector(getErrorMessage);
|
||||
|
||||
const {
|
||||
isShow: isShowProcessingNotification,
|
||||
title: processingNotificationTitle,
|
||||
} = useSelector(getProcessingNotification);
|
||||
|
||||
useEffect(() => {
|
||||
if (savingStatus === RequestStatus.SUCCESSFUL) {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
}, [savingStatus]);
|
||||
|
||||
return {
|
||||
errorMessage,
|
||||
savingStatus,
|
||||
isShowProcessingNotification,
|
||||
processingNotificationTitle,
|
||||
};
|
||||
};
|
||||
|
||||
export default useLayout;
|
||||
62
src/certificates/messages.js
Normal file
62
src/certificates/messages.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
headingTitle: {
|
||||
id: 'course-authoring.certificates.heading.title',
|
||||
defaultMessage: 'Certificates',
|
||||
},
|
||||
headingTitleTabText: {
|
||||
id: 'course-authoring.certificates.heading.title.tab.text',
|
||||
defaultMessage: 'Course certificates',
|
||||
},
|
||||
headingSubtitle: {
|
||||
id: 'course-authoring.certificates.heading.subtitle',
|
||||
defaultMessage: 'Settings',
|
||||
},
|
||||
headingActionsPreview: {
|
||||
id: 'course-authoring.certificates.heading.action.button.preview',
|
||||
defaultMessage: 'Preview certificate',
|
||||
},
|
||||
headingActionsDeactivate: {
|
||||
id: 'course-authoring.certificates.heading.action.button.deactivate',
|
||||
defaultMessage: 'Deactivate',
|
||||
},
|
||||
headingActionsActivate: {
|
||||
id: 'course-authoring.certificates.heading.action.button.activate',
|
||||
defaultMessage: 'Activate',
|
||||
},
|
||||
noCertificatesText: {
|
||||
id: 'course-authoring.certificates.nocertificate.text',
|
||||
defaultMessage: 'You haven\'t added any certificates to this course yet.',
|
||||
},
|
||||
setupCertificateBtn: {
|
||||
id: 'course-authoring.certificates.setup.certificate.button',
|
||||
defaultMessage: 'Add your first certificate',
|
||||
},
|
||||
withoutModesText: {
|
||||
id: 'course-authoring.certificates.without.modes.text',
|
||||
defaultMessage: 'This course does not use a mode that offers certificates.',
|
||||
},
|
||||
cardCreate: {
|
||||
id: 'course-authoring.certificates.create',
|
||||
defaultMessage: 'Create',
|
||||
},
|
||||
cardCancel: {
|
||||
id: 'course-authoring.certificates.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
deleteTooltip: {
|
||||
id: 'course-authoring.certificates.signatories.delete.tooltip',
|
||||
defaultMessage: 'Delete',
|
||||
},
|
||||
editTooltip: {
|
||||
id: 'course-authoring.certificates.signatories.edit.tooltip',
|
||||
defaultMessage: 'Edit',
|
||||
},
|
||||
saveTooltip: {
|
||||
id: 'course-authoring.certificates.signatories.save.tooltip',
|
||||
defaultMessage: 'Save',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
115
src/certificates/scss/Certificates.scss
Normal file
115
src/certificates/scss/Certificates.scss
Normal file
@@ -0,0 +1,115 @@
|
||||
@import "variables";
|
||||
|
||||
.certificates {
|
||||
.section-title {
|
||||
color: $black;
|
||||
}
|
||||
|
||||
.sub-header-actions {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.certificate-details {
|
||||
.certificate-details__info {
|
||||
color: $black;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.certificate-details__info-paragraph {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.certificate-details__info-paragraph-course-number {
|
||||
flex: 1;
|
||||
color: $gray-700;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.signatory {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 2.75rem;
|
||||
}
|
||||
|
||||
.signatory__header {
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
max-width: 18.75rem;
|
||||
}
|
||||
|
||||
.signatory__action-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: .75rem;
|
||||
}
|
||||
|
||||
.signatory__fields-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.signatory__text {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.signatory__image-container {
|
||||
flex: 2;
|
||||
max-width: 18.75rem;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.signatory__image {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: map-get($grid-breakpoints, "xl")) {
|
||||
.signatory {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.signatory__header {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.signatory__text {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.signatory__image-container {
|
||||
max-width: none;
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.signatory__image {
|
||||
display: flex;
|
||||
margin: .625rem auto;
|
||||
max-width: 23.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.certificates-card-form {
|
||||
.pgn__form-control-description,
|
||||
.pgn__form-text {
|
||||
margin-top: .62rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.certificates.alert-toast {
|
||||
z-index: $popover;
|
||||
}
|
||||
1
src/certificates/scss/_variables.scss
Normal file
1
src/certificates/scss/_variables.scss
Normal file
@@ -0,0 +1 @@
|
||||
$popover: 9999;
|
||||
15
src/certificates/utils.js
Normal file
15
src/certificates/utils.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { convertObjectToSnakeCase } from '../utils';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const prepareCertificatePayload = (data) => convertObjectToSnakeCase(({
|
||||
...data,
|
||||
courseTitle: data.courseTitle,
|
||||
description: 'Description of the certificate',
|
||||
editing: data.editing || true,
|
||||
isActive: data.isActive || false,
|
||||
name: 'Name of the certificate',
|
||||
version: data.version || 1,
|
||||
signatories: data.signatories
|
||||
.map(signatory => convertObjectToSnakeCase(signatory, true))
|
||||
.map(signatorySnakeCase => ({ ...signatorySnakeCase, certificate: signatorySnakeCase.certificate || null })),
|
||||
}), true);
|
||||
@@ -49,3 +49,23 @@ export const DECODED_ROUTES = {
|
||||
'/container/:blockId',
|
||||
],
|
||||
};
|
||||
|
||||
export const UPLOAD_FILE_MAX_SIZE = 20 * 1024 * 1024; // 100mb
|
||||
|
||||
export const COURSE_BLOCK_NAMES = ({
|
||||
chapter: { id: 'chapter', name: 'Section' },
|
||||
sequential: { id: 'sequential', name: 'Subsection' },
|
||||
vertical: { id: 'vertical', name: 'Unit' },
|
||||
component: { id: 'component', name: 'Component' },
|
||||
});
|
||||
|
||||
export const STUDIO_CLIPBOARD_CHANNEL = 'studio_clipboard_channel';
|
||||
|
||||
export const CLIPBOARD_STATUS = {
|
||||
loading: 'loading',
|
||||
ready: 'ready',
|
||||
expired: 'expired',
|
||||
error: 'error',
|
||||
};
|
||||
|
||||
export const STRUCTURAL_XBLOCK_TYPES = ['vertical', 'sequential', 'chapter', 'course'];
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
// disable prop-types since we're using TypeScript to define the prop types,
|
||||
// but the linter can't detect that in a .jsx file.
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import Select, { components } from 'react-select';
|
||||
import {
|
||||
Badge,
|
||||
Collapsible,
|
||||
Button,
|
||||
Spinner,
|
||||
Chip,
|
||||
Icon,
|
||||
} from '@openedx/paragon';
|
||||
import classNames from 'classnames';
|
||||
import { Tag, KeyboardArrowDown, KeyboardArrowUp } from '@openedx/paragon/icons';
|
||||
import { SelectableBox } from '@edx/frontend-lib-content-components';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { debounce } from 'lodash';
|
||||
@@ -18,14 +19,14 @@ import messages from './messages';
|
||||
|
||||
import ContentTagsDropDownSelector from './ContentTagsDropDownSelector';
|
||||
|
||||
import ContentTagsTree from './ContentTagsTree';
|
||||
|
||||
import useContentTagsCollapsibleHelper from './ContentTagsCollapsibleHelper';
|
||||
import TagsTree from './TagsTree';
|
||||
import { ContentTagsDrawerContext } from './common/context';
|
||||
|
||||
/** @typedef {import("./ContentTagsCollapsible").TagTreeEntry} TagTreeEntry */
|
||||
/** @typedef {import("./ContentTagsCollapsible").TaxonomySelectProps} TaxonomySelectProps */
|
||||
/** @typedef {import("../taxonomy/data/types.mjs").TaxonomyData} TaxonomyData */
|
||||
/** @typedef {import("./data/types.mjs").Tag} ContentTagData */
|
||||
/** @typedef {import("./data/types.mjs").StagedTagData} StagedTagData */
|
||||
|
||||
/**
|
||||
* Custom Menu component for our Select box
|
||||
@@ -76,7 +77,7 @@ const CustomMenu = (props) => {
|
||||
tabIndex="0"
|
||||
ref={selectCancelRef}
|
||||
variant="tertiary"
|
||||
className="cancel-add-tags-button"
|
||||
className="tags-drawer-cancel-button"
|
||||
onClick={handleCancelStagedTags}
|
||||
>
|
||||
{ intl.formatMessage(messages.collapsibleCancelStagedTagsButtonText) }
|
||||
@@ -223,27 +224,35 @@ const CustomIndicatorsContainer = (props) => {
|
||||
*
|
||||
* @param {Object} props - The component props.
|
||||
* @param {string} props.contentId - Id of the content object
|
||||
* @param {{value: string, label: string}[]} props.stagedContentTags
|
||||
* @param {StagedTagData[]} props.stagedContentTags
|
||||
* - Array of staged tags represented as objects with value/label
|
||||
* @param {(taxonomyId: number, tag: {value: string, label: string}) => void} props.addStagedContentTag
|
||||
* - Callback function to add a staged tag for a taxonomy
|
||||
* @param {(taxonomyId: number, tagValue: string) => void} props.removeStagedContentTag
|
||||
* - Callback function to remove a staged tag from a taxonomy
|
||||
* @param {Function} props.setStagedTags - Callback function to set staged tags for a taxonomy to provided tags list
|
||||
* @param {TaxonomyData & {contentTags: ContentTagData[]}} props.taxonomyAndTagsData - Taxonomy metadata & applied tags
|
||||
* @param {boolean} props.collapsibleState - True if the collapsible is open
|
||||
*/
|
||||
const ContentTagsCollapsible = ({
|
||||
contentId, taxonomyAndTagsData, stagedContentTags, addStagedContentTag, removeStagedContentTag, setStagedTags,
|
||||
contentId,
|
||||
taxonomyAndTagsData,
|
||||
stagedContentTags,
|
||||
collapsibleState,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { id: taxonomyId, name, canTagObject } = taxonomyAndTagsData;
|
||||
const selectCancelRef = React.useRef(/** @type {HTMLSelectElement | null} */(null));
|
||||
const selectAddRef = React.useRef(/** @type {HTMLSelectElement | null} */(null));
|
||||
const selectInlineAddRef = React.useRef(/** @type {HTMLSelectElement | null} */(null));
|
||||
const selectInlineEditModeRef = React.useRef(/** @type {HTMLSelectElement | null} */(null));
|
||||
const selectRef = React.useRef(/** @type {HTMLSelectElement | null} */(null));
|
||||
|
||||
const [selectMenuIsOpen, setSelectMenuIsOpen] = React.useState(false);
|
||||
|
||||
const {
|
||||
isEditMode,
|
||||
toEditMode,
|
||||
setStagedTags,
|
||||
openCollapsible,
|
||||
closeCollapsible,
|
||||
} = useContext(ContentTagsDrawerContext);
|
||||
|
||||
const {
|
||||
tagChangeHandler,
|
||||
removeAppliedTagHandler,
|
||||
@@ -251,14 +260,12 @@ const ContentTagsCollapsible = ({
|
||||
stagedContentTagsTree,
|
||||
contentTagsCount,
|
||||
checkedTags,
|
||||
commitStagedTags,
|
||||
commitStagedTagsToGlobal,
|
||||
updateTags,
|
||||
} = useContentTagsCollapsibleHelper(
|
||||
contentId,
|
||||
taxonomyAndTagsData,
|
||||
addStagedContentTag,
|
||||
removeStagedContentTag,
|
||||
stagedContentTags,
|
||||
taxonomyAndTagsData,
|
||||
);
|
||||
|
||||
const [searchTerm, setSearchTerm] = React.useState('');
|
||||
@@ -308,12 +315,12 @@ const ContentTagsCollapsible = ({
|
||||
}, [taxonomyId, setStagedTags, stagedContentTags, tagChangeHandler]);
|
||||
|
||||
const handleCommitStagedTags = React.useCallback(() => {
|
||||
commitStagedTags();
|
||||
commitStagedTagsToGlobal();
|
||||
handleStagedTagsMenuChange([]);
|
||||
selectRef.current?.blur();
|
||||
setSearchTerm('');
|
||||
setSelectMenuIsOpen(false);
|
||||
}, [commitStagedTags, handleStagedTagsMenuChange, selectRef, setSearchTerm]);
|
||||
}, [commitStagedTagsToGlobal, handleStagedTagsMenuChange, selectRef, setSearchTerm]);
|
||||
|
||||
const handleCancelStagedTags = React.useCallback(() => {
|
||||
handleStagedTagsMenuChange([]);
|
||||
@@ -363,71 +370,111 @@ const ContentTagsCollapsible = ({
|
||||
|
||||
return (
|
||||
<div className="d-flex">
|
||||
<Collapsible title={name} styling="card-lg" className="taxonomy-tags-collapsible">
|
||||
<div key={taxonomyId}>
|
||||
<ContentTagsTree tagsTree={appliedContentTagsTree} removeTagHandler={removeAppliedTagHandler} />
|
||||
</div>
|
||||
<Collapsible.Advanced
|
||||
className="collapsible-card-lg taxonomy-tags-collapsible"
|
||||
open={collapsibleState}
|
||||
onClose={() => closeCollapsible(taxonomyId)}
|
||||
onOpen={() => openCollapsible(taxonomyId)}
|
||||
>
|
||||
<Collapsible.Trigger className="collapsible-trigger pl-2.5">
|
||||
<Collapsible.Visible whenClosed>
|
||||
<Icon src={KeyboardArrowDown} />
|
||||
</Collapsible.Visible>
|
||||
|
||||
<div className="d-flex taxonomy-tags-selector-menu">
|
||||
<Collapsible.Visible whenOpen>
|
||||
<Icon src={KeyboardArrowUp} />
|
||||
</Collapsible.Visible>
|
||||
<h3 className="h5 flex-grow-1 pl-2">{name}</h3>
|
||||
</Collapsible.Trigger>
|
||||
|
||||
{canTagObject && (
|
||||
<Select
|
||||
onBlur={handleOnBlur}
|
||||
styles={{
|
||||
// Overriding 'x' button styles for staged tags when navigating by keyboard
|
||||
multiValueRemove: (base, state) => ({
|
||||
...base,
|
||||
background: state.isFocused ? 'black' : base.background,
|
||||
color: state.isFocused ? 'white' : base.color,
|
||||
}),
|
||||
}}
|
||||
menuIsOpen={selectMenuIsOpen}
|
||||
onFocus={onSelectMenuFocus}
|
||||
onKeyDown={handleSelectOnKeyDown}
|
||||
ref={/** @type {React.RefObject} */(selectRef)}
|
||||
isMulti
|
||||
isLoading={updateTags.isLoading}
|
||||
isDisabled={updateTags.isLoading}
|
||||
name="tags-select"
|
||||
placeholder={intl.formatMessage(messages.collapsibleAddTagsPlaceholderText)}
|
||||
isSearchable
|
||||
className="d-flex flex-column flex-fill"
|
||||
classNamePrefix="react-select-add-tags"
|
||||
onInputChange={handleSearchChange}
|
||||
onChange={handleStagedTagsMenuChange}
|
||||
components={{
|
||||
Menu: CustomMenu,
|
||||
LoadingIndicator: CustomLoadingIndicator,
|
||||
IndicatorsContainer: CustomIndicatorsContainer,
|
||||
}}
|
||||
closeMenuOnSelect={false}
|
||||
blurInputOnSelect={false}
|
||||
handleSelectableBoxChange={handleSelectableBoxChange}
|
||||
checkedTags={checkedTags}
|
||||
taxonomyId={taxonomyId}
|
||||
appliedContentTagsTree={appliedContentTagsTree}
|
||||
stagedContentTagsTree={stagedContentTagsTree}
|
||||
handleCommitStagedTags={handleCommitStagedTags}
|
||||
handleCancelStagedTags={handleCancelStagedTags}
|
||||
searchTerm={searchTerm}
|
||||
selectCancelRef={selectCancelRef}
|
||||
selectAddRef={selectAddRef}
|
||||
selectInlineAddRef={selectInlineAddRef}
|
||||
value={stagedContentTags}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Collapsible>
|
||||
<div className="d-flex">
|
||||
<Badge
|
||||
variant="light"
|
||||
pill
|
||||
className={classNames('align-self-start', 'mt-3', {
|
||||
invisible: contentTagsCount === 0,
|
||||
})}
|
||||
<Collapsible.Body className="collapsible-body">
|
||||
{ Object.keys(appliedContentTagsTree).length === 0 && !isEditMode
|
||||
&& (
|
||||
<div className="mb-3" key={taxonomyId}>
|
||||
<p className="text-gray-500">{intl.formatMessage(messages.collapsibleNoTagsAddedText)}
|
||||
<Button
|
||||
tabIndex="0"
|
||||
size="inline"
|
||||
ref={selectInlineEditModeRef}
|
||||
variant="link"
|
||||
className="text-info-500 add-tags-button"
|
||||
onClick={toEditMode}
|
||||
>
|
||||
{ intl.formatMessage(messages.collapsibleAddStagedTagsButtonText) }
|
||||
</Button>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{ Object.keys(appliedContentTagsTree).length !== 0
|
||||
&& (
|
||||
<div className="mb-3" key={taxonomyId}>
|
||||
<TagsTree
|
||||
tags={appliedContentTagsTree}
|
||||
parentKey={taxonomyId.toString()}
|
||||
removeTagHandler={removeAppliedTagHandler}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="d-flex taxonomy-tags-selector-menu">
|
||||
{isEditMode && canTagObject && (
|
||||
<Select
|
||||
onBlur={handleOnBlur}
|
||||
styles={{
|
||||
// Overriding 'x' button styles for staged tags when navigating by keyboard
|
||||
multiValueRemove: (base, state) => ({
|
||||
...base,
|
||||
background: state.isFocused ? 'black' : base.background,
|
||||
color: state.isFocused ? 'white' : base.color,
|
||||
}),
|
||||
}}
|
||||
menuIsOpen={selectMenuIsOpen}
|
||||
onFocus={onSelectMenuFocus}
|
||||
onKeyDown={handleSelectOnKeyDown}
|
||||
ref={/** @type {React.RefObject} */(selectRef)}
|
||||
isMulti
|
||||
isLoading={updateTags.isLoading}
|
||||
isDisabled={updateTags.isLoading}
|
||||
name="tags-select"
|
||||
placeholder={intl.formatMessage(messages.collapsibleAddTagsPlaceholderText)}
|
||||
isSearchable
|
||||
className="d-flex flex-column flex-fill"
|
||||
classNamePrefix="react-select-add-tags"
|
||||
onInputChange={handleSearchChange}
|
||||
onChange={handleStagedTagsMenuChange}
|
||||
components={{
|
||||
Menu: CustomMenu,
|
||||
LoadingIndicator: CustomLoadingIndicator,
|
||||
IndicatorsContainer: CustomIndicatorsContainer,
|
||||
}}
|
||||
closeMenuOnSelect={false}
|
||||
blurInputOnSelect={false}
|
||||
handleSelectableBoxChange={handleSelectableBoxChange}
|
||||
checkedTags={checkedTags}
|
||||
taxonomyId={taxonomyId}
|
||||
appliedContentTagsTree={appliedContentTagsTree}
|
||||
stagedContentTagsTree={stagedContentTagsTree}
|
||||
handleCommitStagedTags={handleCommitStagedTags}
|
||||
handleCancelStagedTags={handleCancelStagedTags}
|
||||
searchTerm={searchTerm}
|
||||
selectCancelRef={selectCancelRef}
|
||||
selectAddRef={selectAddRef}
|
||||
selectInlineAddRef={selectInlineAddRef}
|
||||
value={stagedContentTags}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
<div className="d-flex align-items-start pt-2.5 taxonomy-tags-count-chip">
|
||||
<Chip
|
||||
className="border-0"
|
||||
iconBefore={Tag}
|
||||
iconBeforeAlt="icon-before"
|
||||
disabled={contentTagsCount === 0}
|
||||
>
|
||||
{contentTagsCount}
|
||||
</Badge>
|
||||
</Chip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
.collapsible-trigger {
|
||||
border: none !important;
|
||||
|
||||
.pgn__icon {
|
||||
margin-left: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-tree {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +41,6 @@
|
||||
color: $info-900 !important;
|
||||
}
|
||||
|
||||
.cancel-add-tags-button:hover {
|
||||
background-color: transparent;
|
||||
color: $gray-300 !important;
|
||||
}
|
||||
|
||||
.react-select-add-tags__control {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
@@ -57,3 +60,7 @@
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
|
||||
.taxonomy-tags-count-chip > .pgn__chip {
|
||||
background: none;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
act,
|
||||
render,
|
||||
fireEvent,
|
||||
screen,
|
||||
within,
|
||||
} from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import ContentTagsCollapsible from './ContentTagsCollapsible';
|
||||
import messages from './messages';
|
||||
import { ContentTagsDrawerContext } from './common/context';
|
||||
|
||||
const taxonomyMockData = {
|
||||
hasMorePages: false,
|
||||
@@ -122,6 +125,17 @@ const data = {
|
||||
addStagedContentTag: jest.fn(),
|
||||
removeStagedContentTag: jest.fn(),
|
||||
setStagedTags: jest.fn(),
|
||||
removeGlobalStagedContentTag: jest.fn(),
|
||||
addRemovedContentTag: jest.fn(),
|
||||
deleteRemovedContentTag: jest.fn(),
|
||||
globalStagedContentTags: {},
|
||||
globalStagedRemovedContentTags: {},
|
||||
setGlobalStagedContentTags: jest.fn(),
|
||||
isEditMode: true,
|
||||
toEditMode: jest.fn(),
|
||||
collapsibleState: true,
|
||||
openCollapsible: jest.fn(),
|
||||
closeCollapsible: jest.fn(),
|
||||
};
|
||||
|
||||
const ContentTagsCollapsibleComponent = ({
|
||||
@@ -131,18 +145,46 @@ const ContentTagsCollapsibleComponent = ({
|
||||
addStagedContentTag,
|
||||
removeStagedContentTag,
|
||||
setStagedTags,
|
||||
}) => (
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<ContentTagsCollapsible
|
||||
contentId={contentId}
|
||||
taxonomyAndTagsData={taxonomyAndTagsData}
|
||||
stagedContentTags={stagedContentTags}
|
||||
addStagedContentTag={addStagedContentTag}
|
||||
removeStagedContentTag={removeStagedContentTag}
|
||||
setStagedTags={setStagedTags}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
removeGlobalStagedContentTag,
|
||||
addRemovedContentTag,
|
||||
deleteRemovedContentTag,
|
||||
globalStagedContentTags,
|
||||
globalStagedRemovedContentTags,
|
||||
setGlobalStagedContentTags,
|
||||
isEditMode,
|
||||
toEditMode,
|
||||
collapsibleState,
|
||||
openCollapsible,
|
||||
closeCollapsible,
|
||||
}) => {
|
||||
const context = useMemo(() => ({
|
||||
addStagedContentTag,
|
||||
removeStagedContentTag,
|
||||
setStagedTags,
|
||||
removeGlobalStagedContentTag,
|
||||
addRemovedContentTag,
|
||||
deleteRemovedContentTag,
|
||||
globalStagedContentTags,
|
||||
globalStagedRemovedContentTags,
|
||||
setGlobalStagedContentTags,
|
||||
isEditMode,
|
||||
toEditMode,
|
||||
openCollapsible,
|
||||
closeCollapsible,
|
||||
}), []);
|
||||
return (
|
||||
<ContentTagsDrawerContext.Provider value={context}>
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<ContentTagsCollapsible
|
||||
contentId={contentId}
|
||||
taxonomyAndTagsData={taxonomyAndTagsData}
|
||||
stagedContentTags={stagedContentTags}
|
||||
collapsibleState={collapsibleState}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</ContentTagsDrawerContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
ContentTagsCollapsibleComponent.propTypes = ContentTagsCollapsible.propTypes;
|
||||
|
||||
@@ -170,6 +212,17 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
addStagedContentTag={componentData.addStagedContentTag}
|
||||
removeStagedContentTag={componentData.removeStagedContentTag}
|
||||
setStagedTags={componentData.setStagedTags}
|
||||
removeGlobalStagedContentTag={componentData.removeGlobalStagedContentTag}
|
||||
addRemovedContentTag={componentData.addRemovedContentTag}
|
||||
deleteRemovedContentTag={componentData.deleteRemovedContentTag}
|
||||
globalStagedContentTags={componentData.globalStagedContentTags}
|
||||
globalStagedRemovedContentTags={componentData.globalStagedRemovedContentTags}
|
||||
setGlobalStagedContentTags={componentData.setGlobalStagedContentTags}
|
||||
isEditMode={componentData.isEditMode}
|
||||
toEditMode={componentData.toEditMode}
|
||||
collapsibleState={componentData.collapsibleState}
|
||||
openCollapsible={componentData.openCollapsible}
|
||||
closeCollapsible={componentData.closeCollapsible}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
@@ -177,17 +230,89 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
it('should render taxonomy tags data along content tags number badge', async () => {
|
||||
const { container, getByText } = await getComponent();
|
||||
expect(getByText('Taxonomy 1')).toBeInTheDocument();
|
||||
expect(container.getElementsByClassName('badge').length).toBe(1);
|
||||
expect(container.getElementsByClassName('taxonomy-tags-count-chip').length).toBe(1);
|
||||
expect(getByText('3')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call `addStagedContentTag` when tag checked in the dropdown', async () => {
|
||||
const { container, getByText, getAllByText } = await getComponent();
|
||||
it('should render read mode', async () => {
|
||||
await getComponent({
|
||||
...data,
|
||||
isEditMode: false,
|
||||
});
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
expect(screen.queryByRole('button', { name: /delete/i })).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/add a tag/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render edit mode', async () => {
|
||||
await getComponent();
|
||||
|
||||
expect(screen.getAllByRole(
|
||||
'button',
|
||||
{ name: /delete/i },
|
||||
).length).toBe(3);
|
||||
expect(screen.getByText(/add a tag/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render "no tags added yet" when expanded in read mode', async () => {
|
||||
await getComponent({
|
||||
...data,
|
||||
isEditMode: false,
|
||||
taxonomyAndTagsData: {
|
||||
id: 123,
|
||||
name: 'Taxonomy 1',
|
||||
canTagObject: true,
|
||||
contentTags: [],
|
||||
},
|
||||
});
|
||||
|
||||
const expandToggle = screen.getByRole('button', {
|
||||
name: /taxonomy 1/i,
|
||||
});
|
||||
fireEvent.click(expandToggle);
|
||||
expect(screen.queryByText(/no tags added yet/i)).toBeInTheDocument();
|
||||
|
||||
const addTags = screen.getByRole('button', {
|
||||
name: /add tags/i,
|
||||
});
|
||||
expect(addTags).toBeInTheDocument();
|
||||
fireEvent.click(addTags);
|
||||
expect(data.toEditMode).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should call `openCollapsible` when click in the collapsible', async () => {
|
||||
await getComponent({
|
||||
...data,
|
||||
collapsibleState: false,
|
||||
});
|
||||
|
||||
const expandToggle = screen.getByRole('button', {
|
||||
name: /taxonomy 1/i,
|
||||
});
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
expect(data.openCollapsible).toHaveBeenCalledTimes(1);
|
||||
expect(data.closeCollapsible).toHaveBeenCalledTimes(0);
|
||||
expect(screen.queryByText(/no tags added yet/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call `closeCollapsible` when click in the collapsible', async () => {
|
||||
await getComponent({
|
||||
...data,
|
||||
collapsibleState: true,
|
||||
});
|
||||
|
||||
const expandToggle = screen.getByRole('button', {
|
||||
name: /taxonomy 1/i,
|
||||
});
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
expect(data.closeCollapsible).toHaveBeenCalledTimes(1);
|
||||
expect(data.openCollapsible).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should call `addStagedContentTag` when tag checked in the dropdown', async () => {
|
||||
const { getByText, getAllByText } = await getComponent();
|
||||
|
||||
// Click on "Add a tag" button to open dropdown to select new tags
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
@@ -213,12 +338,7 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
});
|
||||
|
||||
it('should call `removeStagedContentTag` when tag staged tag unchecked in the dropdown', async () => {
|
||||
const { container, getByText, getAllByText } = await getComponent();
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
const { getByText, getAllByText } = await getComponent();
|
||||
|
||||
// Click on "Add a tag" button to open dropdown to select new tags
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
@@ -242,9 +362,57 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
expect(data.removeStagedContentTag).toHaveBeenCalledWith(taxonomyId, tagValue);
|
||||
});
|
||||
|
||||
it('should call `removeGlobalStagedContentTag` when global staged tag is deleted', async () => {
|
||||
await getComponent({
|
||||
...data,
|
||||
taxonomyAndTagsData: {
|
||||
id: 123,
|
||||
name: 'Taxonomy 1',
|
||||
canTagObject: true,
|
||||
contentTags: [
|
||||
{
|
||||
value: 'Tag 3',
|
||||
lineage: ['Tag 3'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
globalStagedContentTags: {
|
||||
123: [{
|
||||
value: 'Tag 3',
|
||||
lineage: ['Tag 3'],
|
||||
canDeleteObjecttag: true,
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
||||
const deleteButton = screen.getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
const taxonomyId = 123;
|
||||
expect(data.removeGlobalStagedContentTag).toHaveBeenCalledTimes(1);
|
||||
expect(data.removeGlobalStagedContentTag).toHaveBeenCalledWith(taxonomyId, 'Tag 3');
|
||||
});
|
||||
|
||||
it('should call `addRemovedContentTag` when a feched tag is deleted', async () => {
|
||||
await getComponent();
|
||||
|
||||
const tag = screen.getByText(/tag 2/i);
|
||||
const deleteButton = within(tag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
const taxonomyId = 123;
|
||||
expect(data.addRemovedContentTag).toHaveBeenCalledTimes(1);
|
||||
expect(data.addRemovedContentTag).toHaveBeenCalledWith(taxonomyId, 'Tag 2');
|
||||
});
|
||||
|
||||
it('should call `setStagedTags` to clear staged tags when clicking inline "Add" button', async () => {
|
||||
// Setup component to have staged tags
|
||||
const { container, getByText } = await getComponent({
|
||||
const { getByText } = await getComponent({
|
||||
...data,
|
||||
stagedContentTags: [{
|
||||
value: 'Tag%203',
|
||||
@@ -252,11 +420,6 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
}],
|
||||
});
|
||||
|
||||
// Expand the Taxonomy to view applied tags and staged tags
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
// Click on inline "Add" button and check that the appropriate methods are called
|
||||
const inlineAdd = getByText(messages.collapsibleInlineAddStagedTagsButtonText.defaultMessage);
|
||||
fireEvent.click(inlineAdd);
|
||||
@@ -277,11 +440,6 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
}],
|
||||
});
|
||||
|
||||
// Expand the Taxonomy to view applied tags and staged tags
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
// Click on dropdown with staged tags to expand it
|
||||
const selectTagsDropdown = container.getElementsByClassName('react-select-add-tags__control')[0];
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
@@ -307,11 +465,6 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
}],
|
||||
});
|
||||
|
||||
// Expand the Taxonomy to view applied tags and staged tags
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
// Click on dropdown with staged tags to expand it
|
||||
const selectTagsDropdown = container.getElementsByClassName('react-select-add-tags__control')[0];
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
@@ -332,13 +485,9 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
|
||||
it('should handle search term change', async () => {
|
||||
const {
|
||||
container, getByText, getByRole, getByDisplayValue,
|
||||
getByText, getByRole, getByDisplayValue,
|
||||
} = await getComponent();
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to click
|
||||
@@ -369,12 +518,7 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
});
|
||||
|
||||
it('should close dropdown selector when clicking away', async () => {
|
||||
const { container, getByText, queryByText } = await getComponent();
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
const { getByText, queryByText } = await getComponent();
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
@@ -398,17 +542,11 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
|
||||
it('should test keyboard navigation of add tags widget', async () => {
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
queryByText,
|
||||
queryAllByText,
|
||||
} = await getComponent();
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
@@ -530,29 +668,27 @@ describe('<ContentTagsCollapsible />', () => {
|
||||
});
|
||||
|
||||
it('should remove applied tags when clicking on `x` of tag bubble', async () => {
|
||||
const { container, getByText } = await getComponent();
|
||||
|
||||
// Expand the Taxonomy to view applied tags
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
await getComponent();
|
||||
|
||||
// Click on 'x' of applied tag to remove it
|
||||
const appliedTag = getByText('Tag 2');
|
||||
const xButtonAppliedTag = appliedTag.nextSibling;
|
||||
const appliedTag = screen.getByText(/tag 2/i);
|
||||
const xButtonAppliedTag = within(appliedTag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
xButtonAppliedTag.click();
|
||||
|
||||
// Check that the applied tag has been removed
|
||||
expect(appliedTag).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render taxonomy tags data without tags number badge', async () => {
|
||||
it('should render taxonomy tags data with tags number badge as cero', async () => {
|
||||
const updatedData = { ...data };
|
||||
updatedData.taxonomyAndTagsData = { ...updatedData.taxonomyAndTagsData };
|
||||
updatedData.taxonomyAndTagsData.contentTags = [];
|
||||
const { container, getByText } = await getComponent(updatedData);
|
||||
|
||||
expect(getByText('Taxonomy 1')).toBeInTheDocument();
|
||||
expect(container.getElementsByClassName('invisible').length).toBe(1);
|
||||
expect(container.getElementsByClassName('taxonomy-tags-count-chip').length).toBe(1);
|
||||
expect(getByText('0')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,10 +4,13 @@ import { useCheckboxSetValues } from '@openedx/paragon';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
import { useContentTaxonomyTagsUpdater } from './data/apiHooks';
|
||||
import { ContentTagsDrawerContext } from './common/context';
|
||||
|
||||
/** @typedef {import("../taxonomy/data/types.mjs").TaxonomyData} TaxonomyData */
|
||||
/** @typedef {import("./data/types.mjs").Tag} ContentTagData */
|
||||
/** @typedef {import("./ContentTagsCollapsible").TagTreeEntry} TagTreeEntry */
|
||||
/** @typedef {import("./data/types.mjs").StagedTagData} StagedTagData */
|
||||
/** @typedef {import("./data/types.mjs").UpdateTagsData} UpdateTagsData */
|
||||
|
||||
/**
|
||||
* Util function that sorts the keys of a tree in alphabetical order.
|
||||
@@ -33,16 +36,22 @@ const sortKeysAlphabetically = (tree) => {
|
||||
* tags selected in the staged tags tree
|
||||
*
|
||||
* @param {object} tree - tree to extract the leaf tags from
|
||||
* @returns {Array<string>} array of leaf (explicit) tags of provided tree
|
||||
* @returns {StagedTagData[]} array of leaf (explicit) tags of provided tree
|
||||
*/
|
||||
const getLeafTags = (tree) => {
|
||||
const leafKeys = [];
|
||||
const leafTags = [];
|
||||
|
||||
function traverse(node) {
|
||||
Object.keys(node).forEach(key => {
|
||||
const child = node[key];
|
||||
if (Object.keys(child.children).length === 0) {
|
||||
leafKeys.push(key);
|
||||
leafTags.push({
|
||||
value: key,
|
||||
// Always true because this is a new added tag,
|
||||
// so the user can delete.
|
||||
canDeleteObjecttag: true,
|
||||
lineage: child.lineage,
|
||||
});
|
||||
} else {
|
||||
traverse(child.children);
|
||||
}
|
||||
@@ -50,16 +59,15 @@ const getLeafTags = (tree) => {
|
||||
}
|
||||
|
||||
traverse(tree);
|
||||
return leafKeys;
|
||||
return leafTags;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles all the underlying logic for the ContentTagsCollapsible component
|
||||
* @param {string} contentId The ID of the content we're tagging (e.g. usage key)
|
||||
* @param {StagedTagData[]} stagedContentTags
|
||||
* - Array of staged tags represented as objects with value/label
|
||||
* @param {TaxonomyData & {contentTags: ContentTagData[]}} taxonomyAndTagsData
|
||||
* @param {(taxonomyId: number, tag: {value: string, label: string}) => void} addStagedContentTag
|
||||
* @param {(taxonomyId: number, tagValue: string) => void} removeStagedContentTag
|
||||
* @param {{value: string, label: string}[]} stagedContentTags
|
||||
* @returns {{
|
||||
* tagChangeHandler: (tagSelectableBoxValue: string, checked: boolean) => void,
|
||||
* removeAppliedTagHandler: (tagSelectableBoxValue: string) => void,
|
||||
@@ -67,24 +75,33 @@ const getLeafTags = (tree) => {
|
||||
* stagedContentTagsTree: Record<string, TagTreeEntry>,
|
||||
* contentTagsCount: number,
|
||||
* checkedTags: any,
|
||||
* commitStagedTags: () => void,
|
||||
* updateTags: import('@tanstack/react-query').UseMutationResult<any, unknown, { tags: string[]; }, unknown>
|
||||
* commitStagedTagsToGlobal: () => void,
|
||||
* updateTags: import('@tanstack/react-query').UseMutationResult<
|
||||
* any, unknown, { tagsData: Promise<UpdateTagsData[]>; }, unknown
|
||||
* >
|
||||
* }}
|
||||
*/
|
||||
const useContentTagsCollapsibleHelper = (
|
||||
contentId,
|
||||
taxonomyAndTagsData,
|
||||
addStagedContentTag,
|
||||
removeStagedContentTag,
|
||||
stagedContentTags,
|
||||
taxonomyAndTagsData,
|
||||
) => {
|
||||
const {
|
||||
id, contentTags, canTagObject,
|
||||
isEditMode,
|
||||
addStagedContentTag,
|
||||
removeStagedContentTag,
|
||||
removeGlobalStagedContentTag,
|
||||
addRemovedContentTag,
|
||||
deleteRemovedContentTag,
|
||||
globalStagedContentTags,
|
||||
setGlobalStagedContentTags,
|
||||
globalStagedRemovedContentTags,
|
||||
} = React.useContext(ContentTagsDrawerContext);
|
||||
|
||||
const {
|
||||
id, contentTags,
|
||||
} = taxonomyAndTagsData;
|
||||
// State to determine whether an applied tag was removed so we make a call
|
||||
// to the update endpoint to the reflect those changes
|
||||
const [removingAppliedTag, setRemoveAppliedTag] = React.useState(false);
|
||||
const updateTags = useContentTaxonomyTagsUpdater(contentId, id);
|
||||
const updateTags = useContentTaxonomyTagsUpdater(contentId);
|
||||
|
||||
// Keeps track of the content objects tags count (both implicit and explicit)
|
||||
const [contentTagsCount, setContentTagsCount] = React.useState(0);
|
||||
@@ -94,27 +111,13 @@ const useContentTagsCollapsibleHelper = (
|
||||
const [stagedContentTagsTree, setStagedContentTagsTree] = React.useState({});
|
||||
|
||||
// To handle checking/unchecking tags in the SelectableBox
|
||||
const [checkedTags, { add, remove }] = useCheckboxSetValues();
|
||||
const [checkedTags, { add, remove, clear }] = useCheckboxSetValues();
|
||||
|
||||
// State to keep track of the staged tags (and along with ancestors) that should be removed
|
||||
const [stagedTagsToRemove, setStagedTagsToRemove] = React.useState(/** @type string[] */([]));
|
||||
|
||||
// Handles making requests to the backend when applied tags are removed
|
||||
React.useEffect(() => {
|
||||
// We have this check because this hook is fired when the component first loads
|
||||
// and reloads (on refocus). We only want to make a request to the update endpoint when
|
||||
// the user removes an applied tag
|
||||
if (removingAppliedTag) {
|
||||
setRemoveAppliedTag(false);
|
||||
|
||||
// Filter out staged tags from the checktags so they do not get committed
|
||||
const tags = checkedTags.map(t => decodeURIComponent(t.split(',').slice(-1)));
|
||||
const staged = stagedContentTags.map(t => t.label);
|
||||
const remainingAppliedTags = tags.filter(t => !staged.includes(t));
|
||||
|
||||
updateTags.mutate({ tags: remainingAppliedTags });
|
||||
}
|
||||
}, [contentId, id, canTagObject, checkedTags, stagedContentTags]);
|
||||
// State to keep track of the global tags (stagged and feched) that should be removed
|
||||
const [globalTagsToRemove, setGlobalTagsToRemove] = React.useState(/** @type string[] */([]));
|
||||
|
||||
// Handles the removal of staged content tags based on what was removed
|
||||
// from the staged tags tree. We are doing it in a useEffect since the removeTag
|
||||
@@ -124,16 +127,57 @@ const useContentTagsCollapsibleHelper = (
|
||||
stagedTagsToRemove.forEach(tag => removeStagedContentTag(id, tag));
|
||||
}, [stagedTagsToRemove, removeStagedContentTag, id]);
|
||||
|
||||
// When you change the drawer mode, it is necessary to clear
|
||||
// all checked tags in the select.
|
||||
React.useEffect(() => {
|
||||
clear();
|
||||
}, [isEditMode]);
|
||||
|
||||
React.useEffect(() => {
|
||||
globalTagsToRemove.forEach((tag) => {
|
||||
if (globalStagedContentTags[id]
|
||||
&& globalStagedContentTags[id].some(t => t.value === tag)) {
|
||||
// A new tag has been removed
|
||||
removeGlobalStagedContentTag(id, tag);
|
||||
} else if (contentTags.some(t => t.value === tag)) {
|
||||
// A feched tag has been removed
|
||||
addRemovedContentTag(id, tag);
|
||||
}
|
||||
});
|
||||
}, [globalTagsToRemove, removeGlobalStagedContentTag, id]);
|
||||
|
||||
// Handles making requests to the update endpoint when the staged tags need to be committed
|
||||
const commitStagedTags = React.useCallback(() => {
|
||||
const commitStagedTagsToGlobal = React.useCallback(() => {
|
||||
// Filter out only leaf nodes of staging tree to commit
|
||||
const explicitStaged = getLeafTags(stagedContentTagsTree);
|
||||
|
||||
// Filter out applied tags that should become implicit because a child tag was committed
|
||||
const stagedLineages = stagedContentTags.map(st => decodeURIComponent(st.value).split(',').slice(0, -1)).flat();
|
||||
const applied = contentTags.map((t) => t.value).filter(t => !stagedLineages.includes(t));
|
||||
const globalTags = cloneDeep(globalStagedContentTags);
|
||||
const newGlobalTags = [];
|
||||
|
||||
updateTags.mutate({ tags: [...applied, ...explicitStaged] });
|
||||
explicitStaged.forEach((tag) => {
|
||||
if (globalStagedRemovedContentTags[id]
|
||||
&& globalStagedRemovedContentTags[id].includes(tag.value)) {
|
||||
// A feched tag that has been removed has been added again
|
||||
deleteRemovedContentTag(id, tag.value);
|
||||
} else {
|
||||
// New tag added
|
||||
newGlobalTags.push(tag);
|
||||
}
|
||||
});
|
||||
|
||||
if (newGlobalTags) {
|
||||
if (!globalTags[id]) {
|
||||
globalTags[id] = newGlobalTags;
|
||||
} else {
|
||||
// Filter out applied tags that should become implicit because a child tag was committed
|
||||
const stagedLineages = stagedContentTags.map(st => decodeURIComponent(st.value).split(',').slice(0, -1)).flat();
|
||||
const applied = globalTags[id].filter(t => !stagedLineages.includes(t.value));
|
||||
|
||||
globalTags[id] = [...applied, ...newGlobalTags];
|
||||
}
|
||||
|
||||
setGlobalStagedContentTags(globalTags);
|
||||
}
|
||||
}, [contentTags, stagedContentTags, stagedContentTagsTree, updateTags]);
|
||||
|
||||
// This converts the contentTags prop to the tree structure mentioned above
|
||||
@@ -246,8 +290,12 @@ const useContentTagsCollapsibleHelper = (
|
||||
canChangeObjecttag: false,
|
||||
canDeleteObjecttag: false,
|
||||
};
|
||||
} else {
|
||||
if (isExplicit) {
|
||||
traversal[tag].lineage = tagLineage;
|
||||
}
|
||||
} /* istanbul ignore next */ else {
|
||||
traversal[tag].explicit = isExplicit;
|
||||
traversal[tag].lineage = tagLineage;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
@@ -301,10 +349,10 @@ const useContentTagsCollapsibleHelper = (
|
||||
remove(tagSelectableBoxValue);
|
||||
|
||||
// Remove tags from applied tags
|
||||
const tagsToRemove = removeTags(appliedContentTagsTree, tagLineage, false, tagLineage);
|
||||
setStagedTagsToRemove(tagsToRemove);
|
||||
removeTags(appliedContentTagsTree, tagLineage, false, tagLineage);
|
||||
const selectedTag = tagLineage.slice(-1)[0];
|
||||
|
||||
setRemoveAppliedTag(true);
|
||||
setGlobalTagsToRemove([selectedTag]);
|
||||
}, [appliedContentTagsTree, id, removeStagedContentTag]);
|
||||
|
||||
return {
|
||||
@@ -314,7 +362,7 @@ const useContentTagsCollapsibleHelper = (
|
||||
stagedContentTagsTree: sortKeysAlphabetically(stagedContentTagsTree),
|
||||
contentTagsCount,
|
||||
checkedTags,
|
||||
commitStagedTags,
|
||||
commitStagedTagsToGlobal,
|
||||
updateTags,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,30 +1,78 @@
|
||||
// @ts-check
|
||||
import React, {
|
||||
useMemo,
|
||||
useEffect,
|
||||
useState,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Container,
|
||||
CloseButton,
|
||||
Spinner,
|
||||
Stack,
|
||||
Button,
|
||||
Toast,
|
||||
} from '@openedx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import messages from './messages';
|
||||
import ContentTagsCollapsible from './ContentTagsCollapsible';
|
||||
import { extractOrgFromContentId } from './utils';
|
||||
import {
|
||||
useContentTaxonomyTagsData,
|
||||
useContentData,
|
||||
} from './data/apiHooks';
|
||||
import { useTaxonomyList } from '../taxonomy/data/apiHooks';
|
||||
import Loading from '../generic/Loading';
|
||||
import useContentTagsDrawerContext from './ContentTagsDrawerHelper';
|
||||
import { ContentTagsDrawerContext, ContentTagsDrawerSheetContext } from './common/context';
|
||||
|
||||
/** @typedef {import("../taxonomy/data/types.mjs").TaxonomyData} TaxonomyData */
|
||||
/** @typedef {import("./data/types.mjs").Tag} ContentTagData */
|
||||
const TaxonomyList = ({ contentId }) => {
|
||||
const navigate = useNavigate();
|
||||
const intl = useIntl();
|
||||
|
||||
const {
|
||||
isTaxonomyListLoaded,
|
||||
isContentTaxonomyTagsLoaded,
|
||||
tagsByTaxonomy,
|
||||
stagedContentTags,
|
||||
collapsibleStates,
|
||||
} = React.useContext(ContentTagsDrawerContext);
|
||||
|
||||
if (isTaxonomyListLoaded && isContentTaxonomyTagsLoaded) {
|
||||
if (tagsByTaxonomy.length !== 0) {
|
||||
return (
|
||||
<div>
|
||||
{ tagsByTaxonomy.map((data) => (
|
||||
<div key={`taxonomy-tags-collapsible-${data.id}`}>
|
||||
<ContentTagsCollapsible
|
||||
contentId={contentId}
|
||||
taxonomyAndTagsData={data}
|
||||
stagedContentTags={stagedContentTags[data.id] || []}
|
||||
collapsibleState={collapsibleStates[data.id] || false}
|
||||
/>
|
||||
<hr />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormattedMessage
|
||||
{...messages.emptyDrawerContent}
|
||||
values={{
|
||||
link: (
|
||||
<Button
|
||||
tabIndex="0"
|
||||
size="inline"
|
||||
variant="link"
|
||||
className="text-info-500 p-0 enable-taxonomies-button"
|
||||
onClick={() => navigate('/taxonomies')}
|
||||
>
|
||||
{ intl.formatMessage(messages.emptyDrawerContentLink) }
|
||||
</Button>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <Loading />;
|
||||
};
|
||||
|
||||
TaxonomyList.propTypes = {
|
||||
contentId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* Drawer with the functionality to show and manage tags in a certain content.
|
||||
@@ -41,49 +89,27 @@ const ContentTagsDrawer = ({ id, onClose }) => {
|
||||
const params = useParams();
|
||||
const contentId = id ?? params.contentId;
|
||||
|
||||
const org = extractOrgFromContentId(contentId);
|
||||
const context = useContentTagsDrawerContext(contentId);
|
||||
const { blockingSheet } = useContext(ContentTagsDrawerSheetContext);
|
||||
|
||||
const [stagedContentTags, setStagedContentTags] = useState({});
|
||||
|
||||
// Add a content tags to the staged tags for a taxonomy
|
||||
const addStagedContentTag = useCallback((taxonomyId, addedTag) => {
|
||||
setStagedContentTags(prevStagedContentTags => {
|
||||
const updatedStagedContentTags = {
|
||||
...prevStagedContentTags,
|
||||
[taxonomyId]: [...(prevStagedContentTags[taxonomyId] ?? []), addedTag],
|
||||
};
|
||||
return updatedStagedContentTags;
|
||||
});
|
||||
}, [setStagedContentTags]);
|
||||
|
||||
// Remove a content tag from the staged tags for a taxonomy
|
||||
const removeStagedContentTag = useCallback((taxonomyId, tagValue) => {
|
||||
setStagedContentTags(prevStagedContentTags => ({
|
||||
...prevStagedContentTags,
|
||||
[taxonomyId]: prevStagedContentTags[taxonomyId].filter((t) => t.value !== tagValue),
|
||||
}));
|
||||
}, [setStagedContentTags]);
|
||||
|
||||
// Sets the staged content tags for taxonomy to the provided list of tags
|
||||
const setStagedTags = useCallback((taxonomyId, tagsList) => {
|
||||
setStagedContentTags(prevStagedContentTags => ({ ...prevStagedContentTags, [taxonomyId]: tagsList }));
|
||||
}, [setStagedContentTags]);
|
||||
|
||||
const { data: contentData, isSuccess: isContentDataLoaded } = useContentData(contentId);
|
||||
const {
|
||||
data: contentTaxonomyTagsData,
|
||||
isSuccess: isContentTaxonomyTagsLoaded,
|
||||
} = useContentTaxonomyTagsData(contentId);
|
||||
const { data: taxonomyListData, isSuccess: isTaxonomyListLoaded } = useTaxonomyList(org);
|
||||
|
||||
let contentName = '';
|
||||
if (isContentDataLoaded) {
|
||||
if ('displayName' in contentData) {
|
||||
contentName = contentData.displayName;
|
||||
} else {
|
||||
contentName = contentData.courseDisplayNameWithDefault;
|
||||
}
|
||||
}
|
||||
showToastAfterSave,
|
||||
toReadMode,
|
||||
commitGlobalStagedTagsStatus,
|
||||
isContentDataLoaded,
|
||||
contentName,
|
||||
isTaxonomyListLoaded,
|
||||
isContentTaxonomyTagsLoaded,
|
||||
stagedContentTags,
|
||||
collapsibleStates,
|
||||
isEditMode,
|
||||
commitGlobalStagedTags,
|
||||
toEditMode,
|
||||
toastMessage,
|
||||
closeToast,
|
||||
setCollapsibleToInitalState,
|
||||
otherTaxonomies,
|
||||
} = context;
|
||||
|
||||
let onCloseDrawer = onClose;
|
||||
if (onCloseDrawer === undefined) {
|
||||
@@ -97,7 +123,7 @@ const ContentTagsDrawer = ({ id, onClose }) => {
|
||||
const handleEsc = (event) => {
|
||||
/* Close drawer when ESC-key is pressed and selectable dropdown box not open */
|
||||
const selectableBoxOpen = document.querySelector('[data-selectable-box="taxonomy-tags"]');
|
||||
if (event.key === 'Escape' && !selectableBoxOpen) {
|
||||
if (event.key === 'Escape' && !selectableBoxOpen && !blockingSheet) {
|
||||
onCloseDrawer();
|
||||
}
|
||||
};
|
||||
@@ -106,69 +132,121 @@ const ContentTagsDrawer = ({ id, onClose }) => {
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleEsc);
|
||||
};
|
||||
}, []);
|
||||
}, [blockingSheet]);
|
||||
|
||||
const taxonomies = useMemo(() => {
|
||||
if (taxonomyListData && contentTaxonomyTagsData) {
|
||||
// Initialize list of content tags in taxonomies to populate
|
||||
const taxonomiesList = taxonomyListData.results.map((taxonomy) => ({
|
||||
...taxonomy,
|
||||
contentTags: /** @type {ContentTagData[]} */([]),
|
||||
}));
|
||||
|
||||
const contentTaxonomies = contentTaxonomyTagsData.taxonomies;
|
||||
|
||||
// eslint-disable-next-line array-callback-return
|
||||
contentTaxonomies.map((contentTaxonomyTags) => {
|
||||
const contentTaxonomy = taxonomiesList.find((taxonomy) => taxonomy.id === contentTaxonomyTags.taxonomyId);
|
||||
if (contentTaxonomy) {
|
||||
contentTaxonomy.contentTags = contentTaxonomyTags.tags;
|
||||
}
|
||||
});
|
||||
|
||||
return taxonomiesList;
|
||||
useEffect(() => {
|
||||
/* istanbul ignore next */
|
||||
if (commitGlobalStagedTagsStatus === 'success') {
|
||||
showToastAfterSave();
|
||||
toReadMode();
|
||||
}
|
||||
return [];
|
||||
}, [taxonomyListData, contentTaxonomyTagsData]);
|
||||
}, [commitGlobalStagedTagsStatus]);
|
||||
|
||||
// First call of the initial collapsible states
|
||||
React.useEffect(() => {
|
||||
setCollapsibleToInitalState();
|
||||
}, [isTaxonomyListLoaded, isContentTaxonomyTagsLoaded]);
|
||||
|
||||
return (
|
||||
<ContentTagsDrawerContext.Provider value={context}>
|
||||
<div id="content-tags-drawer" className="mt-1 tags-drawer d-flex flex-column justify-content-between min-vh-100 pt-3">
|
||||
<Container size="xl">
|
||||
{ isContentDataLoaded
|
||||
? <h2 className="h3 pl-2.5">{ contentName }</h2>
|
||||
: (
|
||||
<div className="d-flex justify-content-center align-items-center flex-column">
|
||||
<Spinner
|
||||
animation="border"
|
||||
size="xl"
|
||||
screenReaderText={intl.formatMessage(messages.loadingMessage)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<hr />
|
||||
<Container>
|
||||
<p className="h4 text-gray-500 font-weight-bold">
|
||||
{intl.formatMessage(messages.headerSubtitle)}
|
||||
</p>
|
||||
<TaxonomyList contentId={contentId} />
|
||||
{otherTaxonomies.length !== 0 && (
|
||||
<div>
|
||||
<p className="h4 text-gray-500 font-weight-bold">
|
||||
{intl.formatMessage(messages.otherTagsHeader)}
|
||||
</p>
|
||||
<p className="other-description text-gray-500">
|
||||
{intl.formatMessage(messages.otherTagsDescription)}
|
||||
</p>
|
||||
{ isTaxonomyListLoaded && isContentTaxonomyTagsLoaded && (
|
||||
otherTaxonomies.map((data) => (
|
||||
<div key={`taxonomy-tags-collapsible-${data.id}`}>
|
||||
<ContentTagsCollapsible
|
||||
contentId={contentId}
|
||||
taxonomyAndTagsData={data}
|
||||
stagedContentTags={stagedContentTags[data.id] || []}
|
||||
collapsibleState={collapsibleStates[data.id] || false}
|
||||
/>
|
||||
<hr />
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
</Container>
|
||||
|
||||
<div className="mt-1">
|
||||
<Container size="xl">
|
||||
<CloseButton onClick={() => onCloseDrawer()} data-testid="drawer-close-button" />
|
||||
<span>{intl.formatMessage(messages.headerSubtitle)}</span>
|
||||
{ isContentDataLoaded
|
||||
? <h3>{ contentName }</h3>
|
||||
: (
|
||||
<div className="d-flex justify-content-center align-items-center flex-column">
|
||||
<Spinner
|
||||
animation="border"
|
||||
size="xl"
|
||||
screenReaderText={intl.formatMessage(messages.loadingMessage)}
|
||||
/>
|
||||
{ isTaxonomyListLoaded && isContentTaxonomyTagsLoaded && (
|
||||
<Container
|
||||
className="bg-white position-sticky p-3.5 box-shadow-up-2 tags-drawer-footer"
|
||||
>
|
||||
<div className="d-flex justify-content-end">
|
||||
{ commitGlobalStagedTagsStatus !== 'loading' ? (
|
||||
<Stack direction="horizontal" gap={2}>
|
||||
<Button
|
||||
className="font-weight-bold tags-drawer-cancel-button"
|
||||
variant="tertiary"
|
||||
onClick={isEditMode
|
||||
? toReadMode
|
||||
: onCloseDrawer}
|
||||
>
|
||||
{ intl.formatMessage(isEditMode
|
||||
? messages.tagsDrawerCancelButtonText
|
||||
: messages.tagsDrawerCloseButtonText)}
|
||||
</Button>
|
||||
<Button
|
||||
variant="dark"
|
||||
className="rounded-0"
|
||||
onClick={isEditMode
|
||||
? commitGlobalStagedTags
|
||||
: toEditMode}
|
||||
>
|
||||
{ intl.formatMessage(isEditMode
|
||||
? messages.tagsDrawerSaveButtonText
|
||||
: messages.tagsDrawerEditTagsButtonText)}
|
||||
</Button>
|
||||
</Stack>
|
||||
)
|
||||
: (
|
||||
<Spinner
|
||||
animation="border"
|
||||
size="xl"
|
||||
screenReaderText={intl.formatMessage(messages.loadingMessage)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<hr />
|
||||
|
||||
{ isTaxonomyListLoaded && isContentTaxonomyTagsLoaded
|
||||
? taxonomies.map((data) => (
|
||||
<div key={`taxonomy-tags-collapsible-${data.id}`}>
|
||||
<ContentTagsCollapsible
|
||||
contentId={contentId}
|
||||
taxonomyAndTagsData={data}
|
||||
stagedContentTags={stagedContentTags[data.id] || []}
|
||||
addStagedContentTag={addStagedContentTag}
|
||||
removeStagedContentTag={removeStagedContentTag}
|
||||
setStagedTags={setStagedTags}
|
||||
/>
|
||||
<hr />
|
||||
</div>
|
||||
))
|
||||
: <Loading />}
|
||||
|
||||
</Container>
|
||||
</div>
|
||||
</Container>
|
||||
)}
|
||||
{/* istanbul ignore next */
|
||||
toastMessage && (
|
||||
<Toast
|
||||
show
|
||||
onClose={closeToast}
|
||||
>
|
||||
{toastMessage}
|
||||
</Toast>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</ContentTagsDrawerContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
39
src/content-tags-drawer/ContentTagsDrawer.scss
Normal file
39
src/content-tags-drawer/ContentTagsDrawer.scss
Normal file
@@ -0,0 +1,39 @@
|
||||
.pgn__sheet-component:has(#content-tags-drawer) {
|
||||
min-width: max(500px, 33vw);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
.pgn__sheet-component:has(#content-tags-drawer) {
|
||||
min-width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-drawer {
|
||||
.tags-drawer-footer {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.tags-drawer-cancel-button:hover {
|
||||
background-color: transparent;
|
||||
color: $gray-300 !important;
|
||||
}
|
||||
|
||||
.other-description {
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.enable-taxonomies-button:not([disabled]):hover {
|
||||
background-color: transparent;
|
||||
color: $info-900 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply styles to sheet only if it has a child with a .tags-drawer class
|
||||
.pgn__sheet-component {
|
||||
&:has(.tags-drawer) {
|
||||
overflow-y: scroll;
|
||||
padding: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
render,
|
||||
waitFor,
|
||||
screen,
|
||||
within,
|
||||
} from '@testing-library/react';
|
||||
|
||||
import ContentTagsDrawer from './ContentTagsDrawer';
|
||||
@@ -14,32 +15,37 @@ import {
|
||||
useContentTaxonomyTagsData,
|
||||
useContentData,
|
||||
useTaxonomyTagsData,
|
||||
useContentTaxonomyTagsUpdater,
|
||||
} from './data/apiHooks';
|
||||
import { getTaxonomyListData } from '../taxonomy/data/api';
|
||||
import messages from './messages';
|
||||
import { ContentTagsDrawerSheetContext } from './common/context';
|
||||
import { languageExportId } from './utils';
|
||||
|
||||
const contentId = 'block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@7f47fe2dbcaf47c5a071671c741fe1ab';
|
||||
const mockOnClose = jest.fn();
|
||||
const mockMutate = jest.fn();
|
||||
const mockSetBlockingSheet = jest.fn();
|
||||
const mockNavigate = jest.fn();
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useParams: () => ({
|
||||
contentId,
|
||||
}),
|
||||
useNavigate: () => mockNavigate,
|
||||
}));
|
||||
|
||||
// FIXME: replace these mocks with API mocks
|
||||
jest.mock('./data/apiHooks', () => ({
|
||||
useContentTaxonomyTagsData: jest.fn(() => ({
|
||||
isSuccess: false,
|
||||
data: {},
|
||||
})),
|
||||
useContentTaxonomyTagsData: jest.fn(() => {}),
|
||||
useContentData: jest.fn(() => ({
|
||||
isSuccess: false,
|
||||
data: {},
|
||||
})),
|
||||
useContentTaxonomyTagsUpdater: jest.fn(() => ({
|
||||
isError: false,
|
||||
mutate: mockMutate,
|
||||
})),
|
||||
useTaxonomyTagsData: jest.fn(() => ({
|
||||
hasMorePages: false,
|
||||
@@ -60,19 +66,26 @@ jest.mock('../taxonomy/data/api', () => ({
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const RootWrapper = (params) => (
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ContentTagsDrawer {...params} />
|
||||
</QueryClientProvider>
|
||||
</IntlProvider>
|
||||
<ContentTagsDrawerSheetContext.Provider value={params}>
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ContentTagsDrawer {...params} />
|
||||
</QueryClientProvider>
|
||||
</IntlProvider>
|
||||
</ContentTagsDrawerSheetContext.Provider>
|
||||
);
|
||||
|
||||
describe('<ContentTagsDrawer />', () => {
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
await queryClient.resetQueries();
|
||||
// By default, we mock the API call with a promise that never resolves.
|
||||
// You can override this in specific test.
|
||||
getTaxonomyListData.mockReturnValue(new Promise(() => {}));
|
||||
useContentTaxonomyTagsUpdater.mockReturnValue({
|
||||
isError: false,
|
||||
mutate: mockMutate,
|
||||
});
|
||||
});
|
||||
|
||||
const setupMockDataForStagedTagsTesting = () => {
|
||||
@@ -101,12 +114,322 @@ describe('<ContentTagsDrawer />', () => {
|
||||
},
|
||||
});
|
||||
getTaxonomyListData.mockResolvedValue({
|
||||
results: [{
|
||||
id: 123,
|
||||
name: 'Taxonomy 1',
|
||||
description: 'This is a description 1',
|
||||
canTagObject: true,
|
||||
}],
|
||||
results: [
|
||||
{
|
||||
id: 123,
|
||||
name: 'Taxonomy 1',
|
||||
description: 'This is a description 1',
|
||||
canTagObject: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
useTaxonomyTagsData.mockReturnValue({
|
||||
hasMorePages: false,
|
||||
canAddTag: false,
|
||||
tagPages: {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
data: [{
|
||||
value: 'Tag 1',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12345,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}, {
|
||||
value: 'Tag 2',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12346,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}, {
|
||||
value: 'Tag 3',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12347,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const setupMockDataWithOtherTagsTestings = () => {
|
||||
useContentTaxonomyTagsData.mockReturnValue({
|
||||
isSuccess: true,
|
||||
data: {
|
||||
taxonomies: [
|
||||
{
|
||||
name: 'Taxonomy 1',
|
||||
taxonomyId: 123,
|
||||
canTagObject: true,
|
||||
tags: [
|
||||
{
|
||||
value: 'Tag 1',
|
||||
lineage: ['Tag 1'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
{
|
||||
value: 'Tag 2',
|
||||
lineage: ['Tag 2'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Taxonomy 2',
|
||||
taxonomyId: 1234,
|
||||
canTagObject: false,
|
||||
tags: [
|
||||
{
|
||||
value: 'Tag 3',
|
||||
lineage: ['Tag 3'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
{
|
||||
value: 'Tag 4',
|
||||
lineage: ['Tag 4'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
getTaxonomyListData.mockResolvedValue({
|
||||
results: [
|
||||
{
|
||||
id: 123,
|
||||
name: 'Taxonomy 1',
|
||||
description: 'This is a description 1',
|
||||
canTagObject: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
useTaxonomyTagsData.mockReturnValue({
|
||||
hasMorePages: false,
|
||||
canAddTag: false,
|
||||
tagPages: {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
data: [{
|
||||
value: 'Tag 1',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12345,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}, {
|
||||
value: 'Tag 2',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12346,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}, {
|
||||
value: 'Tag 3',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12347,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const setupMockDataLanguageTaxonomyTestings = (hasTags) => {
|
||||
useContentTaxonomyTagsData.mockReturnValue({
|
||||
isSuccess: true,
|
||||
data: {
|
||||
taxonomies: [
|
||||
{
|
||||
name: 'Languages',
|
||||
taxonomyId: 123,
|
||||
exportId: languageExportId,
|
||||
canTagObject: true,
|
||||
tags: hasTags ? [
|
||||
{
|
||||
value: 'Tag 1',
|
||||
lineage: ['Tag 1'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
] : [],
|
||||
},
|
||||
{
|
||||
name: 'Taxonomy 1',
|
||||
taxonomyId: 1234,
|
||||
canTagObject: true,
|
||||
tags: [
|
||||
{
|
||||
value: 'Tag 1',
|
||||
lineage: ['Tag 1'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
{
|
||||
value: 'Tag 2',
|
||||
lineage: ['Tag 2'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
getTaxonomyListData.mockResolvedValue({
|
||||
results: [
|
||||
{
|
||||
id: 123,
|
||||
name: 'Languages',
|
||||
description: 'This is a description 1',
|
||||
exportId: languageExportId,
|
||||
canTagObject: true,
|
||||
},
|
||||
{
|
||||
id: 1234,
|
||||
name: 'Taxonomy 1',
|
||||
description: 'This is a description 2',
|
||||
canTagObject: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
useTaxonomyTagsData.mockReturnValue({
|
||||
hasMorePages: false,
|
||||
canAddTag: false,
|
||||
tagPages: {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
data: [{
|
||||
value: 'Tag 1',
|
||||
externalId: null,
|
||||
childCount: 0,
|
||||
depth: 0,
|
||||
parentValue: null,
|
||||
id: 12345,
|
||||
subTagsUrl: null,
|
||||
canChangeTag: false,
|
||||
canDeleteTag: false,
|
||||
}],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const setupLargeMockDataForStagedTagsTesting = () => {
|
||||
useContentTaxonomyTagsData.mockReturnValue({
|
||||
isSuccess: true,
|
||||
data: {
|
||||
taxonomies: [
|
||||
{
|
||||
name: 'Taxonomy 1',
|
||||
taxonomyId: 123,
|
||||
canTagObject: true,
|
||||
tags: [
|
||||
{
|
||||
value: 'Tag 1',
|
||||
lineage: ['Tag 1'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
{
|
||||
value: 'Tag 2',
|
||||
lineage: ['Tag 2'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Taxonomy 2',
|
||||
taxonomyId: 124,
|
||||
canTagObject: true,
|
||||
tags: [
|
||||
{
|
||||
value: 'Tag 1',
|
||||
lineage: ['Tag 1'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Taxonomy 3',
|
||||
taxonomyId: 125,
|
||||
canTagObject: true,
|
||||
tags: [
|
||||
{
|
||||
value: 'Tag 1.1.1',
|
||||
lineage: ['Tag 1', 'Tag 1.1', 'Tag 1.1.1'],
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '(B) Taxonomy 4',
|
||||
taxonomyId: 126,
|
||||
canTagObject: true,
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: '(A) Taxonomy 5',
|
||||
taxonomyId: 127,
|
||||
canTagObject: true,
|
||||
tags: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
getTaxonomyListData.mockResolvedValue({
|
||||
results: [
|
||||
{
|
||||
id: 123,
|
||||
name: 'Taxonomy 1',
|
||||
description: 'This is a description 1',
|
||||
canTagObject: true,
|
||||
},
|
||||
{
|
||||
id: 124,
|
||||
name: 'Taxonomy 2',
|
||||
description: 'This is a description 2',
|
||||
canTagObject: true,
|
||||
},
|
||||
{
|
||||
id: 125,
|
||||
name: 'Taxonomy 3',
|
||||
description: 'This is a description 3',
|
||||
canTagObject: true,
|
||||
},
|
||||
{
|
||||
id: 127,
|
||||
name: '(A) Taxonomy 5',
|
||||
description: 'This is a description 5',
|
||||
canTagObject: true,
|
||||
},
|
||||
{
|
||||
id: 126,
|
||||
name: '(B) Taxonomy 4',
|
||||
description: 'This is a description 4',
|
||||
canTagObject: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
useTaxonomyTagsData.mockReturnValue({
|
||||
@@ -151,6 +474,7 @@ describe('<ContentTagsDrawer />', () => {
|
||||
};
|
||||
|
||||
it('should render page and page title correctly', () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
const { getByText } = render(<RootWrapper />);
|
||||
expect(getByText('Manage tags')).toBeInTheDocument();
|
||||
});
|
||||
@@ -250,68 +574,149 @@ describe('<ContentTagsDrawer />', () => {
|
||||
await waitFor(() => { expect(getByText('Taxonomy 1')).toBeInTheDocument(); });
|
||||
expect(getByText('Taxonomy 1')).toBeInTheDocument();
|
||||
expect(getByText('Taxonomy 2')).toBeInTheDocument();
|
||||
const tagCountBadges = container.getElementsByClassName('badge');
|
||||
const tagCountBadges = container.getElementsByClassName('taxonomy-tags-count-chip');
|
||||
expect(tagCountBadges[0].textContent).toBe('2');
|
||||
expect(tagCountBadges[1].textContent).toBe('1');
|
||||
});
|
||||
});
|
||||
|
||||
it('should be read only on first render', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
// Not show delete tag buttons
|
||||
expect(screen.queryByRole('button', { name: /delete/i })).not.toBeInTheDocument();
|
||||
|
||||
// Not show add a tag select
|
||||
expect(screen.queryByText(/add a tag/i)).not.toBeInTheDocument();
|
||||
|
||||
// Not show cancel button
|
||||
expect(screen.queryByRole('button', { name: /cancel/i })).not.toBeInTheDocument();
|
||||
|
||||
// Not show save button
|
||||
expect(screen.queryByRole('button', { name: /save/i })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should change to edit mode when click on `Edit tags`', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Show delete tag buttons
|
||||
expect(screen.getAllByRole('button', {
|
||||
name: /delete/i,
|
||||
}).length).toBe(2);
|
||||
|
||||
// Show add a tag select
|
||||
expect(screen.getByText(/add a tag/i)).toBeInTheDocument();
|
||||
|
||||
// Show cancel button
|
||||
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
|
||||
|
||||
// Show save button
|
||||
expect(screen.getByRole('button', { name: /save/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should change to read mode when click on `Cancel`', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
const cancelButton = screen.getByRole('button', {
|
||||
name: /cancel/i,
|
||||
});
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
// Not show delete tag buttons
|
||||
expect(screen.queryByRole('button', { name: /delete/i })).not.toBeInTheDocument();
|
||||
|
||||
// Not show add a tag select
|
||||
expect(screen.queryByText(/add a tag/i)).not.toBeInTheDocument();
|
||||
|
||||
// Not show cancel button
|
||||
expect(screen.queryByRole('button', { name: /cancel/i })).not.toBeInTheDocument();
|
||||
|
||||
// Not show save button
|
||||
expect(screen.queryByRole('button', { name: /save/i })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows spinner when loading commit tags', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
useContentTaxonomyTagsUpdater.mockReturnValue({
|
||||
status: 'loading',
|
||||
isError: false,
|
||||
mutate: mockMutate,
|
||||
});
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
expect(screen.getByRole('status')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should test adding a content tag to the staged tags for a taxonomy', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
const { container, getByText, getAllByText } = render(<RootWrapper />);
|
||||
await waitFor(() => { expect(getByText('Taxonomy 1')).toBeInTheDocument(); });
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
const addTagsButton = screen.getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
// Tag 3 should only appear in dropdown selector, (i.e. the dropdown is open, since Tag 3 is not applied)
|
||||
expect(getAllByText('Tag 3').length).toBe(1);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(1);
|
||||
|
||||
// Click to check Tag 3
|
||||
const tag3 = getByText('Tag 3');
|
||||
const tag3 = screen.getByText('Tag 3');
|
||||
fireEvent.click(tag3);
|
||||
|
||||
// Check that Tag 3 has been staged, i.e. there should be 2 of them on the page
|
||||
expect(getAllByText('Tag 3').length).toBe(2);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should test removing a staged content from a taxonomy', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
const { container, getByText, getAllByText } = render(<RootWrapper />);
|
||||
await waitFor(() => { expect(getByText('Taxonomy 1')).toBeInTheDocument(); });
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
const addTagsButton = screen.getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
// Tag 3 should only appear in dropdown selector, (i.e. the dropdown is open, since Tag 3 is not applied)
|
||||
expect(getAllByText('Tag 3').length).toBe(1);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(1);
|
||||
|
||||
// Click to check Tag 3
|
||||
const tag3 = getByText('Tag 3');
|
||||
const tag3 = screen.getByText('Tag 3');
|
||||
fireEvent.click(tag3);
|
||||
|
||||
// Check that Tag 3 has been staged, i.e. there should be 2 of them on the page
|
||||
expect(getAllByText('Tag 3').length).toBe(2);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(2);
|
||||
|
||||
// Click it again to unstage it and confirm that there is only one on the page
|
||||
fireEvent.click(tag3);
|
||||
expect(getAllByText('Tag 3').length).toBe(1);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should test clearing staged tags for a taxonomy', async () => {
|
||||
@@ -319,61 +724,192 @@ describe('<ContentTagsDrawer />', () => {
|
||||
|
||||
const {
|
||||
container,
|
||||
getByText,
|
||||
getAllByText,
|
||||
queryByText,
|
||||
} = render(<RootWrapper />);
|
||||
await waitFor(() => { expect(getByText('Taxonomy 1')).toBeInTheDocument(); });
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
// Expand the Taxonomy to view applied tags and "Add a tag" button
|
||||
const expandToggle = container.getElementsByClassName('collapsible-trigger')[0];
|
||||
|
||||
fireEvent.click(expandToggle);
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = getByText(messages.collapsibleAddTagsPlaceholderText.defaultMessage);
|
||||
const addTagsButton = screen.getByText(/add a tag/i);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
// Tag 3 should only appear in dropdown selector, (i.e. the dropdown is open, since Tag 3 is not applied)
|
||||
expect(getAllByText('Tag 3').length).toBe(1);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(1);
|
||||
|
||||
// Click to check Tag 3
|
||||
const tag3 = getByText('Tag 3');
|
||||
const tag3 = screen.getByText('Tag 3');
|
||||
fireEvent.click(tag3);
|
||||
|
||||
// Check that Tag 3 has been staged, i.e. there should be 2 of them on the page
|
||||
expect(getAllByText('Tag 3').length).toBe(2);
|
||||
expect(screen.getAllByText('Tag 3').length).toBe(2);
|
||||
|
||||
// Click on the Cancel button in the dropdown to clear the staged tags
|
||||
const dropdownCancel = getByText(messages.collapsibleCancelStagedTagsButtonText.defaultMessage);
|
||||
const dropdown = container.querySelector('#content-tags-drawer > div:nth-child(1) > div');
|
||||
const dropdownCancel = within(dropdown).getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(dropdownCancel);
|
||||
|
||||
// Check that there are no more Tag 3 on the page, since the staged one is cleared
|
||||
// and the dropdown has been closed
|
||||
expect(queryByText('Tag 3')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Tag 3')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call closeManageTagsDrawer when CloseButton is clicked', async () => {
|
||||
const postMessageSpy = jest.spyOn(window.parent, 'postMessage');
|
||||
it('should test adding global staged tags and cancel', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
const { getByTestId } = render(<RootWrapper />);
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Find the CloseButton element by its test ID and trigger a click event
|
||||
const closeButton = getByTestId('drawer-close-button');
|
||||
fireEvent.click(closeButton);
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = screen.getByText(/add a tag/i);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
expect(postMessageSpy).toHaveBeenCalledWith('closeManageTagsDrawer', '*');
|
||||
// Click to check Tag 3
|
||||
const tag3 = screen.getByText(/tag 3/i);
|
||||
fireEvent.click(tag3);
|
||||
|
||||
postMessageSpy.mockRestore();
|
||||
// Click "Add tags" to save to global staged tags
|
||||
const addTags = screen.getByRole('button', { name: /add tags/i });
|
||||
fireEvent.click(addTags);
|
||||
|
||||
expect(screen.getByText(/tag 3/i)).toBeInTheDocument();
|
||||
|
||||
// Click "Cancel"
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(screen.queryByText(/tag 3/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call onClose param when CloseButton is clicked', async () => {
|
||||
it('should test delete feched tags and cancel', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Delete the tag
|
||||
const tag = screen.getByText(/tag 2/i);
|
||||
const deleteButton = within(tag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
expect(tag).not.toBeInTheDocument();
|
||||
|
||||
// Click "Cancel"
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(screen.getByText(/tag 2/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should test delete global staged tags and cancel', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = screen.getByText(/add a tag/i);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
// Click to check Tag 3
|
||||
const tag3 = screen.getByText(/tag 3/i);
|
||||
fireEvent.click(tag3);
|
||||
|
||||
// Click "Add tags" to save to global staged tags
|
||||
const addTags = screen.getByRole('button', { name: /add tags/i });
|
||||
fireEvent.click(addTags);
|
||||
|
||||
const tag = screen.getByText(/tag 3/i);
|
||||
expect(screen.getByText(/tag 3/i)).toBeInTheDocument();
|
||||
|
||||
// Delete the tag
|
||||
const deleteButton = within(tag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
expect(tag).not.toBeInTheDocument();
|
||||
|
||||
// Click "Cancel"
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(screen.queryByText(/tag 3/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should test add removed feched tags and cancel', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Delete the tag
|
||||
const tag = screen.getByText(/tag 2/i);
|
||||
const deleteButton = within(tag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
expect(tag).not.toBeInTheDocument();
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = screen.getByText(/add a tag/i);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
// Click to check Tag 2
|
||||
const tag2 = screen.getByText(/tag 2/i);
|
||||
fireEvent.click(tag2);
|
||||
|
||||
// Click "Add tags" to save to global staged tags
|
||||
const addTags = screen.getByRole('button', { name: /add tags/i });
|
||||
fireEvent.click(addTags);
|
||||
|
||||
expect(screen.getByText(/tag 2/i)).toBeInTheDocument();
|
||||
|
||||
// Click "Cancel"
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(screen.getByText(/tag 2/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call onClose when cancel is clicked', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper onClose={mockOnClose} />);
|
||||
|
||||
// Find the CloseButton element by its test ID and trigger a click event
|
||||
const closeButton = screen.getByTestId('drawer-close-button');
|
||||
fireEvent.click(closeButton);
|
||||
const cancelButton = await screen.findByRole('button', {
|
||||
name: /close/i,
|
||||
});
|
||||
expect(cancelButton).toBeInTheDocument();
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
@@ -392,6 +928,16 @@ describe('<ContentTagsDrawer />', () => {
|
||||
postMessageSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should call `onClose` when Escape key is pressed and no selectable box is active', () => {
|
||||
const { container } = render(<RootWrapper onClose={mockOnClose} />);
|
||||
|
||||
fireEvent.keyDown(container, {
|
||||
key: 'Escape',
|
||||
});
|
||||
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call closeManageTagsDrawer when Escape key is pressed and a selectable box is active', () => {
|
||||
const postMessageSpy = jest.spyOn(window.parent, 'postMessage');
|
||||
|
||||
@@ -413,4 +959,225 @@ describe('<ContentTagsDrawer />', () => {
|
||||
|
||||
postMessageSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should not call `onClose` when Escape key is pressed and a selectable box is active', () => {
|
||||
const { container } = render(<RootWrapper onClose={mockOnClose} />);
|
||||
|
||||
// Simulate that the selectable box is open by adding an element with the data attribute
|
||||
const selectableBox = document.createElement('div');
|
||||
selectableBox.setAttribute('data-selectable-box', 'taxonomy-tags');
|
||||
document.body.appendChild(selectableBox);
|
||||
|
||||
fireEvent.keyDown(container, {
|
||||
key: 'Escape',
|
||||
});
|
||||
|
||||
expect(mockOnClose).not.toHaveBeenCalled();
|
||||
|
||||
// Remove the added element
|
||||
document.body.removeChild(selectableBox);
|
||||
});
|
||||
|
||||
it('should not call closeManageTagsDrawer when Escape key is pressed and container is blocked', () => {
|
||||
const postMessageSpy = jest.spyOn(window.parent, 'postMessage');
|
||||
|
||||
const { container } = render(<RootWrapper blockingSheet />);
|
||||
fireEvent.keyDown(container, {
|
||||
key: 'Escape',
|
||||
});
|
||||
|
||||
expect(postMessageSpy).not.toHaveBeenCalled();
|
||||
|
||||
postMessageSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should not call `onClose` when Escape key is pressed and container is blocked', () => {
|
||||
const { container } = render(<RootWrapper blockingSheet onClose={mockOnClose} />);
|
||||
fireEvent.keyDown(container, {
|
||||
key: 'Escape',
|
||||
});
|
||||
|
||||
expect(mockOnClose).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call `setBlockingSheet` on add a tag', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper blockingSheet setBlockingSheet={mockSetBlockingSheet} />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
expect(mockSetBlockingSheet).toHaveBeenCalledWith(false);
|
||||
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Click on "Add a tag" button to open dropdown
|
||||
const addTagsButton = screen.getByText(/add a tag/i);
|
||||
// Use `mouseDown` instead of `click` since the react-select didn't respond to `click`
|
||||
fireEvent.mouseDown(addTagsButton);
|
||||
|
||||
// Click to check Tag 3
|
||||
const tag3 = screen.getByText(/tag 3/i);
|
||||
fireEvent.click(tag3);
|
||||
|
||||
// Click "Add tags" to save to global staged tags
|
||||
const addTags = screen.getByRole('button', { name: /add tags/i });
|
||||
fireEvent.click(addTags);
|
||||
|
||||
expect(mockSetBlockingSheet).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should call `setBlockingSheet` on delete a tag', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper blockingSheet setBlockingSheet={mockSetBlockingSheet} />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
expect(mockSetBlockingSheet).toHaveBeenCalledWith(false);
|
||||
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Delete the tag
|
||||
const tag = screen.getByText(/tag 2/i);
|
||||
const deleteButton = within(tag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
expect(mockSetBlockingSheet).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should call `updateTags` mutation on save', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
const saveButton = screen.getByRole('button', {
|
||||
name: /save/i,
|
||||
});
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
expect(mockMutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should taxonomies must be ordered', async () => {
|
||||
setupLargeMockDataForStagedTagsTesting();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
// First, taxonomies with content sorted by count implicit
|
||||
// Later, empty taxonomies sorted by name
|
||||
const expectedOrder = [
|
||||
'Taxonomy 3', // 3 tags
|
||||
'Taxonomy 1', // 2 tags
|
||||
'Taxonomy 2', // 1 tag
|
||||
'(A) Taxonomy 5',
|
||||
'(B) Taxonomy 4',
|
||||
];
|
||||
|
||||
const taxonomies = screen.getAllByText(/.*Taxonomy.*/);
|
||||
for (let i = 0; i !== taxonomies.length; i++) {
|
||||
expect(taxonomies[i].textContent).toBe(expectedOrder[i]);
|
||||
}
|
||||
});
|
||||
|
||||
it('should not show "Other tags" section', async () => {
|
||||
setupMockDataForStagedTagsTesting();
|
||||
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText('Other tags')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show "Other tags" section', async () => {
|
||||
setupMockDataWithOtherTagsTestings();
|
||||
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText('Other tags')).toBeInTheDocument();
|
||||
expect(screen.getByText('Taxonomy 2')).toBeInTheDocument();
|
||||
expect(screen.getByText('Tag 3')).toBeInTheDocument();
|
||||
expect(screen.getByText('Tag 4')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should test delete "Other tags" and cancel', async () => {
|
||||
setupMockDataWithOtherTagsTestings();
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 2')).toBeInTheDocument();
|
||||
|
||||
// To edit mode
|
||||
const editTagsButton = screen.getByRole('button', {
|
||||
name: /edit tags/i,
|
||||
});
|
||||
fireEvent.click(editTagsButton);
|
||||
|
||||
// Delete the tag
|
||||
const tag = screen.getByText(/tag 3/i);
|
||||
const deleteButton = within(tag).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(deleteButton);
|
||||
|
||||
expect(tag).not.toBeInTheDocument();
|
||||
|
||||
// Click "Cancel"
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(screen.getByText(/tag 3/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show Language Taxonomy', async () => {
|
||||
setupMockDataLanguageTaxonomyTestings(true);
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Languages')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should hide Language Taxonomy', async () => {
|
||||
setupMockDataLanguageTaxonomyTestings(false);
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText('Taxonomy 1')).toBeInTheDocument();
|
||||
|
||||
expect(screen.queryByText('Languages')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show empty drawer message', async () => {
|
||||
useContentTaxonomyTagsData.mockReturnValue({
|
||||
isSuccess: true,
|
||||
data: {
|
||||
taxonomies: [],
|
||||
},
|
||||
});
|
||||
getTaxonomyListData.mockResolvedValue({
|
||||
results: [],
|
||||
});
|
||||
useTaxonomyTagsData.mockReturnValue({
|
||||
hasMorePages: false,
|
||||
canAddTag: false,
|
||||
tagPages: {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
data: [],
|
||||
},
|
||||
});
|
||||
|
||||
render(<RootWrapper />);
|
||||
expect(await screen.findByText(/to use tags, please or contact your administrator\./i)).toBeInTheDocument();
|
||||
const enableButton = screen.getByRole('button', {
|
||||
name: /enable a taxonomy/i,
|
||||
});
|
||||
fireEvent.click(enableButton);
|
||||
expect(mockNavigate).toHaveBeenCalledWith('/taxonomies');
|
||||
});
|
||||
});
|
||||
|
||||
467
src/content-tags-drawer/ContentTagsDrawerHelper.jsx
Normal file
467
src/content-tags-drawer/ContentTagsDrawerHelper.jsx
Normal file
@@ -0,0 +1,467 @@
|
||||
// @ts-check
|
||||
import React from 'react';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { useContentData, useContentTaxonomyTagsData, useContentTaxonomyTagsUpdater } from './data/apiHooks';
|
||||
import { useTaxonomyList } from '../taxonomy/data/apiHooks';
|
||||
import { extractOrgFromContentId, languageExportId } from './utils';
|
||||
import messages from './messages';
|
||||
import { ContentTagsDrawerSheetContext } from './common/context';
|
||||
|
||||
/** @typedef {import("./data/types.mjs").Tag} ContentTagData */
|
||||
/** @typedef {import("./data/types.mjs").StagedTagData} StagedTagData */
|
||||
/** @typedef {import("./data/types.mjs").TagsInTaxonomy} TagsInTaxonomy */
|
||||
|
||||
/**
|
||||
* Handles the context and all the underlying logic for the ContentTagsDrawer component
|
||||
* @param {string} contentId
|
||||
* @returns {{
|
||||
* stagedContentTags: Record<number, StagedTagData[]>,
|
||||
* addStagedContentTag: (taxonomyId: number, addedTag: StagedTagData) => void,
|
||||
* removeStagedContentTag: (taxonomyId: number, tagValue: string) => void,
|
||||
* removeGlobalStagedContentTag: (taxonomyId: number, tagValue: string) => void,
|
||||
* addRemovedContentTag: (taxonomyId: number, tagValue: string) => void,
|
||||
* deleteRemovedContentTag: (taxonomyId: number, tagValue: string) => void,
|
||||
* setStagedTags: (taxonomyId: number, tagsList: StagedTagData[]) => void,
|
||||
* globalStagedContentTags: Record<number, StagedTagData[]>,
|
||||
* globalStagedRemovedContentTags: Record<number, string>,
|
||||
* setGlobalStagedContentTags: Function,
|
||||
* commitGlobalStagedTags: () => void,
|
||||
* commitGlobalStagedTagsStatus: string,
|
||||
* isContentDataLoaded: boolean,
|
||||
* isContentTaxonomyTagsLoaded: boolean,
|
||||
* isTaxonomyListLoaded: boolean,
|
||||
* contentName: string,
|
||||
* tagsByTaxonomy: TagsInTaxonomy[],
|
||||
* isEditMode: boolean,
|
||||
* toEditMode: () => void,
|
||||
* toReadMode: () => void,
|
||||
* collapsibleStates: Record<number, boolean>,
|
||||
* openCollapsible: (taxonomyId: number) => void,
|
||||
* closeCollapsible: (taxonomyId: number) => void,
|
||||
* toastMessage: string | undefined,
|
||||
* showToastAfterSave: () => void,
|
||||
* closeToast: () => void,
|
||||
* setCollapsibleToInitalState: () => void,
|
||||
* otherTaxonomies: TagsInTaxonomy[],
|
||||
* }}
|
||||
*/
|
||||
const useContentTagsDrawerContext = (contentId) => {
|
||||
const intl = useIntl();
|
||||
const org = extractOrgFromContentId(contentId);
|
||||
|
||||
const { setBlockingSheet } = React.useContext(ContentTagsDrawerSheetContext);
|
||||
|
||||
// True if the drawer is on edit mode.
|
||||
const [isEditMode, setIsEditMode] = React.useState(false);
|
||||
// This stores the tags added on the add tags Select in all taxonomies.
|
||||
const [stagedContentTags, setStagedContentTags] = React.useState({});
|
||||
// When a staged tags on a taxonomy is commitet then is saved on this map.
|
||||
const [globalStagedContentTags, setGlobalStagedContentTags] = React.useState({});
|
||||
// This stores feched tags deleted by the user.
|
||||
const [globalStagedRemovedContentTags, setGlobalStagedRemovedContentTags] = React.useState({});
|
||||
// Merges feched tags, global staged tags and global removed staged tags
|
||||
const [tagsByTaxonomy, setTagsByTaxonomy] = React.useState(/** @type TagsInTaxonomy[] */ ([]));
|
||||
// Other taxonomies that the user doesn't have permissions
|
||||
const [otherTaxonomies, setOtherTaxonomies] = React.useState(/** @type TagsInTaxonomy[] */ ([]));
|
||||
// This stores taxonomy collapsible states (open/close).
|
||||
const [collapsibleStates, setColapsibleStates] = React.useState({});
|
||||
// Message to show a toast in the content drawer.
|
||||
const [toastMessage, setToastMessage] = React.useState(/** @type string | undefined */ (undefined));
|
||||
// Mutation to update tags
|
||||
const updateTags = useContentTaxonomyTagsUpdater(contentId);
|
||||
|
||||
// Fetch from database
|
||||
const { data: contentData, isSuccess: isContentDataLoaded } = useContentData(contentId);
|
||||
const {
|
||||
data: contentTaxonomyTagsData,
|
||||
isSuccess: isContentTaxonomyTagsLoaded,
|
||||
} = useContentTaxonomyTagsData(contentId);
|
||||
const { data: taxonomyListData, isSuccess: isTaxonomyListLoaded } = useTaxonomyList(org);
|
||||
|
||||
// Tags feched from database
|
||||
const { fechedTaxonomies, fechedOtherTaxonomies } = React.useMemo(() => {
|
||||
const sortTaxonomies = (taxonomiesList) => {
|
||||
const taxonomiesWithData = taxonomiesList.filter(
|
||||
(t) => t.contentTags.length !== 0,
|
||||
);
|
||||
|
||||
// Count implicit tags per taxonomy.
|
||||
// TODO This count is also calculated individually
|
||||
// in ContentTagsCollapsible. It should only be calculated once.
|
||||
const tagsCountBytaxonomy = {};
|
||||
taxonomiesWithData.forEach((tax) => {
|
||||
tagsCountBytaxonomy[tax.id] = new Set(
|
||||
tax.contentTags.flatMap(item => item.lineage),
|
||||
).size;
|
||||
});
|
||||
|
||||
// Sort taxonomies with data by implicit count
|
||||
const sortedTaxonomiesWithData = taxonomiesWithData.sort(
|
||||
(a, b) => tagsCountBytaxonomy[b.id] - tagsCountBytaxonomy[a.id],
|
||||
);
|
||||
|
||||
// Empty taxonomies sorted by name.
|
||||
// Since the query returns sorted by name,
|
||||
// it is not necessary to do another sorting here.
|
||||
const emptyTaxonomies = taxonomiesList.filter(
|
||||
(t) => t.contentTags.length === 0,
|
||||
);
|
||||
|
||||
return [...sortedTaxonomiesWithData, ...emptyTaxonomies];
|
||||
};
|
||||
|
||||
if (taxonomyListData && contentTaxonomyTagsData) {
|
||||
// Initialize list of content tags in taxonomies to populate
|
||||
const taxonomiesList = taxonomyListData.results.map((taxonomy) => ({
|
||||
...taxonomy,
|
||||
contentTags: /** @type {ContentTagData[]} */([]),
|
||||
}));
|
||||
|
||||
const contentTaxonomies = contentTaxonomyTagsData.taxonomies;
|
||||
|
||||
const otherTaxonomiesList = [];
|
||||
|
||||
// eslint-disable-next-line array-callback-return
|
||||
contentTaxonomies.map((contentTaxonomyTags) => {
|
||||
const contentTaxonomy = taxonomiesList.find((taxonomy) => taxonomy.id === contentTaxonomyTags.taxonomyId);
|
||||
if (contentTaxonomy) {
|
||||
contentTaxonomy.contentTags = contentTaxonomyTags.tags;
|
||||
} else {
|
||||
otherTaxonomiesList.push({
|
||||
canChangeTaxonomy: false,
|
||||
canDeleteTaxonomy: false,
|
||||
canTagObject: false,
|
||||
contentTags: contentTaxonomyTags.tags,
|
||||
enabled: true,
|
||||
exportId: contentTaxonomyTags.exportId,
|
||||
id: contentTaxonomyTags.taxonomyId,
|
||||
name: contentTaxonomyTags.name,
|
||||
visibleToAuthors: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Delete Language taxonomy if is empty
|
||||
const filteredTaxonomies = taxonomiesList.filter(
|
||||
(taxonomy) => taxonomy.exportId !== languageExportId
|
||||
|| taxonomy.contentTags.length !== 0,
|
||||
);
|
||||
|
||||
return {
|
||||
fechedTaxonomies: sortTaxonomies(filteredTaxonomies),
|
||||
fechedOtherTaxonomies: otherTaxonomiesList,
|
||||
};
|
||||
}
|
||||
return {
|
||||
fechedTaxonomies: [],
|
||||
fechedOtherTaxonomies: [],
|
||||
};
|
||||
}, [taxonomyListData, contentTaxonomyTagsData]);
|
||||
|
||||
// Add a content tags to the staged tags for a taxonomy
|
||||
const addStagedContentTag = React.useCallback((taxonomyId, addedTag) => {
|
||||
setStagedContentTags(prevStagedContentTags => {
|
||||
const updatedStagedContentTags = {
|
||||
...prevStagedContentTags,
|
||||
[taxonomyId]: [...(prevStagedContentTags[taxonomyId] ?? []), addedTag],
|
||||
};
|
||||
return updatedStagedContentTags;
|
||||
});
|
||||
}, [setStagedContentTags]);
|
||||
|
||||
// Remove a content tag from the staged tags for a taxonomy
|
||||
const removeStagedContentTag = React.useCallback((taxonomyId, tagValue) => {
|
||||
setStagedContentTags(prevStagedContentTags => ({
|
||||
...prevStagedContentTags,
|
||||
[taxonomyId]: prevStagedContentTags[taxonomyId].filter((t) => t.value !== tagValue),
|
||||
}));
|
||||
}, [setStagedContentTags]);
|
||||
|
||||
// Remove a content tag from the global staged tags for a taxonomy
|
||||
const removeGlobalStagedContentTag = React.useCallback((taxonomyId, tagValue) => {
|
||||
setGlobalStagedContentTags(prevContentTags => ({
|
||||
...prevContentTags,
|
||||
[taxonomyId]: prevContentTags[taxonomyId].filter((t) => t.value !== tagValue),
|
||||
}));
|
||||
}, [setGlobalStagedContentTags]);
|
||||
|
||||
// Add a content tags to the removed tags for a taxonomy
|
||||
const addRemovedContentTag = React.useCallback((taxonomyId, addedTag) => {
|
||||
setGlobalStagedRemovedContentTags(prevContentTags => {
|
||||
const updatedStagedContentTags = {
|
||||
...prevContentTags,
|
||||
[taxonomyId]: [...(prevContentTags[taxonomyId] ?? []), addedTag],
|
||||
};
|
||||
return updatedStagedContentTags;
|
||||
});
|
||||
}, [setGlobalStagedRemovedContentTags]);
|
||||
|
||||
// Remove a content tag from the removed tags for a taxonomy
|
||||
const deleteRemovedContentTag = React.useCallback((taxonomyId, tagValue) => {
|
||||
setGlobalStagedRemovedContentTags(prevContentTags => ({
|
||||
...prevContentTags,
|
||||
[taxonomyId]: prevContentTags[taxonomyId].filter((t) => t !== tagValue),
|
||||
}));
|
||||
}, [setGlobalStagedRemovedContentTags]);
|
||||
|
||||
// Sets the staged content tags for taxonomy to the provided list of tags
|
||||
const setStagedTags = React.useCallback((taxonomyId, tagsList) => {
|
||||
setStagedContentTags(prevStagedContentTags => ({ ...prevStagedContentTags, [taxonomyId]: tagsList }));
|
||||
}, [setStagedContentTags]);
|
||||
|
||||
// Open a collapsible of a taxonomy
|
||||
/* istanbul ignore next */
|
||||
const openCollapsible = React.useCallback((taxonomyId) => {
|
||||
setColapsibleStates(prevStates => ({
|
||||
...prevStates,
|
||||
[taxonomyId]: true,
|
||||
}));
|
||||
}, [setColapsibleStates]);
|
||||
|
||||
// Close a collapsible of a taxonomy
|
||||
/* istanbul ignore next */
|
||||
const closeCollapsible = React.useCallback((taxonomyId) => {
|
||||
setColapsibleStates(prevStates => ({
|
||||
...prevStates,
|
||||
[taxonomyId]: false,
|
||||
}));
|
||||
}, [setColapsibleStates]);
|
||||
|
||||
const openAllCollapsible = React.useCallback(() => {
|
||||
const updatedState = {};
|
||||
fechedTaxonomies.forEach((taxonomy) => {
|
||||
updatedState[taxonomy.id] = true;
|
||||
});
|
||||
fechedOtherTaxonomies.forEach((taxonomy) => {
|
||||
updatedState[taxonomy.id] = true;
|
||||
});
|
||||
setColapsibleStates(updatedState);
|
||||
}, [fechedTaxonomies, setColapsibleStates]);
|
||||
|
||||
// Set initial state of collapsible based on content tags
|
||||
const setCollapsibleToInitalState = React.useCallback(() => {
|
||||
const updatedState = {};
|
||||
fechedTaxonomies.forEach((taxonomy) => {
|
||||
// Taxonomy with content tags must be open
|
||||
updatedState[taxonomy.id] = taxonomy.contentTags.length !== 0;
|
||||
});
|
||||
fechedOtherTaxonomies.forEach((taxonomy) => {
|
||||
// Taxonomy with content tags must be open
|
||||
updatedState[taxonomy.id] = taxonomy.contentTags.length !== 0;
|
||||
});
|
||||
setColapsibleStates(updatedState);
|
||||
}, [fechedTaxonomies, setColapsibleStates]);
|
||||
|
||||
// Changes the drawer mode to edit
|
||||
const toEditMode = React.useCallback(() => {
|
||||
setIsEditMode(true);
|
||||
openAllCollapsible();
|
||||
}, [setIsEditMode, openAllCollapsible]);
|
||||
|
||||
// Changes the drawer mode to read and clears all staged tags and states.
|
||||
const toReadMode = React.useCallback(() => {
|
||||
setIsEditMode(false);
|
||||
setStagedContentTags({});
|
||||
setGlobalStagedContentTags({});
|
||||
setGlobalStagedRemovedContentTags({});
|
||||
setCollapsibleToInitalState();
|
||||
}, [
|
||||
setIsEditMode,
|
||||
setStagedContentTags,
|
||||
setGlobalStagedContentTags,
|
||||
setGlobalStagedRemovedContentTags,
|
||||
setCollapsibleToInitalState,
|
||||
]);
|
||||
|
||||
// Count added and removed tags
|
||||
/* istanbul ignore next */
|
||||
const countTags = React.useCallback(() => {
|
||||
const tagsAddedList = Object.values(globalStagedContentTags);
|
||||
const tagsRemovedList = Object.values(globalStagedRemovedContentTags);
|
||||
|
||||
const tagsAdded = tagsAddedList.length === 1 ? tagsAddedList[0].length : tagsAddedList.reduce(
|
||||
/* istanbul ignore next */
|
||||
(acc, curr) => acc + curr.length,
|
||||
0,
|
||||
);
|
||||
const tagsRemoved = tagsRemovedList.length === 1 ? tagsRemovedList[0].length : tagsRemovedList.reduce(
|
||||
/* istanbul ignore next */
|
||||
(acc, curr) => acc + curr.length,
|
||||
0,
|
||||
);
|
||||
return {
|
||||
tagsAdded,
|
||||
tagsRemoved,
|
||||
};
|
||||
}, [globalStagedContentTags, globalStagedRemovedContentTags]);
|
||||
|
||||
// Build toast message and show toast after save drawer.
|
||||
/* istanbul ignore next */
|
||||
const showToastAfterSave = React.useCallback(() => {
|
||||
const { tagsAdded, tagsRemoved } = countTags();
|
||||
|
||||
let message;
|
||||
if (tagsAdded && tagsRemoved) {
|
||||
message = `${intl.formatMessage(
|
||||
messages.tagsSaveToastTextTypeAdded,
|
||||
{ tagsAdded },
|
||||
)
|
||||
} ${
|
||||
intl.formatMessage(
|
||||
messages.tagsSaveToastTextTypeRemoved,
|
||||
{ tagsRemoved },
|
||||
)
|
||||
}`;
|
||||
} else if (tagsAdded) {
|
||||
message = intl.formatMessage(
|
||||
messages.tagsSaveToastTextTypeAdded,
|
||||
{ tagsAdded },
|
||||
);
|
||||
} else if (tagsRemoved) {
|
||||
message = intl.formatMessage(
|
||||
messages.tagsSaveToastTextTypeRemoved,
|
||||
{ tagsRemoved },
|
||||
);
|
||||
}
|
||||
setToastMessage(message);
|
||||
}, [setToastMessage, countTags]);
|
||||
|
||||
// Close the toast
|
||||
const closeToast = React.useCallback(() => setToastMessage(undefined), [setToastMessage]);
|
||||
|
||||
let contentName = '';
|
||||
if (isContentDataLoaded) {
|
||||
if ('displayName' in contentData) {
|
||||
contentName = contentData.displayName;
|
||||
} else {
|
||||
contentName = contentData.courseDisplayNameWithDefault;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates `tagsByTaxonomy` merged feched tags, global staged tags
|
||||
// and global removed staged tags.
|
||||
React.useEffect(() => {
|
||||
const mergedTags = cloneDeep(fechedTaxonomies).reduce((acc, obj) => (
|
||||
{ ...acc, [obj.id]: obj }
|
||||
), {});
|
||||
|
||||
const mergedOtherTaxonomies = cloneDeep(fechedOtherTaxonomies).reduce((acc, obj) => (
|
||||
{ ...acc, [obj.id]: obj }
|
||||
), {});
|
||||
|
||||
Object.keys(globalStagedContentTags).forEach((taxonomyId) => {
|
||||
if (mergedTags[taxonomyId]) {
|
||||
// TODO test this
|
||||
// Filter out applied tags that should become implicit because a child tag was committed
|
||||
const stagedLineages = globalStagedContentTags[taxonomyId].map((t) => t.lineage.slice(0, -1)).flat();
|
||||
const fechedTags = mergedTags[taxonomyId].contentTags.filter((t) => !stagedLineages.includes(t.value));
|
||||
|
||||
mergedTags[taxonomyId].contentTags = [
|
||||
...fechedTags,
|
||||
...globalStagedContentTags[taxonomyId],
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(globalStagedRemovedContentTags).forEach((taxonomyId) => {
|
||||
if (mergedTags[taxonomyId]) {
|
||||
mergedTags[taxonomyId].contentTags = mergedTags[taxonomyId].contentTags.filter(
|
||||
(t) => !globalStagedRemovedContentTags[taxonomyId].includes(t.value),
|
||||
);
|
||||
} else if (mergedOtherTaxonomies[taxonomyId]) {
|
||||
mergedOtherTaxonomies[taxonomyId].contentTags = mergedOtherTaxonomies[taxonomyId].contentTags.filter(
|
||||
(t) => !globalStagedRemovedContentTags[taxonomyId].includes(t.value),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// It is constructed this way to maintain the order
|
||||
// of the list `fechedTaxonomies`
|
||||
const mergedTagsArray = fechedTaxonomies.map(obj => mergedTags[obj.id]);
|
||||
|
||||
setTagsByTaxonomy(mergedTagsArray);
|
||||
setOtherTaxonomies(Object.values(mergedOtherTaxonomies));
|
||||
|
||||
if (setBlockingSheet) {
|
||||
const areChangesInTags = () => {
|
||||
// It is calculated in this way, because there are cases in which
|
||||
// there are keys in the map, but they contain empty lists
|
||||
// (e.g. add a tag, and remove the same tag later).
|
||||
|
||||
const tagsAddedList = Object.values(globalStagedContentTags);
|
||||
const tagsRemovedList = Object.values(globalStagedRemovedContentTags);
|
||||
|
||||
if (tagsAddedList.some(tags => tags.length > 0)) {
|
||||
return true;
|
||||
}
|
||||
if (tagsRemovedList.some(tags => tags.length > 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (areChangesInTags()) {
|
||||
setBlockingSheet(true);
|
||||
} else {
|
||||
setBlockingSheet(false);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
fechedTaxonomies,
|
||||
fechedOtherTaxonomies,
|
||||
globalStagedContentTags,
|
||||
globalStagedRemovedContentTags,
|
||||
]);
|
||||
|
||||
const commitGlobalStagedTags = React.useCallback(() => {
|
||||
const tagsData = [];
|
||||
tagsByTaxonomy.forEach((tags) => {
|
||||
tagsData.push({
|
||||
taxonomy: tags.id,
|
||||
tags: tags.contentTags.map(t => t.value),
|
||||
});
|
||||
});
|
||||
otherTaxonomies.forEach((tags) => {
|
||||
tagsData.push({
|
||||
taxonomy: tags.id,
|
||||
tags: tags.contentTags.map(t => t.value),
|
||||
});
|
||||
});
|
||||
// @ts-ignore
|
||||
updateTags.mutate({ tagsData });
|
||||
}, [tagsByTaxonomy]);
|
||||
|
||||
return {
|
||||
stagedContentTags,
|
||||
addStagedContentTag,
|
||||
removeStagedContentTag,
|
||||
removeGlobalStagedContentTag,
|
||||
addRemovedContentTag,
|
||||
deleteRemovedContentTag,
|
||||
setStagedTags,
|
||||
globalStagedContentTags,
|
||||
globalStagedRemovedContentTags,
|
||||
setGlobalStagedContentTags,
|
||||
commitGlobalStagedTags,
|
||||
commitGlobalStagedTagsStatus: updateTags.status,
|
||||
isContentDataLoaded,
|
||||
isContentTaxonomyTagsLoaded,
|
||||
isTaxonomyListLoaded,
|
||||
contentName,
|
||||
tagsByTaxonomy,
|
||||
isEditMode,
|
||||
toEditMode,
|
||||
toReadMode,
|
||||
collapsibleStates,
|
||||
openCollapsible,
|
||||
closeCollapsible,
|
||||
toastMessage,
|
||||
showToastAfterSave,
|
||||
closeToast,
|
||||
setCollapsibleToInitalState,
|
||||
otherTaxonomies,
|
||||
};
|
||||
};
|
||||
|
||||
export default useContentTagsDrawerContext;
|
||||
44
src/content-tags-drawer/ContentTagsDrawerSheet.jsx
Normal file
44
src/content-tags-drawer/ContentTagsDrawerSheet.jsx
Normal file
@@ -0,0 +1,44 @@
|
||||
// @ts-check
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Sheet } from '@openedx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
import ContentTagsDrawer from './ContentTagsDrawer';
|
||||
import { ContentTagsDrawerSheetContext } from './common/context';
|
||||
|
||||
const ContentTagsDrawerSheet = ({ id, onClose, showSheet }) => {
|
||||
const [blockingSheet, setBlockingSheet] = useState(false);
|
||||
|
||||
const context = useMemo(() => ({
|
||||
blockingSheet, setBlockingSheet,
|
||||
}), [blockingSheet, setBlockingSheet]);
|
||||
|
||||
return (
|
||||
<ContentTagsDrawerSheetContext.Provider value={context}>
|
||||
<Sheet
|
||||
position="right"
|
||||
show={showSheet}
|
||||
onClose={onClose}
|
||||
blocking={blockingSheet}
|
||||
>
|
||||
<ContentTagsDrawer
|
||||
id={id}
|
||||
onClose={onClose}
|
||||
/>
|
||||
</Sheet>
|
||||
</ContentTagsDrawerSheetContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
ContentTagsDrawerSheet.propTypes = {
|
||||
id: PropTypes.string,
|
||||
onClose: PropTypes.func,
|
||||
showSheet: PropTypes.bool,
|
||||
};
|
||||
|
||||
ContentTagsDrawerSheet.defaultProps = {
|
||||
id: undefined,
|
||||
onClose: undefined,
|
||||
showSheet: false,
|
||||
};
|
||||
|
||||
export default ContentTagsDrawerSheet;
|
||||
@@ -283,7 +283,7 @@ const ContentTagsDropDownSelector = ({
|
||||
<Icon
|
||||
src={isOpen(tagData.value) ? ArrowDropUp : ArrowDropDown}
|
||||
onClick={() => clickAndEnterHandler(tagData.value)}
|
||||
tabIndex="-1"
|
||||
tabIndex={-1}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -323,7 +323,9 @@ const ContentTagsDropDownSelector = ({
|
||||
|
||||
{ tagPages.data.length === 0 && !tagPages.isLoading && (
|
||||
<div className="d-flex justify-content-center muted-text">
|
||||
<FormattedMessage {...messages.noTagsFoundMessage} values={{ searchTerm }} />
|
||||
{ searchTerm
|
||||
? <FormattedMessage {...messages.noTagsFoundMessage} values={{ searchTerm }} />
|
||||
: <FormattedMessage {...messages.noTagsInTaxonomyMessage} />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -282,4 +282,28 @@ describe('<ContentTagsDropDownSelector />', () => {
|
||||
expect(getByText(message)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render "noTagsInTaxonomy" message if taxonomy is empty', async () => {
|
||||
useTaxonomyTagsData.mockReturnValueOnce({
|
||||
hasMorePages: false,
|
||||
tagPages: {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
isSuccess: true,
|
||||
data: [],
|
||||
},
|
||||
});
|
||||
|
||||
const searchTerm = '';
|
||||
await act(async () => {
|
||||
const { getByText } = await getComponent({ ...data, searchTerm });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(useTaxonomyTagsData).toBeCalledWith(data.taxonomyId, null, 1, searchTerm);
|
||||
});
|
||||
|
||||
const message = 'No tags in this taxonomy yet';
|
||||
expect(getByText(message)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// @ts-check
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import TagBubble from './TagBubble';
|
||||
|
||||
/**
|
||||
* Component that renders Tags under a Taxonomy in the nested tree format.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "Science and Research": {
|
||||
* explicit: false,
|
||||
* children: {
|
||||
* "Genetics Subcategory": {
|
||||
* explicit: false,
|
||||
* children: {
|
||||
* "DNA Sequencing": {
|
||||
* explicit: true,
|
||||
* children: {}
|
||||
* }
|
||||
* }
|
||||
* },
|
||||
* "Molecular, Cellular, and Microbiology": {
|
||||
* explicit: false,
|
||||
* children: {
|
||||
* "Virology": {
|
||||
* explicit: true,
|
||||
* children: {}
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* @param {Object} props - The component props.
|
||||
* @param {Object} props.tagsTree - Array of taxonomy tags that are applied to the content.
|
||||
* @param {(
|
||||
* tagSelectableBoxValue: string,
|
||||
* checked: boolean
|
||||
* ) => void} props.removeTagHandler - Function that is called when removing tags from the tree.
|
||||
*/
|
||||
const ContentTagsTree = ({ tagsTree, removeTagHandler }) => {
|
||||
const renderTagsTree = (tag, level, lineage) => Object.keys(tag).map((key) => {
|
||||
const updatedLineage = [...lineage, encodeURIComponent(key)];
|
||||
if (tag[key] !== undefined) {
|
||||
return (
|
||||
<div key={`tag-${key}-level-${level}`}>
|
||||
<TagBubble
|
||||
key={`tag-${key}`}
|
||||
value={key}
|
||||
implicit={!tag[key].explicit}
|
||||
level={level}
|
||||
lineage={updatedLineage}
|
||||
removeTagHandler={removeTagHandler}
|
||||
canRemove={tag[key].canDeleteObjecttag}
|
||||
/>
|
||||
{ renderTagsTree(tag[key].children, level + 1, updatedLineage) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
return <>{renderTagsTree(tagsTree, 0, [])}</>;
|
||||
};
|
||||
|
||||
ContentTagsTree.propTypes = {
|
||||
tagsTree: PropTypes.objectOf(
|
||||
PropTypes.shape({
|
||||
explicit: PropTypes.bool.isRequired,
|
||||
children: PropTypes.shape({}).isRequired,
|
||||
canDeleteObjecttag: PropTypes.bool.isRequired,
|
||||
}).isRequired,
|
||||
).isRequired,
|
||||
removeTagHandler: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ContentTagsTree;
|
||||
@@ -1,57 +0,0 @@
|
||||
import React from 'react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { act, render } from '@testing-library/react';
|
||||
|
||||
import ContentTagsTree from './ContentTagsTree';
|
||||
|
||||
const data = {
|
||||
'Science and Research': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: false,
|
||||
children: {
|
||||
'Genetics Subcategory': {
|
||||
explicit: false,
|
||||
children: {
|
||||
'DNA Sequencing': {
|
||||
explicit: true,
|
||||
children: {},
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
},
|
||||
canDeleteObjecttag: false,
|
||||
},
|
||||
'Molecular, Cellular, and Microbiology': {
|
||||
explicit: false,
|
||||
children: {
|
||||
Virology: {
|
||||
explicit: true,
|
||||
children: {},
|
||||
canDeleteObjecttag: true,
|
||||
},
|
||||
},
|
||||
canDeleteObjecttag: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const ContentTagsTreeComponent = ({ tagsTree, removeTagHandler }) => (
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<ContentTagsTree tagsTree={tagsTree} removeTagHandler={removeTagHandler} />
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
ContentTagsTreeComponent.propTypes = ContentTagsTree.propTypes;
|
||||
|
||||
describe('<ContentTagsTree />', () => {
|
||||
it('should render taxonomy tags data along content tags number badge', async () => {
|
||||
await act(async () => {
|
||||
const { getByText } = render(<ContentTagsTreeComponent tagsTree={data} removeTagHandler={() => {}} />);
|
||||
expect(getByText('Science and Research')).toBeInTheDocument();
|
||||
expect(getByText('Genetics Subcategory')).toBeInTheDocument();
|
||||
expect(getByText('Molecular, Cellular, and Microbiology')).toBeInTheDocument();
|
||||
expect(getByText('DNA Sequencing')).toBeInTheDocument();
|
||||
expect(getByText('Virology')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Chip,
|
||||
} from '@openedx/paragon';
|
||||
import { Tag, Close } from '@openedx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import TagOutlineIcon from './TagOutlineIcon';
|
||||
|
||||
const TagBubble = ({
|
||||
value, implicit, level, lineage, removeTagHandler, canRemove,
|
||||
}) => {
|
||||
const className = `tag-bubble mb-2 border-light-300 ${implicit ? 'implicit' : ''}`;
|
||||
|
||||
const handleClick = React.useCallback(() => {
|
||||
if (!implicit && canRemove) {
|
||||
removeTagHandler(lineage.join(','));
|
||||
}
|
||||
}, [implicit, lineage, canRemove, removeTagHandler]);
|
||||
|
||||
return (
|
||||
<div style={{ paddingLeft: `${level * 1}rem` }}>
|
||||
<Chip
|
||||
className={className}
|
||||
variant="light"
|
||||
iconBefore={!implicit ? Tag : TagOutlineIcon}
|
||||
iconAfter={!implicit && canRemove ? Close : null}
|
||||
onIconAfterClick={handleClick}
|
||||
>
|
||||
{value}
|
||||
</Chip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
TagBubble.defaultProps = {
|
||||
implicit: true,
|
||||
level: 0,
|
||||
canRemove: false,
|
||||
};
|
||||
|
||||
TagBubble.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
implicit: PropTypes.bool,
|
||||
level: PropTypes.number,
|
||||
lineage: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
removeTagHandler: PropTypes.func.isRequired,
|
||||
canRemove: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default TagBubble;
|
||||
@@ -1,5 +0,0 @@
|
||||
.tag-bubble.pgn__chip {
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
import React from 'react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
|
||||
import TagBubble from './TagBubble';
|
||||
|
||||
const data = {
|
||||
value: 'Tag 1',
|
||||
lineage: [],
|
||||
removeTagHandler: jest.fn(),
|
||||
};
|
||||
|
||||
const TagBubbleComponent = ({
|
||||
value, implicit, level, lineage, removeTagHandler, canRemove,
|
||||
}) => (
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<TagBubble
|
||||
value={value}
|
||||
implicit={implicit}
|
||||
level={level}
|
||||
lineage={lineage}
|
||||
removeTagHandler={removeTagHandler}
|
||||
canRemove={canRemove}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
TagBubbleComponent.defaultProps = {
|
||||
implicit: true,
|
||||
level: 0,
|
||||
canRemove: false,
|
||||
};
|
||||
|
||||
TagBubbleComponent.propTypes = TagBubble.propTypes;
|
||||
|
||||
describe('<TagBubble />', () => {
|
||||
it('should render implicit tag', () => {
|
||||
const { container, getByText } = render(
|
||||
<TagBubbleComponent
|
||||
value={data.value}
|
||||
lineage={data.lineage}
|
||||
removeTagHandler={data.removeTagHandler}
|
||||
/>,
|
||||
);
|
||||
expect(getByText(data.value)).toBeInTheDocument();
|
||||
expect(container.getElementsByClassName('implicit').length).toBe(1);
|
||||
expect(container.getElementsByClassName('pgn__chip__icon-after').length).toBe(0);
|
||||
});
|
||||
|
||||
it('should render explicit tag', () => {
|
||||
const tagBubbleData = {
|
||||
implicit: false,
|
||||
canRemove: true,
|
||||
...data,
|
||||
};
|
||||
const { container, getByText } = render(
|
||||
<TagBubbleComponent
|
||||
value={tagBubbleData.value}
|
||||
canRemove={tagBubbleData.canRemove}
|
||||
lineage={data.lineage}
|
||||
implicit={tagBubbleData.implicit}
|
||||
removeTagHandler={tagBubbleData.removeTagHandler}
|
||||
/>,
|
||||
);
|
||||
expect(getByText(`${tagBubbleData.value}`)).toBeInTheDocument();
|
||||
expect(container.getElementsByClassName('implicit').length).toBe(0);
|
||||
expect(container.getElementsByClassName('pgn__chip__icon-after').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should call removeTagHandler when "x" clicked on explicit tag', async () => {
|
||||
const tagBubbleData = {
|
||||
implicit: false,
|
||||
canRemove: true,
|
||||
...data,
|
||||
};
|
||||
const { container } = render(
|
||||
<TagBubbleComponent
|
||||
value={tagBubbleData.value}
|
||||
canRemove={tagBubbleData.canRemove}
|
||||
lineage={data.lineage}
|
||||
implicit={tagBubbleData.implicit}
|
||||
removeTagHandler={tagBubbleData.removeTagHandler}
|
||||
/>,
|
||||
);
|
||||
|
||||
const xButton = container.getElementsByClassName('pgn__chip__icon-after')[0];
|
||||
fireEvent.click(xButton);
|
||||
expect(data.removeTagHandler).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not show "x" when canRemove is not allowed', async () => {
|
||||
const tagBubbleData = {
|
||||
implicit: false,
|
||||
canRemove: false,
|
||||
...data,
|
||||
};
|
||||
const { container } = render(
|
||||
<TagBubbleComponent
|
||||
value={tagBubbleData.value}
|
||||
canRemove={tagBubbleData.canRemove}
|
||||
lineage={data.lineage}
|
||||
implicit={tagBubbleData.implicit}
|
||||
removeTagHandler={tagBubbleData.removeTagHandler}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container.getElementsByClassName('pgn__chip__icon-after')[0]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
168
src/content-tags-drawer/TagsTree.jsx
Normal file
168
src/content-tags-drawer/TagsTree.jsx
Normal file
@@ -0,0 +1,168 @@
|
||||
// @ts-check
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Icon, Stack, IconButton } from '@openedx/paragon';
|
||||
import { Tag, Close } from '@openedx/paragon/icons';
|
||||
import messages from './messages';
|
||||
import { ContentTagsDrawerContext } from './common/context';
|
||||
|
||||
const TagComponent = ({
|
||||
value,
|
||||
canDelete,
|
||||
explicit,
|
||||
removeTagHandler,
|
||||
lineage,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleClick = React.useCallback(() => {
|
||||
if (explicit && canDelete) {
|
||||
removeTagHandler(lineage.join(','));
|
||||
}
|
||||
}, [explicit, lineage, canDelete, removeTagHandler]);
|
||||
|
||||
return (
|
||||
<Stack direction="horizontal">
|
||||
<Icon src={Tag} className="mr-1 pb-1.5 text-info-500" />
|
||||
{value}
|
||||
{explicit && canDelete && (
|
||||
<IconButton
|
||||
isActive
|
||||
key={value}
|
||||
src={Close}
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(messages.tagsDeleteAltText)}
|
||||
onClick={handleClick}
|
||||
variant="light"
|
||||
className="tags-tree-delete-button ml-2 text-gray-600"
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
TagComponent.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
canDelete: PropTypes.bool,
|
||||
explicit: PropTypes.bool,
|
||||
lineage: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
removeTagHandler: PropTypes.func,
|
||||
};
|
||||
|
||||
TagComponent.defaultProps = {
|
||||
removeTagHandler: undefined,
|
||||
canDelete: false,
|
||||
explicit: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Component that renders Tags under a Taxonomy in the nested tree format.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "Science and Research": {
|
||||
* explicit: false,
|
||||
* canDeleteObjecttag: true,
|
||||
* children: {
|
||||
* "Genetics Subcategory": {
|
||||
* explicit: false,
|
||||
* canDeleteObjecttag: true,
|
||||
* children: {
|
||||
* "DNA Sequencing": {
|
||||
* explicit: true,
|
||||
* canDeleteObjecttag: false,
|
||||
* children: {}
|
||||
* }
|
||||
* }
|
||||
* },
|
||||
* "Molecular, Cellular, and Microbiology": {
|
||||
* explicit: false,
|
||||
* canDeleteObjecttag: false,
|
||||
* children: {
|
||||
* "Virology": {
|
||||
* explicit: true,
|
||||
* canDeleteObjecttag: true,
|
||||
* children: {}
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* @param {Object} props - The component props.
|
||||
* @param {Object} props.tags - Array of taxonomy tags that are applied to the content.
|
||||
* @param {number} props.rootDepth - Depth of the parent tag (root), used to render tabs for the tree.
|
||||
* @param {string} props.parentKey - Key of the parent tag.
|
||||
* @param {string[]} props.lineage - Lineage of the tag.
|
||||
* @param {(
|
||||
* tagSelectableBoxValue: string,
|
||||
* checked: boolean
|
||||
* ) => void} props.removeTagHandler - Function that is called when removing tags from the tree.
|
||||
*/
|
||||
const TagsTree = ({
|
||||
tags,
|
||||
rootDepth,
|
||||
parentKey,
|
||||
lineage,
|
||||
removeTagHandler,
|
||||
}) => {
|
||||
const { isEditMode } = useContext(ContentTagsDrawerContext);
|
||||
|
||||
if (Object.keys(tags).length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Used to Generate tabs for the parents of this tree
|
||||
const tabsNumberArray = Array.from({ length: rootDepth }, (_, index) => index + 1);
|
||||
|
||||
return (
|
||||
<div className="tags-tree" key={parentKey}>
|
||||
{Object.keys(tags).map((key) => (
|
||||
<div className="mt-1.5 mb-1.5" key={key}>
|
||||
<div className="d-flex pl-2.5" key={key}>
|
||||
{
|
||||
tabsNumberArray.map((index) => <span className="d-inline-block ml-4" key={`${key}-${index}`} />)
|
||||
}
|
||||
<TagComponent
|
||||
value={key}
|
||||
canDelete={isEditMode && tags[key].canDeleteObjecttag}
|
||||
explicit={tags[key].explicit}
|
||||
lineage={[...lineage, encodeURIComponent(key)]}
|
||||
removeTagHandler={removeTagHandler}
|
||||
/>
|
||||
</div>
|
||||
{ tags[key].children
|
||||
&& (
|
||||
<TagsTree
|
||||
tags={tags[key].children}
|
||||
rootDepth={rootDepth + 1}
|
||||
parentKey={key}
|
||||
lineage={[...lineage, encodeURIComponent(key)]}
|
||||
removeTagHandler={removeTagHandler}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
TagsTree.propTypes = {
|
||||
tags: PropTypes.shape({}).isRequired,
|
||||
parentKey: PropTypes.string,
|
||||
rootDepth: PropTypes.number,
|
||||
lineage: PropTypes.arrayOf(PropTypes.string),
|
||||
removeTagHandler: PropTypes.func,
|
||||
};
|
||||
|
||||
TagsTree.defaultProps = {
|
||||
rootDepth: 0,
|
||||
parentKey: undefined,
|
||||
lineage: [],
|
||||
removeTagHandler: undefined,
|
||||
};
|
||||
|
||||
export default TagsTree;
|
||||
21
src/content-tags-drawer/TagsTree.scss
Normal file
21
src/content-tags-drawer/TagsTree.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.tags-tree {
|
||||
.tags-tree-delete-button {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
||||
svg {
|
||||
padding: .3rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
color: $gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
border: 2px solid;
|
||||
border-color: $gray-900;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/content-tags-drawer/TagsTree.test.jsx
Normal file
60
src/content-tags-drawer/TagsTree.test.jsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
render, screen, within, fireEvent,
|
||||
} from '@testing-library/react';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import TagsTree from './TagsTree';
|
||||
import { contentTaxonomyTagsTreeMock } from './__mocks__';
|
||||
import { ContentTagsDrawerContext } from './common/context';
|
||||
|
||||
const mockRemoveTagHandler = jest.fn();
|
||||
|
||||
const RootWrapper = (params) => {
|
||||
const context = useMemo(() => ({
|
||||
isEditMode: params.isEditMode,
|
||||
}), []);
|
||||
return (
|
||||
<ContentTagsDrawerContext.Provider value={context}>
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<TagsTree {...params} />
|
||||
</IntlProvider>
|
||||
</ContentTagsDrawerContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('<TagsTree>', () => {
|
||||
it('should render component and tags correctly', () => {
|
||||
render(<RootWrapper tags={contentTaxonomyTagsTreeMock} />);
|
||||
expect(screen.getByText('hierarchical taxonomy tag 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('hierarchical taxonomy tag 2.13')).toBeInTheDocument();
|
||||
expect(screen.getByText('hierarchical taxonomy tag 3.4.50')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show delete buttons on read mode', () => {
|
||||
render(
|
||||
<RootWrapper
|
||||
tags={contentTaxonomyTagsTreeMock}
|
||||
/>,
|
||||
);
|
||||
expect(screen.queryByRole('button', {
|
||||
name: /delete/i,
|
||||
})).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call removeTagHandler when "x" clicked on explicit tag', async () => {
|
||||
render(
|
||||
<RootWrapper
|
||||
tags={contentTaxonomyTagsTreeMock}
|
||||
removeTagHandler={mockRemoveTagHandler}
|
||||
isEditMode
|
||||
/>,
|
||||
);
|
||||
|
||||
const view = screen.getByText(/hierarchical taxonomy tag 1\.7\.59/i);
|
||||
const xButton = within(view).getByRole('button', {
|
||||
name: /delete/i,
|
||||
});
|
||||
fireEvent.click(xButton);
|
||||
expect(mockRemoveTagHandler).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,9 +1,15 @@
|
||||
module.exports = {
|
||||
'hierarchical taxonomy tag 1': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {
|
||||
'hierarchical taxonomy tag 1.7': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {
|
||||
'hierarchical taxonomy tag 1.7.59': {
|
||||
explicit: true,
|
||||
canDeleteObjecttag: true,
|
||||
children: {},
|
||||
},
|
||||
},
|
||||
@@ -11,10 +17,16 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
'hierarchical taxonomy tag 2': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {
|
||||
'hierarchical taxonomy tag 2.13': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {
|
||||
'hierarchical taxonomy tag 2.13.46': {
|
||||
explicit: true,
|
||||
canDeleteObjecttag: true,
|
||||
children: {},
|
||||
},
|
||||
},
|
||||
@@ -22,10 +34,16 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
'hierarchical taxonomy tag 3': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {
|
||||
'hierarchical taxonomy tag 3.4': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {
|
||||
'hierarchical taxonomy tag 3.4.50': {
|
||||
explicit: false,
|
||||
canDeleteObjecttag: true,
|
||||
children: {},
|
||||
},
|
||||
},
|
||||
|
||||
49
src/content-tags-drawer/common/context.js
Normal file
49
src/content-tags-drawer/common/context.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// @ts-check
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import React from 'react';
|
||||
|
||||
/** @typedef {import("../data/types.mjs").TagsInTaxonomy} TagsInTaxonomy */
|
||||
/** @typedef {import("../data/types.mjs").StagedTagData} StagedTagData */
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const ContentTagsDrawerContext = React.createContext({
|
||||
stagedContentTags: /** @type{Record<number, StagedTagData[]>} */ ({}),
|
||||
globalStagedContentTags: /** @type{Record<number, StagedTagData[]>} */ ({}),
|
||||
globalStagedRemovedContentTags: /** @type{Record<number, string>} */ ({}),
|
||||
addStagedContentTag: /** @type{(taxonomyId: number, addedTag: StagedTagData) => void} */ (() => {}),
|
||||
removeStagedContentTag: /** @type{(taxonomyId: number, tagValue: string) => void} */ (() => {}),
|
||||
removeGlobalStagedContentTag: /** @type{(taxonomyId: number, tagValue: string) => void} */ (() => {}),
|
||||
addRemovedContentTag: /** @type{(taxonomyId: number, tagValue: string) => void} */ (() => {}),
|
||||
deleteRemovedContentTag: /** @type{(taxonomyId: number, tagValue: string) => void} */ (() => {}),
|
||||
setStagedTags: /** @type{(taxonomyId: number, tagsList: StagedTagData[]) => void} */ (() => {}),
|
||||
setGlobalStagedContentTags: /** @type{Function} */ (() => {}),
|
||||
commitGlobalStagedTags: /** @type{() => void} */ (() => {}),
|
||||
commitGlobalStagedTagsStatus: /** @type{null|string} */ (null),
|
||||
isContentDataLoaded: /** @type{boolean} */ (false),
|
||||
isContentTaxonomyTagsLoaded: /** @type{boolean} */ (false),
|
||||
isTaxonomyListLoaded: /** @type{boolean} */ (false),
|
||||
contentName: /** @type{string} */ (''),
|
||||
tagsByTaxonomy: /** @type{TagsInTaxonomy[]} */ ([]),
|
||||
isEditMode: /** @type{boolean} */ (false),
|
||||
toEditMode: /** @type{() => void} */ (() => {}),
|
||||
toReadMode: /** @type{() => void} */ (() => {}),
|
||||
collapsibleStates: /** @type{Record<number, boolean>} */ ({}),
|
||||
openCollapsible: /** @type{(taxonomyId: number) => void} */ (() => {}),
|
||||
closeCollapsible: /** @type{(taxonomyId: number) => void} */ (() => {}),
|
||||
toastMessage: /** @type{string|undefined} */ (undefined),
|
||||
showToastAfterSave: /** @type{() => void} */ (() => {}),
|
||||
closeToast: /** @type{() => void} */ (() => {}),
|
||||
setCollapsibleToInitalState: /** @type{() => void} */ (() => {}),
|
||||
otherTaxonomies: /** @type{TagsInTaxonomy[]} */ ([]),
|
||||
});
|
||||
|
||||
// This context has not been added to ContentTagsDrawerContext because it has been
|
||||
// created one level higher to control the behavior of the Sheet that contatins the Drawer.
|
||||
// This logic is not used in legacy edx-platform screens. But it can be separated if we keep
|
||||
// the contexts separate.
|
||||
// TODO We can join both contexts when the Drawer is no longer used on edx-platform
|
||||
/* istanbul ignore next */
|
||||
export const ContentTagsDrawerSheetContext = React.createContext({
|
||||
blockingSheet: /** @type{boolean} */ (false),
|
||||
setBlockingSheet: /** @type{Function} */ (() => {}),
|
||||
});
|
||||
@@ -90,13 +90,11 @@ export async function getContentData(contentId) {
|
||||
/**
|
||||
* Update content object's applied tags
|
||||
* @param {string} contentId The id of the content object (unit/component)
|
||||
* @param {number} taxonomyId The id of the taxonomy the tags belong to
|
||||
* @param {string[]} tags The list of tags (values) to set on content object
|
||||
* @param {Promise<import("./types.mjs").UpdateTagsData[]>} tagsData The list of tags (values) to set on content object
|
||||
* @returns {Promise<import("./types.mjs").ContentTaxonomyTagsData>}
|
||||
*/
|
||||
export async function updateContentTaxonomyTags(contentId, taxonomyId, tags) {
|
||||
export async function updateContentTaxonomyTags(contentId, tagsData) {
|
||||
const url = getContentTaxonomyTagsApiUrl(contentId);
|
||||
const params = { taxonomy: taxonomyId };
|
||||
const { data } = await getAuthenticatedHttpClient().put(url, { tags }, { params });
|
||||
const { data } = await getAuthenticatedHttpClient().put(url, { tagsData });
|
||||
return camelCaseObject(data[contentId]);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,11 @@ describe('content tags drawer api calls', () => {
|
||||
const taxonomyId = 3;
|
||||
const tags = ['flat taxonomy tag 100', 'flat taxonomy tag 3856'];
|
||||
axiosMock.onPut(`${getContentTaxonomyTagsApiUrl(contentId)}`).reply(200, updateContentTaxonomyTagsMock);
|
||||
const result = await updateContentTaxonomyTags(contentId, taxonomyId, tags);
|
||||
// @ts-ignore
|
||||
const result = await updateContentTaxonomyTags(contentId, [{
|
||||
taxonomy: taxonomyId,
|
||||
tags,
|
||||
}]);
|
||||
|
||||
expect(axiosMock.history.put[0].url).toEqual(`${getContentTaxonomyTagsApiUrl(contentId)}`);
|
||||
expect(result).toEqual(updateContentTaxonomyTagsMock[contentId]);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// @ts-check
|
||||
import { useMemo } from 'react';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import {
|
||||
useQuery,
|
||||
useQueries,
|
||||
@@ -11,6 +12,7 @@ import {
|
||||
getContentTaxonomyTagsData,
|
||||
getContentData,
|
||||
updateContentTaxonomyTags,
|
||||
getContentTaxonomyTagsCount,
|
||||
} from './api';
|
||||
|
||||
/** @typedef {import("../../taxonomy/tag-list/data/types.mjs").TagListData} TagListData */
|
||||
@@ -119,9 +121,8 @@ export const useContentData = (contentId) => (
|
||||
/**
|
||||
* Builds the mutation to update the tags applied to the content object
|
||||
* @param {string} contentId The id of the content object to update tags for
|
||||
* @param {number} taxonomyId The id of the taxonomy the tags belong to
|
||||
*/
|
||||
export const useContentTaxonomyTagsUpdater = (contentId, taxonomyId) => {
|
||||
export const useContentTaxonomyTagsUpdater = (contentId) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
@@ -130,11 +131,11 @@ export const useContentTaxonomyTagsUpdater = (contentId, taxonomyId) => {
|
||||
* any,
|
||||
* any,
|
||||
* {
|
||||
* tags: string[]
|
||||
* tagsData: Promise<import("./types.mjs").UpdateTagsData[]>
|
||||
* }
|
||||
* >}
|
||||
*/
|
||||
mutationFn: ({ tags }) => updateContentTaxonomyTags(contentId, taxonomyId, tags),
|
||||
mutationFn: ({ tagsData }) => updateContentTaxonomyTags(contentId, tagsData),
|
||||
onSettled: /* istanbul ignore next */ () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['contentTaxonomyTags', contentId] });
|
||||
/// Invalidate query with pattern on course outline
|
||||
@@ -146,5 +147,40 @@ export const useContentTaxonomyTagsUpdater = (contentId, taxonomyId) => {
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: ['contentTagsCount', contentPattern] });
|
||||
},
|
||||
onSuccess: /* istanbul ignore next */ () => {
|
||||
/* istanbul ignore next */
|
||||
if (window.top != null) {
|
||||
// This send messages to the parent page if the drawer is called from a iframe.
|
||||
// Is used on Studio to update tags data and counts.
|
||||
// In the future, when the Course Outline Page and Unit Page are integrated into this MFE,
|
||||
// they should just use React Query to load the tag counts, and React Query will automatically
|
||||
// refresh those counts when the mutation invalidates them. So this postMessage is just a temporary
|
||||
// feature to support the legacy Django template courseware page.
|
||||
|
||||
// Sends content tags.
|
||||
getContentTaxonomyTagsData(contentId).then((data) => {
|
||||
const contentData = {
|
||||
contentId,
|
||||
...data,
|
||||
};
|
||||
window.top?.postMessage(
|
||||
{ type: 'authoring.events.tags.updated', data: contentData },
|
||||
getConfig().STUDIO_BASE_URL,
|
||||
);
|
||||
});
|
||||
|
||||
// Sends tags count.
|
||||
getContentTaxonomyTagsCount(contentId).then((data) => {
|
||||
const contentData = {
|
||||
contentId,
|
||||
count: data,
|
||||
};
|
||||
window.top?.postMessage(
|
||||
{ type: 'authoring.events.tags.count.updated', data: contentData },
|
||||
getConfig().STUDIO_BASE_URL,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -158,8 +158,12 @@ describe('useContentTaxonomyTagsUpdater', () => {
|
||||
|
||||
const contentId = 'testerContent';
|
||||
const taxonomyId = 123;
|
||||
const mutation = useContentTaxonomyTagsUpdater(contentId, taxonomyId);
|
||||
mutation.mutate({ tags: ['tag1', 'tag2'] });
|
||||
const mutation = useContentTaxonomyTagsUpdater(contentId);
|
||||
const tagsData = [{
|
||||
taxonomy: taxonomyId,
|
||||
tags: ['tag1', 'tag2'],
|
||||
}];
|
||||
mutation.mutate({ tagsData });
|
||||
|
||||
expect(useMutation).toBeCalled();
|
||||
|
||||
@@ -167,9 +171,8 @@ describe('useContentTaxonomyTagsUpdater', () => {
|
||||
const { mutationFn } = config;
|
||||
|
||||
await act(async () => {
|
||||
const tags = ['tag1', 'tag2'];
|
||||
await mutationFn({ tags });
|
||||
expect(updateContentTaxonomyTags).toBeCalledWith(contentId, taxonomyId, tags);
|
||||
await mutationFn({ tagsData });
|
||||
expect(updateContentTaxonomyTags).toBeCalledWith(contentId, tagsData);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* @property {number} taxonomyId
|
||||
* @property {boolean} canTagObject
|
||||
* @property {Tag[]} tags
|
||||
* @property {string} exportId
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -59,6 +60,25 @@
|
||||
* @property {boolean} hasPartitionGroupComponents
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} TagsInTaxonomy
|
||||
* @property {boolean} allOrgs
|
||||
* @property {boolean} allowFreeText
|
||||
* @property {boolean} allowMultiple
|
||||
* @property {boolean} canChangeTaxonomy
|
||||
* @property {boolean} canDeleteTaxonomy
|
||||
* @property {boolean} canTagObject
|
||||
* @property {Tag[]} contentTags
|
||||
* @property {string} description
|
||||
* @property {boolean} enabled
|
||||
* @property {string} exportId
|
||||
* @property {number} id
|
||||
* @property {string} name
|
||||
* @property {boolean} systemDefined
|
||||
* @property {number} tagsCount
|
||||
* @property {boolean} visibleToAuthors
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CourseData
|
||||
* @property {string} courseDisplayNameWithDefault
|
||||
@@ -67,3 +87,15 @@
|
||||
/**
|
||||
* @typedef {XBlockData | CourseData} ContentData
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} UpdateTagsData
|
||||
* @property {number} taxonomy
|
||||
* @property {string[]} tags
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} StagedTagData
|
||||
* @property {string} value
|
||||
* @property {string} label
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user