From 2896393c535ff21567bd91e68fcc35246de5466c Mon Sep 17 00:00:00 2001 From: connorhaugh <49422820+connorhaugh@users.noreply.github.com> Date: Thu, 22 Dec 2022 16:52:21 -0500 Subject: [PATCH] feat: add problem type select Co-authored-by: Kristin Aoki <42981026+KristinAoki@users.noreply.github.com> Co-authored-by: Raymond Zhou <56318341+rayzhou-bit@users.noreply.github.com> --- .../__snapshots__/TypeCard.test.jsx.snap | 52 +- .../components/EditProblemView/index.jsx | 4 + .../SelectTypeWrapper/SelectTypeFooter.jsx | 33 +- .../SelectTypeFooter.test.jsx | 55 + .../SelectTypeFooter.test.jsx.snap | 41 + .../__snapshots__/index.test.jsx.snap | 29 + .../SelectTypeWrapper/index.jsx | 10 +- .../SelectTypeWrapper/index.test.jsx | 33 + .../SelectTypeWrapper/messages.js | 24 + .../__snapshots__/index.test.jsx.snap | 24 + .../content/AdvanceTypeSelect.jsx | 92 + .../content/AdvanceTypeSelect.test.jsx | 55 + .../SelectTypeModal/content/Preview.jsx | 44 +- .../SelectTypeModal/content/Preview.test.jsx | 44 + .../content/ProblemTypeSelect.jsx | 46 +- .../content/ProblemTypeSelect.test.jsx | 39 + .../AdvanceTypeSelect.test.jsx.snap | 2241 +++++++++++++++++ .../__snapshots__/Preview.test.jsx.snap | 203 ++ .../ProblemTypeSelect.test.jsx.snap | 316 +++ .../SelectTypeModal/content/messages.js | 69 + .../components/SelectTypeModal/hooks.js | 55 +- .../components/SelectTypeModal/hooks.test.js | 168 ++ .../components/SelectTypeModal/index.jsx | 39 +- .../components/SelectTypeModal/index.test.jsx | 21 + .../ProblemEditor/data/OLXParser.js | 19 +- .../__snapshots__/index.test.jsx.snap | 40 +- .../__snapshots__/index.test.jsx.snap | 8 +- .../olxTemplates/circuitschematic.js | 92 + .../constants/olxTemplates/customgrader.js | 79 + .../constants/olxTemplates/drag_and_drop.js | 88 + .../constants/olxTemplates/formularesponse.js | 16 + .../constants/olxTemplates/imageresponse.js | 33 + .../olxTemplates/jsinput_response.js | 81 + .../olxTemplates/problem_with_hint.js | 46 + src/editors/data/constants/problem.js | 109 +- src/editors/data/constants/requests.js | 2 + src/editors/data/images/dropdown.png | Bin 0 -> 3170 bytes src/editors/data/images/multiSelect.png | Bin 0 -> 4690 bytes src/editors/data/images/numericalInput.png | Bin 0 -> 7320 bytes src/editors/data/images/singleSelect.png | Bin 0 -> 7893 bytes src/editors/data/images/textInput.png | Bin 0 -> 3945 bytes src/editors/data/redux/problem/reducers.js | 10 +- .../data/redux/thunkActions/problem.js | 31 +- .../data/redux/thunkActions/requests.js | 12 + src/editors/data/services/cms/api.js | 3 + src/editors/data/services/cms/mockApi.js | 16 +- src/editors/data/services/cms/urls.js | 4 + src/setupTest.js | 6 +- 48 files changed, 4277 insertions(+), 155 deletions(-) create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/SelectTypeFooter.test.jsx.snap create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.js create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js create mode 100644 src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx create mode 100644 src/editors/data/constants/olxTemplates/circuitschematic.js create mode 100644 src/editors/data/constants/olxTemplates/customgrader.js create mode 100644 src/editors/data/constants/olxTemplates/drag_and_drop.js create mode 100644 src/editors/data/constants/olxTemplates/formularesponse.js create mode 100644 src/editors/data/constants/olxTemplates/imageresponse.js create mode 100644 src/editors/data/constants/olxTemplates/jsinput_response.js create mode 100644 src/editors/data/constants/olxTemplates/problem_with_hint.js create mode 100644 src/editors/data/images/dropdown.png create mode 100644 src/editors/data/images/multiSelect.png create mode 100644 src/editors/data/images/numericalInput.png create mode 100644 src/editors/data/images/singleSelect.png create mode 100644 src/editors/data/images/textInput.png diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap index a110e60d1..251289f10 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/SettingsWidget/settingsComponents/__snapshots__/TypeCard.test.jsx.snap @@ -6,27 +6,11 @@ exports[`TypeCard snapshot snapshot: renders type setting card 1`] = ` title="Type" > - - + + + diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx index 604760210..5600f9e3a 100644 --- a/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx +++ b/src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx @@ -10,6 +10,7 @@ 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'; export const EditProblemView = ({ problemType, @@ -23,6 +24,9 @@ export const EditProblemView = ({ olx: reactOLXParser.buildOLX(), }; }; + if (Object.values(AdvanceProblemKeys).includes(problemType)) { + return `hello raw editor with ${problemType}`; + } return ( diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx index 8ecd629c4..e7f279fe7 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.jsx @@ -7,33 +7,38 @@ import { Button, ModalDialog, } from '@edx/paragon'; -import { FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n'; +import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import messages from './messages'; +import hooks from '../hooks'; import { actions } from '../../../../../data/redux'; export const SelectTypeFooter = ({ - selected, onCancel, - // Redux - onSelect, + selected, + // redux + setProblemType, + updateField, + // injected, + intl, }) => ( -
+
@@ -47,14 +52,18 @@ SelectTypeFooter.defaultProps = { SelectTypeFooter.propTypes = { onCancel: PropTypes.func.isRequired, selected: PropTypes.string, - onSelect: PropTypes.func.isRequired, + setProblemType: PropTypes.func.isRequired, + updateField: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, }; export const mapStateToProps = () => ({ }); export const mapDispatchToProps = { - initializeEditor: actions.problem.onSelect, + setProblemType: actions.problem.setProblemType, + updateField: actions.problem.updateField, }; export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(SelectTypeFooter)); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx new file mode 100644 index 000000000..9d22bbf52 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/SelectTypeFooter.test.jsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Button } from '@edx/paragon'; +import { formatMessage } from '../../../../../../testUtils'; +import * as module from './SelectTypeFooter'; +import hooks from '../hooks'; +import { actions } from '../../../../../data/redux'; + +jest.mock('../hooks', () => ({ + onSelect: jest.fn().mockName('onSelect'), +})); + +describe('SelectTypeFooter', () => { + const props = { + onCancel: jest.fn().mockName('onCancel'), + selected: null, + // redux + setProblemType: jest.fn().mockName('setProblemType'), + // inject + intl: { formatMessage }, + }; + + test('snapshot', () => { + expect(shallow()).toMatchSnapshot(); + }); + + describe('behavior', () => { + let el; + beforeEach(() => { + el = shallow(); + }); + test('close behavior is linked to modal onCancel', () => { + const expected = props.onCancel; + expect(el.find(Button).first().props().onClick) + .toEqual(expected); + }); + test('select behavior is linked to modal onSelect', () => { + const expected = hooks.onSelect(props.setProblemType, props.selected); + expect(el.find(Button).last().props().onClick) + .toEqual(expected); + }); + }); + + describe('mapStateToProps', () => { + test('is empty', () => { + expect(module.mapStateToProps()).toEqual({}); + }); + }); + describe('mapDispatchToProps', () => { + test('loads setProblemType from problem.setProblemType actions', () => { + expect(module.mapDispatchToProps.setProblemType).toEqual(actions.problem.setProblemType); + }); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/SelectTypeFooter.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/SelectTypeFooter.test.jsx.snap new file mode 100644 index 000000000..760a9d35c --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/SelectTypeFooter.test.jsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SelectTypeFooter snapshot 1`] = ` +
+ + + + + + + +
+`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap new file mode 100644 index 000000000..d88ab2baf --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/__snapshots__/index.test.jsx.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SelectTypeWrapper snapshot 1`] = ` +
+ + +

