This PR aims to fix the commit mistakes I made when trying to merge with a refactored fork. This will keep the changes I made in the refactor.
This commit is contained in:
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
136
docs/decisions/0005-internal-editor-testability-decisions.md
Normal file
136
docs/decisions/0005-internal-editor-testability-decisions.md
Normal file
@@ -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(<MyElement {...props} />)).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');
|
||||
```
|
||||
1836
package-lock.json
generated
1836
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -30,7 +30,7 @@ export const Editor = ({
|
||||
|
||||
const EditorComponent = supportedEditors[blockType];
|
||||
return (
|
||||
<div className="d-flex flex-column vh-100">
|
||||
<div className="d-flex flex-column">
|
||||
<div
|
||||
className="pgn__modal-fullscreen"
|
||||
role="dialog"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`Editor render presents error message if no relevant editor found and ref ready 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column vh-100"
|
||||
className="d-flex flex-column"
|
||||
>
|
||||
<div
|
||||
aria-label="fAkEBlock"
|
||||
@@ -20,7 +20,7 @@ exports[`Editor render presents error message if no relevant editor found and re
|
||||
|
||||
exports[`Editor render snapshot: renders correct editor given blockType (html -> TextEditor) 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column vh-100"
|
||||
className="d-flex flex-column"
|
||||
>
|
||||
<div
|
||||
aria-label="html"
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`EditorContainer component render snapshot: initialized. enable save and pass to header 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="position-relative zindex-0"
|
||||
>
|
||||
<BaseModal
|
||||
close={[MockFunction closeCancelConfirmModal]}
|
||||
confirmAction={
|
||||
<Button
|
||||
onClick={
|
||||
Object {
|
||||
"handleCancel": Object {
|
||||
"onClose": [MockFunction props.onClose],
|
||||
},
|
||||
}
|
||||
}
|
||||
variant="primary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="OK"
|
||||
description="Label for OK button"
|
||||
id="authoring.editorContainer.okButton.label"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
isOpen={false}
|
||||
size="md"
|
||||
title="Exit the editor?"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to exit the editor? Any unsaved changes will be lost."
|
||||
description="Description text for modal confirming cancellation"
|
||||
id="authoring.editorContainer.cancelConfirm.description"
|
||||
/>
|
||||
</BaseModal>
|
||||
<ModalDialog.Header
|
||||
className="shadow-sm zindex-10"
|
||||
>
|
||||
@@ -23,30 +56,22 @@ exports[`EditorContainer component render snapshot: initialized. enable save and
|
||||
>
|
||||
<IconButton
|
||||
iconAs="Icon"
|
||||
onClick={
|
||||
Object {
|
||||
"handleCancelClicked": Object {
|
||||
"onClose": [MockFunction props.onClose],
|
||||
},
|
||||
}
|
||||
}
|
||||
onClick={[MockFunction openCancelConfirmModal]}
|
||||
src={[MockFunction icons.Close]}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog.Title>
|
||||
</ModalDialog.Header>
|
||||
<h1>
|
||||
My test content
|
||||
</h1>
|
||||
<ModalDialog.Body
|
||||
className="pb-6"
|
||||
>
|
||||
<h1>
|
||||
My test content
|
||||
</h1>
|
||||
</ModalDialog.Body>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
disableSave={false}
|
||||
onCancel={
|
||||
Object {
|
||||
"handleCancelClicked": Object {
|
||||
"onClose": [MockFunction props.onClose],
|
||||
},
|
||||
}
|
||||
}
|
||||
onCancel={[MockFunction openCancelConfirmModal]}
|
||||
onSave={
|
||||
Object {
|
||||
"handleSaveClicked": Object {
|
||||
@@ -61,7 +86,40 @@ exports[`EditorContainer component render snapshot: initialized. enable save and
|
||||
`;
|
||||
|
||||
exports[`EditorContainer component render snapshot: not initialized. disable save and pass to header 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="position-relative zindex-0"
|
||||
>
|
||||
<BaseModal
|
||||
close={[MockFunction closeCancelConfirmModal]}
|
||||
confirmAction={
|
||||
<Button
|
||||
onClick={
|
||||
Object {
|
||||
"handleCancel": Object {
|
||||
"onClose": [MockFunction props.onClose],
|
||||
},
|
||||
}
|
||||
}
|
||||
variant="primary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="OK"
|
||||
description="Label for OK button"
|
||||
id="authoring.editorContainer.okButton.label"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
isOpen={false}
|
||||
size="md"
|
||||
title="Exit the editor?"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to exit the editor? Any unsaved changes will be lost."
|
||||
description="Description text for modal confirming cancellation"
|
||||
id="authoring.editorContainer.cancelConfirm.description"
|
||||
/>
|
||||
</BaseModal>
|
||||
<ModalDialog.Header
|
||||
className="shadow-sm zindex-10"
|
||||
>
|
||||
@@ -83,27 +141,18 @@ exports[`EditorContainer component render snapshot: not initialized. disable sav
|
||||
>
|
||||
<IconButton
|
||||
iconAs="Icon"
|
||||
onClick={
|
||||
Object {
|
||||
"handleCancelClicked": Object {
|
||||
"onClose": [MockFunction props.onClose],
|
||||
},
|
||||
}
|
||||
}
|
||||
onClick={[MockFunction openCancelConfirmModal]}
|
||||
src={[MockFunction icons.Close]}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog.Title>
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body
|
||||
className="pb-6"
|
||||
/>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
disableSave={true}
|
||||
onCancel={
|
||||
Object {
|
||||
"handleCancelClicked": Object {
|
||||
"onClose": [MockFunction props.onClose],
|
||||
},
|
||||
}
|
||||
}
|
||||
onCancel={[MockFunction openCancelConfirmModal]}
|
||||
onSave={
|
||||
Object {
|
||||
"handleSaveClicked": Object {
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
|
||||
exports[`EditorFooter render snapshot: default args (disableSave: false, saveFailed: false) 1`] = `
|
||||
<div
|
||||
className="editor-footer"
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"position": "sticky",
|
||||
}
|
||||
}
|
||||
className="editor-footer fixed-bottom"
|
||||
>
|
||||
<ModalDialog.Footer
|
||||
className="shadow-sm"
|
||||
@@ -44,13 +38,7 @@ exports[`EditorFooter render snapshot: default args (disableSave: false, saveFai
|
||||
|
||||
exports[`EditorFooter render snapshot: save disabled. Show button spinner 1`] = `
|
||||
<div
|
||||
className="editor-footer"
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"position": "sticky",
|
||||
}
|
||||
}
|
||||
className="editor-footer fixed-bottom"
|
||||
>
|
||||
<ModalDialog.Footer
|
||||
className="shadow-sm"
|
||||
@@ -85,13 +73,7 @@ exports[`EditorFooter render snapshot: save disabled. Show button spinner 1`] =
|
||||
|
||||
exports[`EditorFooter render snapshot: save failed. Show error message 1`] = `
|
||||
<div
|
||||
className="editor-footer"
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"position": "sticky",
|
||||
}
|
||||
}
|
||||
className="editor-footer fixed-bottom"
|
||||
>
|
||||
<Toast
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
|
||||
@@ -21,7 +21,7 @@ export const EditorFooter = ({
|
||||
// injected
|
||||
intl,
|
||||
}) => (
|
||||
<div className="editor-footer" style={{ position: 'sticky', bottom: 0 }}>
|
||||
<div className="editor-footer fixed-bottom">
|
||||
{saveFailed && (
|
||||
<Toast show onClose={nullMethod}>
|
||||
<FormattedMessage {...messages.contentSaveFailed} />
|
||||
|
||||
@@ -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 })
|
||||
));
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<div>
|
||||
<div
|
||||
className="position-relative zindex-0"
|
||||
>
|
||||
<BaseModal
|
||||
size="md"
|
||||
confirmAction={(
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleCancel}
|
||||
>
|
||||
<FormattedMessage {...messages.okButtonLabel} />
|
||||
</Button>
|
||||
)}
|
||||
isOpen={isCancelConfirmOpen}
|
||||
close={closeCancelConfirmModal}
|
||||
title={intl.formatMessage(messages.cancelConfirmTitle)}
|
||||
>
|
||||
<FormattedMessage {...messages.cancelConfirmDescription} />
|
||||
</BaseModal>
|
||||
<ModalDialog.Header className="shadow-sm zindex-10">
|
||||
<ModalDialog.Title>
|
||||
<div
|
||||
@@ -31,14 +57,16 @@ export const EditorContainer = ({
|
||||
<IconButton
|
||||
src={Close}
|
||||
iconAs={Icon}
|
||||
onClick={handleCancelClicked}
|
||||
onClick={openCancelConfirmModal}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog.Title>
|
||||
</ModalDialog.Header>
|
||||
{isInitialized && children}
|
||||
<ModalDialog.Body className="pb-6">
|
||||
{isInitialized && children}
|
||||
</ModalDialog.Body>
|
||||
<EditorFooter
|
||||
onCancel={handleCancelClicked}
|
||||
onCancel={openCancelConfirmModal}
|
||||
onSave={hooks.handleSaveClicked({ dispatch, getContent, validateEntry })}
|
||||
disableSave={!isInitialized}
|
||||
saveFailed={hooks.saveFailed()}
|
||||
@@ -55,6 +83,8 @@ EditorContainer.propTypes = {
|
||||
getContent: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func,
|
||||
validateEntry: PropTypes.func,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default EditorContainer;
|
||||
export default injectIntl(EditorContainer);
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
import { IconButton } from '@edx/paragon';
|
||||
import { shallow } from 'enzyme';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { EditorContainer } from '.';
|
||||
import * as hooks from './hooks';
|
||||
import { formatMessage } from '../../../testUtils';
|
||||
|
||||
const props = {
|
||||
getContent: jest.fn().mockName('props.getContent'),
|
||||
onClose: jest.fn().mockName('props.onClose'),
|
||||
validateEntry: jest.fn().mockName('props.validateEntry'),
|
||||
// inject
|
||||
intl: { formatMessage },
|
||||
};
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
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(<EditorContainer {...props}>{testContent}</EditorContainer>);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
19
src/editors/containers/EditorContainer/messages.js
Normal file
19
src/editors/containers/EditorContainer/messages.js
Normal file
@@ -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;
|
||||
@@ -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 (
|
||||
<CheckerType
|
||||
className="pl-4 mt-3"
|
||||
value={answer.id}
|
||||
onChange={(e) => setAnswer({ correct: e.target.checked })}
|
||||
checked={answer.correct}
|
||||
>
|
||||
{answer.id}
|
||||
</CheckerType>
|
||||
);
|
||||
};
|
||||
|
||||
const FeedbackControl = ({
|
||||
feedback, onChange, labelMessage, labelMessageBoldUnderline, key, answer, intl,
|
||||
}) => (
|
||||
<Form.Group key={key}>
|
||||
<Form.Label className="mb-3">
|
||||
<FormattedMessage
|
||||
{...labelMessage}
|
||||
values={{
|
||||
answerId: answer.id,
|
||||
boldunderline: <b><u><FormattedMessage {...labelMessageBoldUnderline} /></u></b>,
|
||||
}}
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Control
|
||||
placeholder={intl.formatMessage(messages.feedbackPlaceholder)}
|
||||
value={feedback}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</Form.Group>
|
||||
);
|
||||
|
||||
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 (
|
||||
<Collapsible.Advanced
|
||||
open={isFeedbackVisible}
|
||||
onToggle={toggleFeedback}
|
||||
className="collapsible-card"
|
||||
className="answer-option d-flex flex-row justify-content-between flex-nowrap pb-2 pt-2"
|
||||
>
|
||||
<Row className="my-2">
|
||||
|
||||
<Col xs={1}>
|
||||
<Checker
|
||||
hasSingleAnswer={hasSingleAnswer}
|
||||
<div className="answer-option-flex-item-1 mr-1 d-flex">
|
||||
<Checker
|
||||
hasSingleAnswer={hasSingleAnswer}
|
||||
answer={answer}
|
||||
setAnswer={setAnswer}
|
||||
/>
|
||||
</div>
|
||||
<div className="answer-option-flex-item-2 ml-1">
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
className="answer-option-textarea text-gray-500 small"
|
||||
autoResize
|
||||
rows={1}
|
||||
value={answer.title}
|
||||
onChange={(e) => { setAnswer({ title: e.target.value }); }}
|
||||
placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)}
|
||||
/>
|
||||
<Collapsible.Body>
|
||||
<FeedbackBox
|
||||
problemType={problemType}
|
||||
answer={answer}
|
||||
setAnswer={setAnswer}
|
||||
intl={intl}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col xs={10}>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
rows={1}
|
||||
value={answer.title}
|
||||
onChange={(e) => { setAnswer({ title: e.target.value }); }}
|
||||
placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)}
|
||||
/>
|
||||
|
||||
<Collapsible.Body>
|
||||
<div className="bg-dark-100 p-4 mt-3">
|
||||
{displayFeedbackControl(answer)}
|
||||
</div>
|
||||
</Collapsible.Body>
|
||||
</Col>
|
||||
|
||||
<Col xs={1} className="d-inline-flex mt-1">
|
||||
<Collapsible.Trigger>
|
||||
<IconButton
|
||||
src={AddComment}
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(messages.feedbackToggleIconAltText)}
|
||||
variant="primary"
|
||||
/>
|
||||
</Collapsible.Trigger>
|
||||
</Collapsible.Body>
|
||||
</div>
|
||||
<div className="answer-option-flex-item-3 d-flex flex-row flex-nowrap">
|
||||
<Collapsible.Trigger>
|
||||
<IconButton
|
||||
src={Delete}
|
||||
src={FeedbackOutline}
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(messages.answerDeleteIconAltText)}
|
||||
onClick={removeAnswer}
|
||||
alt={intl.formatMessage(messages.feedbackToggleIconAltText)}
|
||||
variant="primary"
|
||||
/>
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
</Collapsible.Trigger>
|
||||
<IconButton
|
||||
src={DeleteOutline}
|
||||
iconAs={Icon}
|
||||
alt={intl.formatMessage(messages.answerDeleteIconAltText)}
|
||||
onClick={removeAnswer}
|
||||
variant="primary"
|
||||
/>
|
||||
</div>
|
||||
</Collapsible.Advanced>
|
||||
);
|
||||
};
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -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(<AnswerOption {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: renders correct option with selected unselected feedback', () => {
|
||||
expect(shallow(<AnswerOption {...props} answer={answerWithSelectedUnselectedFeedback} />)).toMatchSnapshot();
|
||||
expect(shallow(<AnswerOption {...props} problemType="choiceresponse" answer={answerWithSelectedUnselectedFeedback} />)).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));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<div>
|
||||
<div className="border border-light-700 rounded py-4 pl-4 pr-3">
|
||||
{answers.map((answer) => (
|
||||
<AnswerOption
|
||||
key={answer.id}
|
||||
@@ -29,7 +32,7 @@ export const AnswersContainer = ({
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
className="pl-0 text-primary-500"
|
||||
iconBefore={Add}
|
||||
variant="tertiary"
|
||||
onClick={addAnswer}
|
||||
@@ -44,6 +47,7 @@ AnswersContainer.propTypes = {
|
||||
problemType: PropTypes.string.isRequired,
|
||||
answers: PropTypes.arrayOf(answerOptionProps).isRequired,
|
||||
addAnswer: PropTypes.func.isRequired,
|
||||
updateField: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
@@ -52,6 +56,7 @@ export const mapStateToProps = (state) => ({
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
addAnswer: actions.problem.addAnswer,
|
||||
updateField: actions.problem.updateField,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AnswersContainer);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
|
||||
import { actions, selectors } from '../../../../../data/redux';
|
||||
|
||||
import * as module from './AnswersContainer';
|
||||
|
||||
import { AnswersContainer as AnswersContainerWithoutHOC } from './AnswersContainer';
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
FormattedMessage: ({ defaultMessage }) => (<p>{defaultMessage}</p>),
|
||||
injectIntl: (args) => args,
|
||||
intlShape: {},
|
||||
}));
|
||||
|
||||
jest.mock('./AnswerOption', () => () => <div>MockAnswerOption</div>);
|
||||
|
||||
jest.mock('../../../../../data/redux', () => ({
|
||||
actions: {
|
||||
problem: {
|
||||
updateField: jest.fn().mockName('actions.problem.updateField'),
|
||||
addAnswer: jest.fn().mockName('actions.problem.addAnswer'),
|
||||
},
|
||||
},
|
||||
selectors: {
|
||||
problem: {
|
||||
answers: jest.fn(state => ({ answers: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
describe('AnswersContainer', () => {
|
||||
const props = {
|
||||
answers: [],
|
||||
updateField: jest.fn(),
|
||||
addAnswer: jest.fn(),
|
||||
};
|
||||
describe('render', () => {
|
||||
test('snapshot: renders correct default', () => {
|
||||
act(() => {
|
||||
expect(shallow(<module.AnswersContainer {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
test('snapshot: renders correctly with answers', () => {
|
||||
act(() => {
|
||||
expect(shallow(
|
||||
<module.AnswersContainer
|
||||
{...props}
|
||||
answers={[{ id: 'a', title: 'sOMetITlE', correct: true }, { id: 'b', title: 'sOMetITlE', correct: true }]}
|
||||
/>,
|
||||
)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('with react-testing-library', async () => {
|
||||
let container = null;
|
||||
await act(async () => {
|
||||
const wrapper = render(
|
||||
<AnswersContainerWithoutHOC
|
||||
{...props}
|
||||
answers={[{ id: 'a', title: 'sOMetITlE', correct: true }, { id: 'b', title: 'sOMetITlE', correct: true }]}
|
||||
/>,
|
||||
);
|
||||
container = wrapper.container;
|
||||
});
|
||||
|
||||
await waitFor(() => expect(container.querySelector('button')).toBeTruthy());
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
expect(props.updateField).toHaveBeenCalledWith(expect.objectContaining({ correctAnswerCount: 2 }));
|
||||
});
|
||||
});
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
|
||||
test('answers from problem.answers', () => {
|
||||
expect(
|
||||
module.mapStateToProps(testState).answers,
|
||||
).toEqual(selectors.problem.answers(testState));
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('updateField from actions.problem.updateField', () => {
|
||||
expect(module.mapDispatchToProps.updateField).toEqual(actions.problem.updateField);
|
||||
});
|
||||
test('updateField from actions.problem.addAnswer', () => {
|
||||
expect(module.mapDispatchToProps.addAnswer).toEqual(actions.problem.addAnswer);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,113 +2,115 @@
|
||||
|
||||
exports[`AnswerOption render snapshot: renders correct option with feedback 1`] = `
|
||||
<Advanced
|
||||
className="collapsible-card"
|
||||
className="answer-option d-flex flex-row justify-content-between flex-nowrap pb-2 pt-2"
|
||||
onToggle={[Function]}
|
||||
open={false}
|
||||
>
|
||||
<Row
|
||||
className="my-2"
|
||||
<div
|
||||
className="answer-option-flex-item-1 mr-1 d-flex"
|
||||
>
|
||||
<Component
|
||||
xs={1}
|
||||
>
|
||||
<Checker
|
||||
<Checker
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"id": "A",
|
||||
"selectedFeedback": "some feedback",
|
||||
"title": "Answer 1",
|
||||
}
|
||||
}
|
||||
hasSingleAnswer={false}
|
||||
setAnswer={[Function]}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="answer-option-flex-item-2 ml-1"
|
||||
>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
autoResize={true}
|
||||
className="answer-option-textarea text-gray-500 small"
|
||||
onChange={[Function]}
|
||||
placeholder="Enter an answer"
|
||||
rows={1}
|
||||
value="Answer 1"
|
||||
/>
|
||||
<Body>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"feedback": "some feedback",
|
||||
"id": "A",
|
||||
"selectedFeedback": "some feedback",
|
||||
"title": "Answer 1",
|
||||
}
|
||||
}
|
||||
hasSingleAnswer={false}
|
||||
intl={
|
||||
Object {
|
||||
"formatMessage": [Function],
|
||||
}
|
||||
}
|
||||
problemType="multiplechoiceresponse"
|
||||
setAnswer={[Function]}
|
||||
/>
|
||||
</Component>
|
||||
<Component
|
||||
xs={10}
|
||||
>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
onChange={[Function]}
|
||||
placeholder="Enter an answer"
|
||||
rows={1}
|
||||
value="Answer 1"
|
||||
/>
|
||||
<Body>
|
||||
<div
|
||||
className="bg-dark-100 p-4 mt-3"
|
||||
>
|
||||
<Form.Group
|
||||
key="feedback-A"
|
||||
>
|
||||
<Form.Label
|
||||
className="mb-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Show following feedback when {answerId} {boldunderline}:"
|
||||
description="Label text for feedback if option is selected"
|
||||
id="authoring.answerwidget.feedback.selected.label"
|
||||
values={
|
||||
Object {
|
||||
"answerId": "A",
|
||||
"boldunderline": <b>
|
||||
<u>
|
||||
<FormattedMessage
|
||||
defaultMessage="is selected"
|
||||
description="Bold & underlined text for feedback if option is selected"
|
||||
id="authoring.answerwidget.feedback.selected.label.boldunderline"
|
||||
/>
|
||||
</u>
|
||||
</b>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Control
|
||||
onChange={[Function]}
|
||||
placeholder="Feedback message"
|
||||
value="some feedback"
|
||||
/>
|
||||
</Form.Group>
|
||||
</div>
|
||||
</Body>
|
||||
</Component>
|
||||
<Component
|
||||
className="d-inline-flex mt-1"
|
||||
xs={1}
|
||||
>
|
||||
<Trigger>
|
||||
<IconButton
|
||||
alt="Toggle feedback"
|
||||
iconAs="Icon"
|
||||
variant="primary"
|
||||
/>
|
||||
</Trigger>
|
||||
</Body>
|
||||
</div>
|
||||
<div
|
||||
className="answer-option-flex-item-3 d-flex flex-row flex-nowrap"
|
||||
>
|
||||
<Trigger>
|
||||
<IconButton
|
||||
alt="Delete answer"
|
||||
alt="Toggle feedback"
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
variant="primary"
|
||||
/>
|
||||
</Component>
|
||||
</Row>
|
||||
</Trigger>
|
||||
<IconButton
|
||||
alt="Delete answer"
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
variant="primary"
|
||||
/>
|
||||
</div>
|
||||
</Advanced>
|
||||
`;
|
||||
|
||||
exports[`AnswerOption render snapshot: renders correct option with selected unselected feedback 1`] = `
|
||||
<Advanced
|
||||
className="collapsible-card"
|
||||
className="answer-option d-flex flex-row justify-content-between flex-nowrap pb-2 pt-2"
|
||||
onToggle={[Function]}
|
||||
open={false}
|
||||
>
|
||||
<Row
|
||||
className="my-2"
|
||||
<div
|
||||
className="answer-option-flex-item-1 mr-1 d-flex"
|
||||
>
|
||||
<Component
|
||||
xs={1}
|
||||
>
|
||||
<Checker
|
||||
<Checker
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"id": "A",
|
||||
"selectedFeedback": "selected feedback",
|
||||
"title": "Answer 1",
|
||||
"unselectedFeedback": "unselected feedback",
|
||||
}
|
||||
}
|
||||
hasSingleAnswer={false}
|
||||
setAnswer={[Function]}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="answer-option-flex-item-2 ml-1"
|
||||
>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
autoResize={true}
|
||||
className="answer-option-textarea text-gray-500 small"
|
||||
onChange={[Function]}
|
||||
placeholder="Enter an answer"
|
||||
rows={1}
|
||||
value="Answer 1"
|
||||
/>
|
||||
<Body>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
@@ -118,76 +120,32 @@ exports[`AnswerOption render snapshot: renders correct option with selected unse
|
||||
"unselectedFeedback": "unselected feedback",
|
||||
}
|
||||
}
|
||||
hasSingleAnswer={false}
|
||||
intl={
|
||||
Object {
|
||||
"formatMessage": [Function],
|
||||
}
|
||||
}
|
||||
problemType="choiceresponse"
|
||||
setAnswer={[Function]}
|
||||
/>
|
||||
</Component>
|
||||
<Component
|
||||
xs={10}
|
||||
>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
onChange={[Function]}
|
||||
placeholder="Enter an answer"
|
||||
rows={1}
|
||||
value="Answer 1"
|
||||
/>
|
||||
<Body>
|
||||
<div
|
||||
className="bg-dark-100 p-4 mt-3"
|
||||
>
|
||||
<Form.Group
|
||||
key="feedback-A"
|
||||
>
|
||||
<Form.Label
|
||||
className="mb-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Show following feedback when {answerId} {boldunderline}:"
|
||||
description="Label text for feedback if option is selected"
|
||||
id="authoring.answerwidget.feedback.selected.label"
|
||||
values={
|
||||
Object {
|
||||
"answerId": "A",
|
||||
"boldunderline": <b>
|
||||
<u>
|
||||
<FormattedMessage
|
||||
defaultMessage="is selected"
|
||||
description="Bold & underlined text for feedback if option is selected"
|
||||
id="authoring.answerwidget.feedback.selected.label.boldunderline"
|
||||
/>
|
||||
</u>
|
||||
</b>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Control
|
||||
onChange={[Function]}
|
||||
placeholder="Feedback message"
|
||||
/>
|
||||
</Form.Group>
|
||||
</div>
|
||||
</Body>
|
||||
</Component>
|
||||
<Component
|
||||
className="d-inline-flex mt-1"
|
||||
xs={1}
|
||||
>
|
||||
<Trigger>
|
||||
<IconButton
|
||||
alt="Toggle feedback"
|
||||
iconAs="Icon"
|
||||
variant="primary"
|
||||
/>
|
||||
</Trigger>
|
||||
</Body>
|
||||
</div>
|
||||
<div
|
||||
className="answer-option-flex-item-3 d-flex flex-row flex-nowrap"
|
||||
>
|
||||
<Trigger>
|
||||
<IconButton
|
||||
alt="Delete answer"
|
||||
alt="Toggle feedback"
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
variant="primary"
|
||||
/>
|
||||
</Component>
|
||||
</Row>
|
||||
</Trigger>
|
||||
<IconButton
|
||||
alt="Delete answer"
|
||||
iconAs="Icon"
|
||||
onClick={[Function]}
|
||||
variant="primary"
|
||||
/>
|
||||
</div>
|
||||
</Advanced>
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AnswersContainer render snapshot: renders correct default 1`] = `
|
||||
<div
|
||||
className="border border-light-700 rounded py-4 pl-4 pr-3"
|
||||
>
|
||||
<Button
|
||||
className="pl-0 text-primary-500"
|
||||
onClick={[MockFunction]}
|
||||
variant="tertiary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add answer"
|
||||
description="Button text to add answer"
|
||||
id="authoring.answerwidget.answer.addAnswerButton"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AnswersContainer render snapshot: renders correctly with answers 1`] = `
|
||||
<div
|
||||
className="border border-light-700 rounded py-4 pl-4 pr-3"
|
||||
>
|
||||
<Component
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"id": "a",
|
||||
"title": "sOMetITlE",
|
||||
}
|
||||
}
|
||||
hasSingleAnswer={false}
|
||||
key="a"
|
||||
/>
|
||||
<Component
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"id": "b",
|
||||
"title": "sOMetITlE",
|
||||
}
|
||||
}
|
||||
hasSingleAnswer={false}
|
||||
key="b"
|
||||
/>
|
||||
<Button
|
||||
className="pl-0 text-primary-500"
|
||||
onClick={[MockFunction]}
|
||||
variant="tertiary"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Add answer"
|
||||
description="Button text to add answer"
|
||||
id="authoring.answerwidget.answer.addAnswerButton"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,23 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Checker component with multiple answers 1`] = `
|
||||
<Form.Checkbox
|
||||
checked={true}
|
||||
className="pt-2.5"
|
||||
onChange={[Function]}
|
||||
value="A"
|
||||
>
|
||||
A
|
||||
</Form.Checkbox>
|
||||
`;
|
||||
|
||||
exports[`Checker component with single answer 1`] = `
|
||||
<Radio
|
||||
checked={true}
|
||||
className="pt-2.5"
|
||||
onChange={[Function]}
|
||||
value="A"
|
||||
>
|
||||
A
|
||||
</Radio>
|
||||
`;
|
||||
@@ -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 (
|
||||
<CheckerType
|
||||
className="pt-2.5"
|
||||
value={answer.id}
|
||||
onChange={(e) => setAnswer({ correct: e.target.checked })}
|
||||
checked={answer.correct}
|
||||
>
|
||||
{answer.id}
|
||||
</CheckerType>
|
||||
);
|
||||
};
|
||||
Checker.propTypes = {
|
||||
hasSingleAnswer: PropTypes.bool.isRequired,
|
||||
answer: PropTypes.shape({
|
||||
correct: PropTypes.bool,
|
||||
id: PropTypes.number,
|
||||
}).isRequired,
|
||||
setAnswer: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Checker;
|
||||
@@ -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(<Checker {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('with multiple answers', () => {
|
||||
expect(shallow(<Checker {...props} hasSingleAnswer={false} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -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 (
|
||||
<div className="bg-light-300 p-4 mt-3 rounded">
|
||||
<FeedbackControl
|
||||
key={`selectedfeedback-${answer.id}`}
|
||||
feedback={answer.selectedFeedback}
|
||||
labelMessage={messages.selectedFeedbackLabel}
|
||||
labelMessageBoldUnderline={messages.selectedFeedbackLabelBoldUnderlineText}
|
||||
{...props}
|
||||
/>
|
||||
<FeedbackControl
|
||||
key={`unselectedfeedback-${answer.id}`}
|
||||
feedback={answer.unselectedFeedback}
|
||||
labelMessage={messages.unSelectedFeedbackLabel}
|
||||
labelMessageBoldUnderline={messages.unSelectedFeedbackLabelBoldUnderlineText}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
FeedbackBox.propTypes = {
|
||||
answer: answerOptionProps.isRequired,
|
||||
setAnswer: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(FeedbackBox);
|
||||
@@ -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(<FeedbackBox {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
}) => (
|
||||
<Form.Group>
|
||||
<Form.Label className="mb-3">
|
||||
<FormattedMessage
|
||||
{...labelMessage}
|
||||
values={{
|
||||
answerId: answer.id,
|
||||
boldunderline: <b><u><FormattedMessage {...labelMessageBoldUnderline} /></u></b>,
|
||||
}}
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Control
|
||||
placeholder={intl.formatMessage(messages.feedbackPlaceholder)}
|
||||
value={feedback}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</Form.Group>
|
||||
);
|
||||
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;
|
||||
@@ -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(<FeedbackControl {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FeedbackBox component renders 1`] = `
|
||||
<div
|
||||
className="bg-light-300 p-4 mt-3 rounded"
|
||||
>
|
||||
<FeedbackControl
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"id": "A",
|
||||
"selectedFeedback": "some feedback",
|
||||
"title": "Answer 1",
|
||||
"unselectedFeedback": "unselectedFeedback",
|
||||
}
|
||||
}
|
||||
feedback="some feedback"
|
||||
intl={Object {}}
|
||||
key="selectedfeedback-A"
|
||||
labelMessage={
|
||||
Object {
|
||||
"defaultMessage": "Show following feedback when {answerId} {boldunderline}:",
|
||||
"description": "Label text for feedback if option is selected",
|
||||
"id": "authoring.answerwidget.feedback.selected.label",
|
||||
}
|
||||
}
|
||||
labelMessageBoldUnderline={
|
||||
Object {
|
||||
"defaultMessage": "is selected",
|
||||
"description": "Bold & underlined text for feedback if option is selected",
|
||||
"id": "authoring.answerwidget.feedback.selected.label.boldunderline",
|
||||
}
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
<FeedbackControl
|
||||
answer={
|
||||
Object {
|
||||
"correct": true,
|
||||
"id": "A",
|
||||
"selectedFeedback": "some feedback",
|
||||
"title": "Answer 1",
|
||||
"unselectedFeedback": "unselectedFeedback",
|
||||
}
|
||||
}
|
||||
feedback="unselectedFeedback"
|
||||
intl={Object {}}
|
||||
key="unselectedfeedback-A"
|
||||
labelMessage={
|
||||
Object {
|
||||
"defaultMessage": "Show following feedback when {answerId} {boldunderline}:",
|
||||
"description": "Label text for feedback if option is not selected",
|
||||
"id": "authoring.answerwidget.feedback.unselected.label",
|
||||
}
|
||||
}
|
||||
labelMessageBoldUnderline={
|
||||
Object {
|
||||
"defaultMessage": "is not selected",
|
||||
"description": "Bold & underlined text for feedback if option is not selected",
|
||||
"id": "authoring.answerwidget.feedback.unselected.label.boldunderline",
|
||||
}
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,33 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FeedbackControl component renders 1`] = `
|
||||
<Form.Group>
|
||||
<Form.Label
|
||||
className="mb-3"
|
||||
>
|
||||
<FormattedMessage
|
||||
0="m"
|
||||
1="s"
|
||||
2="g"
|
||||
values={
|
||||
Object {
|
||||
"answerId": "A",
|
||||
"boldunderline": <b>
|
||||
<u>
|
||||
<FormattedMessage
|
||||
0="m"
|
||||
1="s"
|
||||
2="g"
|
||||
/>
|
||||
</u>
|
||||
</b>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Control
|
||||
onChange={[MockFunction]}
|
||||
value="feedback"
|
||||
/>
|
||||
</Form.Group>
|
||||
`;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as FeedbackBox } from './FeedbackBox';
|
||||
export { default as FeedbackControl } from './FeedbackControl';
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -15,11 +15,11 @@ const AnswerWidget = ({
|
||||
const problemStaticData = ProblemTypes[problemType];
|
||||
return (
|
||||
<div>
|
||||
<div className="problem-answer">
|
||||
<div className="problem-answer-title">
|
||||
<div className="mt-4 mb-3 text-primary-500">
|
||||
<div className="h4">
|
||||
<FormattedMessage {...messages.answerWidgetTitle} />
|
||||
</div>
|
||||
<div className="problem-answer-description">
|
||||
<div className="small">
|
||||
{problemStaticData.description}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<div>
|
||||
<div>
|
||||
<h1>
|
||||
<FormattedMessage {...messages.questionWidgetTitle} />
|
||||
</h1>
|
||||
<Editor {
|
||||
<div className="question-widget">
|
||||
<div className="h4">
|
||||
<FormattedMessage {...messages.questionWidgetTitle} />
|
||||
</div>
|
||||
<Editor {
|
||||
...hooks.problemEditorConfig({
|
||||
setEditorRef,
|
||||
editorRef,
|
||||
@@ -28,8 +28,7 @@ export const QuestionWidget = ({
|
||||
updateQuestion,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ export const SettingsOption = ({
|
||||
const { isCardCollapsed, toggleCardCollapse } = showFullCard();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card className="border border-light-700 shadow-none">
|
||||
<Card.Section className="settingsCardTitleSection">
|
||||
<Collapsible.Advanced
|
||||
open={isCardCollapsed}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SettingsOption render snapshot: renders correct 1`] = `
|
||||
<Card>
|
||||
<Card
|
||||
className="border border-light-700 shadow-none"
|
||||
>
|
||||
<Card.Section
|
||||
className="settingsCardTitleSection"
|
||||
>
|
||||
|
||||
@@ -2,172 +2,182 @@
|
||||
|
||||
exports[`SettingsWidget snapshot snapshot: renders Settings widget page 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
defaultMessage="Settings"
|
||||
description="Settings Title"
|
||||
id="authoring.problemeditor.settings.settingsWidgetTitle"
|
||||
/>
|
||||
</h3>
|
||||
<Container>
|
||||
<Row>
|
||||
<Component>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="stringresponse"
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="mt-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row>
|
||||
<Advanced
|
||||
open={true}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
size="inline"
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Show advanced settings"
|
||||
description="Button text to show advanced settings"
|
||||
id="authoring.problemeditor.settings.showAdvancedButton"
|
||||
/>
|
||||
</Button>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Row>
|
||||
<Advanced
|
||||
open={false}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Component>
|
||||
</Row>
|
||||
</Container>
|
||||
<div
|
||||
className="h4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Settings"
|
||||
description="Settings Title"
|
||||
id="authoring.problemeditor.settings.settingsWidgetTitle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`SettingsWidget snapshot snapshot: renders Settings widget page advanced settings visible 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
defaultMessage="Settings"
|
||||
description="Settings Title"
|
||||
id="authoring.problemeditor.settings.settingsWidgetTitle"
|
||||
/>
|
||||
</h3>
|
||||
<Container>
|
||||
<Row>
|
||||
<Component>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="stringresponse"
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="mt-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row>
|
||||
<Advanced
|
||||
open={false}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
size="inline"
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Show advanced settings"
|
||||
description="Button text to show advanced settings"
|
||||
id="authoring.problemeditor.settings.showAdvancedButton"
|
||||
/>
|
||||
</Button>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Row>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row
|
||||
className="mb-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="stringresponse"
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="mt-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row>
|
||||
<Advanced
|
||||
open={true}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Row
|
||||
className="my-2"
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
size="inline"
|
||||
variant="link"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<FormattedMessage
|
||||
defaultMessage="Show advanced settings"
|
||||
description="Button text to show advanced settings"
|
||||
id="authoring.problemeditor.settings.showAdvancedButton"
|
||||
/>
|
||||
</Button>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Component>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
</Row>
|
||||
<Advanced
|
||||
open={false}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`SettingsWidget snapshot snapshot: renders Settings widget page advanced settings visible 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="h4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Settings"
|
||||
description="Settings Title"
|
||||
id="authoring.problemeditor.settings.settingsWidgetTitle"
|
||||
/>
|
||||
</div>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row
|
||||
className="mb-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="stringresponse"
|
||||
/>
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="mt-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row>
|
||||
<Advanced
|
||||
open={false}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
size="inline"
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Show advanced settings"
|
||||
description="Button text to show advanced settings"
|
||||
id="authoring.problemeditor.settings.showAdvancedButton"
|
||||
/>
|
||||
</Button>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Row>
|
||||
<Advanced
|
||||
open={true}
|
||||
>
|
||||
<Body
|
||||
className="collapsible-body"
|
||||
>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
<Row
|
||||
className="my-2"
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
</Row>
|
||||
</Body>
|
||||
</Advanced>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<div>
|
||||
<div>
|
||||
<h3>
|
||||
<FormattedMessage {...messages.settingsWidgetTitle} />
|
||||
</h3>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row className="my-2">
|
||||
<TypeCard problemType={problemType} updateField={updateField} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<ScoringCard scoring={settings.scoring} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="mt-2">
|
||||
<HintsCard hints={settings.hints} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<div className="h4">
|
||||
<FormattedMessage {...messages.settingsWidgetTitle} />
|
||||
</div>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<Row className="mb-2">
|
||||
<TypeCard
|
||||
answers={answers}
|
||||
correctAnswerCount={correctAnswerCount}
|
||||
problemType={problemType}
|
||||
updateField={updateField}
|
||||
updateAnswer={updateAnswer}
|
||||
/>
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<ScoringCard scoring={settings.scoring} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="mt-2">
|
||||
<HintsCard hints={settings.hints} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Collapsible.Advanced open={!isAdvancedCardsVisible}>
|
||||
<Collapsible.Body className="collapsible-body">
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
variant="link"
|
||||
size="inline"
|
||||
onClick={showAdvancedCards}
|
||||
>
|
||||
<FormattedMessage {...messages.showAdvanceSettingsButtonText} />
|
||||
</Button>
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
</Row>
|
||||
|
||||
<Collapsible.Advanced open={isAdvancedCardsVisible}>
|
||||
<Row>
|
||||
<Collapsible.Advanced open={!isAdvancedCardsVisible}>
|
||||
<Collapsible.Body className="collapsible-body">
|
||||
<Row className="my-2">
|
||||
<ShowAnswerCard showAnswer={settings.showAnswer} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<ResetCard showResetButton={settings.showResetButton} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<TimerCard timeBetween={settings.timeBetween} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<MatlabCard matLabApiKey={settings.matLabApiKey} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
variant="link"
|
||||
size="inline"
|
||||
onClick={showAdvancedCards}
|
||||
>
|
||||
<FormattedMessage {...messages.showAdvanceSettingsButtonText} />
|
||||
</Button>
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
</Row>
|
||||
|
||||
<Collapsible.Advanced open={isAdvancedCardsVisible}>
|
||||
<Collapsible.Body className="collapsible-body">
|
||||
<Row className="my-2">
|
||||
<ShowAnswerCard showAnswer={settings.showAnswer} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<ResetCard showResetButton={settings.showResetButton} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<TimerCard timeBetween={settings.timeBetween} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<MatlabCard matLabApiKey={settings.matLabApiKey} updateSettings={updateSettings} />
|
||||
</Row>
|
||||
<Row className="my-2">
|
||||
<SwitchToAdvancedEditorCard />
|
||||
</Row>
|
||||
</Collapsible.Body>
|
||||
</Collapsible.Advanced>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -29,7 +29,7 @@ export const HintsCard = ({
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
className="pl-0 text-primary-500"
|
||||
iconBefore={Add}
|
||||
variant="tertiary"
|
||||
onClick={handleAdd}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Form } from '@edx/paragon';
|
||||
import SettingsOption from '../SettingsOption';
|
||||
import messages from '../messages';
|
||||
@@ -14,12 +14,23 @@ export const ScoringCard = ({
|
||||
}) => {
|
||||
const { handleMaxAttemptChange, handleWeightChange } = scoringCardHooks(scoring, updateSettings);
|
||||
|
||||
const getScoringSummary = (attempts, unlimited, weight) => {
|
||||
let summary = unlimited
|
||||
? intl.formatMessage(messages.unlimitedAttemptsSummary)
|
||||
: intl.formatMessage(messages.attemptsSummary, { attempts });
|
||||
summary += ` ${String.fromCharCode(183)} `;
|
||||
summary += intl.formatMessage(messages.weightSummary, { weight });
|
||||
return summary;
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsOption
|
||||
title={intl.formatMessage(messages.scoringSettingsTitle)}
|
||||
summary={intl.formatMessage(messages.scoringSummary,
|
||||
{ attempts: scoring.attempts.number, weight: scoring.weight })}
|
||||
summary={getScoringSummary(scoring.attempts.number, scoring.attempts.unlimited, scoring.weight)}
|
||||
>
|
||||
<Form.Label className="mb-4">
|
||||
<FormattedMessage {...messages.scoringSettingsLabel} />
|
||||
</Form.Label>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
type="number"
|
||||
@@ -27,6 +38,9 @@ export const ScoringCard = ({
|
||||
onChange={handleMaxAttemptChange}
|
||||
floatingLabel={intl.formatMessage(messages.scoringAttemptsInputLabel)}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage {...messages.attemptsHint} />
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
@@ -35,6 +49,9 @@ export const ScoringCard = ({
|
||||
onChange={handleWeightChange}
|
||||
floatingLabel={intl.formatMessage(messages.scoringWeightInputLabel)}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage {...messages.weightHint} />
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
</SettingsOption>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Form, Hyperlink } from '@edx/paragon';
|
||||
import SettingsOption from '../SettingsOption';
|
||||
import { ShowAnswerTypes, ShowAnswerTypesKeys } from '../../../../../../data/constants/problem';
|
||||
import { selectors } from '../../../../../../data/redux';
|
||||
import messages from '../messages';
|
||||
import { showAnswerCardHooks } from '../hooks';
|
||||
|
||||
@@ -12,6 +14,9 @@ export const ShowAnswerCard = ({
|
||||
updateSettings,
|
||||
// inject
|
||||
intl,
|
||||
// redux
|
||||
studioEndpointUrl,
|
||||
learningContextId,
|
||||
}) => {
|
||||
const {
|
||||
handleShowAnswerChange,
|
||||
@@ -29,7 +34,7 @@ export const ShowAnswerCard = ({
|
||||
</span>
|
||||
</div>
|
||||
<div className="spacedMessage">
|
||||
<Hyperlink destination="#" target="_blank">
|
||||
<Hyperlink destination={`${studioEndpointUrl}/settings/advanced/${learningContextId}`} target="_blank">
|
||||
<FormattedMessage {...messages.advancedSettingsLinkText} />
|
||||
</Hyperlink>
|
||||
</div>
|
||||
@@ -49,7 +54,7 @@ export const ShowAnswerCard = ({
|
||||
))}
|
||||
</Form.Control>
|
||||
</Form.Group>
|
||||
{ showAttempts
|
||||
{showAttempts
|
||||
&& (
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
@@ -69,6 +74,15 @@ ShowAnswerCard.propTypes = {
|
||||
// eslint-disable-next-line
|
||||
showAnswer: PropTypes.any.isRequired,
|
||||
updateSettings: PropTypes.func.isRequired,
|
||||
studioEndpointUrl: PropTypes.string.isRequired,
|
||||
learningContextId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(ShowAnswerCard);
|
||||
export const mapStateToProps = (state) => ({
|
||||
studioEndpointUrl: selectors.app.studioEndpointUrl(state),
|
||||
learningContextId: selectors.app.learningContextId(state),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {};
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ShowAnswerCard));
|
||||
|
||||
@@ -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(<ShowAnswerCard {...props} />)).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({});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<Card className="border border-light-700 shadow-none">
|
||||
<BaseModal
|
||||
isOpen={isConfirmOpen}
|
||||
close={() => { setConfirmOpen(false); }}
|
||||
title={(<FormattedMessage {...messages.ConfirmSwitchMessageTitle} />)}
|
||||
confirmAction={(
|
||||
<Button
|
||||
onClick={switchToAdvancedEditor}
|
||||
>
|
||||
<FormattedMessage {...messages.ConfirmSwitchButtonLabel} />
|
||||
</Button>
|
||||
)}
|
||||
size="md"
|
||||
>
|
||||
<FormattedMessage {...messages.ConfirmSwitchMessage} />
|
||||
</BaseModal>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
variant="link"
|
||||
size="inline"
|
||||
onClick={() => { setConfirmOpen(true); }}
|
||||
>
|
||||
<FormattedMessage {...messages.SwitchButtonLabel} />
|
||||
</Button>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
SwitchToAdvancedEditorCard.propTypes = {
|
||||
switchToAdvancedEditor: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export const mapStateToProps = () => ({
|
||||
});
|
||||
export const mapDispatchToProps = {
|
||||
switchToAdvancedEditor: thunkActions.problem.switchToAdvancedEditor,
|
||||
};
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SwitchToAdvancedEditorCard));
|
||||
@@ -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(<SwitchToAdvancedEditorCard switchToAdvancedEditor={mockSwitchToAdvancedEditor} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -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 (
|
||||
<SettingsOption
|
||||
@@ -21,12 +26,15 @@ export const TypeCard = ({
|
||||
>
|
||||
{problemTypeKeysArray.map((typeKey, i) => (
|
||||
<TypeRow
|
||||
answers={answers}
|
||||
correctAnswerCount={correctAnswerCount}
|
||||
key={typeKey}
|
||||
typeKey={typeKey}
|
||||
label={ProblemTypes[typeKey].title}
|
||||
selected={typeKey !== problemType}
|
||||
lastRow={(i + 1) === problemTypeKeysArray.length}
|
||||
updateField={updateField}
|
||||
updateAnswer={updateAnswer}
|
||||
/>
|
||||
))}
|
||||
</SettingsOption>
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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(<TypeRow {...props} />);
|
||||
expect(typeRowHooks).toHaveBeenCalledWith(typeKey, props.updateField);
|
||||
expect(typeRowHooks).toHaveBeenCalledWith({
|
||||
answers: props.answers,
|
||||
correctAnswerCount: props.correctAnswerCount,
|
||||
typeKey,
|
||||
updateField: props.updateField,
|
||||
updateAnswer: props.updateAnswer,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ exports[`HintRow snapshot snapshot: renders hints row 1`] = `
|
||||
fluid={true}
|
||||
>
|
||||
<Row>
|
||||
<Component
|
||||
<Col
|
||||
xs={10}
|
||||
>
|
||||
<Form.Group>
|
||||
@@ -15,8 +15,8 @@ exports[`HintRow snapshot snapshot: renders hints row 1`] = `
|
||||
value="hint_1"
|
||||
/>
|
||||
</Form.Group>
|
||||
</Component>
|
||||
<Component
|
||||
</Col>
|
||||
<Col
|
||||
xs={2}
|
||||
>
|
||||
<IconButton
|
||||
@@ -25,7 +25,7 @@ exports[`HintRow snapshot snapshot: renders hints row 1`] = `
|
||||
onClick={[MockFunction]}
|
||||
variant="secondary"
|
||||
/>
|
||||
</Component>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
@@ -20,7 +20,7 @@ exports[`HintsCard snapshot snapshot: renders hints setting card multiple hints
|
||||
value=""
|
||||
/>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
className="pl-0 text-primary-500"
|
||||
onClick={[MockFunction hintsCardHooks.handleAdd]}
|
||||
variant="tertiary"
|
||||
>
|
||||
@@ -35,11 +35,11 @@ exports[`HintsCard snapshot snapshot: renders hints setting card multiple hints
|
||||
|
||||
exports[`HintsCard snapshot snapshot: renders hints setting card no hints 1`] = `
|
||||
<SettingsOption
|
||||
summary="No Hints"
|
||||
summary="None"
|
||||
title="Hints"
|
||||
>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
className="pl-0 text-primary-500"
|
||||
onClick={[MockFunction hintsCardHooks.handleAdd]}
|
||||
variant="tertiary"
|
||||
>
|
||||
@@ -65,7 +65,7 @@ exports[`HintsCard snapshot snapshot: renders hints setting card one hint 1`] =
|
||||
value="hint1"
|
||||
/>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
className="pl-0 text-primary-500"
|
||||
onClick={[MockFunction hintsCardHooks.handleAdd]}
|
||||
variant="tertiary"
|
||||
>
|
||||
|
||||
@@ -2,9 +2,18 @@
|
||||
|
||||
exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = `
|
||||
<SettingsOption
|
||||
summary="{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}"
|
||||
summary="{attempts, plural, =1 {# attempt} other {# attempts}} · {weight, plural, =0 {Ungraded} other {# points}}"
|
||||
title="Scoring"
|
||||
>
|
||||
<Form.Label
|
||||
className="mb-4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Specify point weight and the number of answer attempts"
|
||||
description="Descriptive text for scoring settings"
|
||||
id="authoring.problemeditor.settings.scoring.label"
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
floatingLabel="Attempts"
|
||||
@@ -12,6 +21,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = `
|
||||
type="number"
|
||||
value={5}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage
|
||||
defaultMessage="If a value is not set, unlimited attempts are allowed"
|
||||
description="Summary text for scoring weight"
|
||||
id="authoring.problemeditor.settings.scoring.attempts.hint"
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
@@ -20,15 +36,31 @@ exports[`ScoringCard snapshot snapshot: scoring setting card 1`] = `
|
||||
type="number"
|
||||
value={1.5}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage
|
||||
defaultMessage="If a value is not set, the problem is worth one point"
|
||||
description="Summary text for scoring weight"
|
||||
id="authoring.problemeditor.settings.scoring.weight.hint"
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
</SettingsOption>
|
||||
`;
|
||||
|
||||
exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] = `
|
||||
<SettingsOption
|
||||
summary="{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}"
|
||||
summary="Unlimited attempts · {weight, plural, =0 {Ungraded} other {# points}}"
|
||||
title="Scoring"
|
||||
>
|
||||
<Form.Label
|
||||
className="mb-4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Specify point weight and the number of answer attempts"
|
||||
description="Descriptive text for scoring settings"
|
||||
id="authoring.problemeditor.settings.scoring.label"
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
floatingLabel="Attempts"
|
||||
@@ -36,6 +68,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] =
|
||||
type="number"
|
||||
value={0}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage
|
||||
defaultMessage="If a value is not set, unlimited attempts are allowed"
|
||||
description="Summary text for scoring weight"
|
||||
id="authoring.problemeditor.settings.scoring.attempts.hint"
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
@@ -44,15 +83,31 @@ exports[`ScoringCard snapshot snapshot: scoring setting card max attempts 1`] =
|
||||
type="number"
|
||||
value={1.5}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage
|
||||
defaultMessage="If a value is not set, the problem is worth one point"
|
||||
description="Summary text for scoring weight"
|
||||
id="authoring.problemeditor.settings.scoring.weight.hint"
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
</SettingsOption>
|
||||
`;
|
||||
|
||||
exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`] = `
|
||||
<SettingsOption
|
||||
summary="{attempts, plural, =0 {Unlimited} other {#}} attempts - {weight, plural, =0 {Ungraded} other {# points}}"
|
||||
summary="{attempts, plural, =1 {# attempt} other {# attempts}} · {weight, plural, =0 {Ungraded} other {# points}}"
|
||||
title="Scoring"
|
||||
>
|
||||
<Form.Label
|
||||
className="mb-4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Specify point weight and the number of answer attempts"
|
||||
description="Descriptive text for scoring settings"
|
||||
id="authoring.problemeditor.settings.scoring.label"
|
||||
/>
|
||||
</Form.Label>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
floatingLabel="Attempts"
|
||||
@@ -60,6 +115,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`
|
||||
type="number"
|
||||
value={5}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage
|
||||
defaultMessage="If a value is not set, unlimited attempts are allowed"
|
||||
description="Summary text for scoring weight"
|
||||
id="authoring.problemeditor.settings.scoring.attempts.hint"
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Control
|
||||
@@ -68,6 +130,13 @@ exports[`ScoringCard snapshot snapshot: scoring setting card zero zero weight 1`
|
||||
type="number"
|
||||
value={0}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage
|
||||
defaultMessage="If a value is not set, the problem is worth one point"
|
||||
description="Summary text for scoring weight"
|
||||
id="authoring.problemeditor.settings.scoring.weight.hint"
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
</SettingsOption>
|
||||
`;
|
||||
|
||||
@@ -20,7 +20,7 @@ exports[`ShowAnswerCard snapshot snapshot: show answer setting card 1`] = `
|
||||
className="spacedMessage"
|
||||
>
|
||||
<Hyperlink
|
||||
destination="#"
|
||||
destination="SoMEeNDpOinT/settings/advanced/sOMEcouRseId"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SwitchToAdvancedEditorCard snapshot snapshot: SwitchToAdvancedEditorCard 1`] = `
|
||||
<Card
|
||||
className="border border-light-700 shadow-none"
|
||||
>
|
||||
<BaseModal
|
||||
close={[Function]}
|
||||
confirmAction={
|
||||
<Button
|
||||
onClick={[MockFunction switchToAdvancedEditor]}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Switch To Advanced Editor"
|
||||
description="message to confirm that a user wants to use the advanced editor"
|
||||
id="authoring.problemeditor.settings.switchtoadvancededitor.message"
|
||||
/>
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
isOpen={false}
|
||||
size="md"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Convert to OLX?"
|
||||
description="message to confirm that a user wants to use the advanced editor"
|
||||
id="authoring.problemeditor.settings.switchtoadvancededitor.message"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
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"
|
||||
id="authoring.problemeditor.settings.switchtoadvancededitor.message"
|
||||
/>
|
||||
</BaseModal>
|
||||
<Button
|
||||
className="my-3 ml-2"
|
||||
onClick={[Function]}
|
||||
size="inline"
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Switch To Advanced Editor"
|
||||
description="button to switch to the advanced mode of the editor."
|
||||
id="authoring.problemeditor.settings.switchtoadvancededitor.label"
|
||||
/>
|
||||
</Button>
|
||||
</Card>
|
||||
`;
|
||||
@@ -2,55 +2,62 @@
|
||||
|
||||
exports[`TypeCard snapshot snapshot: renders type setting card 1`] = `
|
||||
<SettingsOption
|
||||
summary="Text Input Problem"
|
||||
summary="Text input"
|
||||
title="Type"
|
||||
>
|
||||
<TypeRow
|
||||
answers={Array []}
|
||||
correctAnswerCount={0}
|
||||
key="multiplechoiceresponse"
|
||||
label="Single Select Problem"
|
||||
label="Single select"
|
||||
lastRow={false}
|
||||
selected={true}
|
||||
typeKey="multiplechoiceresponse"
|
||||
updateAnswer={[MockFunction args.updateAnswer]}
|
||||
updateField={[MockFunction args.updateField]}
|
||||
/>
|
||||
<TypeRow
|
||||
answers={Array []}
|
||||
correctAnswerCount={0}
|
||||
key="choiceresponse"
|
||||
label="Multi Select Problem"
|
||||
label="Multi-select"
|
||||
lastRow={false}
|
||||
selected={true}
|
||||
typeKey="choiceresponse"
|
||||
updateAnswer={[MockFunction args.updateAnswer]}
|
||||
updateField={[MockFunction args.updateField]}
|
||||
/>
|
||||
<TypeRow
|
||||
answers={Array []}
|
||||
correctAnswerCount={0}
|
||||
key="optionresponse"
|
||||
label="Dropdown Problem"
|
||||
label="Dropdown"
|
||||
lastRow={false}
|
||||
selected={true}
|
||||
typeKey="optionresponse"
|
||||
updateAnswer={[MockFunction args.updateAnswer]}
|
||||
updateField={[MockFunction args.updateField]}
|
||||
/>
|
||||
<TypeRow
|
||||
answers={Array []}
|
||||
correctAnswerCount={0}
|
||||
key="numericalresponse"
|
||||
label="Numeric Response Problem"
|
||||
label="Numerical input"
|
||||
lastRow={false}
|
||||
selected={true}
|
||||
typeKey="numericalresponse"
|
||||
updateAnswer={[MockFunction args.updateAnswer]}
|
||||
updateField={[MockFunction args.updateField]}
|
||||
/>
|
||||
<TypeRow
|
||||
answers={Array []}
|
||||
correctAnswerCount={0}
|
||||
key="stringresponse"
|
||||
label="Text Input Problem"
|
||||
lastRow={false}
|
||||
label="Text input"
|
||||
lastRow={true}
|
||||
selected={false}
|
||||
typeKey="stringresponse"
|
||||
updateField={[MockFunction args.updateField]}
|
||||
/>
|
||||
<TypeRow
|
||||
key="advanced"
|
||||
label="Advanced Problem"
|
||||
lastRow={true}
|
||||
selected={true}
|
||||
typeKey="advanced"
|
||||
updateAnswer={[MockFunction args.updateAnswer]}
|
||||
updateField={[MockFunction args.updateField]}
|
||||
/>
|
||||
</SettingsOption>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`EditorProblemView component renders raw editor 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
getContent={[Function]}
|
||||
>
|
||||
<Container
|
||||
className="mt-3 px-4"
|
||||
fluid={true}
|
||||
>
|
||||
<Row>
|
||||
<Col
|
||||
xs={9}
|
||||
>
|
||||
<RawEditor
|
||||
content={null}
|
||||
editorRef={
|
||||
Object {
|
||||
"current": null,
|
||||
}
|
||||
}
|
||||
lang="xml"
|
||||
/>
|
||||
</Col>
|
||||
<Col
|
||||
xs={3}
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="advanced"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
`;
|
||||
|
||||
exports[`EditorProblemView component renders simple view 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
getContent={[Function]}
|
||||
>
|
||||
<Container
|
||||
className="mt-3 px-4"
|
||||
fluid={true}
|
||||
>
|
||||
<Row>
|
||||
<Col
|
||||
xs={9}
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent) />
|
||||
<AnswerWidget
|
||||
problemType="multiplechoiceresponse"
|
||||
/>
|
||||
</Col>
|
||||
<Col
|
||||
xs={3}
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="multiplechoiceresponse"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
`;
|
||||
@@ -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(),
|
||||
};
|
||||
};
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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 (
|
||||
<EditorContainer getContent={parseState(problemState)}>
|
||||
<Container fluid>
|
||||
<EditorContainer getContent={getContent}>
|
||||
<Container fluid className="mt-3 px-4">
|
||||
<Row>
|
||||
<Col xs={9}>
|
||||
<QuestionWidget />
|
||||
<AnswerWidget problemType={problemType} />
|
||||
{isAdvancedProblemType ? (
|
||||
<RawEditor editorRef={editorRef} lang="xml" content={problemState.rawOLX} />
|
||||
) : (
|
||||
<>
|
||||
<QuestionWidget />
|
||||
<AnswerWidget problemType={problemType} />
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
<Col xs={3}>
|
||||
<SettingsWidget problemType={problemType} />
|
||||
|
||||
@@ -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(<EditProblemView problemType={ProblemTypeKeys.SINGLESELECT} problemState={{}} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.find(AnswerWidget).length).toBe(1);
|
||||
});
|
||||
|
||||
test('renders raw editor', () => {
|
||||
const wrapper = shallow(<EditProblemView problemType={ProblemTypeKeys.ADVANCED} problemState={{}} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.find(AnswerWidget).length).toBe(0);
|
||||
expect(wrapper.find(RawEditor).length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -17,12 +17,12 @@ export const SelectTypeFooter = ({
|
||||
onCancel,
|
||||
selected,
|
||||
// redux
|
||||
setProblemType,
|
||||
updateField,
|
||||
setBlockTitle,
|
||||
// injected,
|
||||
intl,
|
||||
}) => (
|
||||
<div className="editor-footer position-sticky" style={{ bottom: 0 }}>
|
||||
<div className="editor-footer fixed-bottom">
|
||||
<ModalDialog.Footer className="border-top-0">
|
||||
<ActionRow>
|
||||
<ActionRow.Spacer />
|
||||
@@ -35,7 +35,7 @@ export const SelectTypeFooter = ({
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={intl.formatMessage(messages.selectButtonAriaLabel)}
|
||||
onClick={hooks.onSelect(setProblemType, selected, updateField)}
|
||||
onClick={hooks.onSelect({ selected, updateField, setBlockTitle })}
|
||||
disabled={!selected}
|
||||
>
|
||||
<FormattedMessage {...messages.selectButtonLabel} />
|
||||
@@ -52,8 +52,8 @@ SelectTypeFooter.defaultProps = {
|
||||
SelectTypeFooter.propTypes = {
|
||||
onCancel: PropTypes.func.isRequired,
|
||||
selected: PropTypes.string,
|
||||
setProblemType: PropTypes.func.isRequired,
|
||||
updateField: PropTypes.func.isRequired,
|
||||
setBlockTitle: PropTypes.func.isRequired,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
@@ -62,8 +62,8 @@ export const mapStateToProps = () => ({
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
setProblemType: actions.problem.setProblemType,
|
||||
updateField: actions.problem.updateField,
|
||||
setBlockTitle: actions.app.setBlockTitle,
|
||||
};
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SelectTypeFooter));
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('SelectTypeFooter', () => {
|
||||
onCancel: jest.fn().mockName('onCancel'),
|
||||
selected: null,
|
||||
// redux
|
||||
setProblemType: jest.fn().mockName('setProblemType'),
|
||||
updateField: jest.fn().mockName('UpdateField'),
|
||||
// inject
|
||||
intl: { formatMessage },
|
||||
};
|
||||
@@ -36,7 +36,7 @@ describe('SelectTypeFooter', () => {
|
||||
.toEqual(expected);
|
||||
});
|
||||
test('select behavior is linked to modal onSelect', () => {
|
||||
const expected = hooks.onSelect(props.setProblemType, props.selected);
|
||||
const expected = hooks.onSelect(props.selected, props.updateField);
|
||||
expect(el.find(Button).last().props().onClick)
|
||||
.toEqual(expected);
|
||||
});
|
||||
@@ -48,8 +48,8 @@ describe('SelectTypeFooter', () => {
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('loads setProblemType from problem.setProblemType actions', () => {
|
||||
expect(module.mapDispatchToProps.setProblemType).toEqual(actions.problem.setProblemType);
|
||||
test('loads updateField from problem.updateField actions', () => {
|
||||
expect(module.mapDispatchToProps.updateField).toEqual(actions.problem.updateField);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
|
||||
exports[`SelectTypeFooter snapshot 1`] = `
|
||||
<div
|
||||
className="editor-footer position-sticky"
|
||||
style={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
}
|
||||
}
|
||||
className="editor-footer fixed-bottom"
|
||||
>
|
||||
<ModalDialog.Footer
|
||||
className="border-top-0"
|
||||
|
||||
@@ -4,9 +4,11 @@ exports[`SelectTypeWrapper snapshot 1`] = `
|
||||
<div>
|
||||
<ModalDialog.Header>
|
||||
<ModalDialog.Title>
|
||||
<p>
|
||||
Select Problem type
|
||||
</p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Select problem type"
|
||||
description="Title for select problem type modal"
|
||||
id="authoring.problemEditor.selectType.title"
|
||||
/>
|
||||
<div
|
||||
className="pgn__modal-close-container"
|
||||
>
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { Icon, ModalDialog, IconButton } from '@edx/paragon';
|
||||
import { Close } from '@edx/paragon/icons';
|
||||
import SelectTypeFooter from './SelectTypeFooter';
|
||||
|
||||
import * as hooks from '../../../../EditorContainer/hooks';
|
||||
import messages from './messages';
|
||||
|
||||
export const SelectTypeWrapper = ({
|
||||
children,
|
||||
onClose,
|
||||
selected,
|
||||
}) => {
|
||||
const handleCancelClicked = hooks.handleCancelClicked({ onClose });
|
||||
const handleCancel = hooks.handleCancel({ onClose });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ModalDialog.Header>
|
||||
<ModalDialog.Title>
|
||||
<p>Select Problem type</p>
|
||||
<FormattedMessage {...messages.selectTypeTitle} />
|
||||
<div className="pgn__modal-close-container">
|
||||
<IconButton
|
||||
src={Close}
|
||||
iconAs={Icon}
|
||||
onClick={handleCancelClicked}
|
||||
onClick={handleCancel}
|
||||
/>
|
||||
</div>
|
||||
</ModalDialog.Title>
|
||||
@@ -33,7 +34,7 @@ export const SelectTypeWrapper = ({
|
||||
</ModalDialog.Body>
|
||||
<SelectTypeFooter
|
||||
selected={selected}
|
||||
onCancel={handleCancelClicked}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -48,4 +49,4 @@ SelectTypeWrapper.propTypes = {
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
export default SelectTypeWrapper;
|
||||
export default injectIntl(SelectTypeWrapper);
|
||||
|
||||
@@ -2,10 +2,10 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { IconButton } from '@edx/paragon';
|
||||
import * as module from '.';
|
||||
import { handleCancelClicked } from '../../../../EditorContainer/hooks';
|
||||
import { handleCancel } from '../../../../EditorContainer/hooks';
|
||||
|
||||
jest.mock('../../../../EditorContainer/hooks', () => ({
|
||||
handleCancelClicked: jest.fn().mockName('handleCancelClicked'),
|
||||
handleCancel: jest.fn().mockName('handleCancel'),
|
||||
}));
|
||||
|
||||
describe('SelectTypeWrapper', () => {
|
||||
@@ -25,7 +25,7 @@ describe('SelectTypeWrapper', () => {
|
||||
el = shallow(<module.SelectTypeWrapper {...props} />);
|
||||
});
|
||||
test('close behavior is linked to modal onClose', () => {
|
||||
const expected = handleCancelClicked({ onClose: props.onClose });
|
||||
const expected = handleCancel({ onClose: props.onClose });
|
||||
expect(el.find(IconButton).props().onClick)
|
||||
.toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export const messages = {
|
||||
selectTypeTitle: {
|
||||
id: 'authoring.problemEditor.selectType.title',
|
||||
defaultMessage: 'Select problem type',
|
||||
description: 'Title for select problem type modal',
|
||||
},
|
||||
cancelButtonLabel: {
|
||||
id: 'authoring.problemeditor.selecttype.cancelButton.label',
|
||||
defaultMessage: 'Cancel',
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SelectTypeModal snapshot 1`] = `
|
||||
<SelectTypeWrapper
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
onClose={[MockFunction]}
|
||||
selected="mOcKsELEcted"
|
||||
>
|
||||
<Row
|
||||
className="justify-content-center align-items-center m-4"
|
||||
className="justify-content-center"
|
||||
>
|
||||
<Component>
|
||||
<Stack
|
||||
className="flex-wrap"
|
||||
direction="horizontal"
|
||||
gap={4}
|
||||
>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
selected="mOcKsELEcted"
|
||||
setSelected={[MockFunction setSelected]}
|
||||
/>
|
||||
</Component>
|
||||
<Component>
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
problemType="mOcKsELEcted"
|
||||
/>
|
||||
</Component>
|
||||
</Stack>
|
||||
</Row>
|
||||
</SelectTypeWrapper>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
`;
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
Icon,
|
||||
OverlayTrigger,
|
||||
Tooltip,
|
||||
Hyperlink,
|
||||
Col,
|
||||
} from '@edx/paragon';
|
||||
import { ArrowBack } from '@edx/paragon/icons';
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
@@ -22,8 +24,8 @@ export const AdvanceTypeSelect = ({
|
||||
}) => {
|
||||
const handleChange = e => { setSelected(e.target.value); };
|
||||
return (
|
||||
<div className="col col-8 border rounded p-0 justify-content-center">
|
||||
<Form.Group className="p-0">
|
||||
<Col xs={12} md={8} className="justify-content-center">
|
||||
<Form.Group className="border rounded text-primary-500 p-0">
|
||||
<ActionRow className="border-primary-100 border-bottom py-3 pl-2.5 pr-4">
|
||||
<IconButton src={ArrowBack} iconAs={Icon} onClick={() => setSelected(ProblemTypeKeys.SINGLESELECT)} />
|
||||
<ActionRow.Spacer />
|
||||
@@ -56,7 +58,7 @@ export const AdvanceTypeSelect = ({
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<div className="text-gray-500">
|
||||
{intl.formatMessage(messages.problemSupportStatus, { supportStatus: data.status })}
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -74,7 +76,13 @@ export const AdvanceTypeSelect = ({
|
||||
})}
|
||||
</Form.RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage {...messages.learnMoreAdvancedButtonLabel} />
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import { Hyperlink, Image, Container } from '@edx/paragon';
|
||||
import {
|
||||
FormattedMessage,
|
||||
injectIntl,
|
||||
@@ -19,7 +19,7 @@ export const Preview = ({
|
||||
}
|
||||
const data = ProblemTypes[problemType];
|
||||
return (
|
||||
<div className="bg-light-300 rounded p-4">
|
||||
<Container style={{ width: '494px', height: '400px' }} className="bg-light-300 rounded p-4">
|
||||
<div className="small">
|
||||
{intl.formatMessage(messages.previewTitle, { previewTitle: data.title })}
|
||||
</div>
|
||||
@@ -38,7 +38,7 @@ export const Preview = ({
|
||||
>
|
||||
<FormattedMessage {...messages.learnMoreButtonLabel} />
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, SelectableBox } from '@edx/paragon';
|
||||
import { Button, Container, SelectableBox } from '@edx/paragon';
|
||||
import { FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n';
|
||||
import { ProblemTypes, ProblemTypeKeys, AdvanceProblemKeys } from '../../../../../data/constants/problem';
|
||||
import messages from './messages';
|
||||
@@ -14,7 +14,7 @@ export const ProblemTypeSelect = ({
|
||||
const settings = { 'aria-label': 'checkbox', type: 'radio' };
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container style={{ width: '494px', height: '400px' }}>
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
onChange={handleChange}
|
||||
@@ -24,7 +24,12 @@ export const ProblemTypeSelect = ({
|
||||
{Object.values(ProblemTypeKeys).map((key) => (
|
||||
key !== 'advanced'
|
||||
? (
|
||||
<SelectableBox id={key} value={key} {...settings}>
|
||||
<SelectableBox
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id={key}
|
||||
value={key}
|
||||
{...settings}
|
||||
>
|
||||
{ProblemTypes[key].title}
|
||||
</SelectableBox>
|
||||
)
|
||||
@@ -34,7 +39,7 @@ export const ProblemTypeSelect = ({
|
||||
<Button variant="link" className="pl-0 mt-2" onClick={handleClick}>
|
||||
<FormattedMessage {...messages.advanceProblemButtonLabel} />
|
||||
</Button>
|
||||
</>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
ProblemTypeSelect.propTypes = {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default props 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -39,7 +41,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -80,7 +82,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -133,53 +137,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -217,7 +181,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -270,22 +236,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is circuitschematic 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -319,7 +299,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -360,7 +340,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -413,53 +395,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -497,7 +439,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -550,22 +494,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is customgrader 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -599,7 +557,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -640,7 +598,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -693,53 +653,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -777,7 +697,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -830,22 +752,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is drag_and_drop 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -879,7 +815,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -920,7 +856,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -973,53 +911,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -1057,7 +955,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1110,22 +1010,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is formularesponse 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -1159,7 +1073,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -1200,7 +1114,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1253,53 +1169,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -1337,7 +1213,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1390,22 +1268,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is imageresponse 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -1439,7 +1331,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -1480,7 +1372,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1533,53 +1427,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -1617,7 +1471,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1670,22 +1526,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is jsinput_response 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -1719,7 +1589,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -1760,7 +1630,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1813,53 +1685,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -1897,7 +1729,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -1950,22 +1784,36 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is problem_with_hint 1`] = `
|
||||
<div
|
||||
className="col col-8 border rounded p-0 justify-content-center"
|
||||
<Col
|
||||
className="justify-content-center"
|
||||
md={8}
|
||||
xs={12}
|
||||
>
|
||||
<Form.Group
|
||||
className="p-0"
|
||||
className="border rounded text-primary-500 p-0"
|
||||
>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom py-3 pl-2.5 pr-4"
|
||||
@@ -1999,7 +1847,7 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
id="blankadvanced"
|
||||
value="blankadvanced"
|
||||
>
|
||||
Blank advance problem
|
||||
Blank advanced problem
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
</ActionRow>
|
||||
@@ -2040,7 +1888,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -2093,53 +1943,13 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Provisional
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
<Radio
|
||||
id="draganddrop"
|
||||
value="draganddrop"
|
||||
>
|
||||
Drag and drop (deprecated version)
|
||||
</Radio>
|
||||
<ActionRow.Spacer />
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div
|
||||
className="text-gray-300 text-left"
|
||||
>
|
||||
{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 { }
|
||||
}
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
<ActionRow
|
||||
className="border-primary-100 border-bottom m-0 py-3 w-100"
|
||||
>
|
||||
@@ -2177,7 +1987,9 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -2230,12 +2042,24 @@ exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problem
|
||||
}
|
||||
placement="right"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="text-gray-500"
|
||||
>
|
||||
Not supported
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</ActionRow>
|
||||
</RadioSet>
|
||||
</Form.Group>
|
||||
</div>
|
||||
<Hyperlink
|
||||
destination="https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/create_exercises_and_tools.html#advanced"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about advanced problem types"
|
||||
description="Label for Learn more about advanced problem types button"
|
||||
id="authoring.problemEditor.advanceProblem.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</Col>
|
||||
`;
|
||||
|
||||
@@ -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`] = `
|
||||
<div
|
||||
<Container
|
||||
className="bg-light-300 rounded p-4"
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="small"
|
||||
>
|
||||
Multi Select Problem
|
||||
Multi-select problem
|
||||
</div>
|
||||
<Image
|
||||
alt="A preview illustration of a {problemType, select,
|
||||
@@ -34,22 +40,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is ch
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn More"
|
||||
description="Label for Learn More button"
|
||||
defaultMessage="Learn more"
|
||||
description="Label for Learn more button"
|
||||
id="authoring.problemEditor.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`Preview snapshots snapshots: renders as expected with problemType is multiplechoiceresponse 1`] = `
|
||||
<div
|
||||
<Container
|
||||
className="bg-light-300 rounded p-4"
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="small"
|
||||
>
|
||||
Single Select Problem
|
||||
Single select problem
|
||||
</div>
|
||||
<Image
|
||||
alt="A preview illustration of a {problemType, select,
|
||||
@@ -74,22 +86,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is mu
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn More"
|
||||
description="Label for Learn More button"
|
||||
defaultMessage="Learn more"
|
||||
description="Label for Learn more button"
|
||||
id="authoring.problemEditor.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`Preview snapshots snapshots: renders as expected with problemType is numericalresponse 1`] = `
|
||||
<div
|
||||
<Container
|
||||
className="bg-light-300 rounded p-4"
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="small"
|
||||
>
|
||||
Numeric Response Problem
|
||||
Numerical input problem
|
||||
</div>
|
||||
<Image
|
||||
alt="A preview illustration of a {problemType, select,
|
||||
@@ -114,22 +132,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is nu
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn More"
|
||||
description="Label for Learn More button"
|
||||
defaultMessage="Learn more"
|
||||
description="Label for Learn more button"
|
||||
id="authoring.problemEditor.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`Preview snapshots snapshots: renders as expected with problemType is optionresponse 1`] = `
|
||||
<div
|
||||
<Container
|
||||
className="bg-light-300 rounded p-4"
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="small"
|
||||
>
|
||||
Dropdown Problem
|
||||
Dropdown problem
|
||||
</div>
|
||||
<Image
|
||||
alt="A preview illustration of a {problemType, select,
|
||||
@@ -154,22 +178,28 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is op
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn More"
|
||||
description="Label for Learn More button"
|
||||
defaultMessage="Learn more"
|
||||
description="Label for Learn more button"
|
||||
id="authoring.problemEditor.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`Preview snapshots snapshots: renders as expected with problemType is stringresponse 1`] = `
|
||||
<div
|
||||
<Container
|
||||
className="bg-light-300 rounded p-4"
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="small"
|
||||
>
|
||||
Text Input Problem
|
||||
Text input problem
|
||||
</div>
|
||||
<Image
|
||||
alt="A preview illustration of a {problemType, select,
|
||||
@@ -194,10 +224,10 @@ exports[`Preview snapshots snapshots: renders as expected with problemType is st
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn More"
|
||||
description="Label for Learn More button"
|
||||
defaultMessage="Learn more"
|
||||
description="Label for Learn more button"
|
||||
id="authoring.problemEditor.learnMoreButtonLabel.label"
|
||||
/>
|
||||
</Hyperlink>
|
||||
</div>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = `
|
||||
<Fragment>
|
||||
<Container
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
onChange={[Function]}
|
||||
@@ -10,43 +17,48 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = `
|
||||
>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="multiplechoiceresponse"
|
||||
type="radio"
|
||||
value="multiplechoiceresponse"
|
||||
>
|
||||
Single Select Problem
|
||||
Single select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="choiceresponse"
|
||||
type="radio"
|
||||
value="choiceresponse"
|
||||
>
|
||||
Multi Select Problem
|
||||
Multi-select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="optionresponse"
|
||||
type="radio"
|
||||
value="optionresponse"
|
||||
>
|
||||
Dropdown Problem
|
||||
Dropdown
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="numericalresponse"
|
||||
type="radio"
|
||||
value="numericalresponse"
|
||||
>
|
||||
Numeric Response Problem
|
||||
Numerical input
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="stringresponse"
|
||||
type="radio"
|
||||
value="stringresponse"
|
||||
>
|
||||
Text Input Problem
|
||||
Text input
|
||||
</SelectableBox>
|
||||
</SelectableBox.Set>
|
||||
<Button
|
||||
@@ -55,16 +67,23 @@ exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = `
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Advance problem types"
|
||||
defaultMessage="Advanced problem types"
|
||||
description="Button label for advance problem types option"
|
||||
id="authoring.problemEditor.problemSelect.advanceButton.label"
|
||||
/>
|
||||
</Button>
|
||||
</Fragment>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = `
|
||||
<Fragment>
|
||||
<Container
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
onChange={[Function]}
|
||||
@@ -73,43 +92,48 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = `
|
||||
>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="multiplechoiceresponse"
|
||||
type="radio"
|
||||
value="multiplechoiceresponse"
|
||||
>
|
||||
Single Select Problem
|
||||
Single select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="choiceresponse"
|
||||
type="radio"
|
||||
value="choiceresponse"
|
||||
>
|
||||
Multi Select Problem
|
||||
Multi-select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="optionresponse"
|
||||
type="radio"
|
||||
value="optionresponse"
|
||||
>
|
||||
Dropdown Problem
|
||||
Dropdown
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="numericalresponse"
|
||||
type="radio"
|
||||
value="numericalresponse"
|
||||
>
|
||||
Numeric Response Problem
|
||||
Numerical input
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="stringresponse"
|
||||
type="radio"
|
||||
value="stringresponse"
|
||||
>
|
||||
Text Input Problem
|
||||
Text input
|
||||
</SelectableBox>
|
||||
</SelectableBox.Set>
|
||||
<Button
|
||||
@@ -118,16 +142,23 @@ exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = `
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Advance problem types"
|
||||
defaultMessage="Advanced problem types"
|
||||
description="Button label for advance problem types option"
|
||||
id="authoring.problemEditor.problemSelect.advanceButton.label"
|
||||
/>
|
||||
</Button>
|
||||
</Fragment>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`ProblemTypeSelect snapshot NUMERIC 1`] = `
|
||||
<Fragment>
|
||||
<Container
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
onChange={[Function]}
|
||||
@@ -136,43 +167,48 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = `
|
||||
>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="multiplechoiceresponse"
|
||||
type="radio"
|
||||
value="multiplechoiceresponse"
|
||||
>
|
||||
Single Select Problem
|
||||
Single select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="choiceresponse"
|
||||
type="radio"
|
||||
value="choiceresponse"
|
||||
>
|
||||
Multi Select Problem
|
||||
Multi-select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="optionresponse"
|
||||
type="radio"
|
||||
value="optionresponse"
|
||||
>
|
||||
Dropdown Problem
|
||||
Dropdown
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="numericalresponse"
|
||||
type="radio"
|
||||
value="numericalresponse"
|
||||
>
|
||||
Numeric Response Problem
|
||||
Numerical input
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="stringresponse"
|
||||
type="radio"
|
||||
value="stringresponse"
|
||||
>
|
||||
Text Input Problem
|
||||
Text input
|
||||
</SelectableBox>
|
||||
</SelectableBox.Set>
|
||||
<Button
|
||||
@@ -181,16 +217,23 @@ exports[`ProblemTypeSelect snapshot NUMERIC 1`] = `
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Advance problem types"
|
||||
defaultMessage="Advanced problem types"
|
||||
description="Button label for advance problem types option"
|
||||
id="authoring.problemEditor.problemSelect.advanceButton.label"
|
||||
/>
|
||||
</Button>
|
||||
</Fragment>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = `
|
||||
<Fragment>
|
||||
<Container
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
onChange={[Function]}
|
||||
@@ -199,43 +242,48 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = `
|
||||
>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="multiplechoiceresponse"
|
||||
type="radio"
|
||||
value="multiplechoiceresponse"
|
||||
>
|
||||
Single Select Problem
|
||||
Single select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="choiceresponse"
|
||||
type="radio"
|
||||
value="choiceresponse"
|
||||
>
|
||||
Multi Select Problem
|
||||
Multi-select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="optionresponse"
|
||||
type="radio"
|
||||
value="optionresponse"
|
||||
>
|
||||
Dropdown Problem
|
||||
Dropdown
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="numericalresponse"
|
||||
type="radio"
|
||||
value="numericalresponse"
|
||||
>
|
||||
Numeric Response Problem
|
||||
Numerical input
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="stringresponse"
|
||||
type="radio"
|
||||
value="stringresponse"
|
||||
>
|
||||
Text Input Problem
|
||||
Text input
|
||||
</SelectableBox>
|
||||
</SelectableBox.Set>
|
||||
<Button
|
||||
@@ -244,16 +292,23 @@ exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = `
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Advance problem types"
|
||||
defaultMessage="Advanced problem types"
|
||||
description="Button label for advance problem types option"
|
||||
id="authoring.problemEditor.problemSelect.advanceButton.label"
|
||||
/>
|
||||
</Button>
|
||||
</Fragment>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = `
|
||||
<Fragment>
|
||||
<Container
|
||||
style={
|
||||
Object {
|
||||
"height": "400px",
|
||||
"width": "494px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
onChange={[Function]}
|
||||
@@ -262,43 +317,48 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = `
|
||||
>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="multiplechoiceresponse"
|
||||
type="radio"
|
||||
value="multiplechoiceresponse"
|
||||
>
|
||||
Single Select Problem
|
||||
Single select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="choiceresponse"
|
||||
type="radio"
|
||||
value="choiceresponse"
|
||||
>
|
||||
Multi Select Problem
|
||||
Multi-select
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="optionresponse"
|
||||
type="radio"
|
||||
value="optionresponse"
|
||||
>
|
||||
Dropdown Problem
|
||||
Dropdown
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="numericalresponse"
|
||||
type="radio"
|
||||
value="numericalresponse"
|
||||
>
|
||||
Numeric Response Problem
|
||||
Numerical input
|
||||
</SelectableBox>
|
||||
<SelectableBox
|
||||
aria-label="checkbox"
|
||||
className="border border-light-400 text-primary-500 shadow-none"
|
||||
id="stringresponse"
|
||||
type="radio"
|
||||
value="stringresponse"
|
||||
>
|
||||
Text Input Problem
|
||||
Text input
|
||||
</SelectableBox>
|
||||
</SelectableBox.Set>
|
||||
<Button
|
||||
@@ -307,10 +367,10 @@ exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = `
|
||||
variant="link"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Advance problem types"
|
||||
defaultMessage="Advanced problem types"
|
||||
description="Button label for advance problem types option"
|
||||
id="authoring.problemEditor.problemSelect.advanceButton.label"
|
||||
/>
|
||||
</Button>
|
||||
</Fragment>
|
||||
</Container>
|
||||
`;
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<SelectTypeWrapper onClose={onClose} selected={selected}>
|
||||
<Row className="justify-content-center align-items-center m-4">
|
||||
<Row className="justify-content-center">
|
||||
{(!Object.values(AdvanceProblemKeys).includes(selected)) ? (
|
||||
<>
|
||||
<Col>
|
||||
<ProblemTypeSelect selected={selected} setSelected={setSelected} />
|
||||
</Col>
|
||||
<Col>
|
||||
<Preview problemType={selected} />
|
||||
</Col>
|
||||
</>
|
||||
<Stack direction="horizontal" gap={4} className="flex-wrap">
|
||||
<ProblemTypeSelect selected={selected} setSelected={setSelected} />
|
||||
<Preview problemType={selected} />
|
||||
</Stack>
|
||||
) : <AdvanceTypeSelect selected={selected} setSelected={setSelected} />}
|
||||
</Row>
|
||||
</SelectTypeWrapper>
|
||||
|
||||
@@ -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 `<problem></problem>` 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 {};
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ export const checkboxesOLXWithFeedbackAndHintsOLX = {
|
||||
},
|
||||
],
|
||||
},
|
||||
question: '<p>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.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>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.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<choiceresponse>
|
||||
<p>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.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<checkboxgroup>
|
||||
<choice correct="true">
|
||||
@@ -160,11 +160,11 @@ export const dropdownOLXWithFeedbackAndHintsOLX = {
|
||||
},
|
||||
],
|
||||
},
|
||||
question: '<p>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.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>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.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<optionresponse>
|
||||
<p>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.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<optioninput>
|
||||
<option correct="false">
|
||||
@@ -233,11 +233,11 @@ export const mutlipleChoiceWithFeedbackAndHintsOLX = {
|
||||
},
|
||||
],
|
||||
},
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for multiple choice with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for multiple choice with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<multiplechoiceresponse>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for multiple choice with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<choicegroup>
|
||||
<choice correct="false">
|
||||
@@ -299,10 +299,10 @@ export const numericInputWithFeedbackAndHintsOLX = {
|
||||
},
|
||||
],
|
||||
},
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for numerical input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for numerical input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for numerical input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<numericalresponse answer="100">
|
||||
<responseparam type="tolerance" default="5"></responseparam>
|
||||
@@ -373,11 +373,11 @@ export const textInputWithFeedbackAndHintsOLX = {
|
||||
},
|
||||
},
|
||||
},
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for text input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for text input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<stringresponse answer="the correct answer" type="ci">
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for text input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<correcthint>You can specify optional feedback like this, which appears after this answer is submitted.</correcthint>
|
||||
<additional_answer answer="optional acceptable variant of the correct answer"></additional_answer>
|
||||
@@ -452,11 +452,11 @@ export const textInputWithFeedbackAndHintsOLXWithMultipleAnswers = {
|
||||
},
|
||||
},
|
||||
},
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for text input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for text input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<stringresponse answer="the correct answer" type="ci">
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for text input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<correcthint>You can specify optional feedback like this, which appears after this answer is submitted.</correcthint>
|
||||
<additional_answer answer="300">
|
||||
@@ -531,10 +531,10 @@ export const numericInputWithFeedbackAndHintsOLXException = {
|
||||
},
|
||||
],
|
||||
},
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for numerical input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><bold>Add the question text, or prompt, here. This text is required.</bold><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
question: '<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for numerical input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p><strong>Add the question text, or prompt, here. This text is required.</strong><em>You can add an optional tip or note related to the prompt like this.</em>',
|
||||
buildOLX: `<problem>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for numerical input with hints and feedback problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<bold>Add the question text, or prompt, here. This text is required.</bold>
|
||||
<strong>Add the question text, or prompt, here. This text is required.</strong>
|
||||
<em>You can add an optional tip or note related to the prompt like this.</em>
|
||||
<numericalresponse answer="300">
|
||||
<additional_answer answer="100">
|
||||
@@ -553,3 +553,17 @@ export const numericInputWithFeedbackAndHintsOLXException = {
|
||||
</problem>
|
||||
`,
|
||||
};
|
||||
export const advancedProblemOlX = {
|
||||
rawOLX: `<problem>
|
||||
<formularesponse type="ci" samples="R_1,R_2,R_3@1,2,3:3,4,5#10" answer="R_1*R_2/R_3">
|
||||
<p>You can use this template as a guide to the OLX markup to use for math expression problems. Edit this component to replace the example with your own assessment.</p>
|
||||
<label>Add the question text, or prompt, here. This text is required. Example: Write an expression for the product of R_1, R_2, and the inverse of R_3.</label>
|
||||
<description>You can add an optional tip or note related to the prompt like this. Example: To test this example, the correct answer is R_1*R_2/R_3</description>
|
||||
<responseparam type="tolerance" default="0.00001"/>
|
||||
<formulaequationinput size="40"/>
|
||||
</formularesponse>
|
||||
</problem>`,
|
||||
};
|
||||
export const blankProblemOLX = {
|
||||
rawOLX: '<problem></problem>',
|
||||
};
|
||||
|
||||
@@ -217,7 +217,7 @@ export const numericWithHints = {
|
||||
scoring: {
|
||||
weight: 2.5,
|
||||
attempts: {
|
||||
unlimited: true,
|
||||
unlimited: false,
|
||||
number: 0,
|
||||
},
|
||||
},
|
||||
@@ -288,7 +288,7 @@ export const textInputWithHints = {
|
||||
scoring: {
|
||||
weight: 2.5,
|
||||
attempts: {
|
||||
unlimited: true,
|
||||
unlimited: false,
|
||||
number: 0,
|
||||
},
|
||||
},
|
||||
@@ -315,7 +315,7 @@ not=optional incorrect answer such as a frequent misconception {{You can specify
|
||||
},
|
||||
};
|
||||
|
||||
export const sigleSelectWithHints = {
|
||||
export const singleSelectWithHints = {
|
||||
state: {
|
||||
rawOLX: '<problem>\n<p>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.</p>\n\n<label>Add the question text, or prompt, here. This text is required.</label>\n<description>You can add an optional tip or note related to the prompt like this.</description>\n<multiplechoiceresponse>\n <choicegroup type="MultipleChoice">\n <choice correct="true">a correct answer <choicehint>selected: You can specify optional feedback that appears after the learner selects and submits this answer. }, { unselected: You can specify optional feedback that appears after the learner clears and submits this answer.</choicehint></choice>\n <choice correct="false">an incorrect answer</choice>\n <choice correct="false">an incorrect answer <choicehint>selected: You can specify optional feedback for none, all, or a subset of the answers. }, { unselected: You can specify optional feedback for selected answers, cleared answers, or both.</choicehint></choice>\n <choice correct="false">an incorrect answer again</choice>\n </choicegroup>\n</multiplechoiceresponse>\n<choiceresponse>\n <checkboxgroup>\n <compoundhint value="A B D">You can specify optional feedback for a combination of answers which appears after the specified set of answers is submitted.</compoundhint>\n <compoundhint value="A B C D">You can specify optional feedback for one, several, or all answer combinations.</compoundhint>\n </checkboxgroup>\n</choiceresponse>\n\n\n<demandhint>\n <hint>You can add an optional hint like this. Problems that have a hint include a hint button, and this text appears the first time learners select the button.</hint>\n <hint>If you add more than one hint, a different hint appears each time learners select the hint button.</hint>\n</demandhint>\n</problem>',
|
||||
problemType: 'SINGLESELECT',
|
||||
@@ -362,7 +362,7 @@ export const sigleSelectWithHints = {
|
||||
weight: 0,
|
||||
attempts: {
|
||||
unlimited: true,
|
||||
number: 0,
|
||||
number: null,
|
||||
},
|
||||
},
|
||||
timeBetween: 0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
useRef, useCallback, useState, useEffect,
|
||||
} from 'react';
|
||||
import { ProblemTypeKeys } from '../../data/constants/problem';
|
||||
import tinyMCEStyles from '../../data/constants/tinyMCEStyles';
|
||||
import { StrictDict } from '../../utils';
|
||||
import * as module from './hooks';
|
||||
|
||||
@@ -19,6 +19,13 @@ export const problemEditorConfig = ({
|
||||
setEditorRef(editor);
|
||||
},
|
||||
initialValue: question || '',
|
||||
init: {
|
||||
skin: false,
|
||||
content_css: false,
|
||||
content_style: tinyMCEStyles,
|
||||
menubar: false,
|
||||
branding: false,
|
||||
},
|
||||
onFocusOut: () => {
|
||||
const content = editorRef.current.getContent();
|
||||
updateQuestion(content);
|
||||
@@ -34,8 +41,3 @@ export const prepareEditorRef = () => {
|
||||
useEffect(() => setRefReady(true), [setRefReady]);
|
||||
return { editorRef, refReady, setEditorRef };
|
||||
};
|
||||
|
||||
export const initializeAnswerContainer = (problemType) => {
|
||||
const hasSingleAnswer = problemType === ProblemTypeKeys.DROPDOWN || problemType === ProblemTypeKeys.SINGLESELECT;
|
||||
return { hasSingleAnswer };
|
||||
};
|
||||
|
||||
@@ -17,8 +17,6 @@ export const ProblemEditor = ({
|
||||
blockValue,
|
||||
initializeProblemEditor,
|
||||
}) => {
|
||||
React.useEffect(() => initializeProblemEditor(blockValue), [blockValue]);
|
||||
// TODO: INTL MSG, Add LOAD FAILED ERROR using BLOCKFAILED
|
||||
if (!blockFinished || !studioViewFinished) {
|
||||
return (
|
||||
<div className="text-center p-6">
|
||||
@@ -31,6 +29,8 @@ export const ProblemEditor = ({
|
||||
);
|
||||
}
|
||||
// once data is loaded, init store
|
||||
React.useEffect(() => initializeProblemEditor(blockValue), [blockValue]);
|
||||
// TODO: INTL MSG, Add LOAD FAILED ERROR using BLOCKFAILED
|
||||
|
||||
if (problemType === null) {
|
||||
return (<SelectTypeModal onClose={onClose} />);
|
||||
|
||||
@@ -236,6 +236,13 @@ exports[`TextEditor snapshots loaded, raw editor 1`] = `
|
||||
/>
|
||||
</Toast>
|
||||
<RawEditor
|
||||
content={
|
||||
Object {
|
||||
"data": Object {
|
||||
"data": "eDiTablE Text",
|
||||
},
|
||||
}
|
||||
}
|
||||
editorRef={
|
||||
Object {
|
||||
"current": Object {
|
||||
@@ -243,13 +250,7 @@ exports[`TextEditor snapshots loaded, raw editor 1`] = `
|
||||
},
|
||||
}
|
||||
}
|
||||
text={
|
||||
Object {
|
||||
"data": Object {
|
||||
"data": "eDiTablE Text",
|
||||
},
|
||||
}
|
||||
}
|
||||
lang="html"
|
||||
/>
|
||||
</div>
|
||||
</EditorContainer>
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
Button,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { basicSetup } from 'codemirror';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { html } from '@codemirror/lang-html';
|
||||
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import alphanumericMap from './constants';
|
||||
import * as module from './index';
|
||||
import messages from './messages';
|
||||
import './index.scss';
|
||||
|
||||
export const hooks = {
|
||||
|
||||
state: {
|
||||
showBtnEscapeHTML: (val) => React.useState(val),
|
||||
},
|
||||
|
||||
prepareShowBtnEscapeHTML: () => {
|
||||
const [visibility, setVisibility] = hooks.state.showBtnEscapeHTML(true);
|
||||
const hide = () => setVisibility(false);
|
||||
return { showBtnEscapeHTML: visibility, hideBtn: hide };
|
||||
},
|
||||
|
||||
createCodeMirrorDomNode: ({ ref, initialText, upstreamRef }) => {
|
||||
useEffect(() => {
|
||||
const cleanText = hooks.cleanHTML({ initialText });
|
||||
const state = EditorState.create({
|
||||
doc: cleanText,
|
||||
extensions: [basicSetup, html(), EditorView.lineWrapping],
|
||||
});
|
||||
const view = new EditorView({ state, parent: ref.current });
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
upstreamRef.current = view;
|
||||
view.focus();
|
||||
return () => {
|
||||
// called on cleanup
|
||||
view.destroy();
|
||||
};
|
||||
}, []);
|
||||
},
|
||||
cleanHTML: ({ initialText }) => {
|
||||
const translateRegex = new RegExp(`&(${Object.keys(alphanumericMap).join('|')});`, 'g');
|
||||
const translator = ($0, $1) => alphanumericMap[$1];
|
||||
return initialText.replace(translateRegex, translator);
|
||||
},
|
||||
escapeHTMLSpecialChars: ({ ref, hideBtn }) => {
|
||||
const text = ref.current.state.doc.toString(); let
|
||||
pos = 0;
|
||||
const changes = [];
|
||||
Object.keys(alphanumericMap).forEach(
|
||||
(escapedKeyword) => {
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
for (let next; (next = text.indexOf(alphanumericMap[escapedKeyword], pos)) > -1;) {
|
||||
changes.push({ from: next, to: next + 1, insert: `&${escapedKeyword};` });
|
||||
pos = next + 1;
|
||||
}
|
||||
},
|
||||
);
|
||||
ref.current.dispatch({ changes });
|
||||
hideBtn();
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export const CodeEditor = ({
|
||||
innerRef,
|
||||
value,
|
||||
// injected
|
||||
intl,
|
||||
}) => {
|
||||
const DOMref = useRef();
|
||||
const btnRef = useRef();
|
||||
module.hooks.createCodeMirrorDomNode({ ref: DOMref, initialText: value, upstreamRef: innerRef });
|
||||
const { showBtnEscapeHTML, hideBtn } = module.hooks.prepareShowBtnEscapeHTML();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id="CodeMirror" ref={DOMref} />
|
||||
{showBtnEscapeHTML && (
|
||||
<Button
|
||||
variant="tertiary"
|
||||
aria-label={intl.formatMessage(messages.escapeHTMLButtonLabel)}
|
||||
ref={btnRef}
|
||||
onClick={() => module.hooks.escapeHTMLSpecialChars({ ref: innerRef, hideBtn })}
|
||||
>
|
||||
<FormattedMessage {...messages.escapeHTMLButtonLabel} />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CodeEditor.propTypes = {
|
||||
innerRef: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.shape({ current: PropTypes.any }),
|
||||
]).isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(CodeEditor);
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Alert } from '@edx/paragon';
|
||||
|
||||
import CodeEditor from '../CodeEditor';
|
||||
|
||||
export const RawEditor = ({
|
||||
editorRef,
|
||||
text,
|
||||
}) => (
|
||||
<div style={{ padding: '10px 30px', height: '600px' }}>
|
||||
<Alert variant="danger">
|
||||
You are using the raw HTML editor.
|
||||
</Alert>
|
||||
{ text && text.data.data ? (
|
||||
<CodeEditor
|
||||
innerRef={editorRef}
|
||||
value={text.data.data}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
</div>
|
||||
);
|
||||
RawEditor.defaultProps = {
|
||||
editorRef: null,
|
||||
text: null,
|
||||
};
|
||||
RawEditor.propTypes = {
|
||||
editorRef: PropTypes.oneOfType([
|
||||
PropTypes.func,
|
||||
PropTypes.shape({ current: PropTypes.any }),
|
||||
]),
|
||||
text: PropTypes.shape({
|
||||
data: PropTypes.shape({ data: PropTypes.string }),
|
||||
}),
|
||||
};
|
||||
|
||||
export default RawEditor;
|
||||
@@ -12,7 +12,7 @@ import messages from './messages';
|
||||
import hooks from './hooks';
|
||||
import BaseModal from '../BaseModal';
|
||||
|
||||
import CodeEditor from '../CodeEditor';
|
||||
import CodeEditor from '../../../../sharedComponents/CodeEditor';
|
||||
|
||||
export const SourceCodeModal = ({
|
||||
isOpen,
|
||||
|
||||
@@ -32,7 +32,7 @@ import { RequestKeys } from '../../data/constants/requests';
|
||||
import EditorContainer from '../EditorContainer';
|
||||
import ImageUploadModal from './components/ImageUploadModal';
|
||||
import SourceCodeModal from './components/SourceCodeModal';
|
||||
import RawEditor from './components/RawEditor';
|
||||
import RawEditor from '../../sharedComponents/RawEditor';
|
||||
import * as hooks from './hooks';
|
||||
import messages from './messages';
|
||||
|
||||
@@ -64,7 +64,7 @@ export const TextEditor = ({
|
||||
return (
|
||||
<RawEditor
|
||||
editorRef={editorRef}
|
||||
text={blockValue}
|
||||
content={blockValue}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { Col, Form } from '@edx/paragon';
|
||||
|
||||
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { keyStore } from '../../../../../utils';
|
||||
import CollapsibleFormWidget from './CollapsibleFormWidget';
|
||||
import hooks from './hooks';
|
||||
import { durationFromValue } from './duration';
|
||||
import messages from './messages';
|
||||
|
||||
/**
|
||||
* Collapsible Form widget controlling video start and end times
|
||||
* Also displays the total run time of the video.
|
||||
*/
|
||||
export const DurationWidget = ({
|
||||
// injected
|
||||
intl,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const { duration } = hooks.widgetValues({
|
||||
dispatch,
|
||||
fields: { [hooks.selectorKeys.duration]: hooks.durationWidget },
|
||||
});
|
||||
const timeKeys = keyStore(duration.formValue);
|
||||
|
||||
const getTotalLabel = (startTime, stopTime, subtitle) => {
|
||||
if (!stopTime) {
|
||||
if (!startTime) {
|
||||
return intl.formatMessage(messages.fullVideoLength);
|
||||
}
|
||||
if (subtitle) {
|
||||
return intl.formatMessage(messages.startsAt, { startTime: durationFromValue(startTime) });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const total = stopTime - (startTime || 0);
|
||||
return intl.formatMessage(messages.total, { total: durationFromValue(total) });
|
||||
};
|
||||
|
||||
return (
|
||||
<CollapsibleFormWidget
|
||||
fontSize="x-small"
|
||||
title={intl.formatMessage(messages.durationTitle)}
|
||||
subtitle={getTotalLabel(duration.formValue.startTime, duration.formValue.stopTime, true)}
|
||||
>
|
||||
<FormattedMessage {...messages.durationDescription} />
|
||||
<Form.Row className="mt-4.5">
|
||||
<Form.Group as={Col}>
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.startTimeLabel)}
|
||||
onBlur={duration.onBlur(timeKeys.startTime)}
|
||||
onChange={duration.onChange(timeKeys.startTime)}
|
||||
onKeyDown={duration.onKeyDown(timeKeys.startTime)}
|
||||
value={duration.local.startTime}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage {...messages.durationHint} />
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Form.Group as={Col}>
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.stopTimeLabel)}
|
||||
onBlur={duration.onBlur(timeKeys.stopTime)}
|
||||
onChange={duration.onChange(timeKeys.stopTime)}
|
||||
onKeyDown={duration.onKeyDown(timeKeys.stopTime)}
|
||||
value={duration.local.stopTime}
|
||||
/>
|
||||
<Form.Control.Feedback>
|
||||
<FormattedMessage {...messages.durationHint} />
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
</Form.Row>
|
||||
<div className="mt-4">
|
||||
{getTotalLabel(duration.formValue.startTime, duration.formValue.stopTime)}
|
||||
</div>
|
||||
</CollapsibleFormWidget>
|
||||
);
|
||||
};
|
||||
|
||||
DurationWidget.propTypes = {
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(DurationWidget);
|
||||
@@ -1,22 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { formatMessage } from '../../../../../../testUtils';
|
||||
import { DurationWidget } from './DurationWidget';
|
||||
|
||||
describe('DurationWidget', () => {
|
||||
const props = {
|
||||
isError: false,
|
||||
subtitle: 'SuBTItle',
|
||||
title: 'tiTLE',
|
||||
// inject
|
||||
intl: { formatMessage },
|
||||
};
|
||||
describe('render', () => {
|
||||
test('snapshots: renders as expected with default props', () => {
|
||||
expect(
|
||||
shallow(<DurationWidget {...props} />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
exports[`DurationWidget render snapshots: renders as expected with default props 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
fontSize="x-small"
|
||||
subtitle="Full video length"
|
||||
subtitle="Total: 00:00:00"
|
||||
title="Duration"
|
||||
>
|
||||
<FormattedMessage
|
||||
@@ -14,7 +14,9 @@ exports[`DurationWidget render snapshots: renders as expected with default props
|
||||
<Form.Row
|
||||
className="mt-4.5"
|
||||
>
|
||||
<Form.Group>
|
||||
<Form.Group
|
||||
as="Col"
|
||||
>
|
||||
<Form.Control
|
||||
floatingLabel="Start time"
|
||||
onBlur={[Function]}
|
||||
@@ -30,7 +32,9 @@ exports[`DurationWidget render snapshots: renders as expected with default props
|
||||
/>
|
||||
</Form.Control.Feedback>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Group
|
||||
as="Col"
|
||||
>
|
||||
<Form.Control
|
||||
floatingLabel="Stop time"
|
||||
onBlur={[Function]}
|
||||
@@ -50,7 +54,7 @@ exports[`DurationWidget render snapshots: renders as expected with default props
|
||||
<div
|
||||
className="mt-4"
|
||||
>
|
||||
Full video length
|
||||
Total: 00:00:00
|
||||
</div>
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
`;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user