diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ab04a8c0..a1007f8a7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,4 +36,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_NPM_TOKEN }} - run: npx semantic-release + run: npx semantic-release@19.0.5 diff --git a/README.md b/README.md index f80760868..81796b73c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This guide presumes you have a functioning devstack. 2. In devstack + venv, run `$ make dev.provision.lms+studio+frontend-app-course-authoring` to make up the required services. Minimum services required are lms, studio and frontend-app-course-authoring. 4. In [Studio Django Admin](http://localhost:18000/admin/waffle/flag/) turn on `new_core_editors.use_new_text_editor` flag for HTML editor, `new_core_editors.use_new_video_editor` flag for new video editor, and `new_core_editors.use_new_problem_editor` flag for problems. The list of supported flags is in [toggles.py. ](https://github.com/openedx/edx-platform/blob/master/cms/djangoapps/contentstore/toggles.py). you might have to add a flag for your xblock of choice. 2. Clone this repo into the [`${DEVSTACK_WORKSPACE}/src` directory](https://edx.readthedocs.io/projects/open-edx-devstack/en/latest/readme.html?highlight=DEVSTACK_WORKSPACE#id9) the sibling repo of your edx devstack `/src`. -3. In the course authoring app, follow the guide to use your [local verison of frontend-lib-content-components. ](https://github.com/openedx/frontend-build#local-module-configuration-for-webpack) The moduleconfig.js in the frontend-app-course-authoring repo will be: +3. In the course authoring app, follow the guide to use your [local verison of frontend-lib-content-components. ](https://github.com/openedx/frontend-build#local-module-configuration-for-webpack) The module.config.js in the frontend-app-course-authoring repo will be: ``` module.exports = { diff --git a/docs/decisions/0005-internal-editor-testability-decisions.md b/docs/decisions/0005-internal-editor-testability-decisions.md new file mode 100644 index 000000000..cd7e43455 --- /dev/null +++ b/docs/decisions/0005-internal-editor-testability-decisions.md @@ -0,0 +1,136 @@ +# Internal editor testability decision + +# Increased complexity for the sake of testability +The internally-managed editors in this repo (as of now planned to include text, video, and problem types) follow a number of patterns that increase the complexity of parts of the code slightly, in favor of providing increased testability around their behavior. + +## Note - Strict Dictionaries +Javacript is generally fairly lackadaisical with regards to dictionary access of missing/invalid keys. This is fine and expected in many cases, but also prevents us from using dictionary access on something like a key store to ensure we are calling something that actually exists. + +For this purpose, there are a pair of utilities in this repo called `StrictDict` and `keyStore`. + +`StrictDict` takes an object and returns a version that will complain (throw an error) if called with an invalid key. + +`keyStore` takes an object and returns a StrictDict of just the keys of that object. (this is useful particularly for mocking and spying on specific methods and fields) + +## Note - Self imports +Javascript webpack imports can be problematic around the specific issue of attempting to mock a single method being used in another method in the same file. + +Problem: File A includes methodA and methodB (which calls methodA). We want to be able to test methodA and then test methodB *without* having to re-test methodA as part of that test. We want to be able to mock methodA *only* while we are testing methodB. + +Solution: Self-imports. By importing the module into itself (which webpack handles nicely, don't worry), we provide tests the ability to spy on and mock individual methods from that module separately on a per-test basis. + +Ex: +```javascript +// myFile.js +import * as module from './myFile'; + +export const methodA = (val) => // do something complex with val and return a number +export const methodB = (val) => module.methodA(val) * 2; + +// myFile.test.js +import * as module from './myFile'; +import { keyStore } from './utils'; + +cosnt moduleKeys = keyStore(module); + +describe('myFile', () => { + describe('methodA', () => ...); + describe('methodB', () => { + const mockMethodA = (val) => val + 3 + const testValue = 23; + beforeEach(() => { + jest.spyOn(module, moduleKeys).mockImplementationValueOnce(mockMethodA); + }); + it('returns double the output of methodA with the given value', () => { + expect(module.methodB(testValue)).toEqual(mockMethodA(testValue) + 3); + }); + }); +}); +``` + +## Hooks and Snapshots - Separation from components for increased viability of snapshots +As part of the testing of these internal editors, we are relying on snapshot testing to ensure stability of the display of the components themselves. This can be a fragile solution in certain situations where components are too large or complex to adequately snapshot and verify. + +For this purpose, we have opted for a general pattern of separating all of the behavior of components withing these editors into separate `hooks` files. + +These hook files contain methods that utilize both `react` and `react-redux` hooks, along with arguments passed directly into the component, in order to generate the resulting desired behaviors. + +From there, components are tested by mocking out the behavior of these hooks to return verifyable data in the snapshots. + +As part of this separation, there are a number of additional patterns that are followed + +### Snapshot considerations +#### Callbacks +Any callback that is included in render in a component should be separated such that is is either passed in as a prop or derived from a hook, and should be mocked with a `mockName` using jest, to ensure that they are uniquely identifyable in the snapshots. + +Ex: +```javascript +const props = { + onClick: jest.fn().mockName('props.onClick'); +} +expect(shallow()).toMatchSnapshot(); +``` + +#### Imported components +Imported compoents are mocked to return simple string components based on their existing name. This results in shallow renders that display the components by name, with passed props, but do not attempt to render *any* logic from those components. + +This is a bit more complex for components with sub-components, but we have provided a test utility in `src/testUtils` called `mockNestedComponent` that will allow you to easily mock these for your snapshots as well. + +Ex: +```javascript +jest.mock('componentModule', () => { + const { mockNestedComponent } = jest.requireActual('./testUtils'); + return { + SimpleComponents: () => 'SimpleComponent', + NestedComponent: mockNestedComponent('NestedComponent', { + NestedChild1: 'NestedComponent.NestedChild1', + NestedChild2: 'NestedComponent.NestedChild2', + }), +}); +``` +#### Top-level mocked imports +We have mocked out all paragon components and icons being used in the repo, as well as a number of other common methods, hooks, and components in our module's `setupTests` file, which will ensure that those components show up reasonably in snapshots. + +### Hook Considerations +#### useState and mockUseState +React's useState hook is a very powerful alternative to class components, but is also somewhat problematic to test, as it returns different values based on where it is called in a hook, as well as based on previous runs of that hook. + +To resolve this, we are using a custom test utility to mock a hook modules state values for easy testing. + +This requires a particular structure to hook modules that use the useState, for the sake of enabling the mock process (which is documented with the utility). + +Ex: +```javascript +import * as module from './hooks'; +const state = { + myStateValue: (val) => useState(val), +}; +const myHook = () => { + const [myStateValue, setMyStateValue] = module.state.myStateValue('initialValue'); +}; +``` +Examples on how to use this for testing are included with the mock class in `src/testUtils` + +#### useCallback, useEffect +These hooks provide behavior that calls a method based on given prerequisite behaviors. +For this reason, we use general-purpose mocks for these hooks that return an object containing the passed callback and prerequisites for easy test access. + +#### Additional Considrations +*useIntl not available* + +We are using react-intl under the hood for our i18n support, but do not have access to some of the more recent features in that library due to the pinned version in frontend-platform. Specifically, this includes a `useIntl` hook available in later versions that is still unavailable to us, requiring us to use the older `injectIntl` pattern. + +*useDispatch* + +React-redux's `useDispatch` hook does not play nicely with being called in a method called by a component, and really wants to be called *in* the component. For this reason, the dispatch method is generated in components and passed through to hook components. + +## Notes for integration testing +Because of the top-level mocks in setupTest, any integration tests will need to be sure to unmock most of these. + +Ex: +```javascript +jest.unmock('@edx/frontend-platform/i18n'); +jest.unmock('@edx/paragon'); +jest.unmock('@edx/paragon/icons'); +jest.unmock('react-redux'); +``` diff --git a/package-lock.json b/package-lock.json index 1c73363eb..27075c386 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "AGPL-3.0", "dependencies": { "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@reduxjs/toolkit": "^1.8.1", @@ -35,9 +36,9 @@ "devDependencies": { "@edx/frontend-build": "^11.0.2", "@edx/frontend-platform": "2.4.0", - "@edx/paragon": "^20.21.3", + "@edx/paragon": "^20.27.0", "@testing-library/dom": "^8.13.0", - "@testing-library/react": "12.1.1", + "@testing-library/react": "^12.1.1", "@testing-library/user-event": "^13.5.0", "codecov": "3.8.3", "enzyme": "3.11.0", @@ -192,15 +193,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/code-frame/node_modules/@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -437,24 +429,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/core/node_modules/@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -478,18 +452,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/core/node_modules/@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -525,20 +487,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/core/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/core/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -638,6 +586,36 @@ "node": ">=0.10.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/plugin-proposal-class-properties": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", @@ -796,36 +774,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/plugin-proposal-class-properties/node_modules/@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -861,20 +809,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-proposal-class-properties/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/plugin-proposal-class-properties/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -1444,24 +1378,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/preset-env/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/preset-env/node_modules/@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -1486,18 +1402,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/preset-env/node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", "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.18.6.tgz", @@ -2466,20 +2370,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/preset-env/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/preset-env/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -2722,24 +2612,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/preset-react/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/preset-react/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/preset-react/node_modules/@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -2829,20 +2701,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-react/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/runtime": { "version": "7.20.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", @@ -2854,6 +2712,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@codemirror/autocomplete": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.0.tgz", @@ -2912,14 +2784,6 @@ "@lezer/javascript": "^1.0.0" } }, - "node_modules/@codemirror/lang-javascript/node_modules/@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, "node_modules/@codemirror/lang-javascript/node_modules/@lezer/javascript": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.0.tgz", @@ -2929,12 +2793,16 @@ "@lezer/lr": "^1.0.0" } }, - "node_modules/@codemirror/lang-javascript/node_modules/@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", + "node_modules/@codemirror/lang-xml": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.1.tgz", + "integrity": "sha512-0tvycUTElajCcRKgsszhKjWX+uuOogdu5+enpfqYA+j0gnP8ek7LRxujh2/XMPRdXt/hwOML4slJLE7r2eX3yQ==", "dependencies": { - "@lezer/common": "^1.0.0" + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" } }, "node_modules/@codemirror/language": { @@ -2950,22 +2818,6 @@ "style-mod": "^4.0.0" } }, - "node_modules/@codemirror/language/node_modules/@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/language/node_modules/@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, "node_modules/@codemirror/language/node_modules/style-mod": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", @@ -3288,12 +3140,6 @@ "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, - "node_modules/@edx/frontend-build/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/@edx/frontend-build/node_modules/@types/webpack": { "version": "5.28.0", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz", @@ -4481,9 +4327,9 @@ } }, "node_modules/@edx/paragon": { - "version": "20.21.5", - "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.21.5.tgz", - "integrity": "sha512-7+pRDS3MejiF3tsOFs9R6PC66zZJb8eN2nYObNWnyUmKZ7DfzzpHVsDuUYUg+J5cm3dYMY2imyIrMrqov6ettA==", + "version": "20.27.0", + "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.27.0.tgz", + "integrity": "sha512-jy62ZEBdAVlsP6tAm1/YDyMtc9fiD47H00whoW+y2Z+lLZqPsv6D5boIPQIcdBeg0W4f2gCU4TEy2+b2q8mYGA==", "dev": true, "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.1", @@ -4567,23 +4413,6 @@ "integrity": "sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==", "dev": true }, - "node_modules/@edx/paragon/node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "node_modules/@edx/paragon/node_modules/@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "node_modules/@edx/paragon/node_modules/@types/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -5242,7 +5071,7 @@ "@lezer/lr": "^1.0.0" } }, - "node_modules/@lezer/css/node_modules/@lezer/highlight": { + "node_modules/@lezer/highlight": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", @@ -5250,14 +5079,6 @@ "@lezer/common": "^1.0.0" } }, - "node_modules/@lezer/css/node_modules/@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, "node_modules/@lezer/html": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.0.tgz", @@ -5268,20 +5089,21 @@ "@lezer/lr": "^1.0.0" } }, - "node_modules/@lezer/html/node_modules/@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", + "node_modules/@lezer/lr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.0.tgz", + "integrity": "sha512-rpvS+WPS/PlbJCiW+bzXPbIFIRXmzRiTEDzMvrvgpED05w5ZQO59AzH3BJen2AnHuJIlP3DcJRjsKLTrkknUNA==", "dependencies": { "@lezer/common": "^1.0.0" } }, - "node_modules/@lezer/html/node_modules/@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", + "node_modules/@lezer/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-jMDXrV953sDAUEMI25VNrI9dz94Ai96FfeglytFINhhwQ867HKlCE2jt3AwZTCT7M528WxdDWv/Ty8e9wizwmQ==", "dependencies": { - "@lezer/common": "^1.0.0" + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" } }, "node_modules/@mapbox/node-pre-gyp": { @@ -5635,10 +5457,36 @@ } }, "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "dev": true + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "dev": true + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz", + "integrity": "sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, "node_modules/@svgr/webpack": { "version": "6.2.1", @@ -5931,24 +5779,6 @@ "node": ">=6.9.0" } }, - "node_modules/@svgr/webpack/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@svgr/webpack/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@svgr/webpack/node_modules/@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -5972,18 +5802,6 @@ "node": ">=6.9.0" } }, - "node_modules/@svgr/webpack/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@svgr/webpack/node_modules/@babel/plugin-syntax-typescript": { "version": "7.20.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", @@ -6083,20 +5901,6 @@ "node": ">=6.9.0" } }, - "node_modules/@svgr/webpack/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@svgr/webpack/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -6585,15 +6389,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/@svgr/webpack/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@svgr/webpack/node_modules/svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", @@ -6702,16 +6497,42 @@ "dev": true }, "node_modules/@types/babel__generator": { - "dev": true + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } }, "node_modules/@types/babel__template": { - "dev": true + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } }, "node_modules/@types/babel__traverse": { - "dev": true + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } }, "node_modules/@types/body-parser": { - "dev": true + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } }, "node_modules/@types/cheerio": { "version": "0.22.31", @@ -6722,41 +6543,151 @@ "@types/node": "*" } }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, "node_modules/@types/node": { + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", "dev": true }, "node_modules/@types/prop-types": { - "dev": true + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, - "node_modules/@types/react": {}, + "node_modules/@types/react": { + "version": "18.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", + "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/scheduler": { - "dev": true + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, "node_modules/@types/uglify-js": { - "dev": true + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.1.tgz", + "integrity": "sha512-GkewRA4i5oXacU/n4MA9+bLgt5/L3F1mKrYvFGm7r2ouLXhRKjuWwo9XHNnbx6WF3vlGW21S3fCvgqxvxXXc5g==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } }, "node_modules/@types/webpack-sources": { - "dev": true + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.0.tgz", + "integrity": "sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } + }, + "node_modules/@types/webpack-sources/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } }, "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "node_modules/@videojs/http-streaming": { @@ -8333,36 +8264,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-eslint/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-eslint/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-eslint/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/babel-eslint/node_modules/@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -8398,20 +8299,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-eslint/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/babel-eslint/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -8512,50 +8399,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-jest/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-jest/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-jest/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/babel-jest/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/babel-jest/node_modules/@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -8652,12 +8495,6 @@ "@types/node": "*" } }, - "node_modules/babel-jest/node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, "node_modules/babel-jest/node_modules/@types/istanbul-reports": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", @@ -9580,15 +9417,6 @@ "node": ">=0.10.0" } }, - "node_modules/babel-jest/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/babel-jest/node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -9705,12 +9533,6 @@ "webpack": ">=2" } }, - "node_modules/babel-loader/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/babel-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -9903,50 +9725,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-plugin-react-intl/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-plugin-react-intl/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-plugin-react-intl/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/babel-plugin-react-intl/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/babel-plugin-react-intl/node_modules/@formatjs/ecma402-abstract": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.4.0.tgz", @@ -10027,12 +9805,6 @@ "@types/node": "*" } }, - "node_modules/babel-plugin-react-intl/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/babel-plugin-react-intl/node_modules/@types/schema-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/schema-utils/-/schema-utils-2.4.0.tgz", @@ -10111,38 +9883,6 @@ "is-valid-path": "^0.1.1" } }, - "node_modules/babel-plugin-transform-imports/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-plugin-transform-imports/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-plugin-transform-imports/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/babel-polyfill": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", @@ -10204,36 +9944,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-preset-jest/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-preset-jest/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/babel-preset-jest/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/babel-preset-jest/node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -10395,20 +10105,6 @@ "node": ">=6.9.0" } }, - "node_modules/babel-preset-jest/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/babel-preset-jest/node_modules/@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -10422,15 +10118,6 @@ "@types/babel__traverse": "*" } }, - "node_modules/babel-preset-jest/node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, "node_modules/babel-preset-jest/node_modules/babel-plugin-jest-hoist": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", @@ -11247,15 +10934,6 @@ "source-map": "^0.6.0" } }, - "node_modules/clean-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -11594,12 +11272,6 @@ "webpack": "^4.27.0 || ^5.0.0" } }, - "node_modules/css-loader/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/css-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -12496,15 +12168,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, - "node_modules/cssnano/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cssnano/node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -14755,12 +14418,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/file-loader/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/file-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -16695,15 +16352,6 @@ "strip-ansi": "^6.0.1" } }, - "node_modules/html-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/html-webpack-plugin/node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -16946,12 +16594,6 @@ "@types/node": "*" } }, - "node_modules/image-webpack-loader/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/image-webpack-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -20688,16 +20330,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/imagemin-svgo/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/imagemin-svgo/node_modules/svgo": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", @@ -22789,11 +22421,6 @@ } } }, - "node_modules/jest-resolve": { - "dev": true, - "optional": true, - "peer": true - }, "node_modules/jest/node_modules/@babel/generator": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", @@ -22863,36 +22490,6 @@ "node": ">=6.9.0" } }, - "node_modules/jest/node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/jest/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/jest/node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/jest/node_modules/@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -22928,20 +22525,6 @@ "node": ">=6.9.0" } }, - "node_modules/jest/node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/jest/node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -23291,15 +22874,6 @@ "node": ">= 6" } }, - "node_modules/jest/node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, "node_modules/jest/node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -23309,12 +22883,6 @@ "@types/node": "*" } }, - "node_modules/jest/node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, "node_modules/jest/node_modules/@types/istanbul-reports": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", @@ -25560,15 +25128,6 @@ "node": ">=0.10.0" } }, - "node_modules/jest/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/jest/node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -26501,12 +26060,6 @@ "webpack": "^4.4.0 || ^5.0.0" } }, - "node_modules/mini-css-extract-plugin/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -26566,15 +26119,6 @@ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, - "node_modules/mini-css-extract-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mini-css-extract-plugin/node_modules/webpack-sources": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", @@ -28742,12 +28286,6 @@ "node": ">= 8" } }, - "node_modules/react-dev-utils/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/react-dev-utils/node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -29440,17 +28978,6 @@ "hoist-non-react-statics": "^3.3.0" } }, - "node_modules/react-intl/node_modules/@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "node_modules/react-intl/node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -30009,15 +29536,6 @@ "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", "dev": true }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve/node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -30641,6 +30159,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-loader": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", @@ -31292,12 +30819,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/style-loader/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/style-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -32038,12 +31559,6 @@ } } }, - "node_modules/url-loader/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/url-loader/node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -32814,12 +32329,6 @@ "@types/node": "*" } }, - "node_modules/webpack-dev-server/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "node_modules/webpack-dev-server/node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -34387,13 +33896,6 @@ "dev": true, "peer": true }, - "node_modules/webpack/node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "peer": true - }, "node_modules/webpack/node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -34694,16 +34196,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/webpack/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/webpack/node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -35144,12 +34636,6 @@ "@babel/highlight": "^7.18.6" }, "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, "@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -35333,18 +34819,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, "@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -35362,12 +34836,6 @@ "@babel/types": "^7.20.5" } }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -35397,17 +34865,6 @@ "globals": "^11.1.0" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -35479,6 +34936,24 @@ } } }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "dev": true + }, "@babel/plugin-proposal-class-properties": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", @@ -35595,24 +35070,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -35642,17 +35099,6 @@ "globals": "^11.1.0" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -36090,18 +35536,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, "@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -36120,12 +35554,6 @@ "@babel/types": "^7.20.5" } }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", "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.18.6.tgz", @@ -36755,17 +36183,6 @@ "globals": "^11.1.0" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -36951,18 +36368,6 @@ "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, "@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -37018,17 +36423,6 @@ "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" } - }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } } } }, @@ -37040,6 +36434,17 @@ "regenerator-runtime": "^0.13.11" } }, + "@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, "@codemirror/autocomplete": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.0.tgz", @@ -37092,14 +36497,6 @@ "@lezer/javascript": "^1.0.0" }, "dependencies": { - "@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, "@lezer/javascript": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.0.tgz", @@ -37108,17 +36505,21 @@ "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } - }, - "@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", - "requires": { - "@lezer/common": "^1.0.0" - } } } }, + "@codemirror/lang-xml": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.1.tgz", + "integrity": "sha512-0tvycUTElajCcRKgsszhKjWX+uuOogdu5+enpfqYA+j0gnP8ek7LRxujh2/XMPRdXt/hwOML4slJLE7r2eX3yQ==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, "@codemirror/language": { "version": "6.3.2", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.3.2.tgz", @@ -37132,22 +36533,6 @@ "style-mod": "^4.0.0" }, "dependencies": { - "@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, "style-mod": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", @@ -37393,12 +36778,6 @@ "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "@types/webpack": { "version": "5.28.0", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz", @@ -38316,9 +37695,9 @@ } }, "@edx/paragon": { - "version": "20.21.5", - "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.21.5.tgz", - "integrity": "sha512-7+pRDS3MejiF3tsOFs9R6PC66zZJb8eN2nYObNWnyUmKZ7DfzzpHVsDuUYUg+J5cm3dYMY2imyIrMrqov6ettA==", + "version": "20.27.0", + "resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.27.0.tgz", + "integrity": "sha512-jy62ZEBdAVlsP6tAm1/YDyMtc9fiD47H00whoW+y2Z+lLZqPsv6D5boIPQIcdBeg0W4f2gCU4TEy2+b2q8mYGA==", "dev": true, "requires": { "@fortawesome/fontawesome-svg-core": "^6.1.1", @@ -38384,23 +37763,6 @@ "integrity": "sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==", "dev": true }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "@types/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -38875,24 +38237,14 @@ "requires": { "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" - }, - "dependencies": { - "@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", - "requires": { - "@lezer/common": "^1.0.0" - } - } + } + }, + "@lezer/highlight": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", + "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", + "requires": { + "@lezer/common": "^1.0.0" } }, "@lezer/html": { @@ -38903,24 +38255,23 @@ "@lezer/common": "^1.0.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" - }, - "dependencies": { - "@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/lr": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.5.tgz", - "integrity": "sha512-f9319YG1A/3ysgUE3bqCHEd7g+3ZZ71MWlwEc42mpnLVYXgfJJgtu1XAyBB4Kz8FmqmnFe9caopDqKeMMMAU6g==", - "requires": { - "@lezer/common": "^1.0.0" - } - } + } + }, + "@lezer/lr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.0.tgz", + "integrity": "sha512-rpvS+WPS/PlbJCiW+bzXPbIFIRXmzRiTEDzMvrvgpED05w5ZQO59AzH3BJen2AnHuJIlP3DcJRjsKLTrkknUNA==", + "requires": { + "@lezer/common": "^1.0.0" + } + }, + "@lezer/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-jMDXrV953sDAUEMI25VNrI9dz94Ai96FfeglytFINhhwQ867HKlCE2jt3AwZTCT7M528WxdDWv/Ty8e9wizwmQ==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" } }, "@mapbox/node-pre-gyp": { @@ -39195,10 +38546,18 @@ } }, "@svgr/babel-plugin-remove-jsx-attribute": { - "dev": true + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-6.5.0.tgz", + "integrity": "sha512-8zYdkym7qNyfXpWvu4yq46k41pyNM9SOstoWhKlm+IfdCE1DdnRKeMUPsWIEO/DEkaWxJ8T9esNdG3QwQ93jBA==", + "dev": true, + "requires": {} }, "@svgr/babel-plugin-remove-jsx-empty-expression": { - "dev": true + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-6.5.0.tgz", + "integrity": "sha512-NFdxMq3xA42Kb1UbzCVxplUc0iqSyM9X8kopImvFnB+uSDdzIHOdbs1op8ofAvVRtbg4oZiyRl3fTYeKcOe9Iw==", + "dev": true, + "requires": {} }, "@svgr/webpack": { "version": "6.2.1", @@ -39419,18 +38778,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, "@babel/helper-validator-option": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", @@ -39448,12 +38795,6 @@ "@babel/types": "^7.20.5" } }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/plugin-syntax-typescript": { "version": "7.20.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", @@ -39523,17 +38864,6 @@ "globals": "^11.1.0" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -39842,12 +39172,6 @@ "boolbase": "^1.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "svg-parser": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", @@ -39928,16 +39252,42 @@ "dev": true }, "@types/babel__generator": { - "dev": true + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } }, "@types/babel__template": { - "dev": true + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } }, "@types/babel__traverse": { - "dev": true + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } }, "@types/body-parser": { - "dev": true + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } }, "@types/cheerio": { "version": "0.22.31", @@ -39948,41 +39298,150 @@ "@types/node": "*" } }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, "@types/node": { + "version": "18.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", "dev": true }, "@types/prop-types": { - "dev": true + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, - "@types/react": {}, + "@types/react": { + "version": "18.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", + "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/scheduler": { - "dev": true + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, "@types/uglify-js": { - "dev": true + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.1.tgz", + "integrity": "sha512-GkewRA4i5oXacU/n4MA9+bLgt5/L3F1mKrYvFGm7r2ouLXhRKjuWwo9XHNnbx6WF3vlGW21S3fCvgqxvxXXc5g==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } }, "@types/webpack-sources": { - "dev": true + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.0.tgz", + "integrity": "sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + } + } }, "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "@videojs/http-streaming": { @@ -41126,24 +40585,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -41173,17 +40614,6 @@ "globals": "^11.1.0" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -41259,35 +40689,6 @@ "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -41369,12 +40770,6 @@ "@types/node": "*" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, "@types/istanbul-reports": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", @@ -42125,12 +41520,6 @@ } } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -42227,12 +41616,6 @@ "schema-utils": "^2.6.5" }, "dependencies": { - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -42375,35 +41758,6 @@ "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@formatjs/ecma402-abstract": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.4.0.tgz", @@ -42477,12 +41831,6 @@ "@types/node": "*" } }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "@types/schema-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/schema-utils/-/schema-utils-2.4.0.tgz", @@ -42547,31 +41895,6 @@ "requires": { "@babel/types": "^7.4", "is-valid-path": "^0.1.1" - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } } }, "babel-polyfill": { @@ -42628,24 +41951,6 @@ "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", @@ -42765,17 +42070,6 @@ "@babel/types": "^7.18.10" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@types/babel__core": { "version": "7.1.20", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", @@ -42789,15 +42083,6 @@ "@types/babel__traverse": "*" } }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, "babel-plugin-jest-hoist": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", @@ -43418,12 +42703,6 @@ "anymatch": "^3.0.0", "source-map": "^0.6.0" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -43706,12 +42985,6 @@ "semver": "^7.3.5" }, "dependencies": { - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -44302,12 +43575,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -46041,12 +45308,6 @@ "schema-utils": "^3.0.0" }, "dependencies": { - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -47528,12 +46789,6 @@ "strip-ansi": "^6.0.1" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -47726,12 +46981,6 @@ "@types/node": "*" } }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -50736,13 +49985,6 @@ "boolbase": "^1.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, "svgo": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", @@ -52423,24 +51665,6 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", - "dev": true - }, "@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -52470,17 +51694,6 @@ "globals": "^11.1.0" } }, - "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, "@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -52773,15 +51986,6 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -52791,12 +51995,6 @@ "@types/node": "*" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, "@types/istanbul-reports": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", @@ -54588,12 +53786,6 @@ } } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -54931,11 +54123,6 @@ "dev": true, "requires": {} }, - "jest-resolve": { - "dev": true, - "optional": true, - "peer": true - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -55358,12 +54545,6 @@ "webpack-sources": "^1.1.0" }, "dependencies": { - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -55405,12 +54586,6 @@ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "webpack-sources": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", @@ -57027,12 +56202,6 @@ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -57555,17 +56724,6 @@ "hoist-non-react-statics": "^3.3.0" } }, - "@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -58037,12 +57195,6 @@ "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -58488,6 +57640,12 @@ "sort-keys": "^1.0.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, "source-map-loader": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", @@ -58974,12 +58132,6 @@ "schema-utils": "^3.0.0" }, "dependencies": { - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -59562,12 +58714,6 @@ "schema-utils": "^3.0.0" }, "dependencies": { - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -59862,13 +59008,6 @@ "dev": true, "peer": true }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true, - "peer": true - }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -60137,13 +59276,6 @@ "ajv-keywords": "^3.5.2" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "peer": true - }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -60566,12 +59698,6 @@ "@types/node": "*" } }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", diff --git a/package.json b/package.json index 7b99ac4ab..fc5f9b095 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,9 @@ "devDependencies": { "@edx/frontend-build": "^11.0.2", "@edx/frontend-platform": "2.4.0", - "@edx/paragon": "^20.21.3", + "@edx/paragon": "^20.27.0", "@testing-library/dom": "^8.13.0", - "@testing-library/react": "12.1.1", + "@testing-library/react": "^12.1.1", "@testing-library/user-event": "^13.5.0", "codecov": "3.8.3", "enzyme": "3.11.0", @@ -58,6 +58,7 @@ }, "dependencies": { "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@reduxjs/toolkit": "^1.8.1", diff --git a/src/editors/Editor.jsx b/src/editors/Editor.jsx index d760c72de..6668e5eb3 100644 --- a/src/editors/Editor.jsx +++ b/src/editors/Editor.jsx @@ -30,7 +30,7 @@ export const Editor = ({ const EditorComponent = supportedEditors[blockType]; return ( -
+
TextEditor) 1`] = `
+
+ + + + } + footerAction={null} + isOpen={false} + size="md" + title="Exit the editor?" + > + + @@ -23,30 +56,22 @@ exports[`EditorContainer component render snapshot: initialized. enable save and >
-

- My test content -

+ +

+ My test content +

+
+
+ + + + } + footerAction={null} + isOpen={false} + size="md" + title="Exit the editor?" + > + + @@ -83,27 +141,18 @@ exports[`EditorContainer component render snapshot: not initialized. disable sav >
+ ( -
+
{saveFailed && ( diff --git a/src/editors/containers/EditorContainer/hooks.js b/src/editors/containers/EditorContainer/hooks.js index 7bb918f77..aa5466560 100644 --- a/src/editors/containers/EditorContainer/hooks.js +++ b/src/editors/containers/EditorContainer/hooks.js @@ -1,9 +1,12 @@ import { useSelector } from 'react-redux'; +import { useState } from 'react'; import { RequestKeys } from '../../data/constants/requests'; import { selectors } from '../../data/redux'; import * as appHooks from '../../hooks'; +import * as module from './hooks'; import analyticsEvt from '../../data/constants/analyticsEvt'; +import { StrictDict } from '../../utils'; export const { navigateCallback, @@ -11,6 +14,10 @@ export const { saveBlock, } = appHooks; +export const state = StrictDict({ + isCancelConfirmModalOpen: (val) => useState(val), +}); + export const handleSaveClicked = ({ dispatch, getContent, validateEntry }) => { const destination = useSelector(selectors.app.returnUrl); const analytics = useSelector(selectors.app.analytics); @@ -23,7 +30,16 @@ export const handleSaveClicked = ({ dispatch, getContent, validateEntry }) => { validateEntry, }); }; -export const handleCancelClicked = ({ onClose }) => { +export const cancelConfirmModalToggle = () => { + const [isCancelConfirmOpen, setIsOpen] = module.state.isCancelConfirmModalOpen(false); + return { + isCancelConfirmOpen, + openCancelConfirmModal: () => setIsOpen(true), + closeCancelConfirmModal: () => setIsOpen(false), + }; +}; + +export const handleCancel = ({ onClose }) => { if (onClose) { return onClose; } @@ -34,6 +50,6 @@ export const handleCancelClicked = ({ onClose }) => { }); }; export const isInitialized = () => useSelector(selectors.app.isInitialized); -export const saveFailed = () => useSelector((state) => ( - selectors.requests.isFailed(state, { requestKey: RequestKeys.saveBlock }) +export const saveFailed = () => useSelector((rootState) => ( + selectors.requests.isFailed(rootState, { requestKey: RequestKeys.saveBlock }) )); diff --git a/src/editors/containers/EditorContainer/hooks.test.jsx b/src/editors/containers/EditorContainer/hooks.test.jsx index 098302fba..01b9412a7 100644 --- a/src/editors/containers/EditorContainer/hooks.test.jsx +++ b/src/editors/containers/EditorContainer/hooks.test.jsx @@ -1,4 +1,5 @@ import * as reactRedux from 'react-redux'; +import { MockUseState } from '../../../testUtils'; import { RequestKeys } from '../../data/constants/requests'; import { selectors } from '../../data/redux'; @@ -7,6 +8,8 @@ import * as appHooks from '../../hooks'; import * as hooks from './hooks'; import analyticsEvt from '../../data/constants/analyticsEvt'; +const hookState = new MockUseState(hooks); + jest.mock('../../data/redux', () => ({ selectors: { app: { @@ -67,9 +70,46 @@ describe('EditorContainer hooks', () => { }); }); }); - describe('handleCancelClicked', () => { + + describe('cancelConfirmModalToggle', () => { + const hookKey = hookState.keys.isCancelConfirmModalOpen; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('state hook', () => { + hookState.testGetter(hookKey); + }); + describe('using state', () => { + beforeEach(() => { + hookState.mock(); + }); + afterEach(() => { + hookState.restore(); + }); + + describe('cancelConfirmModalToggle', () => { + let hook; + beforeEach(() => { + hook = hooks.cancelConfirmModalToggle(); + }); + test('isCancelConfirmOpen: state value', () => { + expect(hook.isCancelConfirmOpen).toEqual(hookState.stateVals[hookKey]); + }); + test('openCancelConfirmModal: calls setter with true', () => { + hook.openCancelConfirmModal(); + expect(hookState.setState[hookKey]).toHaveBeenCalledWith(true); + }); + test('closeCancelConfirmModal: calls setter with false', () => { + hook.closeCancelConfirmModal(); + expect(hookState.setState[hookKey]).toHaveBeenCalledWith(false); + }); + }); + }); + }); + + describe('handleCancel', () => { it('calls navigateCallback to returnUrl if onClose is not passed', () => { - expect(hooks.handleCancelClicked({})).toEqual( + expect(hooks.handleCancel({})).toEqual( appHooks.navigateCallback({ destination: reactRedux.useSelector(selectors.app.returnUrl), analyticsEvent: analyticsEvt.editorCancelClick, @@ -79,7 +119,7 @@ describe('EditorContainer hooks', () => { }); it('calls onClose and not navigateCallback if onClose is passed', () => { const onClose = () => 'my close value'; - expect(hooks.handleCancelClicked({ onClose })).toEqual(onClose); + expect(hooks.handleCancel({ onClose })).toEqual(onClose); expect(appHooks.navigateCallback).not.toHaveBeenCalled(); }); }); diff --git a/src/editors/containers/EditorContainer/index.jsx b/src/editors/containers/EditorContainer/index.jsx index b8e5fc9f4..bd3658801 100644 --- a/src/editors/containers/EditorContainer/index.jsx +++ b/src/editors/containers/EditorContainer/index.jsx @@ -2,24 +2,50 @@ import React from 'react'; import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; -import { Icon, ModalDialog, IconButton } from '@edx/paragon'; +import { + Icon, ModalDialog, IconButton, Button, +} from '@edx/paragon'; import { Close } from '@edx/paragon/icons'; +import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n'; import EditorFooter from './components/EditorFooter'; import TitleHeader from './components/TitleHeader'; import * as hooks from './hooks'; +import BaseModal from '../TextEditor/components/BaseModal'; +import messages from './messages'; export const EditorContainer = ({ children, getContent, onClose, validateEntry, + // injected + intl, }) => { const dispatch = useDispatch(); const isInitialized = hooks.isInitialized(); - const handleCancelClicked = hooks.handleCancelClicked({ onClose }); + const { isCancelConfirmOpen, openCancelConfirmModal, closeCancelConfirmModal } = hooks.cancelConfirmModalToggle(); + const handleCancel = hooks.handleCancel({ onClose }); return ( -
+
+ + + + )} + isOpen={isCancelConfirmOpen} + close={closeCancelConfirmModal} + title={intl.formatMessage(messages.cancelConfirmTitle)} + > + +
- {isInitialized && children} + + {isInitialized && children} + ({ isInitialized: jest.fn().mockReturnValue(true), - handleCancelClicked: (args) => ({ handleCancelClicked: args }), + handleCancel: (args) => ({ handleCancel: args }), handleSaveClicked: (args) => ({ handleSaveClicked: args }), saveFailed: jest.fn().mockName('hooks.saveFailed'), + cancelConfirmModalToggle: jest.fn(() => ({ + isCancelConfirmOpen: false, + openCancelConfirmModal: jest.fn().mockName('openCancelConfirmModal'), + closeCancelConfirmModal: jest.fn().mockName('closeCancelConfirmModal'), + })), })); let el; @@ -39,23 +46,13 @@ describe('EditorContainer component', () => { el = shallow({testContent}); }); - test('close behavior is linked to modal onClose', () => { - const expected = hooks.handleCancelClicked({ onClose: props.onClose }); - expect(el.find(IconButton) - .props().onClick).toEqual(expected); - }); - test('close behavior is linked to footer onCancel', () => { - const expected = hooks.handleCancelClicked({ onClose: props.onClose }); - expect(el.children().at(2) - .props().onCancel).toEqual(expected); - }); test('save behavior is linked to footer onSave', () => { const expected = hooks.handleSaveClicked({ dispatch: useDispatch(), getContent: props.getContent, validateEntry: props.validateEntry, }); - expect(el.children().at(2) + expect(el.children().at(3) .props().onSave).toEqual(expected); }); }); diff --git a/src/editors/containers/EditorContainer/messages.js b/src/editors/containers/EditorContainer/messages.js new file mode 100644 index 000000000..c9eb65dce --- /dev/null +++ b/src/editors/containers/EditorContainer/messages.js @@ -0,0 +1,19 @@ +export const messages = { + cancelConfirmTitle: { + id: 'authoring.editorContainer.cancelConfirm.title', + defaultMessage: 'Exit the editor?', + description: 'Label for modal confirming cancellation', + }, + cancelConfirmDescription: { + id: 'authoring.editorContainer.cancelConfirm.description', + defaultMessage: 'Are you sure you want to exit the editor? Any unsaved changes will be lost.', + description: 'Description text for modal confirming cancellation', + }, + okButtonLabel: { + id: 'authoring.editorContainer.okButton.label', + defaultMessage: 'OK', + description: 'Label for OK button', + }, +}; + +export default messages; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.jsx index a8e867ed7..73f07b3ea 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.jsx @@ -2,57 +2,21 @@ import React, { memo } from 'react'; import { connect, useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import { - Col, Collapsible, Icon, IconButton, Form, Row, + Collapsible, + Icon, + IconButton, + Form, } from '@edx/paragon'; -import { AddComment, Delete } from '@edx/paragon/icons'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { FeedbackOutline, DeleteOutline } from '@edx/paragon/icons'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import messages from './messages'; import { selectors } from '../../../../../data/redux'; import { answerOptionProps } from '../../../../../data/services/cms/types'; -import { ProblemTypeKeys } from '../../../../../data/constants/problem'; +import Checker from './components/Checker'; +import { FeedbackBox } from './components/Feedback'; import * as hooks from './hooks'; -const Checker = ({ - hasSingleAnswer, answer, setAnswer, -}) => { - let CheckerType = Form.Checkbox; - if (hasSingleAnswer) { - CheckerType = Form.Radio; - } - return ( - setAnswer({ correct: e.target.checked })} - checked={answer.correct} - > - {answer.id} - - ); -}; - -const FeedbackControl = ({ - feedback, onChange, labelMessage, labelMessageBoldUnderline, key, answer, intl, -}) => ( - - - , - }} - /> - - - -); - export const AnswerOption = ({ answer, hasSingleAnswer, @@ -66,91 +30,55 @@ export const AnswerOption = ({ const setAnswer = hooks.setAnswer({ answer, hasSingleAnswer, dispatch }); const { isFeedbackVisible, toggleFeedback } = hooks.prepareFeedback(answer); - const displayFeedbackControl = (answerObject) => { - if (problemType !== ProblemTypeKeys.MULTISELECT) { - return FeedbackControl({ - key: `feedback-${answerObject.id}`, - feedback: answerObject.feedback, - onChange: (e) => setAnswer({ feedback: e.target.value }), - labelMessage: messages.selectedFeedbackLabel, - labelMessageBoldUnderline: messages.selectedFeedbackLabelBoldUnderlineText, - answer: answerObject, - intl, - }); - } - return [ - FeedbackControl({ - key: `selectedfeedback-${answerObject.id}`, - feedback: answerObject.selectedFeedback, - onChange: (e) => setAnswer({ selectedFeedback: e.target.value }), - labelMessage: messages.selectedFeedbackLabel, - labelMessageBoldUnderline: messages.selectedFeedbackLabelBoldUnderlineText, - answer: answerObject, - intl, - }), - FeedbackControl({ - key: `unselectedfeedback-${answerObject.id}`, - feedback: answerObject.unselectedFeedback, - onChange: (e) => setAnswer({ unselectedFeedback: e.target.value }), - labelMessage: messages.unSelectedFeedbackLabel, - labelMessageBoldUnderline: messages.unSelectedFeedbackLabelBoldUnderlineText, - answer: answerObject, - intl, - }), - ]; - }; - return ( - - - - + +
+
+ { setAnswer({ title: e.target.value }); }} + placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)} + /> + + - - - - { setAnswer({ title: e.target.value }); }} - placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)} - /> - - -
- {displayFeedbackControl(answer)} -
-
- - - - - - +
+
+
+ - - - + + +
); }; @@ -164,22 +92,6 @@ AnswerOption.propTypes = { problemType: PropTypes.string.isRequired, }; -FeedbackControl.propTypes = { - feedback: PropTypes.string.isRequired, - onChange: PropTypes.func.isRequired, - labelMessage: PropTypes.string.isRequired, - labelMessageBoldUnderline: PropTypes.string.isRequired, - key: PropTypes.string.isRequired, - answer: answerOptionProps.isRequired, - intl: intlShape.isRequired, -}; - -Checker.propTypes = { - hasSingleAnswer: PropTypes.bool.isRequired, - answer: answerOptionProps.isRequired, - setAnswer: PropTypes.func.isRequired, -}; - export const mapStateToProps = (state) => ({ problemType: selectors.problem.problemType(state), }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.test.jsx index 5e40a528c..439c597a3 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswerOption.test.jsx @@ -1,14 +1,23 @@ import React from 'react'; import { shallow } from 'enzyme'; import { formatMessage } from '../../../../../../testUtils'; -import { AnswerOption } from './AnswerOption'; +import { selectors } from '../../../../../data/redux'; +import { AnswerOption, mapStateToProps } from './AnswerOption'; + +jest.mock('../../../../../data/redux', () => ({ + selectors: { + problem: { + problemType: jest.fn(state => ({ problemType: state })), + }, + }, +})); describe('AnswerOption', () => { const answerWithOnlyFeedback = { id: 'A', title: 'Answer 1', correct: true, - feedback: 'some feedback', + selectedFeedback: 'some feedback', }; const answerWithSelectedUnselectedFeedback = { id: 'A', @@ -23,15 +32,23 @@ describe('AnswerOption', () => { answer: answerWithOnlyFeedback, // inject intl: { formatMessage }, - deleteAnswer: jest.fn(), - updateAnswer: jest.fn(), + // redux + problemType: 'multiplechoiceresponse', }; describe('render', () => { test('snapshot: renders correct option with feedback', () => { expect(shallow()).toMatchSnapshot(); }); test('snapshot: renders correct option with selected unselected feedback', () => { - expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); + }); + }); + describe('mapStateToProps', () => { + const testState = { A: 'pple', B: 'anana', C: 'ucumber' }; + test('problemType from problem.problemType', () => { + expect( + mapStateToProps(testState).problemType, + ).toEqual(selectors.problem.problemType(testState)); }); }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.jsx index d85b9ea2e..42c079a4f 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/AnswersContainer.jsx @@ -6,7 +6,7 @@ import { Add } from '@edx/paragon/icons'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; import messages from './messages'; -import { initializeAnswerContainer } from '../../../hooks'; +import { useAnswerContainer, isSingleAnswerProblem } from './hooks'; import { actions, selectors } from '../../../../../data/redux'; import { answerOptionProps } from '../../../../../data/services/cms/types'; import AnswerOption from './AnswerOption'; @@ -16,11 +16,14 @@ export const AnswersContainer = ({ // Redux answers, addAnswer, + updateField, }) => { - const { hasSingleAnswer } = initializeAnswerContainer(problemType); + const hasSingleAnswer = isSingleAnswerProblem(problemType); + + useAnswerContainer({ answers, problemType, updateField }); return ( -
+
{answers.map((answer) => ( ))}
+
+ + + - - - - -
- - - - - - - , - } - } - /> - - - -
- -
- - - - + +
+
+ - - + + +
`; exports[`AnswerOption render snapshot: renders correct option with selected unselected feedback 1`] = ` - - - +
+
+ + + - - - - -
- - - - - - - , - } - } - /> - - - -
- -
- - - - + +
+
+ - - + + +
`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/__snapshots__/AnswersContainer.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/__snapshots__/AnswersContainer.test.jsx.snap new file mode 100644 index 000000000..07078350c --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/__snapshots__/AnswersContainer.test.jsx.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AnswersContainer render snapshot: renders correct default 1`] = ` +
+ +
+`; + +exports[`AnswersContainer render snapshot: renders correctly with answers 1`] = ` +
+ + + +
+`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/__snapshots__/index.test.jsx.snap new file mode 100644 index 000000000..a9692438d --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/__snapshots__/index.test.jsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Checker component with multiple answers 1`] = ` + + A + +`; + +exports[`Checker component with single answer 1`] = ` + + A + +`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/index.jsx new file mode 100644 index 000000000..2ac2a4d7a --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/index.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Form } from '@edx/paragon'; + +const Checker = ({ + hasSingleAnswer, answer, setAnswer, +}) => { + let CheckerType = Form.Checkbox; + if (hasSingleAnswer) { + CheckerType = Form.Radio; + } + return ( + setAnswer({ correct: e.target.checked })} + checked={answer.correct} + > + {answer.id} + + ); +}; +Checker.propTypes = { + hasSingleAnswer: PropTypes.bool.isRequired, + answer: PropTypes.shape({ + correct: PropTypes.bool, + id: PropTypes.number, + }).isRequired, + setAnswer: PropTypes.func.isRequired, +}; + +export default Checker; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/index.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/index.test.jsx new file mode 100644 index 000000000..19998a536 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Checker/index.test.jsx @@ -0,0 +1,22 @@ +import { shallow } from 'enzyme'; +import Checker from '.'; + +const props = { + hasSingleAnswer: true, + answer: { + id: 'A', + title: 'Answer 1', + correct: true, + selectedFeedback: 'some feedback', + }, + setAnswer: jest.fn(), +}; +describe('Checker component', () => { + test('with single answer', () => { + expect(shallow()).toMatchSnapshot(); + }); + + test('with multiple answers', () => { + expect(shallow()).toMatchSnapshot(); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackBox.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackBox.jsx new file mode 100644 index 000000000..347f4cd07 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackBox.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; + +import { answerOptionProps } from '../../../../../../../data/services/cms/types'; +import FeedbackControl from './FeedbackControl'; +import { messages } from './messages'; + +export const FeedbackBox = ({ + answer, setAnswer, intl, +}) => { + const props = { + onChange: (e) => setAnswer({ selectedFeedback: e.target.value }), + answer, + intl, + }; + + return ( +
+ + +
+ ); +}; +FeedbackBox.propTypes = { + answer: answerOptionProps.isRequired, + setAnswer: PropTypes.func.isRequired, + intl: intlShape.isRequired, +}; + +export default injectIntl(FeedbackBox); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackBox.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackBox.test.jsx new file mode 100644 index 000000000..117c48255 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackBox.test.jsx @@ -0,0 +1,22 @@ +import { shallow } from 'enzyme'; +import { FeedbackBox } from './FeedbackBox'; + +const answerWithFeedback = { + id: 'A', + title: 'Answer 1', + correct: true, + selectedFeedback: 'some feedback', + unselectedFeedback: 'unselectedFeedback', +}; + +const props = { + answer: answerWithFeedback, + intl: {}, + setAnswer: jest.fn(), +}; + +describe('FeedbackBox component', () => { + test('renders', () => { + expect(shallow()).toMatchSnapshot(); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackControl.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackControl.jsx new file mode 100644 index 000000000..12ff8091d --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackControl.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage, intlShape } from '@edx/frontend-platform/i18n'; +import { Form } from '@edx/paragon'; + +import { answerOptionProps } from '../../../../../../../data/services/cms/types'; +import messages from './messages'; + +const FeedbackControl = ({ + feedback, onChange, labelMessage, labelMessageBoldUnderline, answer, intl, +}) => ( + + + , + }} + /> + + + +); +FeedbackControl.propTypes = { + feedback: PropTypes.string.isRequired, + onChange: PropTypes.func.isRequired, + labelMessage: PropTypes.string.isRequired, + labelMessageBoldUnderline: PropTypes.string.isRequired, + answer: answerOptionProps.isRequired, + intl: intlShape.isRequired, +}; + +export default FeedbackControl; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackControl.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackControl.test.jsx new file mode 100644 index 000000000..93d6499d4 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/FeedbackControl.test.jsx @@ -0,0 +1,26 @@ +import { shallow } from 'enzyme'; +import FeedbackControl from './FeedbackControl'; + +const answerWithFeedback = { + id: 'A', + title: 'Answer 1', + correct: true, + selectedFeedback: 'some feedback', + unselectedFeedback: 'unselectedFeedback', +}; + +const props = { + answer: answerWithFeedback, + intl: { formatMessage: jest.fn() }, + setAnswer: jest.fn(), + feedback: 'feedback', + onChange: jest.fn(), + labelMessage: 'msg', + labelMessageBoldUnderline: 'msg', +}; + +describe('FeedbackControl component', () => { + test('renders', () => { + expect(shallow()).toMatchSnapshot(); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/__snapshots__/FeedbackBox.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/__snapshots__/FeedbackBox.test.jsx.snap new file mode 100644 index 000000000..4c9113846 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/__snapshots__/FeedbackBox.test.jsx.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FeedbackBox component renders 1`] = ` +
+ + +
+`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/__snapshots__/FeedbackControl.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/__snapshots__/FeedbackControl.test.jsx.snap new file mode 100644 index 000000000..40a7fde43 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/__snapshots__/FeedbackControl.test.jsx.snap @@ -0,0 +1,33 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FeedbackControl component renders 1`] = ` + + + + + + + , + } + } + /> + + + +`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/index.jsx new file mode 100644 index 000000000..bce02835a --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/index.jsx @@ -0,0 +1,2 @@ +export { default as FeedbackBox } from './FeedbackBox'; +export { default as FeedbackControl } from './FeedbackControl'; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/messages.js b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/messages.js new file mode 100644 index 000000000..a580c9c7e --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/components/Feedback/messages.js @@ -0,0 +1,34 @@ +export const messages = { + feedbackPlaceholder: { + id: 'authoring.answerwidget.feedback.placeholder', + defaultMessage: 'Feedback message', + description: 'Placeholder text for feedback text', + }, + feedbackToggleIconAltText: { + id: 'authoring.answerwidget.feedback.icon.alt', + defaultMessage: 'Toggle feedback', + description: 'Alt text for feedback toggle icon', + }, + selectedFeedbackLabel: { + id: 'authoring.answerwidget.feedback.selected.label', + defaultMessage: 'Show following feedback when {answerId} {boldunderline}:', + description: 'Label text for feedback if option is selected', + }, + selectedFeedbackLabelBoldUnderlineText: { + id: 'authoring.answerwidget.feedback.selected.label.boldunderline', + defaultMessage: 'is selected', + description: 'Bold & underlined text for feedback if option is selected', + }, + unSelectedFeedbackLabel: { + id: 'authoring.answerwidget.feedback.unselected.label', + defaultMessage: 'Show following feedback when {answerId} {boldunderline}:', + description: 'Label text for feedback if option is not selected', + }, + unSelectedFeedbackLabelBoldUnderlineText: { + id: 'authoring.answerwidget.feedback.unselected.label.boldunderline', + defaultMessage: 'is not selected', + description: 'Bold & underlined text for feedback if option is not selected', + }, +}; + +export default messages; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hook.test.js b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hook.test.js index 892e21af4..ff5d51abe 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hook.test.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hook.test.js @@ -1,5 +1,6 @@ import { useEffect } from 'react'; import { MockUseState } from '../../../../../../testUtils'; +import { ProblemTypeKeys } from '../../../../../data/constants/problem'; import * as module from './hooks'; jest.mock('react', () => { @@ -52,4 +53,15 @@ describe('Answer Options Hooks', () => { expect(state.setState[key]).toHaveBeenCalledWith(true); }); }); + describe('isSingleAnswerProblem()', () => { + test('singleSelect', () => { + expect(module.isSingleAnswerProblem(ProblemTypeKeys.SINGLESELECT)).toBe(true); + }); + test('multiSelect', () => { + expect(module.isSingleAnswerProblem(ProblemTypeKeys.MULTISELECT)).toBe(false); + }); + test('dropdown', () => { + expect(module.isSingleAnswerProblem(ProblemTypeKeys.DROPDOWN)).toBe(true); + }); + }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hooks.js b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hooks.js index 5559b5c70..74f141637 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hooks.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hooks.js @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'; import { StrictDict } from '../../../../../utils'; import * as module from './hooks'; import { actions } from '../../../../../data/redux'; +import { ProblemTypeKeys } from '../../../../../data/constants/problem'; export const state = StrictDict({ isFeedbackVisible: (val) => useState(val), @@ -37,6 +38,22 @@ export const prepareFeedback = (answer) => { }; }; -export default { - state, removeAnswer, setAnswer, prepareFeedback, +export const isSingleAnswerProblem = (problemType) => ( + problemType === ProblemTypeKeys.DROPDOWN || problemType === ProblemTypeKeys.SINGLESELECT +); + +export const useAnswerContainer = ({ answers, updateField }) => { + useEffect(() => { + let answerCount = 0; + answers.forEach(answer => { + if (answer.correct) { + answerCount += 1; + } + }); + updateField({ correctAnswerCount: answerCount }); + }, []); +}; + +export default { + state, removeAnswer, setAnswer, prepareFeedback, isSingleAnswerProblem, useAnswerContainer, }; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.jsx index 7e68f2cc9..e9c9bd928 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.jsx @@ -15,11 +15,11 @@ const AnswerWidget = ({ const problemStaticData = ProblemTypes[problemType]; return (
-
-
+
+
-
+
{problemStaticData.description}
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.scss b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.scss index 622a591a9..59ad4d855 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.scss +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/index.scss @@ -1,11 +1,32 @@ -.problem-answer { - padding: 12px; - color: #00262B; - .problem-answer-title { - font-weight: bold; - } +.answer-option { + .answer-option-flex-item-1 { + flex-basis: 8.33%; + } - .problem-answer-description { - font-size: 0.9rem; + .answer-option-flex-item-2 { + flex-basis: 83.34%; + } + + .answer-option-flex-item-3 { + flex-basis: 8.33%; + } + + .answer-option-textarea { + textarea { + border: none; + resize: none; + + &:active, &:hover, &:focus, &:focus-visible { + border: none; + border-right: none; + border-left: none; + border-radius: 0; + box-shadow: none; + } + + &:focus, &:hover { + border-bottom: 1px solid #000; + } } + } } diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx index 8eceb0277..1e31b2f99 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx @@ -6,6 +6,7 @@ import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; import * as hooks from '../../../hooks'; import { selectors, actions } from '../../../../../data/redux'; import { messages } from './messages'; +import './index.scss'; // This widget should be connected, grab all questions from store, update them as needed. export const QuestionWidget = ({ @@ -15,12 +16,11 @@ export const QuestionWidget = ({ const { editorRef, refReady, setEditorRef } = hooks.prepareEditorRef(); if (!refReady) { return null; } return ( -
-
-

- -

- +
+ +
+ -
+ />
); }; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.scss b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.scss new file mode 100644 index 000000000..9292bef5f --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.scss @@ -0,0 +1,28 @@ +.question-widget { + .tox-tinymce { + border-radius: 0.375rem; + } + + .tox { + .tox-toolbar__primary { + background: none; + } + } + + .tox-statusbar { + border-top: none; + } + + .tox-toolbar__group:not(:last-of-type) { + // TODO: Find a way to override the border without !important + border-right: none !important; + + &:after { + content: ''; + position: relative; + left: 5px; + border: 1px solid #eae6e5; + height: 24px; + } + } +} diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx index f74e04217..d3cc22bfa 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/SettingsOption.jsx @@ -12,7 +12,7 @@ export const SettingsOption = ({ const { isCardCollapsed, toggleCardCollapse } = showFullCard(); return ( - + + diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/index.test.jsx.snap index 346860fd2..432523260 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/index.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/__snapshots__/index.test.jsx.snap @@ -2,172 +2,182 @@ exports[`SettingsWidget snapshot snapshot: renders Settings widget page 1`] = `
-
-

- -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+
-
-`; - -exports[`SettingsWidget snapshot snapshot: renders Settings widget page advanced settings visible 1`] = ` -
-
-

- -

- - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - + + - - - -
+ + + + + + + + + + + + + + + + + + + + + + + +
+`; + +exports[`SettingsWidget snapshot snapshot: renders Settings widget page advanced settings visible 1`] = ` +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js index e77ab6196..47c88e6e7 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.js @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import _ from 'lodash-es'; import * as module from './hooks'; import messages from './messages'; -import { ShowAnswerTypesKeys } from '../../../../../data/constants/problem'; +import { ProblemTypeKeys, ShowAnswerTypesKeys } from '../../../../../data/constants/problem'; export const state = { showAdvanced: (val) => useState(val), @@ -113,14 +113,14 @@ export const resetCardHooks = (updateSettings) => { export const scoringCardHooks = (scoring, updateSettings) => { const handleMaxAttemptChange = (event) => { - let unlimitedAttempts = true; + let unlimitedAttempts = false; let attemptNumber = parseInt(event.target.value); if (_.isNaN(attemptNumber)) { + attemptNumber = null; + unlimitedAttempts = true; + } else if (attemptNumber < 0) { attemptNumber = 0; } - if (attemptNumber > 0) { - unlimitedAttempts = false; - } updateSettings({ scoring: { ...scoring, attempts: { number: attemptNumber, unlimited: unlimitedAttempts } } }); }; @@ -182,11 +182,23 @@ export const timerCardHooks = (updateSettings) => ({ }, }); -export const typeRowHooks = (typeKey, updateField) => { +export const typeRowHooks = ({ + answers, + correctAnswerCount, + typeKey, + updateField, + updateAnswer, +}) => { const onClick = () => { + if (typeKey === ProblemTypeKeys.SINGLESELECT || typeKey === ProblemTypeKeys.DROPDOWN) { + if (correctAnswerCount > 1) { + answers.forEach(answer => { + updateAnswer({ ...answer, correct: false }); + }); + } + } updateField({ problemType: typeKey }); }; - return { onClick, }; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js index 9d9a41b9d..556004402 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/hooks.test.js @@ -18,6 +18,7 @@ jest.mock('../../../../../data/redux', () => ({ problem: { updateSettings: (args) => ({ updateSettings: args }), updateField: (args) => ({ updateField: args }), + updateAnswer: (args) => ({ updateAnswer: args }), }, }, })); @@ -177,7 +178,31 @@ describe('Problem settings hooks', () => { const value = 0; output.handleMaxAttemptChange({ target: { value } }); expect(updateSettings) - .toHaveBeenCalledWith({ scoring: { ...scoring, attempts: { number: value, unlimited: true } } }); + .toHaveBeenCalledWith({ scoring: { ...scoring, attempts: { number: value, unlimited: false } } }); + }); + test('test handleMaxAttemptChange set attempts to null value', () => { + const value = null; + output.handleMaxAttemptChange({ target: { value } }); + expect(updateSettings) + .toHaveBeenCalledWith({ scoring: { ...scoring, attempts: { number: null, unlimited: true } } }); + }); + test('test handleMaxAttemptChange set attempts to empty string', () => { + const value = ''; + output.handleMaxAttemptChange({ target: { value } }); + expect(updateSettings) + .toHaveBeenCalledWith({ scoring: { ...scoring, attempts: { number: null, unlimited: true } } }); + }); + test('test handleMaxAttemptChange set attempts to non-numeric value', () => { + const value = 'abc'; + output.handleMaxAttemptChange({ target: { value } }); + expect(updateSettings) + .toHaveBeenCalledWith({ scoring: { ...scoring, attempts: { number: null, unlimited: true } } }); + }); + test('test handleMaxAttemptChange set attempts to negative value', () => { + const value = -1; + output.handleMaxAttemptChange({ target: { value } }); + expect(updateSettings) + .toHaveBeenCalledWith({ scoring: { ...scoring, attempts: { number: 0, unlimited: false } } }); }); test('test handleWeightChange', () => { const value = 2; @@ -217,10 +242,27 @@ describe('Problem settings hooks', () => { describe('Type row hooks', () => { test('test onClick', () => { - const typekey = 'TEXTINPUT'; + const typekey = 'multiplechoiceresponse'; const updateField = jest.fn(); - output = hooks.typeRowHooks(typekey, updateField); + const updateAnswer = jest.fn(); + const answers = [{ + correct: true, + id: 'a', + }, + { + correct: true, + id: 'b', + }]; + output = hooks.typeRowHooks({ + answers, + correctAnswerCount: 2, + typeKey: typekey, + updateField, + updateAnswer, + }); output.onClick(); + expect(updateAnswer).toHaveBeenNthCalledWith(1, { ...answers[0], correct: false }); + expect(updateAnswer).toHaveBeenNthCalledWith(2, { ...answers[1], correct: false }); expect(updateField).toHaveBeenCalledWith({ problemType: typekey }); }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx index 90e5f904a..b8f0aa374 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/index.jsx @@ -13,6 +13,7 @@ import ResetCard from './settingsComponents/ResetCard'; import MatlabCard from './settingsComponents/MatlabCard'; import TimerCard from './settingsComponents/TimerCard'; import TypeCard from './settingsComponents/TypeCard'; +import SwitchToAdvancedEditorCard from './settingsComponents/SwitchToAdvancedEditorCard'; import messages from './messages'; import { showAdvancedSettingsCards } from './hooks'; @@ -22,72 +23,90 @@ import './index.scss'; export const SettingsWidget = ({ problemType, // redux + answers, + correctAnswerCount, settings, updateSettings, updateField, + updateAnswer, }) => { const { isAdvancedCardsVisible, showAdvancedCards } = showAdvancedSettingsCards(); return (
-
-

- -

- - - - - - - - - - - - +
+ +
+ + + + + + + + + + + + - - - - - - - - - + + - - - - - - - - - - - - + - - - -
+ + + + + + + + + + + + + + + + + + + + + + +
); }; SettingsWidget.propTypes = { + answers: PropTypes.arrayOf(PropTypes.shape({ + correct: PropTypes.bool, + id: PropTypes.string, + selectedFeedback: PropTypes.string, + title: PropTypes.string, + unselectedFeedback: PropTypes.string, + })).isRequired, + correctAnswerCount: PropTypes.number.isRequired, problemType: PropTypes.string.isRequired, + updateAnswer: PropTypes.func.isRequired, updateField: PropTypes.func.isRequired, updateSettings: PropTypes.func.isRequired, // eslint-disable-next-line @@ -96,11 +115,14 @@ SettingsWidget.propTypes = { const mapStateToProps = (state) => ({ settings: selectors.problem.settings(state), + answers: selectors.problem.answers(state), + correctAnswerCount: selectors.problem.correctAnswerCount(state), }); export const mapDispatchToProps = { updateSettings: actions.problem.updateSettings, updateField: actions.problem.updateField, + updateAnswer: actions.problem.updateAnswer, }; export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SettingsWidget)); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js index 4539decc3..ce597208a 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/messages.js @@ -36,7 +36,7 @@ export const messages = { }, noHintSummary: { id: 'authoring.problemeditor.settings.hint.noHintSummary', - defaultMessage: 'No Hints', + defaultMessage: 'None', description: 'Summary text for no hints', }, hintSummary: { @@ -104,10 +104,35 @@ export const messages = { defaultMessage: 'Points', description: 'Scoring weight input label', }, - scoringSummary: { - id: 'authoring.problemeditor.settings.scoring.summary', - defaultMessage: '{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}', - description: 'Summary text for scoring settings', + unlimitedAttemptsSummary: { + id: 'authoring.problemeditor.settings.scoring.unlimited', + defaultMessage: 'Unlimited attempts', + description: 'Summary text for unlimited attempts', + }, + attemptsSummary: { + id: 'authoring.problemeditor.settings.scoring.attempts', + defaultMessage: '{attempts, plural, =1 {# attempt} other {# attempts}}', + description: 'Summary text for number of attempts', + }, + weightSummary: { + id: 'authoring.problemeditor.settings.scoring.weight', + defaultMessage: '{weight, plural, =0 {Ungraded} other {# points}}', + description: 'Summary text for scoring weight', + }, + scoringSettingsLabel: { + id: 'authoring.problemeditor.settings.scoring.label', + defaultMessage: 'Specify point weight and the number of answer attempts', + description: 'Descriptive text for scoring settings', + }, + attemptsHint: { + id: 'authoring.problemeditor.settings.scoring.attempts.hint', + defaultMessage: 'If a value is not set, unlimited attempts are allowed', + description: 'Summary text for scoring weight', + }, + weightHint: { + id: 'authoring.problemeditor.settings.scoring.weight.hint', + defaultMessage: 'If a value is not set, the problem is worth one point', + description: 'Summary text for scoring weight', }, showAnswerSettingsTitle: { id: 'authoring.problemeditor.settings.showAnswer.title', @@ -149,6 +174,26 @@ export const messages = { defaultMessage: 'Type', description: 'Type settings card title', }, + SwitchButtonLabel: { + id: 'authoring.problemeditor.settings.switchtoadvancededitor.label', + defaultMessage: 'Switch To Advanced Editor', + description: 'button to switch to the advanced mode of the editor.', + }, + ConfirmSwitchMessage: { + id: 'authoring.problemeditor.settings.switchtoadvancededitor.message', + defaultMessage: 'If you use the advanced editor, this problem will be converted to OLX and you will not be able to return to the simple editor.', + description: 'message to confirm that a user wants to use the advanced editor', + }, + ConfirmSwitchMessageTitle: { + id: 'authoring.problemeditor.settings.switchtoadvancededitor.message', + defaultMessage: 'Convert to OLX?', + description: 'message to confirm that a user wants to use the advanced editor', + }, + ConfirmSwitchButtonLabel: { + id: 'authoring.problemeditor.settings.switchtoadvancededitor.message', + defaultMessage: 'Switch To Advanced Editor', + description: 'message to confirm that a user wants to use the advanced editor', + }, }; export default messages; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/HintsCard.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/HintsCard.jsx index ef2fff7e0..088fd3eff 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/HintsCard.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/HintsCard.jsx @@ -29,7 +29,7 @@ export const HintsCard = ({ /> ))}
- +
@@ -49,7 +54,7 @@ export const ShowAnswerCard = ({ ))} - { showAttempts + {showAttempts && ( ({ + studioEndpointUrl: selectors.app.studioEndpointUrl(state), + learningContextId: selectors.app.learningContextId(state), +}); + +export const mapDispatchToProps = {}; + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ShowAnswerCard)); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx index e727746e2..63d2e2bfe 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/ShowAnswerCard.test.jsx @@ -1,13 +1,23 @@ import React from 'react'; import { shallow } from 'enzyme'; import { formatMessage } from '../../../../../../../testUtils'; -import { ShowAnswerCard } from './ShowAnswerCard'; +import { selectors } from '../../../../../../data/redux'; +import { ShowAnswerCard, mapStateToProps, mapDispatchToProps } from './ShowAnswerCard'; import { showAnswerCardHooks } from '../hooks'; jest.mock('../hooks', () => ({ showAnswerCardHooks: jest.fn(), })); +jest.mock('../../../../../../data/redux', () => ({ + selectors: { + app: { + studioEndpointUrl: jest.fn(state => ({ studioEndpointUrl: state })), + learningContextId: jest.fn(state => ({ learningContextId: state })), + }, + }, +})); + describe('ShowAnswerCard', () => { const showAnswer = { on: 'after_attempts', @@ -17,7 +27,11 @@ describe('ShowAnswerCard', () => { }; const props = { showAnswer, + // injected intl: { formatMessage }, + // redux + studioEndpointUrl: 'SoMEeNDpOinT', + learningContextId: 'sOMEcouRseId', }; const showAnswerCardHooksProps = { @@ -39,4 +53,22 @@ describe('ShowAnswerCard', () => { expect(shallow()).toMatchSnapshot(); }); }); + describe('mapStateToProps', () => { + const testState = { A: 'pple', B: 'anana', C: 'ucumber' }; + test('studioEndpointUrl from app.studioEndpointUrl', () => { + expect( + mapStateToProps(testState).studioEndpointUrl, + ).toEqual(selectors.app.studioEndpointUrl(testState)); + }); + test('learningContextId from app.learningContextId', () => { + expect( + mapStateToProps(testState).learningContextId, + ).toEqual(selectors.app.learningContextId(testState)); + }); + }); + describe('mapDispatchToProps', () => { + test('equal an empty object', () => { + expect(mapDispatchToProps).toEqual({}); + }); + }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/SwitchToAdvancedEditorCard.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/SwitchToAdvancedEditorCard.jsx new file mode 100644 index 000000000..e68e10351 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/SwitchToAdvancedEditorCard.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; +import { Button, Card } from '@edx/paragon'; +import PropTypes from 'prop-types'; +import messages from '../messages'; +import { thunkActions } from '../../../../../../data/redux'; +import BaseModal from '../../../../../TextEditor/components/BaseModal'; + +export const SwitchToAdvancedEditorCard = ({ + switchToAdvancedEditor, +}) => { + const [isConfirmOpen, setConfirmOpen] = React.useState(false); + return ( + + { setConfirmOpen(false); }} + title={()} + confirmAction={( + + )} + size="md" + > + + + + + ); +}; + +SwitchToAdvancedEditorCard.propTypes = { + switchToAdvancedEditor: PropTypes.func.isRequired, +}; + +export const mapStateToProps = () => ({ +}); +export const mapDispatchToProps = { + switchToAdvancedEditor: thunkActions.problem.switchToAdvancedEditor, +}; + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SwitchToAdvancedEditorCard)); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/SwitchToAdvancedEditorCard.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/SwitchToAdvancedEditorCard.test.jsx new file mode 100644 index 000000000..96d0b4a5c --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/SwitchToAdvancedEditorCard.test.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { SwitchToAdvancedEditorCard } from './SwitchToAdvancedEditorCard'; + +describe('SwitchToAdvancedEditorCard snapshot', () => { + const mockSwitchToAdvancedEditor = jest.fn().mockName('switchToAdvancedEditor'); + test('snapshot: SwitchToAdvancedEditorCard', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.jsx index 06a085db2..c73779a04 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.jsx @@ -7,12 +7,17 @@ import messages from '../messages'; import TypeRow from './TypeRow'; export const TypeCard = ({ + answers, + correctAnswerCount, problemType, updateField, + updateAnswer, // inject intl, }) => { - const problemTypeKeysArray = Object.values(ProblemTypeKeys); + const problemTypeKeysArray = Object.values(ProblemTypeKeys).filter(key => key !== ProblemTypeKeys.ADVANCED); + + if (problemType === ProblemTypeKeys.ADVANCED) { return null; } return ( {problemTypeKeysArray.map((typeKey, i) => ( ))} @@ -34,9 +42,19 @@ export const TypeCard = ({ }; TypeCard.propTypes = { - intl: intlShape.isRequired, + answers: PropTypes.arrayOf(PropTypes.shape({ + correct: PropTypes.bool, + id: PropTypes.string, + selectedFeedback: PropTypes.string, + title: PropTypes.string, + unselectedFeedback: PropTypes.string, + })).isRequired, + correctAnswerCount: PropTypes.number.isRequired, problemType: PropTypes.string.isRequired, updateField: PropTypes.func.isRequired, + updateAnswer: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, }; export default injectIntl(TypeCard); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.test.jsx index 1886661a5..d2a2f8518 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeCard.test.jsx @@ -6,8 +6,12 @@ import { ProblemTypeKeys } from '../../../../../../data/constants/problem'; describe('TypeCard', () => { const props = { + answers: [], + correctAnswerCount: 0, problemType: ProblemTypeKeys.TEXTINPUT, updateField: jest.fn().mockName('args.updateField'), + updateAnswer: jest.fn().mockName('args.updateAnswer'), + // injected intl: { formatMessage }, }; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.jsx index 71810543c..811499d43 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.jsx @@ -5,13 +5,22 @@ import { Check } from '@edx/paragon/icons'; import { typeRowHooks } from '../hooks'; export const TypeRow = ({ + answers, + correctAnswerCount, typeKey, label, selected, lastRow, updateField, + updateAnswer, }) => { - const { onClick } = typeRowHooks(typeKey, updateField); + const { onClick } = typeRowHooks({ + answers, + correctAnswerCount, + typeKey, + updateField, + updateAnswer, + }); return ( <> @@ -25,10 +34,19 @@ export const TypeRow = ({ }; TypeRow.propTypes = { + answers: PropTypes.arrayOf(PropTypes.shape({ + correct: PropTypes.bool, + id: PropTypes.string, + selectedFeedback: PropTypes.string, + title: PropTypes.string, + unselectedFeedback: PropTypes.string, + })).isRequired, + correctAnswerCount: PropTypes.number.isRequired, typeKey: PropTypes.string.isRequired, label: PropTypes.string.isRequired, selected: PropTypes.bool.isRequired, lastRow: PropTypes.bool.isRequired, + updateAnswer: PropTypes.func.isRequired, updateField: PropTypes.func.isRequired, }; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx index 72c4579e8..2065e57c0 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/TypeRow.test.jsx @@ -10,11 +10,14 @@ jest.mock('../hooks', () => ({ describe('TypeRow', () => { const typeKey = 'TEXTINPUT'; const props = { + answers: [], + correctAnswerCount: 0, typeKey, label: 'Text Input Problem', selected: true, lastRow: false, updateField: jest.fn().mockName('args.updateField'), + updateAnswer: jest.fn().mockName('args.updateAnswer'), }; const typeRowHooksProps = { @@ -26,7 +29,13 @@ describe('TypeRow', () => { describe('behavior', () => { it(' calls typeRowHooks when initialized', () => { shallow(); - expect(typeRowHooks).toHaveBeenCalledWith(typeKey, props.updateField); + expect(typeRowHooks).toHaveBeenCalledWith({ + answers: props.answers, + correctAnswerCount: props.correctAnswerCount, + typeKey, + updateField: props.updateField, + updateAnswer: props.updateAnswer, + }); }); }); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintRow.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintRow.test.jsx.snap index ea0adb253..a106c71a8 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintRow.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintRow.test.jsx.snap @@ -5,7 +5,7 @@ exports[`HintRow snapshot snapshot: renders hints row 1`] = ` fluid={true} > - @@ -15,8 +15,8 @@ exports[`HintRow snapshot snapshot: renders hints row 1`] = ` value="hint_1" /> - - + - + `; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap index f25b722aa..2863895dd 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/HintsCard.test.jsx.snap @@ -20,7 +20,7 @@ exports[`HintsCard snapshot snapshot: renders hints setting card multiple hints value="" /> + } + footerAction={null} + isOpen={false} + size="md" + title={ + + } + > + + + +
+`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap index 251289f10..9daac71fe 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap @@ -2,55 +2,62 @@ exports[`TypeCard snapshot snapshot: renders type setting card 1`] = ` - diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap new file mode 100644 index 000000000..f5b33aaa9 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/__snapshots__/index.test.jsx.snap @@ -0,0 +1,64 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EditorProblemView component renders raw editor 1`] = ` + + + + + + + + + + + + +`; + +exports[`EditorProblemView component renders simple view 1`] = ` + + + + + + + + + + + + + +`; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/hooks.js b/src/editors/containers/ProblemEditor/components/EditProblemView/hooks.js new file mode 100644 index 000000000..80298bc56 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/hooks.js @@ -0,0 +1,14 @@ +import ReactStateSettingsParser from '../../data/ReactStateSettingsParser'; +import ReactStateOLXParser from '../../data/ReactStateOLXParser'; + +// eslint-disable-next-line import/prefer-default-export +export const parseState = (problem, isAdvanced, ref) => () => { + const reactSettingsParser = new ReactStateSettingsParser(problem); + const reactOLXParser = new ReactStateOLXParser({ problem }); + const rawOLX = ref?.current?.state.doc.toString(); + + return { + settings: reactSettingsParser.getSettings(), + olx: isAdvanced ? rawOLX : reactOLXParser.buildOLX(), + }; +}; diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/hooks.test.js b/src/editors/containers/ProblemEditor/components/EditProblemView/hooks.test.js new file mode 100644 index 000000000..9cfc8a42f --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/hooks.test.js @@ -0,0 +1,25 @@ +import * as hooks from './hooks'; + +const mockRawOLX = 'rawOLX'; +const mockBuiltOLX = 'builtOLX'; + +jest.mock('../../data/ReactStateOLXParser', () => ( + jest.fn().mockImplementation(() => ({ + buildOLX: () => mockBuiltOLX, + })) +)); +jest.mock('../../data/ReactStateSettingsParser'); + +describe('EditProblemView hooks parseState', () => { + const toStringMock = () => mockRawOLX; + const refMock = { current: { state: { doc: { toString: toStringMock } } } }; + + test('default problem', () => { + const res = hooks.parseState('problem', false, refMock)(); + expect(res.olx).toBe(mockBuiltOLX); + }); + test('advanced problem', () => { + const res = hooks.parseState('problem', true, refMock)(); + expect(res.olx).toBe(mockRawOLX); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx index 5600f9e3a..f43ddd1d2 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useRef } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; @@ -6,34 +6,35 @@ import { Col, Container, Row } from '@edx/paragon'; import AnswerWidget from './AnswerWidget'; import SettingsWidget from './SettingsWidget'; import QuestionWidget from './QuestionWidget'; -import { EditorContainer } from '../../../EditorContainer'; +import EditorContainer from '../../../EditorContainer'; import { selectors } from '../../../../data/redux'; -import ReactStateSettingsParser from '../../data/ReactStateSettingsParser'; -import ReactStateOLXParser from '../../data/ReactStateOLXParser'; -import { AdvanceProblemKeys } from '../../../../data/constants/problem'; +import RawEditor from '../../../../sharedComponents/RawEditor'; +import { ProblemTypeKeys } from '../../../../data/constants/problem'; + +import { parseState } from './hooks'; export const EditProblemView = ({ problemType, problemState, }) => { - const parseState = (problem) => () => { - const reactSettingsParser = new ReactStateSettingsParser(problem); - const reactOLXParser = new ReactStateOLXParser({ problem }); - return { - settings: reactSettingsParser.getSettings(), - olx: reactOLXParser.buildOLX(), - }; - }; - if (Object.values(AdvanceProblemKeys).includes(problemType)) { - return `hello raw editor with ${problemType}`; - } + const editorRef = useRef(null); + const isAdvancedProblemType = problemType === ProblemTypeKeys.ADVANCED; + + const getContent = parseState(problemState, isAdvancedProblemType, editorRef); + return ( - - + + - - + {isAdvancedProblemType ? ( + + ) : ( + <> + + + + )} diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx new file mode 100644 index 000000000..05e934a07 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/index.test.jsx @@ -0,0 +1,20 @@ +import { shallow } from 'enzyme'; +import { EditProblemView } from '.'; +import AnswerWidget from './AnswerWidget'; +import { ProblemTypeKeys } from '../../../../data/constants/problem'; +import RawEditor from '../../../../sharedComponents/RawEditor'; + +describe('EditorProblemView component', () => { + test('renders simple view', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.find(AnswerWidget).length).toBe(1); + }); + + test('renders raw editor', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.find(AnswerWidget).length).toBe(0); + expect(wrapper.find(RawEditor).length).toBe(1); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx index e7f279fe7..1d0e8f870 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx @@ -17,12 +17,12 @@ export const SelectTypeFooter = ({ onCancel, selected, // redux - setProblemType, updateField, + setBlockTitle, // injected, intl, }) => ( -
+
@@ -35,7 +35,7 @@ export const SelectTypeFooter = ({ - + ); }; ProblemTypeSelect.propTypes = { diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap index 040a7ca10..971ee0749 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap @@ -1,11 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default props 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -80,7 +82,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default } placement="right" > -
+
Not supported
@@ -133,53 +137,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -217,7 +181,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default } placement="right" > -
+
Not supported
@@ -270,22 +236,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is circuitschematic 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -360,7 +340,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -413,53 +395,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -497,7 +439,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -550,22 +494,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is customgrader 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -640,7 +598,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -693,53 +653,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -777,7 +697,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -830,22 +752,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is drag_and_drop 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -920,7 +856,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -973,53 +911,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -1057,7 +955,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1110,22 +1010,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is formularesponse 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -1200,7 +1114,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1253,53 +1169,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -1337,7 +1213,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1390,22 +1268,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is imageresponse 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -1480,7 +1372,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1533,53 +1427,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -1617,7 +1471,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1670,22 +1526,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is jsinput_response 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -1760,7 +1630,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1813,53 +1685,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -1897,7 +1729,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -1950,22 +1784,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is problem_with_hint 1`] = ` -
- Blank advance problem + Blank advanced problem @@ -2040,7 +1888,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -2093,53 +1943,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Provisional
- - - Drag and drop (deprecated version) - - - -
- {supportStatus, select, - Provisional {Provisionally supported tools might lack the robustness of functionality - that your courses require. edX does not have control over the quality of the software, - or of the content that can be provided using these tools. - - - - Test these tools thoroughly before using them in your course, especially in graded - sections. Complete documentstion might not be available for provisionally supported - tools, or documentation might be available from sources other than edX.} - Not_supported {Tools with no support are not maintained by edX, and might be deprecated - in the future. They are not recommened for use in courses due to non-compliance with one - or more of the base requirements, such as testing, accessibility, internationalization, - and documentation.} - other { } - } -
- - } - placement="right" - > -
- Not supported -
-
-
@@ -2177,7 +1987,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
@@ -2230,12 +2042,24 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem } placement="right" > -
+
Not supported
-
+ + + + `; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap index 8dd2e23bf..9cc84af14 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap @@ -3,13 +3,19 @@ exports[`Preview snapshots snapshots: renders as expected with default props 1`] = `""`; exports[`Preview snapshots snapshots: renders as expected with problemType is choiceresponse 1`] = ` -
- Multi Select Problem + Multi-select problem
A preview illustration of a {problemType, select,
@@ -34,22 +40,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is ch
     target= -
+ `; exports[`Preview snapshots snapshots: renders as expected with problemType is multiplechoiceresponse 1`] = ` -
- Single Select Problem + Single select problem
A preview illustration of a {problemType, select,
@@ -74,22 +86,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is mu
     target= -
+ `; exports[`Preview snapshots snapshots: renders as expected with problemType is numericalresponse 1`] = ` -
- Numeric Response Problem + Numerical input problem
A preview illustration of a {problemType, select,
@@ -114,22 +132,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is nu
     target= -
+ `; exports[`Preview snapshots snapshots: renders as expected with problemType is optionresponse 1`] = ` -
- Dropdown Problem + Dropdown problem
A preview illustration of a {problemType, select,
@@ -154,22 +178,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is op
     target= -
+ `; exports[`Preview snapshots snapshots: renders as expected with problemType is stringresponse 1`] = ` -
- Text Input Problem + Text input problem
A preview illustration of a {problemType, select,
@@ -194,10 +224,10 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is st
     target= -
+ `; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap index bf2f8389e..775965cf3 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap @@ -1,7 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` - + - Single Select Problem + Single select - Multi Select Problem + Multi-select - Dropdown Problem + Dropdown - Numeric Response Problem + Numerical input - Text Input Problem + Text input - + `; exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` - + - Single Select Problem + Single select - Multi Select Problem + Multi-select - Dropdown Problem + Dropdown - Numeric Response Problem + Numerical input - Text Input Problem + Text input - + `; exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` - + - Single Select Problem + Single select - Multi Select Problem + Multi-select - Dropdown Problem + Dropdown - Numeric Response Problem + Numerical input - Text Input Problem + Text input - + `; exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` - + - Single Select Problem + Single select - Multi Select Problem + Multi-select - Dropdown Problem + Dropdown - Numeric Response Problem + Numerical input - Text Input Problem + Text input - + `; exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` - + - Single Select Problem + Single select - Multi Select Problem + Multi-select - Dropdown Problem + Dropdown - Numeric Response Problem + Numerical input - Text Input Problem + Text input - + `; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js index dae097bb7..9d220f1a1 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js @@ -1,7 +1,7 @@ export const messages = { advanceProblemButtonLabel: { id: 'authoring.problemEditor.problemSelect.advanceButton.label', - defaultMessage: 'Advance problem types', + defaultMessage: 'Advanced problem types', description: 'Button label for advance problem types option', }, advanceMenuTitle: { @@ -39,7 +39,7 @@ export const messages = { }, previewTitle: { id: 'authoring.problemEditor.preview.title', - defaultMessage: '{previewTitle}', + defaultMessage: '{previewTitle} problem', description: 'Title for the problem preview column', }, previewAltText: { @@ -61,8 +61,13 @@ export const messages = { }, learnMoreButtonLabel: { id: 'authoring.problemEditor.learnMoreButtonLabel.label', - defaultMessage: 'Learn More', - description: 'Label for Learn More button', + defaultMessage: 'Learn more', + description: 'Label for Learn more button', + }, + learnMoreAdvancedButtonLabel: { + id: 'authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label', + defaultMessage: 'Learn more about advanced problem types', + description: 'Label for Learn more about advanced problem types button', }, }; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js index f1dace285..f6cf10143 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js @@ -4,6 +4,7 @@ import { } from '../../../../data/constants/problem'; import { StrictDict } from '../../../../utils'; import * as module from './hooks'; +import { getDataFromOlx } from '../../../../data/redux/thunkActions/problem'; export const state = StrictDict({ selected: (val) => useState(val), @@ -17,11 +18,16 @@ export const selectHooks = () => { }; }; -export const onSelect = (setProblemType, selected, updateField) => () => { +export const onSelect = ({ selected, updateField, setBlockTitle }) => () => { if (Object.values(AdvanceProblemKeys).includes(selected)) { - updateField({ rawOLX: AdvanceProblems[selected].template }); + updateField({ problemType: ProblemTypeKeys.ADVANCED, rawOLX: AdvanceProblems[selected].template }); + setBlockTitle(AdvanceProblems[selected].title); + } else { + const newOLX = ProblemTypes[selected].template; + const { settings, ...newState } = getDataFromOlx({ rawOLX: newOLX, rawSettings: {} }); + updateField({ ...newState }); + setBlockTitle(ProblemTypes[selected].title); } - setProblemType({ selected }); }; export const useArrowNav = (selected, setSelected) => { diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js index 50829221e..b44cc4eef 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js @@ -2,7 +2,8 @@ import React from 'react'; import { MockUseState } from '../../../../../testUtils'; import * as module from './hooks'; -import { AdvanceProblems, ProblemTypeKeys } from '../../../../data/constants/problem'; +import { AdvanceProblems, ProblemTypeKeys, ProblemTypes } from '../../../../data/constants/problem'; +import { OLXParser } from '../../data/OLXParser'; jest.mock('react', () => ({ ...jest.requireActual('react'), @@ -11,11 +12,11 @@ jest.mock('react', () => ({ })); const state = new MockUseState(module); -const mockSetProblemType = jest.fn().mockName('setProblemType'); const mockUpdateField = jest.fn().mockName('updateField'); -const mockSelected = 'vAl'; -const mockAdvancedSelected = 'blankadvanced'; +const mockSelected = 'multiplechoiceresponse'; +const mockAdvancedSelected = 'circuitschematic'; const mockSetSelected = jest.fn().mockName('setSelected'); +const mocksetBlockTitle = jest.fn().mockName('setBlockTitle'); let hook; @@ -45,14 +46,26 @@ describe('SelectTypeModal hooks', () => { describe('onSelect', () => { test('updateField is called with selected templated if selected is an Advanced Problem', () => { - module.onSelect(mockSetProblemType, mockAdvancedSelected, mockUpdateField)(); + module.onSelect({ + selected: mockAdvancedSelected, + updateField: mockUpdateField, + setBlockTitle: mocksetBlockTitle, + })(); expect(mockUpdateField).toHaveBeenCalledWith({ + problemType: ProblemTypeKeys.ADVANCED, rawOLX: AdvanceProblems[mockAdvancedSelected].template, }); + expect(mocksetBlockTitle).toHaveBeenCalledWith(AdvanceProblems[mockAdvancedSelected].title); }); - test('setProblemType is called with selected', () => { - module.onSelect(mockSetProblemType, mockSelected, mockUpdateField)(); - expect(mockSetProblemType).toHaveBeenCalledWith({ selected: mockSelected }); + test('updateField is called with selected on visual propblems', () => { + module.onSelect({ selected: mockSelected, updateField: mockUpdateField, setBlockTitle: mocksetBlockTitle })(); + const testOlXParser = new OLXParser(ProblemTypes[mockSelected].template); + const { settings, ...testState } = testOlXParser.getParsedOLXData(); + expect(mockUpdateField).toHaveBeenCalledWith({ + ...testState, + rawOLX: ProblemTypes[mockSelected].template, + }); + expect(mocksetBlockTitle).toHaveBeenCalledWith(ProblemTypes[mockSelected].title); }); }); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx index 49d2ca7b7..0c02e0647 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Col, Row } from '@edx/paragon'; +import { Row, Stack } from '@edx/paragon'; import ProblemTypeSelect from './content/ProblemTypeSelect'; import Preview from './content/Preview'; import AdvanceTypeSelect from './content/AdvanceTypeSelect'; @@ -17,16 +17,12 @@ export const SelectTypeModal = ({ return ( - + {(!Object.values(AdvanceProblemKeys).includes(selected)) ? ( - <> - - - - - - - + + + + ) : } diff --git a/src/editors/containers/ProblemEditor/data/OLXParser.js b/src/editors/containers/ProblemEditor/data/OLXParser.js index 18126a039..865a14999 100644 --- a/src/editors/containers/ProblemEditor/data/OLXParser.js +++ b/src/editors/containers/ProblemEditor/data/OLXParser.js @@ -280,7 +280,7 @@ export class OLXParser { the parsed OLX. */ const tagMap = { - label: 'bold', + label: 'strong', description: 'em', }; @@ -331,10 +331,16 @@ export class OLXParser { getProblemType() { const problemKeys = Object.keys(this.problem); const intersectedProblems = _.intersection(Object.values(ProblemTypeKeys), problemKeys); - if (intersectedProblems.length === 0) { - return null; + // a blank problem is a problem which contains only `` as it's olx. + // blank problems are not given types, so that a type may be selected. + if (problemKeys.length === 1 && problemKeys[0] === '#text' && this.problem[problemKeys[0]] === '') { + return null; + } + // if we have no matching problem type, the problem is advanced. + return ProblemTypeKeys.ADVANCED; } + // make sure compound problems are treated as advanced if (intersectedProblems.length > 1) { return ProblemTypeKeys.ADVANCED; } @@ -369,7 +375,10 @@ export class OLXParser { answersObject = this.parseMultipleChoiceAnswers(ProblemTypeKeys.SINGLESELECT, 'choicegroup', 'choice'); break; case ProblemTypeKeys.ADVANCED: - break; + return { + problemType, + settings: {}, + }; default: // if problem is unset, return null return {}; diff --git a/src/editors/containers/ProblemEditor/data/OLXParser.test.js b/src/editors/containers/ProblemEditor/data/OLXParser.test.js index 3ae946638..5823e4b6e 100644 --- a/src/editors/containers/ProblemEditor/data/OLXParser.test.js +++ b/src/editors/containers/ProblemEditor/data/OLXParser.test.js @@ -7,6 +7,8 @@ import { textInputWithFeedbackAndHintsOLX, mutlipleChoiceWithFeedbackAndHintsOLX, textInputWithFeedbackAndHintsOLXWithMultipleAnswers, + advancedProblemOlX, + blankProblemOLX, } from './mockData/olxTestData'; import { ProblemTypeKeys } from '../../../data/constants/problem'; @@ -36,6 +38,16 @@ describe('Check OLXParser problem type', () => { const problemType = olxparser.getProblemType(); expect(problemType).toBe(ProblemTypeKeys.TEXTINPUT); }); + test('Test Advanced Problem Type', () => { + const olxparser = new OLXParser(advancedProblemOlX.rawOLX); + const problemType = olxparser.getProblemType(); + expect(problemType).toBe(ProblemTypeKeys.ADVANCED); + }); + test('Test Blank Problem Type', () => { + const olxparser = new OLXParser(blankProblemOLX.rawOLX); + const problemType = olxparser.getProblemType(); + expect(problemType).toBe(null); + }); }); describe('Check OLXParser hints', () => { diff --git a/src/editors/containers/ProblemEditor/data/SettingsParser.js b/src/editors/containers/ProblemEditor/data/SettingsParser.js index 8c038efe7..1de0708a0 100644 --- a/src/editors/containers/ProblemEditor/data/SettingsParser.js +++ b/src/editors/containers/ProblemEditor/data/SettingsParser.js @@ -16,10 +16,7 @@ export const parseScoringSettings = (metadata) => { let attempts = popuplateItem({}, 'max_attempts', 'number', metadata); if (!_.isEmpty(attempts)) { - let unlimited = true; - if (attempts.number > 0) { - unlimited = false; - } + const unlimited = _.isNaN(attempts.number); attempts = { ...attempts, unlimited }; scoring = { ...scoring, attempts }; } diff --git a/src/editors/containers/ProblemEditor/data/SettingsParser.test.js b/src/editors/containers/ProblemEditor/data/SettingsParser.test.js index cf3ddc763..871262aa7 100644 --- a/src/editors/containers/ProblemEditor/data/SettingsParser.test.js +++ b/src/editors/containers/ProblemEditor/data/SettingsParser.test.js @@ -4,7 +4,7 @@ import { dropdownWithFeedbackHints, numericWithHints, textInputWithHints, - sigleSelectWithHints, + singleSelectWithHints, } from './mockData/problemTestData'; describe('Test Settings to State Parser', () => { @@ -38,7 +38,7 @@ describe('Test Settings to State Parser', () => { }); test('Test score settings missing', () => { - const settings = parseSettings(sigleSelectWithHints.metadata); + const settings = parseSettings(singleSelectWithHints.metadata); expect(settings.scoring).toBeUndefined(); }); diff --git a/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js b/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js index cc9e2de9d..187ce6514 100644 --- a/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js +++ b/src/editors/containers/ProblemEditor/data/mockData/olxTestData.js @@ -82,11 +82,11 @@ export const checkboxesOLXWithFeedbackAndHintsOLX = { }, ], }, - question: '

You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.

Add the question text, or prompt, here. This text is required.You can add an optional tip or note related to the prompt like this.', + question: '

You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.

Add the question text, or prompt, here. This text is required.You can add an optional tip or note related to the prompt like this.', buildOLX: `

You can use this template as a guide to the simple editor markdown and OLX markup to use for checkboxes with hints and feedback problems. Edit this component to replace this template with your own assessment.

- Add the question text, or prompt, here. This text is required. + Add the question text, or prompt, here. This text is required. You can add an optional tip or note related to the prompt like this. @@ -160,11 +160,11 @@ export const dropdownOLXWithFeedbackAndHintsOLX = { }, ], }, - question: '

You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown with hints and feedback problems. Edit this component to replace this template with your own assessment.

Add the question text, or prompt, here. This text is required.You can add an optional tip or note related to the prompt like this.', + question: '

You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown with hints and feedback problems. Edit this component to replace this template with your own assessment.

Add the question text, or prompt, here. This text is required.You can add an optional tip or note related to the prompt like this.', buildOLX: `

You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown with hints and feedback problems. Edit this component to replace this template with your own assessment.

- Add the question text, or prompt, here. This text is required. + Add the question text, or prompt, here. This text is required. You can add an optional tip or note related to the prompt like this.