+ Select Problem type +

+
+ +
+
+
+ +

+ test child +

+
+ +
+`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx index 4e2b23aa1..b8c63786d 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/index.jsx @@ -8,9 +8,9 @@ import SelectTypeFooter from './SelectTypeFooter'; import * as hooks from '../../../../EditorContainer/hooks'; export const SelectTypeWrapper = ({ - selected, - onClose, children, + onClose, + selected, }) => { const handleCancelClicked = hooks.handleCancelClicked({ onClose }); @@ -28,7 +28,9 @@ export const SelectTypeWrapper = ({
- {children} + + {children} + ({ + handleCancelClicked: jest.fn().mockName('handleCancelClicked'), +})); + +describe('SelectTypeWrapper', () => { + const props = { + children: (

test child

), + onClose: jest.fn(), + selected: 'iMAsElecTedValUE', + }; + + test('snapshot', () => { + expect(shallow()).toMatchSnapshot(); + }); + + describe('behavior', () => { + let el; + beforeEach(() => { + el = shallow(); + }); + test('close behavior is linked to modal onClose', () => { + const expected = handleCancelClicked({ onClose: props.onClose }); + expect(el.find(IconButton).props().onClick) + .toEqual(expected); + }); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.js new file mode 100644 index 000000000..e4e34350f --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/SelectTypeWrapper/messages.js @@ -0,0 +1,24 @@ +export const messages = { + cancelButtonLabel: { + id: 'authoring.problemeditor.selecttype.cancelButton.label', + defaultMessage: 'Cancel', + description: 'Label for cancel button.', + }, + cancelButtonAriaLabel: { + id: 'authoring.problemeditor.selecttype.cancelButton.ariaLabel', + defaultMessage: 'Cancel', + description: 'Screen reader label for cancel button.', + }, + selectButtonLabel: { + id: 'authoring.problemeditor.selecttype.selectButton.label', + defaultMessage: 'Select', + description: 'Label for select button.', + }, + selectButtonAriaLabel: { + id: 'authoring.problemeditor.selecttype.selectButton.ariaLabel', + defaultMessage: 'Select', + description: 'Screen reader label for select button.', + }, +}; + +export default messages; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap new file mode 100644 index 000000000..c111eeb42 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/__snapshots__/index.test.jsx.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SelectTypeModal snapshot 1`] = ` + + + + + + + + + + +`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx new file mode 100644 index 000000000..2ecfa2568 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { + Form, + ActionRow, + IconButton, + Icon, + OverlayTrigger, + Tooltip, +} from '@edx/paragon'; +import { ArrowBack } from '@edx/paragon/icons'; +import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { AdvanceProblems, ProblemTypeKeys } from '../../../../../data/constants/problem'; +import messages from './messages'; + +export const AdvanceTypeSelect = ({ + selected, + setSelected, + // injected + intl, +}) => { + const handleChange = e => { setSelected(e.target.value); }; + return ( +
+ + + setSelected(ProblemTypeKeys.SINGLESELECT)} /> + + + + + + + + {Object.entries(AdvanceProblems).map(([type, data]) => { + if (data.status !== '') { + return ( + + + {intl.formatMessage(messages.advanceProblemTypeLabel, { problemType: data.title })} + + + +
+ {intl.formatMessage(messages.supportStatusTooltipMessage, { supportStatus: data.status.replace(' ', '_') })} +
+ + )} + > +
+ {intl.formatMessage(messages.problemSupportStatus, { supportStatus: data.status })} +
+
+
+ ); + } + return ( + + + {intl.formatMessage(messages.advanceProblemTypeLabel, { problemType: data.title })} + + + + ); + })} +
+
+
+ ); +}; + +AdvanceTypeSelect.defaultProps = { + selected: null, +}; + +AdvanceTypeSelect.propTypes = { + selected: PropTypes.string, + setSelected: PropTypes.func.isRequired, + // injected + intl: intlShape.isRequired, +}; + +export default injectIntl(AdvanceTypeSelect); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx new file mode 100644 index 000000000..d4152a42e --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/AdvanceTypeSelect.test.jsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { formatMessage } from '../../../../../../testUtils'; +import * as module from './AdvanceTypeSelect'; + +describe('AdvanceTypeSelect', () => { + const props = { + intl: { formatMessage }, + selected: 'blankadvanced', + setSelected: jest.fn().mockName('setSelect'), + }; + describe('snapshots', () => { + test('snapshots: renders as expected with default props', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is circuitschematic', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is customgrader', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is drag_and_drop', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is formularesponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is imageresponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is jsinput_response', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is problem_with_hint', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx index d894f22bf..b76b9b9b0 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.jsx @@ -1,28 +1,43 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { Hyperlink, Image } from '@edx/paragon'; +import { + FormattedMessage, + injectIntl, + intlShape, +} from '@edx/frontend-platform/i18n'; +import messages from './messages'; import { ProblemTypes } from '../../../../../data/constants/problem'; -const Preview = ({ +export const Preview = ({ problemType, + // injected + intl, }) => { if (problemType === null) { return null; } const data = ProblemTypes[problemType]; return ( -
-
-

{data.title}

+
+
+ {intl.formatMessage(messages.previewTitle, { previewTitle: data.title })}
-
- {data.preview} -
-
-

{data.description}

-
-
-

{data.helpLink}

+ {intl.formatMessage(messages.previewAltText, +
+ {intl.formatMessage(messages.previewDescription, { previewDescription: data.description })}
+ + +
); }; @@ -30,8 +45,11 @@ const Preview = ({ Preview.defaultProps = { problemType: null, }; + Preview.propTypes = { problemType: PropTypes.string, + // injected + intl: intlShape.isRequired, }; -export default Preview; +export default injectIntl(Preview); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx new file mode 100644 index 000000000..74ad5d203 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/Preview.test.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { formatMessage } from '../../../../../../testUtils'; +import * as module from './Preview'; + +describe('Preview', () => { + const props = { + intl: { formatMessage }, + problemType: null, + }; + describe('snapshots', () => { + test('snapshots: renders as expected with default props', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is stringresponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is numericalresponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is optionresponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is choiceresponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + test('snapshots: renders as expected with problemType is multiplechoiceresponse', () => { + expect( + shallow(), + ).toMatchSnapshot(); + }); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx index 80b9de0e7..e2c8fea06 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.jsx @@ -1,31 +1,45 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Form } from '@edx/paragon'; -import { ProblemTypes } from '../../../../../data/constants/problem'; +import { Button, SelectableBox } from '@edx/paragon'; +import { FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n'; +import { ProblemTypes, ProblemTypeKeys, AdvanceProblemKeys } from '../../../../../data/constants/problem'; +import messages from './messages'; -// TODO: problemtype -const ProblemTypeSelect = ({ - // redux +export const ProblemTypeSelect = ({ + selected, setSelected, }) => { const handleChange = e => setSelected(e.target.value); + const handleClick = () => setSelected(AdvanceProblemKeys.BLANK); + const settings = { 'aria-label': 'checkbox', type: 'radio' }; + return ( - - + - {ProblemTypes.SINGLESELECT.title} - {ProblemTypes.MULTISELECT.title} - {ProblemTypes.DROPDOWN.title} - {ProblemTypes.NUMERIC.title} - {ProblemTypes.TEXTINPUT.title} - - + {Object.values(ProblemTypeKeys).map((key) => ( + key !== 'advanced' + ? ( + + {ProblemTypes[key].title} + + ) + : null + ))} + + + ); }; ProblemTypeSelect.propTypes = { + selected: PropTypes.string.isRequired, setSelected: PropTypes.func.isRequired, }; -export default ProblemTypeSelect; +export default injectIntl(ProblemTypeSelect); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx new file mode 100644 index 000000000..1cea66e9f --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/ProblemTypeSelect.test.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { ProblemTypeKeys } from '../../../../../data/constants/problem'; +import * as module from './ProblemTypeSelect'; + +describe('ProblemTypeSelect', () => { + const props = { + selected: null, + setSelected: jest.fn(), + }; + + describe('snapshot', () => { + test('SINGLESELECT', () => { + expect(shallow( + , + )).toMatchSnapshot(); + }); + test('MULTISELECT', () => { + expect(shallow( + , + )).toMatchSnapshot(); + }); + test('DROPDOWN', () => { + expect(shallow( + , + )).toMatchSnapshot(); + }); + test('NUMERIC', () => { + expect(shallow( + , + )).toMatchSnapshot(); + }); + test('TEXTINPUT', () => { + expect(shallow( + , + )).toMatchSnapshot(); + }); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap new file mode 100644 index 000000000..040a7ca10 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/AdvanceTypeSelect.test.jsx.snap @@ -0,0 +1,2241 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with default props 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is circuitschematic 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is customgrader 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is drag_and_drop 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is formularesponse 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is imageresponse 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is jsinput_response 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; + +exports[`AdvanceTypeSelect snapshots snapshots: renders as expected with problemType is problem_with_hint 1`] = ` +
+ + + + + + + + + + + + + Blank advance problem + + + + + + Circuit schematic builder + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Custom JavaScript display and grading + + + + + + Custom Python-evaluated input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Provisional +
+
+
+ + + Drag and drop (deprecated version) + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Image mapped input + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+ + + Math expression input + + + + + + Problem with adaptive hint + + + +
+ {supportStatus, select, + Provisional {Provisionally supported tools might lack the robustness of functionality + that your courses require. edX does not have control over the quality of the software, + or of the content that can be provided using these tools. + + + + Test these tools thoroughly before using them in your course, especially in graded + sections. Complete documentstion might not be available for provisionally supported + tools, or documentation might be available from sources other than edX.} + Not_supported {Tools with no support are not maintained by edX, and might be deprecated + in the future. They are not recommened for use in courses due to non-compliance with one + or more of the base requirements, such as testing, accessibility, internationalization, + and documentation.} + other { } + } +
+ + } + placement="right" + > +
+ Not supported +
+
+
+
+
+
+`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap new file mode 100644 index 000000000..8dd2e23bf --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/Preview.test.jsx.snap @@ -0,0 +1,203 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Preview snapshots snapshots: renders as expected with default props 1`] = `""`; + +exports[`Preview snapshots snapshots: renders as expected with problemType is choiceresponse 1`] = ` +
+
+ Multi Select Problem +
+ A preview illustration of a {problemType, select,
+      multiplechoiceresponse {single select}
+      stringreponse {text input}
+      numericalresponse {numerical input}
+      optionresponse {dropdown}
+      choiceresponse {multiple select}
+      other {null}
+    } problem +
+ Specify one or more correct answers from a list of possible options. +
+ + + +
+`; + +exports[`Preview snapshots snapshots: renders as expected with problemType is multiplechoiceresponse 1`] = ` +
+
+ Single Select Problem +
+ A preview illustration of a {problemType, select,
+      multiplechoiceresponse {single select}
+      stringreponse {text input}
+      numericalresponse {numerical input}
+      optionresponse {dropdown}
+      choiceresponse {multiple select}
+      other {null}
+    } problem +
+ Specify one correct answer from a list of possible options +
+ + + +
+`; + +exports[`Preview snapshots snapshots: renders as expected with problemType is numericalresponse 1`] = ` +
+
+ Numeric Response Problem +
+ A preview illustration of a {problemType, select,
+      multiplechoiceresponse {single select}
+      stringreponse {text input}
+      numericalresponse {numerical input}
+      optionresponse {dropdown}
+      choiceresponse {multiple select}
+      other {null}
+    } problem +
+ Specify one or more correct numeric answers, submitted in a response field. +
+ + + +
+`; + +exports[`Preview snapshots snapshots: renders as expected with problemType is optionresponse 1`] = ` +
+
+ Dropdown Problem +
+ A preview illustration of a {problemType, select,
+      multiplechoiceresponse {single select}
+      stringreponse {text input}
+      numericalresponse {numerical input}
+      optionresponse {dropdown}
+      choiceresponse {multiple select}
+      other {null}
+    } problem +
+ Specify one correct answer from a list of possible options, selected in a dropdown menu. +
+ + + +
+`; + +exports[`Preview snapshots snapshots: renders as expected with problemType is stringresponse 1`] = ` +
+
+ Text Input Problem +
+ A preview illustration of a {problemType, select,
+      multiplechoiceresponse {single select}
+      stringreponse {text input}
+      numericalresponse {numerical input}
+      optionresponse {dropdown}
+      choiceresponse {multiple select}
+      other {null}
+    } problem +
+ Specify one or more correct text answers, including numbers and special characters, submitted in a response field. +
+ + + +
+`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap new file mode 100644 index 000000000..bf2f8389e --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/__snapshots__/ProblemTypeSelect.test.jsx.snap @@ -0,0 +1,316 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ProblemTypeSelect snapshot DROPDOWN 1`] = ` + + + + Single Select Problem + + + Multi Select Problem + + + Dropdown Problem + + + Numeric Response Problem + + + Text Input Problem + + + + +`; + +exports[`ProblemTypeSelect snapshot MULTISELECT 1`] = ` + + + + Single Select Problem + + + Multi Select Problem + + + Dropdown Problem + + + Numeric Response Problem + + + Text Input Problem + + + + +`; + +exports[`ProblemTypeSelect snapshot NUMERIC 1`] = ` + + + + Single Select Problem + + + Multi Select Problem + + + Dropdown Problem + + + Numeric Response Problem + + + Text Input Problem + + + + +`; + +exports[`ProblemTypeSelect snapshot SINGLESELECT 1`] = ` + + + + Single Select Problem + + + Multi Select Problem + + + Dropdown Problem + + + Numeric Response Problem + + + Text Input Problem + + + + +`; + +exports[`ProblemTypeSelect snapshot TEXTINPUT 1`] = ` + + + + Single Select Problem + + + Multi Select Problem + + + Dropdown Problem + + + Numeric Response Problem + + + Text Input Problem + + + + +`; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js new file mode 100644 index 000000000..dae097bb7 --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/content/messages.js @@ -0,0 +1,69 @@ +export const messages = { + advanceProblemButtonLabel: { + id: 'authoring.problemEditor.problemSelect.advanceButton.label', + defaultMessage: 'Advance problem types', + description: 'Button label for advance problem types option', + }, + advanceMenuTitle: { + id: 'authoring.problemEditor.advanceProblem.menu.title', + defaultMessage: 'Advanced problems', + description: 'Title for advanced problem menu', + }, + advanceProblemTypeLabel: { + id: 'authoring.problemEditor.advanceProblem.problemType.label', + defaultMessage: '{problemType}', + description: 'Label for advance problem type radio select', + }, + problemSupportStatus: { + id: 'authoring.problemEditor.advanceProblem.supportStatus', + defaultMessage: '{supportStatus}', + description: 'Text for advance problem type\'s support status', + }, + supportStatusTooltipMessage: { + id: 'authoring.problemEditor.advanceProblem.supportStatus.tooltipMessage', + defaultMessage: `{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. + \n \n + 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 { } + }`, + description: 'Message for support status tooltip', + }, + previewTitle: { + id: 'authoring.problemEditor.preview.title', + defaultMessage: '{previewTitle}', + description: 'Title for the problem preview column', + }, + previewAltText: { + id: 'authoring.problemEditor.preview.altText', + defaultMessage: `A preview illustration of a {problemType, select, + multiplechoiceresponse {single select} + stringreponse {text input} + numericalresponse {numerical input} + optionresponse {dropdown} + choiceresponse {multiple select} + other {null} + } problem`, + description: 'Alt text for the illustration of the problem preview', + }, + previewDescription: { + id: 'authoring.problemEditor.preview.description', + defaultMessage: '{previewDescription}', + description: 'Description of the selected problem type', + }, + learnMoreButtonLabel: { + id: 'authoring.problemEditor.learnMoreButtonLabel.label', + defaultMessage: 'Learn More', + description: 'Label for Learn More button', + }, +}; + +export default messages; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js index 42d65c681..f1dace285 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.js @@ -1,10 +1,59 @@ +import { useEffect, useState } from 'react'; import { - useState, -} from 'react'; + AdvanceProblemKeys, AdvanceProblems, ProblemTypeKeys, ProblemTypes, +} from '../../../../data/constants/problem'; import { StrictDict } from '../../../../utils'; +import * as module from './hooks'; export const state = StrictDict({ selected: (val) => useState(val), }); -export default { state }; +export const selectHooks = () => { + const [selected, setSelected] = module.state.selected(ProblemTypeKeys.SINGLESELECT); + return { + selected, + setSelected, + }; +}; + +export const onSelect = (setProblemType, selected, updateField) => () => { + if (Object.values(AdvanceProblemKeys).includes(selected)) { + updateField({ rawOLX: AdvanceProblems[selected].template }); + } + setProblemType({ selected }); +}; + +export const useArrowNav = (selected, setSelected) => { + const detectKeyDown = (e) => { + const problemTypeValues = Object.values(ProblemTypeKeys); + switch (e.key) { + case 'ArrowUp': + if (problemTypeValues.includes(selected) && ProblemTypes[selected].prev) { + setSelected(ProblemTypes[selected].prev); + document.getElementById(ProblemTypes[selected].prev).focus(); + } + break; + case 'ArrowDown': + if (problemTypeValues.includes(selected) && ProblemTypes[selected].next) { + setSelected(ProblemTypes[selected].next); + document.getElementById(ProblemTypes[selected].next).focus(); + } + break; + default: + } + }; + useEffect(() => { + document.addEventListener('keydown', detectKeyDown, true); + return () => { + document.removeEventListener('keydown', detectKeyDown, true); + }; + }, [selected, setSelected]); +}; + +export default { + state, + selectHooks, + onSelect, + useArrowNav, +}; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js new file mode 100644 index 000000000..50829221e --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/hooks.test.js @@ -0,0 +1,168 @@ +/* eslint-disable prefer-destructuring */ +import React from 'react'; +import { MockUseState } from '../../../../../testUtils'; +import * as module from './hooks'; +import { AdvanceProblems, ProblemTypeKeys } from '../../../../data/constants/problem'; + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useState: (val) => ({ useState: val }), + useEffect: jest.fn(), +})); + +const state = new MockUseState(module); +const mockSetProblemType = jest.fn().mockName('setProblemType'); +const mockUpdateField = jest.fn().mockName('updateField'); +const mockSelected = 'vAl'; +const mockAdvancedSelected = 'blankadvanced'; +const mockSetSelected = jest.fn().mockName('setSelected'); + +let hook; + +describe('SelectTypeModal hooks', () => { + beforeEach(() => { + state.mock(); + }); + afterEach(() => { + state.restore(); + jest.clearAllMocks(); + }); + + describe('selectHooks', () => { + beforeEach(() => { + hook = module.selectHooks(); + }); + test('selected defaults to SINGLESELECT', () => { + expect(hook.selected).toEqual(ProblemTypeKeys.SINGLESELECT); + }); + test('setSelected sets state as expected', () => { + const expectedArg = 'neWvAl'; + state.mockVal(state.keys.selected, 'mOcKvAl'); + hook.setSelected(expectedArg); + expect(state.setState.selected).toHaveBeenCalledWith(expectedArg); + }); + }); + + describe('onSelect', () => { + test('updateField is called with selected templated if selected is an Advanced Problem', () => { + module.onSelect(mockSetProblemType, mockAdvancedSelected, mockUpdateField)(); + expect(mockUpdateField).toHaveBeenCalledWith({ + rawOLX: AdvanceProblems[mockAdvancedSelected].template, + }); + }); + test('setProblemType is called with selected', () => { + module.onSelect(mockSetProblemType, mockSelected, mockUpdateField)(); + expect(mockSetProblemType).toHaveBeenCalledWith({ selected: mockSelected }); + }); + }); + + describe('useArrowNav', () => { + document.body.innerHTML = ` +
+
+
+
+
+ `; + const mockKeyUp = new KeyboardEvent('keydown', { key: 'ArrowUp' }); + const mockKeyDown = new KeyboardEvent('keydown', { key: 'ArrowDown' }); + let cb; + let prereqs; + + describe('SINGLESELECT', () => { + beforeEach(() => { + module.useArrowNav(ProblemTypeKeys.SINGLESELECT, mockSetSelected); + [cb, prereqs] = React.useEffect.mock.calls[0]; + cb(); + }); + test('pressing up arrow sets MULTISELECT', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.SINGLESELECT, mockSetSelected]); + document.dispatchEvent(mockKeyUp); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.TEXTINPUT); + }); + test('pressing down arrow sets MULTISELECT', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.SINGLESELECT, mockSetSelected]); + document.dispatchEvent(mockKeyDown); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.MULTISELECT); + }); + }); + describe('MULTISELECT', () => { + beforeEach(() => { + module.useArrowNav(ProblemTypeKeys.MULTISELECT, mockSetSelected); + [cb, prereqs] = React.useEffect.mock.calls[0]; + cb(); + }); + test('pressing up arrow sets SINGLESELECT', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.MULTISELECT, mockSetSelected]); + document.dispatchEvent(mockKeyUp); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.SINGLESELECT); + }); + test('pressing down arrow sets DROPDOWN', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.MULTISELECT, mockSetSelected]); + document.dispatchEvent(mockKeyDown); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.DROPDOWN); + }); + }); + describe('DROPDOWN', () => { + beforeEach(() => { + module.useArrowNav(ProblemTypeKeys.DROPDOWN, mockSetSelected); + [cb, prereqs] = React.useEffect.mock.calls[0]; + cb(); + }); + test('pressing up arrow sets MULTISELECT', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.DROPDOWN, mockSetSelected]); + document.dispatchEvent(mockKeyUp); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.MULTISELECT); + }); + test('pressing down arrow sets NUMERIC', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.DROPDOWN, mockSetSelected]); + document.dispatchEvent(mockKeyDown); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.NUMERIC); + }); + }); + describe('NUMERIC', () => { + beforeEach(() => { + module.useArrowNav(ProblemTypeKeys.NUMERIC, mockSetSelected); + [cb, prereqs] = React.useEffect.mock.calls[0]; + cb(); + }); + test('pressing up arrow sets DROPDOWN', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.NUMERIC, mockSetSelected]); + document.dispatchEvent(mockKeyUp); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.DROPDOWN); + }); + test('pressing down arrow sets TEXTINPUT', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.NUMERIC, mockSetSelected]); + document.dispatchEvent(mockKeyDown); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.TEXTINPUT); + }); + }); + describe('TEXTINPUT', () => { + beforeEach(() => { + module.useArrowNav(ProblemTypeKeys.TEXTINPUT, mockSetSelected); + [cb, prereqs] = React.useEffect.mock.calls[0]; + cb(); + }); + test('pressing up arrow sets NUMERIC', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.TEXTINPUT, mockSetSelected]); + document.dispatchEvent(mockKeyUp); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.NUMERIC); + }); + test('pressing down arrow sets SINGLESELECT', () => { + expect(React.useEffect.mock.calls.length).toEqual(1); + expect(prereqs).toStrictEqual([ProblemTypeKeys.TEXTINPUT, mockSetSelected]); + document.dispatchEvent(mockKeyDown); + expect(mockSetSelected).toHaveBeenCalledWith(ProblemTypeKeys.SINGLESELECT); + }); + }); + }); +}); diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx index 6d12dbad2..49d2ca7b7 100644 --- a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.jsx @@ -1,23 +1,40 @@ import React from 'react'; +import PropTypes from 'prop-types'; +import { Col, Row } from '@edx/paragon'; import ProblemTypeSelect from './content/ProblemTypeSelect'; import Preview from './content/Preview'; +import AdvanceTypeSelect from './content/AdvanceTypeSelect'; import SelectTypeWrapper from './SelectTypeWrapper'; -import * as hooks from './hooks'; +import hooks from './hooks'; +import { AdvanceProblemKeys } from '../../../../data/constants/problem'; -export const SelectTypeModal = () => { - const { selected, setSelected } = hooks.state.selected(null); +export const SelectTypeModal = ({ + onClose, +}) => { + const { selected, setSelected } = hooks.selectHooks(); + hooks.useArrowNav(selected, setSelected); return ( -
- - - - -
+ + + {(!Object.values(AdvanceProblemKeys).includes(selected)) ? ( + <> + + + + + + + + ) : } + + ); }; +SelectTypeModal.propTypes = { + onClose: PropTypes.func.isRequired, +}; + export default SelectTypeModal; diff --git a/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx new file mode 100644 index 000000000..05ab1522d --- /dev/null +++ b/src/editors/containers/ProblemEditor/components/SelectTypeModal/index.test.jsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import * as module from '.'; + +jest.mock('./hooks', () => ({ + selectHooks: jest.fn(() => ({ + selected: 'mOcKsELEcted', + setSelected: jest.fn().mockName('setSelected'), + })), + useArrowNav: jest.fn().mockName('useArrowNav'), +})); + +describe('SelectTypeModal', () => { + const props = { + onClose: jest.fn(), + }; + + test('snapshot', () => { + expect(shallow()).toMatchSnapshot(); + }); +}); diff --git a/src/editors/containers/ProblemEditor/data/OLXParser.js b/src/editors/containers/ProblemEditor/data/OLXParser.js index 4fa43f000..18126a039 100644 --- a/src/editors/containers/ProblemEditor/data/OLXParser.js +++ b/src/editors/containers/ProblemEditor/data/OLXParser.js @@ -331,12 +331,12 @@ export class OLXParser { getProblemType() { const problemKeys = Object.keys(this.problem); const intersectedProblems = _.intersection(Object.values(ProblemTypeKeys), problemKeys); + + if (intersectedProblems.length === 0) { + return null; + } if (intersectedProblems.length > 1) { - const errorMessage = { - code: 500, - message: 'More than one problem type is not supported!', - }; - throw errorMessage; + return ProblemTypeKeys.ADVANCED; } const problemType = intersectedProblems[0]; return problemType; @@ -352,10 +352,6 @@ export class OLXParser { const problemType = this.getProblemType(); const hints = this.getHints(); const question = this.parseQuestions(problemType); - const errorMessage = { - code: 500, - message: 'The problem type is not supported!', - }; switch (problemType) { case ProblemTypeKeys.DROPDOWN: answersObject = this.parseMultipleChoiceAnswers(ProblemTypeKeys.DROPDOWN, 'optioninput', 'option'); @@ -372,8 +368,11 @@ export class OLXParser { case ProblemTypeKeys.SINGLESELECT: answersObject = this.parseMultipleChoiceAnswers(ProblemTypeKeys.SINGLESELECT, 'choicegroup', 'choice'); break; + case ProblemTypeKeys.ADVANCED: + break; default: - throw errorMessage; + // if problem is unset, return null + return {}; } if (_.has(answersObject, 'additionalStringAttributes')) { diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/__snapshots__/index.test.jsx.snap b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/__snapshots__/index.test.jsx.snap index 245b798b2..a03d9e42e 100644 --- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/__snapshots__/index.test.jsx.snap +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/__snapshots__/index.test.jsx.snap @@ -55,10 +55,10 @@ exports[`TranscriptWidget component snapshots snapshot: renders ErrorAlert with />
- - + } placement="top" > @@ -78,7 +78,7 @@ exports[`TranscriptWidget component snapshots snapshot: renders ErrorAlert with } } /> - +
- - + } placement="top" > @@ -199,7 +199,7 @@ exports[`TranscriptWidget component snapshots snapshot: renders ErrorAlert with } } /> - +
- - + } placement="top" > @@ -316,7 +316,7 @@ exports[`TranscriptWidget component snapshots snapshots: renders as expected wit } } /> - +
- - + } placement="top" > @@ -490,7 +490,7 @@ exports[`TranscriptWidget component snapshots snapshots: renders as expected wit } } /> - +
- - + } placement="top" > @@ -607,7 +607,7 @@ exports[`TranscriptWidget component snapshots snapshots: renders as expected wit } } /> - +
- - + } placement="top" > @@ -120,7 +120,7 @@ exports[`VideoSourceWidget snapshots snapshots: renders as expected with default } } /> - + diff --git a/src/editors/data/constants/olxTemplates/circuitschematic.js b/src/editors/data/constants/olxTemplates/circuitschematic.js new file mode 100644 index 000000000..571b7c484 --- /dev/null +++ b/src/editors/data/constants/olxTemplates/circuitschematic.js @@ -0,0 +1,92 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Circuit Schematic Builder +// markdown: !!null +// data: | +export const circuitSchematic = ` +

+ Circuit schematic problems allow students to create virtual circuits by + arranging elements such as voltage sources, capacitors, resistors, and + MOSFETs on an interactive grid. The system evaluates a DC, AC, or + transient analysis of the circuit. +

+

+ For more information, see + + Circuit Schematic Builder Problem in Building and Running an edX Course. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

+

You can use the following example problems as models.

+ + +

Make a voltage divider that splits the provided voltage evenly.

+
+ +
+ + dc_value = "dc analysis not found" + for response in submission[0]: + if response[0] == 'dc': + for node in response[1:]: + dc_value = node['output'] + + if dc_value == .5: + correct = ['correct'] + else: + correct = ['incorrect'] + + +
+

Explanation

+

+ You can form a voltage divider that evenly divides the input + voltage with two identically valued resistors, with the sampled + voltage taken in between the two. +

+

+
+
+
+ + +

Make a high-pass filter.

+
+ +
+ + ac_values = None + for response in submission[0]: + if response[0] == 'ac': + for node in response[1:]: + ac_values = node['NodeA'] + print "the ac analysis value:", ac_values + if ac_values == None: + correct = ['incorrect'] + elif ac_values[0][1] < ac_values[1][1]: + correct = ['correct'] + else: + correct = ['incorrect'] + + +
+

Explanation

+

+ You can form a simple high-pass filter without any further + constraints by simply putting a resistor in series with a + capacitor. The actual values of the components do not really + matter in this problem. +

+

+
+
+
+
`; + +export default { circuitSchematic }; diff --git a/src/editors/data/constants/olxTemplates/customgrader.js b/src/editors/data/constants/olxTemplates/customgrader.js new file mode 100644 index 000000000..914fe3bb3 --- /dev/null +++ b/src/editors/data/constants/olxTemplates/customgrader.js @@ -0,0 +1,79 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Custom Python-Evaluated Input +// markdown: !!null +// data: | +export const customGrader = ` +

+ In custom Python-evaluated input (also called "write-your-own-grader" + problems), the grader uses a Python script that you create and embed in + the problem to evaluate a learner's response or provide hints. These + problems can be any type. Numerical input and text input problems are + the most common write-your-own-grader problems. +

+

+ You can use script tag format or answer tag format to create these problems. +

+

+ You can create custom Python-evaluated input problems that provide + partial credit or that randomize variables in the Python code. You can + also add images to the solution by using an HTML "img" tag. Note that + the "img" tag must be between the "div" tags that are inside the + "solution" tags, and that learners do not see these images until they + click the "Show Answer" button. +

+

+ For more information, see + Write-Your-Own-Grader Problem in Building and Running an edX Course. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

+

You can use the following example problem as a model.

+
+ + + +
+ + +
+

Explanation

+

Any set of integers on the line \(y = 10 - x\) satisfy these constraints.

+
+
+
+ + + +
+ + +
+

Explanation

+

Any set of integers on the line \(y = 20 - x\) satisfy these constraints.

+

To add an image to the solution, use an HTML "img" tag. Make sure to include alt text.

+ Description of image, with a primary goal of explaining its
+                relevance to the problem or concept being illustrated for someone
+                who is unable to see the image. +
+
+
+
`; + +export default { customGrader }; diff --git a/src/editors/data/constants/olxTemplates/drag_and_drop.js b/src/editors/data/constants/olxTemplates/drag_and_drop.js new file mode 100644 index 000000000..40d313652 --- /dev/null +++ b/src/editors/data/constants/olxTemplates/drag_and_drop.js @@ -0,0 +1,88 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Drag and Drop (Deprecated Version) +// markdown: !!null +// showanswer: never +// data: | +export const dragAndDrop = ` +

In drag and drop problems, students respond to a question by dragging text or objects to a specific location on an image.

+

+ For more information, see + + Drag and Drop Problem (Deprecated) in Building and Running an edX Course. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. +

+

You can use the following example problems as models.

+
+ +

Simple Drag and Drop

+

Drag each word in the scrollbar to the bucket that matches the number of letters in the word.

+ + + + + + + + + + + + + + + correct_answer = { + '1': [[70, 150], 121], + '6': [[190, 150], 121], + '8': [[190, 150], 121], + '2': [[310, 150], 121], + '9': [[310, 150], 121], + '11': [[310, 150], 121], + '4': [[420, 150], 121], + '7': [[420, 150], 121], + '3': [[550, 150], 121], + '5': [[550, 150], 121], + '10': [[550, 150], 121]} + if draganddrop.grade(submission[0], correct_answer): + correct = ['correct'] + else: + correct = ['incorrect'] + +
+ + +

Drag and Drop with Outline

+

Label the hydrogen atoms connected with the left carbon atom.

+ + + + + + + + + + + + + + + + correct_answer = [{ + 'draggables': ['1', '2'], + 'targets': ['t2', 't3', 't4' ], + 'rule':'anyof' + }] + if draganddrop.grade(submission[0], correct_answer): + correct = ['correct'] + else: + correct = ['incorrect'] + +
+
`; + +export default { dragAndDrop }; diff --git a/src/editors/data/constants/olxTemplates/formularesponse.js b/src/editors/data/constants/olxTemplates/formularesponse.js new file mode 100644 index 000000000..ea5d43987 --- /dev/null +++ b/src/editors/data/constants/olxTemplates/formularesponse.js @@ -0,0 +1,16 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Math Expression Input +// markdown: !!null +// data: | +export const formulaResponse = ` + +

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.

+ + 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 + + +
+
`; +export default { formulaResponse }; diff --git a/src/editors/data/constants/olxTemplates/imageresponse.js b/src/editors/data/constants/olxTemplates/imageresponse.js new file mode 100644 index 000000000..b3b7acb6a --- /dev/null +++ b/src/editors/data/constants/olxTemplates/imageresponse.js @@ -0,0 +1,33 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Image Mapped Input +// markdown: !!null +// data: | +export const imageResponse = ` +

+ In an image mapped input problem, also known as a "pointing on a picture" problem, students click inside a defined region in an image. You define this region by including coordinates in the body of the problem. You can define one rectangular region, + multiple rectangular regions, or one non-rectangular region. For more information, see + Image Mapped Input Problem + in + Building and Running an edx Course. +

+

When you add the problem, be sure to select + Settings + to specify a + Display Name + and other values that apply.

+

You can use the following example problem as a model.

+ +

What country is home to the Great Pyramid of Giza as well as the cities of Cairo and Memphis? Click the country on the map below.

+ + +
+

Explanation

+

Egypt is home to not only the Pyramids, Cairo, and Memphis, but also the Sphinx and the ancient Royal Library of Alexandria.

+
+
+
+
`; + +export default { imageResponse }; diff --git a/src/editors/data/constants/olxTemplates/jsinput_response.js b/src/editors/data/constants/olxTemplates/jsinput_response.js new file mode 100644 index 000000000..3af5a3761 --- /dev/null +++ b/src/editors/data/constants/olxTemplates/jsinput_response.js @@ -0,0 +1,81 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Custom JavaScript Display and Grading +// markdown: !!null +// showanswer: never +// data: | +export const jsInputResponse = ` +

+ In these problems (also called custom JavaScript problems or JS Input + problems), you add a problem or tool that uses JavaScript in Studio. + Studio embeds the problem in an IFrame so that your learners can + interact with it in the LMS. You can grade your learners' work using + JavaScript and some basic Python, and the grading is integrated into the + edX grading system. +

+

+ The JS Input problem that you create must use HTML, JavaScript, and + cascading style sheets (CSS). You can use any application creation tool, + such as the Google Web Toolkit (GWT), to create your JS Input problem. +

+

+ For more information, see + + Custom JavaScript Problem in Building and Running an edX Course. +

+

+ JavaScript developers can also see + + Custom JavaScript Applications in the EdX Developer's Guide. +

+

+ When you add the problem, be sure to select Settings + to specify a Display Name and other values that apply. + Also, be sure to specify a title attribute on the jsinput tag; + this title is used for the title attribute on the generated IFrame. Generally, + the title attribute on the IFrame should match the title tag of the HTML hosted + within the IFrame, which is specified by the html_file attribute. +

+

You can use the following example problem as a model.

+ + + +

This is paragraph text displayed before the IFrame.

+ +
+
`; + +export default { jsInputResponse }; diff --git a/src/editors/data/constants/olxTemplates/problem_with_hint.js b/src/editors/data/constants/olxTemplates/problem_with_hint.js new file mode 100644 index 000000000..10be3531c --- /dev/null +++ b/src/editors/data/constants/olxTemplates/problem_with_hint.js @@ -0,0 +1,46 @@ +/* eslint-disable */ +// --- +// metadata: +// display_name: Problem with Adaptive Hint +// markdown: !!null +// data: | +export const problemWithHint = ` + +

Problem With Adaptive Hint

+

This problem demonstrates a question with hints, based on using the hintfn method.

+ + + + + + + +
+
`; + +export default { problemWithHint }; diff --git a/src/editors/data/constants/problem.js b/src/editors/data/constants/problem.js index 9d884afa4..cc491a9d8 100644 --- a/src/editors/data/constants/problem.js +++ b/src/editors/data/constants/problem.js @@ -1,46 +1,129 @@ import { StrictDict } from '../../utils'; +import singleSelect from '../images/singleSelect.png'; +import multiSelect from '../images/multiSelect.png'; +import dropdown from '../images/dropdown.png'; +import numericalInput from '../images/numericalInput.png'; +import textInput from '../images/textInput.png'; +import { circuitSchematic } from './olxTemplates/circuitschematic'; +import { customGrader } from './olxTemplates/customgrader'; +import { dragAndDrop } from './olxTemplates/drag_and_drop'; +import { formulaResponse } from './olxTemplates/formularesponse'; +import { imageResponse } from './olxTemplates/imageresponse'; +import { jsInputResponse } from './olxTemplates/jsinput_response'; +import { problemWithHint } from './olxTemplates/problem_with_hint'; export const ProblemTypeKeys = StrictDict({ - TEXTINPUT: 'stringresponse', - NUMERIC: 'numericalresponse', - DROPDOWN: 'optionresponse', - MULTISELECT: 'choiceresponse', SINGLESELECT: 'multiplechoiceresponse', + MULTISELECT: 'choiceresponse', + DROPDOWN: 'optionresponse', + NUMERIC: 'numericalresponse', + TEXTINPUT: 'stringresponse', + ADVANCED: 'advanced', }); export const ProblemTypes = StrictDict({ [ProblemTypeKeys.SINGLESELECT]: { title: 'Single Select Problem', - preview: ('
'), + preview: singleSelect, description: 'Specify one correct answer from a list of possible options', - helpLink: 'something.com', + helpLink: 'https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/multiple_choice.html', + prev: ProblemTypeKeys.TEXTINPUT, + next: ProblemTypeKeys.MULTISELECT, }, [ProblemTypeKeys.MULTISELECT]: { title: 'Multi Select Problem', - preview: ('
'), + preview: multiSelect, description: 'Specify one or more correct answers from a list of possible options.', - helpLink: 'something.com', + helpLink: 'https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/checkbox.html', + next: ProblemTypeKeys.DROPDOWN, + prev: ProblemTypeKeys.SINGLESELECT, }, [ProblemTypeKeys.DROPDOWN]: { title: 'Dropdown Problem', - preview: ('
'), + preview: dropdown, description: 'Specify one correct answer from a list of possible options, selected in a dropdown menu.', - helpLink: 'something.com', + helpLink: 'https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/dropdown.html', + next: ProblemTypeKeys.NUMERIC, + prev: ProblemTypeKeys.MULTISELECT, }, [ProblemTypeKeys.NUMERIC]: { title: 'Numeric Response Problem', - preview: ('
'), + preview: numericalInput, description: 'Specify one or more correct numeric answers, submitted in a response field.', - helpLink: 'something.com', + helpLink: 'https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/numerical_input.html', + next: ProblemTypeKeys.TEXTINPUT, + prev: ProblemTypeKeys.DROPDOWN, }, [ProblemTypeKeys.TEXTINPUT]: { title: 'Text Input Problem', - preview: ('
'), + preview: textInput, description: 'Specify one or more correct text answers, including numbers and special characters, submitted in a response field.', + helpLink: 'https://edx.readthedocs.io/projects/edx-partner-course-staff/en/latest/exercises_tools/text_input.html', + prev: ProblemTypeKeys.NUMERIC, + next: ProblemTypeKeys.SINGLESELECT, + }, + [ProblemTypeKeys.ADVANCED]: { + title: 'Advanced Problem', + preview: ('
'), + description: 'An Advanced Problem Type', helpLink: 'something.com', }, }); +export const AdvanceProblemKeys = StrictDict({ + BLANK: 'blankadvanced', + CIRCUITSCHEMATIC: 'circuitschematic', + JSINPUT: 'jsinputresponse', + CUSTOMGRADER: 'customgrader', + DRAGANDDROP: 'draganddrop', + IMAGE: 'imageresponse', + FORMULA: 'formularesponse', + PROBLEMWITHHINT: 'problemwithhint', +}); + +export const AdvanceProblems = StrictDict({ + [AdvanceProblemKeys.BLANK]: { + title: 'Blank advance problem', + status: '', + template: '', + }, + [AdvanceProblemKeys.CIRCUITSCHEMATIC]: { + title: 'Circuit schematic builder', + status: 'Not supported', + template: circuitSchematic, + }, + [AdvanceProblemKeys.JSINPUT]: { + title: 'Custom JavaScript display and grading', + status: '', + template: jsInputResponse, + }, + [AdvanceProblemKeys.CUSTOMGRADER]: { + title: 'Custom Python-evaluated input', + status: 'Provisional', + template: customGrader, + }, + [AdvanceProblemKeys.DRAGANDDROP]: { + title: 'Drag and drop (deprecated version)', + status: 'Not supported', + template: dragAndDrop, + }, + [AdvanceProblemKeys.IMAGE]: { + title: 'Image mapped input', + status: 'Not supported', + template: imageResponse, + }, + [AdvanceProblemKeys.FORMULA]: { + title: 'Math expression input', + status: '', + template: formulaResponse, + }, + [AdvanceProblemKeys.PROBLEMWITHHINT]: { + title: 'Problem with adaptive hint', + status: 'Not supported', + template: problemWithHint, + }, +}); + export const ShowAnswerTypesKeys = StrictDict({ ALWAYS: 'always', ANSWERED: 'answered', diff --git a/src/editors/data/constants/requests.js b/src/editors/data/constants/requests.js index 8efe58cb5..273ec758f 100644 --- a/src/editors/data/constants/requests.js +++ b/src/editors/data/constants/requests.js @@ -22,4 +22,6 @@ export const RequestKeys = StrictDict({ fetchCourseDetails: 'fetchCourseDetails', updateTranscriptLanguage: 'updateTranscriptLanguage', getTranscriptFile: 'getTranscriptFile', + uploadImage: 'uploadImage', + fetchAdvanceSettings: 'fetchAdvanceSettings', }); diff --git a/src/editors/data/images/dropdown.png b/src/editors/data/images/dropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..9fcf02949506cb3582359b0d5fb22684b7af1228 GIT binary patch literal 3170 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 DJlEDX literal 0 HcmV?d00001 diff --git a/src/editors/data/images/multiSelect.png b/src/editors/data/images/multiSelect.png new file mode 100644 index 0000000000000000000000000000000000000000..065716214a19b0daa935c31f1d5aa4cff88b20ed GIT binary patch literal 4690 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 W$6nltB;&xrz!f74L&_!RhyMf1A(Te| literal 0 HcmV?d00001 diff --git a/src/editors/data/images/singleSelect.png b/src/editors/data/images/singleSelect.png new file mode 100644 index 0000000000000000000000000000000000000000..33fe718310e29d266fb295309cebac844a9d84a4 GIT binary patch literal 7893 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 String.fromCharCode(lastId.charCodeAt(0) + 1); const initialState = { rawOLX: '', - problemType: ProblemTypeKeys.SINGLESELECT, + problemType: null, question: '', answers: [], groupFeedbackList: [], @@ -124,9 +124,13 @@ const problem = createSlice({ }, ...payload, }), - onSelect: (state, { payload }) => ({ + setEnableTypeSelection: (state) => ({ ...state, - ...payload, + problemType: null, + }), + setProblemType: (state, { payload: { selected } }) => ({ + ...state, + problemType: selected, }), }, }); diff --git a/src/editors/data/redux/thunkActions/problem.js b/src/editors/data/redux/thunkActions/problem.js index 24a885b93..d1902d46f 100644 --- a/src/editors/data/redux/thunkActions/problem.js +++ b/src/editors/data/redux/thunkActions/problem.js @@ -1,22 +1,31 @@ import _ from 'lodash-es'; +import * as requests from './requests'; import { actions } from '..'; import { OLXParser } from '../../../containers/ProblemEditor/data/OLXParser'; import { parseSettings } from '../../../containers/ProblemEditor/data/SettingsParser'; export const initializeProblem = (blockValue) => (dispatch) => { const rawOLX = _.get(blockValue, 'data.data', {}); - try { - const olxParser = new OLXParser(rawOLX); - const { ...data } = olxParser.getParsedOLXData(); - let { settings } = olxParser.getParsedOLXData(); - settings = { ...settings, ...parseSettings(_.get(blockValue, 'data.metadata', {})) }; - if (!_.isEmpty(rawOLX) && !_.isEmpty(data)) { - dispatch(actions.problem.load({ ...data, rawOLX, settings })); - } - } catch (error) { - // eslint-disable-next-line - console.error(error); + const olxParser = new OLXParser(rawOLX); + + const parsedProblem = olxParser.getParsedOLXData(); + if (_.isEmpty(parsedProblem)) { + // if problem is blank, enable selection. + dispatch(actions.problem.setEnableTypeSelection()); } + const { settings, ...data } = parsedProblem; + const parsedSettings = { ...settings, ...parseSettings(_.get(blockValue, 'data.metadata', {})) }; + if (!_.isEmpty(rawOLX) && !_.isEmpty(data)) { + dispatch(actions.problem.load({ ...data, rawOLX, settings: parsedSettings })); + } + dispatch(requests.fetchAdvanceSettings({ + onSuccess: (response) => { + console.log(response); + if (response.data.allow_unsupported_xblocks.value) { + console.log(response.allow_unsupported_xblocks.value); + } + }, + })); }; export default { initializeProblem }; diff --git a/src/editors/data/redux/thunkActions/requests.js b/src/editors/data/redux/thunkActions/requests.js index 410869763..c21b06798 100644 --- a/src/editors/data/redux/thunkActions/requests.js +++ b/src/editors/data/redux/thunkActions/requests.js @@ -236,6 +236,17 @@ export const fetchCourseDetails = ({ ...rest }) => (dispatch, getState) => { })); }; +export const fetchAdvanceSettings = ({ ...rest }) => (dispatch, getState) => { + dispatch(module.networkRequest({ + requestKey: RequestKeys.fetchAdvanceSettings, + promise: api.fetchAdvanceSettings({ + studioEndpointUrl: selectors.app.studioEndpointUrl(getState()), + learningContextId: selectors.app.learningContextId(getState()), + }), + ...rest, + })); +}; + export default StrictDict({ fetchBlock, fetchStudioView, @@ -250,4 +261,5 @@ export default StrictDict({ updateTranscriptLanguage, fetchCourseDetails, getTranscriptFile, + fetchAdvanceSettings, }); diff --git a/src/editors/data/services/cms/api.js b/src/editors/data/services/cms/api.js index 8d6ca96cd..19d8afe53 100644 --- a/src/editors/data/services/cms/api.js +++ b/src/editors/data/services/cms/api.js @@ -21,6 +21,9 @@ export const apiMethods = { fetchCourseDetails: ({ studioEndpointUrl, learningContextId }) => get( urls.courseDetailsUrl({ studioEndpointUrl, learningContextId }), ), + fetchAdvanceSettings: ({ studioEndpointUrl, learningContextId }) => get( + urls.courseAdvanceSettings({ studioEndpointUrl, learningContextId }), + ), uploadAsset: ({ learningContextId, studioEndpointUrl, diff --git a/src/editors/data/services/cms/mockApi.js b/src/editors/data/services/cms/mockApi.js index f00fbccc1..9a1805baf 100644 --- a/src/editors/data/services/cms/mockApi.js +++ b/src/editors/data/services/cms/mockApi.js @@ -35,17 +35,7 @@ export const fetchBlockById = ({ blockId, studioEndpointUrl }) => { } else if (blockId === 'problem-block-id') { data = { data: ` - -

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

- - You can add an optional tip or note related to the prompt like this. - - - - - -
-
`, + `, display_name: 'Dropdown', metadata: { markdown: `You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown problems. Edit this component to replace this template with your own assessment. @@ -135,6 +125,10 @@ export const fetchCourseDetails = ({ studioEndpointUrl, learningContextId }) => export const allowThumbnailUpload = ({ studioEndpointUrl }) => mockPromise({ data: true, }); +// eslint-disable-next-line +export const fetchAdvanceSettings = ({ studioEndpointUrl, learningContextId }) => mockPromise({ + data: { allow_unsupported_xblocks: { value: true } }, +}); export const normalizeContent = ({ blockId, diff --git a/src/editors/data/services/cms/urls.js b/src/editors/data/services/cms/urls.js index 389a0b775..b6260fcc2 100644 --- a/src/editors/data/services/cms/urls.js +++ b/src/editors/data/services/cms/urls.js @@ -54,3 +54,7 @@ export const downloadVideoHandoutUrl = ({ studioEndpointUrl, handout }) => ( export const courseDetailsUrl = ({ studioEndpointUrl, learningContextId }) => ( `${studioEndpointUrl}/settings/details/${learningContextId}` ); + +export const courseAdvanceSettings = ({ studioEndpointUrl, learningContextId }) => ( + `${studioEndpointUrl}/api/contentstore/v0/advanced_settings/${learningContextId}` +); diff --git a/src/setupTest.js b/src/setupTest.js index b53d50d1e..cc8c8f7d3 100644 --- a/src/setupTest.js +++ b/src/setupTest.js @@ -111,7 +111,11 @@ jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedCompon Label: 'Form.Label', Text: 'Form.Text', Row: 'Form.Row', + Radio: 'Radio', + RadioSet: 'RadioSet', }, + OverlayTrigger: 'OverlayTrigger', + Tooltip: 'Tooltip', FullscreenModal: 'FullscreenModal', Row: 'Row', Scrollable: 'Scrollable', @@ -122,9 +126,7 @@ jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedCompon Spinner: 'Spinner', Stack: 'Stack', Toast: 'Toast', - Tooltip: 'ToolTip', Truncate: 'Truncate', - OverlayTrigger: 'OverLayTrigger', })); jest.mock('@edx/paragon/icons', () => ({