@instructure/quiz-core 17.41.1-rc.9 → 17.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/es/building/components/resources/ActionButtons/presenter.js +2 -1
- package/es/building/components/resources/quizEntry/QuizEntry/presenter.js +4 -1
- package/es/building/components/resources/quizEntry/QuizEntryShow/index.js +1 -0
- package/es/building/components/resources/quizEntry/QuizEntryShow/presenter.js +15 -4
- package/es/common/actions/rce.js +17 -0
- package/es/common/components/SDKApp/index.js +2 -2
- package/es/common/components/resources/stimulus/Stimulus/index.js +1 -0
- package/es/common/components/resources/stimulus/Stimulus/presenter.js +20 -7
- package/es/common/components/resources/stimulus/StimulusShow/index.js +9 -3
- package/es/common/kinesis/config.js +3 -2
- package/es/common/kinesis/eventTypes.js +2 -1
- package/es/common/reducers/rce.js +19 -0
- package/es/common/selectors/rce.js +3 -0
- package/es/common/util/RceConfigProvider.js +63 -28
- package/es/common/util/serializeEvent.js +2 -2
- package/es/common/util/windowChecks.js +6 -0
- package/es/configureStore.js +3 -1
- package/es/index.js +2 -0
- package/es/moderating/components/events/Event.js +7 -1
- package/es/moderating/components/events/RCEEvent.js +34 -0
- package/lib/building/components/resources/ActionButtons/presenter.js +2 -1
- package/lib/building/components/resources/quizEntry/QuizEntry/presenter.js +4 -1
- package/lib/building/components/resources/quizEntry/QuizEntryShow/index.js +1 -0
- package/lib/building/components/resources/quizEntry/QuizEntryShow/presenter.js +15 -4
- package/lib/common/actions/rce.js +30 -0
- package/lib/common/components/SDKApp/index.js +2 -2
- package/lib/common/components/resources/stimulus/Stimulus/index.js +1 -0
- package/lib/common/components/resources/stimulus/Stimulus/presenter.js +20 -7
- package/lib/common/components/resources/stimulus/StimulusShow/index.js +9 -3
- package/lib/common/kinesis/config.js +2 -1
- package/lib/common/kinesis/eventTypes.js +4 -2
- package/lib/common/reducers/rce.js +29 -0
- package/lib/common/selectors/rce.js +12 -0
- package/lib/common/util/RceConfigProvider.js +68 -27
- package/lib/common/util/serializeEvent.js +1 -1
- package/lib/common/util/windowChecks.js +11 -2
- package/lib/configureStore.js +4 -1
- package/lib/index.js +18 -0
- package/lib/moderating/components/events/Event.js +7 -0
- package/lib/moderating/components/events/RCEEvent.js +53 -0
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [17.42.0](https://gerrit.instructure.com/quizzes-ui/compare/v17.41.0...v17.42.0) (2022-11-17)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **itemAnalysis:** remove question marks typo in header ([5fd0aeb](https://gerrit.instructure.com/quizzes-ui/commits/5fd0aeb8f3d35e99e5efb59d939fdc1fe88e384b))
|
|
12
|
+
* **RCE5:** fix URL generation ([82298d4](https://gerrit.instructure.com/quizzes-ui/commits/82298d4336c3f8cbbb8d4059c2b4460e13f65d56))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **blueprint:** disable adding bank entries to locked NQ ([4ee219b](https://gerrit.instructure.com/quizzes-ui/commits/4ee219bd850a5f80f240a4cd3ceaf6af13a01f07))
|
|
18
|
+
* **blueprint:** make quiz entries uneditable when the quiz is locked ([be6a8b3](https://gerrit.instructure.com/quizzes-ui/commits/be6a8b375f5aa8990e3dca5f4c86069120fe5644))
|
|
19
|
+
* **RCE:** Add question stem to quiz logs about token refresh ([e1aac6a](https://gerrit.instructure.com/quizzes-ui/commits/e1aac6a77f456898e81705212b915a5de2d9afd7))
|
|
20
|
+
* **RCE:** Render RCE related log entries in the quiz session log ([ebebbb0](https://gerrit.instructure.com/quizzes-ui/commits/ebebbb0b02c8ce1dbd825ef9ee121c7cb870d65b))
|
|
21
|
+
* **RCE:** Write RCE related errors to store ([345bca5](https://gerrit.instructure.com/quizzes-ui/commits/345bca5e191666a67e63ab33c454c971fef8d01e))
|
|
22
|
+
* **RCE5:** pass canvasOrigin to RCE5 ([b792618](https://gerrit.instructure.com/quizzes-ui/commits/b7926183d2ec243e49fca7549b86308e23384390))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# [17.41.0](https://gerrit.instructure.com/quizzes-ui/compare/v17.40.0...v17.41.0) (2022-10-24)
|
|
7
29
|
|
|
8
30
|
|
|
@@ -121,7 +121,7 @@ export var ActionButtons = (_dec = themeable(theme, styles), _dec(_class = (_tem
|
|
|
121
121
|
quizEntry: this.props.quizEntry,
|
|
122
122
|
quizEntries: this.props.quizEntries,
|
|
123
123
|
disabled: this.props.shouldDisableDragHandle
|
|
124
|
-
}))), /*#__PURE__*/React.createElement(Button, {
|
|
124
|
+
}))), this.props.shouldRenderDelete && /*#__PURE__*/React.createElement(Button, {
|
|
125
125
|
as: "div",
|
|
126
126
|
onClick: this.props.onDelete,
|
|
127
127
|
disabled: this.props.shouldDisableDeleteButton,
|
|
@@ -149,6 +149,7 @@ export var ActionButtons = (_dec = themeable(theme, styles), _dec(_class = (_tem
|
|
|
149
149
|
shouldDisableDragHandle: PropTypes.bool,
|
|
150
150
|
shouldDisableDeleteButton: PropTypes.bool,
|
|
151
151
|
shouldRenderEdit: PropTypes.bool,
|
|
152
|
+
shouldRenderDelete: PropTypes.bool,
|
|
152
153
|
switchOnEditing: PropTypes.func,
|
|
153
154
|
shouldFocusOnMount: PropTypes.bool
|
|
154
155
|
}, _class2.defaultProps = {
|
|
@@ -176,7 +176,7 @@ export var QuizEntry = (_dec = themeable(theme, styles), _dec(_class = (_temp =
|
|
|
176
176
|
clearValidationErrorsFromApi: this.props.clearValidationErrorsFromApi,
|
|
177
177
|
haveValidationErrorsFromApi: Boolean(Object.values(this.props.validationErrorsFromApi).length),
|
|
178
178
|
useNewRce: isNewRCEEnabled()
|
|
179
|
-
}, pick(this.props, ['displayPosition', 'guid', 'draggingOnBuild', 'newHoverPosition', 'quizEntry', 'quizEntries', 'quizId', 'setUi', 'switchOffEditing', 'switchOnEditing', 'shouldClone', 'scrollKey', 'editQuizEntryToggle', 'onEditQuizEntryToggle', 'stimulusOrientation']));
|
|
179
|
+
}, pick(this.props, ['displayPosition', 'guid', 'draggingOnBuild', 'newHoverPosition', 'quizEntry', 'quizEntries', 'quizId', 'isContentLockedByBlueprint', 'setUi', 'switchOffEditing', 'switchOnEditing', 'shouldClone', 'scrollKey', 'editQuizEntryToggle', 'onEditQuizEntryToggle', 'stimulusOrientation']));
|
|
180
180
|
}
|
|
181
181
|
}, {
|
|
182
182
|
key: "isEditing",
|
|
@@ -262,6 +262,7 @@ export var QuizEntry = (_dec = themeable(theme, styles), _dec(_class = (_temp =
|
|
|
262
262
|
dndRef: this.storeDndComponentRef,
|
|
263
263
|
guid: this.props.guid,
|
|
264
264
|
isBankedContent: bankEntryWarningWrapperProps !== void 0,
|
|
265
|
+
isContentLockedByBlueprint: this.props.isContentLockedByBlueprint,
|
|
265
266
|
isEditing: this.isEditing(),
|
|
266
267
|
draggingOnBuild: this.props.draggingOnBuild,
|
|
267
268
|
newHoverPosition: this.props.newHoverPosition // used for DnD
|
|
@@ -358,6 +359,7 @@ export var QuizEntry = (_dec = themeable(theme, styles), _dec(_class = (_temp =
|
|
|
358
359
|
quizEntries: ImmutablePropTypes.listOf(ImmutablePropTypes.record).isRequired,
|
|
359
360
|
quizEntry: ImmutablePropTypes.record.isRequired,
|
|
360
361
|
quizId: PropTypes.string.isRequired,
|
|
362
|
+
isContentLockedByBlueprint: PropTypes.bool.isRequired,
|
|
361
363
|
regradingOn: PropTypes.bool.isRequired,
|
|
362
364
|
screenreaderNotification: PropTypes.func.isRequired,
|
|
363
365
|
scrollKey: PropTypes.string,
|
|
@@ -384,6 +386,7 @@ export var QuizEntry = (_dec = themeable(theme, styles), _dec(_class = (_temp =
|
|
|
384
386
|
draggingOnBuild: false,
|
|
385
387
|
draggingOver: false,
|
|
386
388
|
initialFocusId: null,
|
|
389
|
+
isContentLockedByBlueprint: false,
|
|
387
390
|
isEditing: false,
|
|
388
391
|
partialDeepScoringEnabled: false,
|
|
389
392
|
partialScoringEnabled: false,
|
|
@@ -25,6 +25,7 @@ function mapStateToProps(state, props) {
|
|
|
25
25
|
modificationsClear: itemModsClear && quizEntryModsClear,
|
|
26
26
|
quizEntryWithErrorsShowing: getQuizEntryWithErrorsShowing(state) || props.haveValidationErrorsFromApi,
|
|
27
27
|
richFITBEnabled: featureOn('interaction_type_rich_fill_blank'),
|
|
28
|
+
lockBlueprintContentEnabled: featureOn('lock_blueprint_content'),
|
|
28
29
|
richFITBInteractionID: (richFITBInteraction || Map()).get('id'),
|
|
29
30
|
updateItemCallStatus: state.getIn(['calls', UPDATE_ITEM_CALL, 'requestStatus'], '')
|
|
30
31
|
};
|
|
@@ -263,7 +263,9 @@ var QuizEntryShow = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
|
|
|
263
263
|
draggingOver = _this$props2.draggingOver,
|
|
264
264
|
draggingAboveHalf = _this$props2.draggingAboveHalf,
|
|
265
265
|
quizEntry = _this$props2.quizEntry,
|
|
266
|
-
stimulusOrientation = _this$props2.stimulusOrientation
|
|
266
|
+
stimulusOrientation = _this$props2.stimulusOrientation,
|
|
267
|
+
isContentLockedByBlueprint = _this$props2.isContentLockedByBlueprint,
|
|
268
|
+
lockBlueprintContentEnabled = _this$props2.lockBlueprintContentEnabled;
|
|
267
269
|
var positionToDisplay = this.props.quizEntry.positionToDisplay(displayPosition);
|
|
268
270
|
var positionText = t('Preview of question at position {position}', {
|
|
269
271
|
position: positionToDisplay
|
|
@@ -272,13 +274,15 @@ var QuizEntryShow = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
|
|
|
272
274
|
var propsForDnDZone = {
|
|
273
275
|
draggingOver: draggingOver,
|
|
274
276
|
draggingAboveHalf: draggingAboveHalf
|
|
275
|
-
};
|
|
277
|
+
};
|
|
278
|
+
var shouldLockQuizEntry = lockBlueprintContentEnabled && isContentLockedByBlueprint; // Overlay gets tabIndex === "-1" so that the drag handle is tabbable before
|
|
276
279
|
// the Overlay get focus and opens the quizEntry in edit mode
|
|
277
280
|
|
|
278
281
|
return /*#__PURE__*/React.createElement(Overlay, {
|
|
279
282
|
onClick: this.editingOn,
|
|
280
283
|
wrapperClassName: styles.quizEntryWrapper,
|
|
281
|
-
tabIndex: "-1"
|
|
284
|
+
tabIndex: "-1",
|
|
285
|
+
hideOverlay: shouldLockQuizEntry
|
|
282
286
|
}, /*#__PURE__*/React.createElement(DragAndDropZone, Object.assign({}, propsForDnDZone, {
|
|
283
287
|
location: "above"
|
|
284
288
|
})), connectDragPreview( /*#__PURE__*/React.createElement("div", {
|
|
@@ -303,7 +307,10 @@ var QuizEntryShow = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
|
|
|
303
307
|
scrollKey: this.props.scrollKey,
|
|
304
308
|
shouldDisableDragHandle: this.shouldDisableDragHandle(),
|
|
305
309
|
switchOnEditing: this.editingOn,
|
|
306
|
-
shouldFocusOnMount: this.props.editQuizEntryToggle
|
|
310
|
+
shouldFocusOnMount: this.props.editQuizEntryToggle,
|
|
311
|
+
shouldDisableCopy: shouldLockQuizEntry,
|
|
312
|
+
shouldRenderEdit: !shouldLockQuizEntry,
|
|
313
|
+
shouldRenderDelete: !shouldLockQuizEntry
|
|
307
314
|
}), /*#__PURE__*/React.createElement(ScreenReaderContent, null, srMsg)), /*#__PURE__*/React.createElement("div", {
|
|
308
315
|
className: styles.itemHolder,
|
|
309
316
|
ref: this.setInert,
|
|
@@ -331,10 +338,12 @@ var QuizEntryShow = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
|
|
|
331
338
|
// only used in index.js
|
|
332
339
|
interactionTypeName: PropTypes.string,
|
|
333
340
|
modificationsClear: PropTypes.bool.isRequired,
|
|
341
|
+
lockBlueprintContentEnabled: PropTypes.bool.isRequired,
|
|
334
342
|
quizEntryWithErrorsShowing: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
|
|
335
343
|
quizEntries: ImmutablePropTypes.listOf(ImmutablePropTypes.record).isRequired,
|
|
336
344
|
quizEntry: ImmutablePropTypes.record.isRequired,
|
|
337
345
|
quizId: PropTypes.string.isRequired,
|
|
346
|
+
isContentLockedByBlueprint: PropTypes.bool.isRequired,
|
|
338
347
|
removeQuizEntry: PropTypes.func.isRequired,
|
|
339
348
|
// from connected component
|
|
340
349
|
richFITBEnabled: PropTypes.bool,
|
|
@@ -351,11 +360,13 @@ var QuizEntryShow = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
|
|
|
351
360
|
children: null,
|
|
352
361
|
draggingOver: false,
|
|
353
362
|
draggingAboveHalf: false,
|
|
363
|
+
lockBlueprintContentEnabled: false,
|
|
354
364
|
quizEntryWithErrorsShowing: null,
|
|
355
365
|
scrollKey: void 0,
|
|
356
366
|
editQuizEntryToggle: false,
|
|
357
367
|
haveValidationErrorsFromApi: false,
|
|
358
368
|
interactionTypeName: null,
|
|
369
|
+
isContentLockedByBlueprint: false,
|
|
359
370
|
richFITBEnabled: false,
|
|
360
371
|
richFITBInteractionID: '',
|
|
361
372
|
stimulusOrientation: null
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RCE_EVENT, SET_RCE_ERROR } from '@instructure/quiz-common';
|
|
2
|
+
export var setRCEError = function setRCEError(rceError) {
|
|
3
|
+
return {
|
|
4
|
+
type: SET_RCE_ERROR,
|
|
5
|
+
payload: rceError
|
|
6
|
+
};
|
|
7
|
+
}; // This is not consumed by its reducer
|
|
8
|
+
// Instead it is processed by the eventLoggerMiddleware
|
|
9
|
+
|
|
10
|
+
export var reportRCEEvent = function reportRCEEvent(eventMessage) {
|
|
11
|
+
return {
|
|
12
|
+
type: RCE_EVENT,
|
|
13
|
+
payload: {
|
|
14
|
+
message: eventMessage
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -159,11 +159,11 @@ export var SDKApp = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
|
|
|
159
159
|
rceConfig: PropTypes.shape({
|
|
160
160
|
contextId: PropTypes.string.isRequired,
|
|
161
161
|
contextType: PropTypes.string.isRequired,
|
|
162
|
+
canvasOrigin: PropTypes.string.isRequired,
|
|
162
163
|
canvasUserId: PropTypes.string.isRequired,
|
|
163
164
|
rcsHost: PropTypes.string.isRequired,
|
|
164
165
|
rcsJwt: PropTypes.string.isRequired,
|
|
165
|
-
rcsJwtRefreshFn: PropTypes.func.isRequired
|
|
166
|
-
documentServiceHost: PropTypes.string.isRequired
|
|
166
|
+
rcsJwtRefreshFn: PropTypes.func.isRequired
|
|
167
167
|
}),
|
|
168
168
|
timeZone: PropTypes.string,
|
|
169
169
|
translations: PropTypes.objectOf(PropTypes.shape({
|
|
@@ -15,6 +15,7 @@ var mapStateToProps = function mapStateToProps(state, props) {
|
|
|
15
15
|
dropIntoEmptyStimulus: draggingOver && dropIntoEmptyStimulus,
|
|
16
16
|
draggingOver: draggingOver,
|
|
17
17
|
draggingAboveHalf: draggingOver && draggingAboveHalf,
|
|
18
|
+
lockBlueprintContentEnabled: featureOn('lock_blueprint_content'),
|
|
18
19
|
stimulusOrientationEnabled: featureOn('customizable_stimulus_orientation')
|
|
19
20
|
};
|
|
20
21
|
};
|
|
@@ -75,6 +75,14 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
75
75
|
quizEntry = _this$props.quizEntry;
|
|
76
76
|
return quizEntries.size === quizEntry.positionSlots + 1;
|
|
77
77
|
}
|
|
78
|
+
}, {
|
|
79
|
+
key: "isQuizContentLocked",
|
|
80
|
+
value: function isQuizContentLocked() {
|
|
81
|
+
var _this$props2 = this.props,
|
|
82
|
+
isContentLockedByBlueprint = _this$props2.isContentLockedByBlueprint,
|
|
83
|
+
lockBlueprintContentEnabled = _this$props2.lockBlueprintContentEnabled;
|
|
84
|
+
return lockBlueprintContentEnabled && isContentLockedByBlueprint;
|
|
85
|
+
}
|
|
78
86
|
}, {
|
|
79
87
|
key: "renderChildQuizEntries",
|
|
80
88
|
value: function renderChildQuizEntries() {
|
|
@@ -89,7 +97,7 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
89
97
|
key: childEntry.id
|
|
90
98
|
}, /*#__PURE__*/React.createElement(ConnectedQuizEntry, Object.assign({}, _this2.props.propsForQuizEntry(childEntry, displayPosition), {
|
|
91
99
|
stimulusOrientation: _this2.props.stimulusOrientationEnabled ? _this2.props.stimulus.orientation : null
|
|
92
|
-
})), !_this2.props.draggingOnBuild && /*#__PURE__*/React.createElement(AddContentPopover, {
|
|
100
|
+
})), !_this2.props.draggingOnBuild && !_this2.isQuizContentLocked() && /*#__PURE__*/React.createElement(AddContentPopover, {
|
|
93
101
|
allowStimulusCreation: false,
|
|
94
102
|
stimulusId: _this2.props.stimulus.id,
|
|
95
103
|
parentEntryId: _this2.props.quizEntry.id,
|
|
@@ -123,7 +131,8 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
123
131
|
switchOnEditing: this.props.switchOnEditing,
|
|
124
132
|
switchOffEditing: this.props.switchOffEditing,
|
|
125
133
|
onEditToggle: this.props.onEditStimulusToggle,
|
|
126
|
-
shouldFocusOnMount: this.props.editStimulusToggle
|
|
134
|
+
shouldFocusOnMount: this.props.editStimulusToggle,
|
|
135
|
+
isQuizContentLocked: this.isQuizContentLocked()
|
|
127
136
|
})));
|
|
128
137
|
}
|
|
129
138
|
}, {
|
|
@@ -131,9 +140,9 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
131
140
|
value: function renderPanels(propsForDnDZone) {
|
|
132
141
|
var _classnames2;
|
|
133
142
|
|
|
134
|
-
var _this$
|
|
135
|
-
stimulus = _this$
|
|
136
|
-
stimulusOrientationEnabled = _this$
|
|
143
|
+
var _this$props3 = this.props,
|
|
144
|
+
stimulus = _this$props3.stimulus,
|
|
145
|
+
stimulusOrientationEnabled = _this$props3.stimulusOrientationEnabled;
|
|
137
146
|
var shouldSetHorizontalOrientation = stimulus.orientation === LEFT || !stimulusOrientationEnabled;
|
|
138
147
|
var stimulusPanelClass = classnames(styles.leftPanel, _defineProperty({}, styles.horizontallyAligned, shouldSetHorizontalOrientation));
|
|
139
148
|
var itemsPanelClass = classnames((_classnames2 = {}, _defineProperty(_classnames2, styles.horizontallyAligned, shouldSetHorizontalOrientation), _defineProperty(_classnames2, styles.hidden, stimulus.isTemporary()), _defineProperty(_classnames2, styles.rightPanel, !stimulus.isTemporary()), _classnames2));
|
|
@@ -147,7 +156,7 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
147
156
|
className: itemsPanelClass
|
|
148
157
|
}, /*#__PURE__*/React.createElement("div", null), this.renderChildQuizEntries(), /*#__PURE__*/React.createElement(DragAndDropZone, Object.assign({}, propsForDnDZone, {
|
|
149
158
|
location: "in"
|
|
150
|
-
})), this.props.childEntries.size === 0 && /*#__PURE__*/React.createElement(AddContentPopover, {
|
|
159
|
+
})), this.props.childEntries.size === 0 && !this.isQuizContentLocked() && /*#__PURE__*/React.createElement(AddContentPopover, {
|
|
151
160
|
allowStimulusCreation: false,
|
|
152
161
|
stimulusId: this.props.stimulus.id,
|
|
153
162
|
parentEntryId: this.props.quizEntry.id,
|
|
@@ -189,8 +198,10 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
189
198
|
dropIntoEmptyStimulus: PropTypes.bool,
|
|
190
199
|
displayPosition: PropTypes.number.isRequired,
|
|
191
200
|
isBankedContent: PropTypes.bool,
|
|
201
|
+
isContentLockedByBlueprint: PropTypes.bool.isRequired,
|
|
192
202
|
isEditing: PropTypes.bool,
|
|
193
203
|
guid: PropTypes.string.isRequired,
|
|
204
|
+
lockBlueprintContentEnabled: PropTypes.bool.isRequired,
|
|
194
205
|
openDeleteStimulusModal: PropTypes.func.isRequired,
|
|
195
206
|
propsForQuizEntry: PropTypes.func.isRequired,
|
|
196
207
|
quizEntry: ImmutablePropTypes.record.isRequired,
|
|
@@ -215,7 +226,9 @@ export var Stimulus = (_dec = themeable(theme, styles), _dec(_class = (_temp = _
|
|
|
215
226
|
dropIntoEmptyStimulus: false,
|
|
216
227
|
isBankedContent: false,
|
|
217
228
|
isEditing: false,
|
|
229
|
+
lockBlueprintContentEnabled: false,
|
|
218
230
|
onEditStimulusToggle: function onEditStimulusToggle() {},
|
|
219
|
-
scrollKey: ''
|
|
231
|
+
scrollKey: '',
|
|
232
|
+
isContentLockedByBlueprint: false
|
|
220
233
|
}, _temp)) || _class);
|
|
221
234
|
export default DragSource(ItemTypes.QUIZ_ENTRY, dragSource, collectDrag)(wrapWithOutsideClick(Stimulus));
|
|
@@ -66,7 +66,8 @@ export var StimulusShow = (_dec = themeable(theme, styles), _dec(_class = (_temp
|
|
|
66
66
|
return /*#__PURE__*/React.createElement(Overlay, {
|
|
67
67
|
onClick: this.switchOnEditing,
|
|
68
68
|
wrapperClassName: styles.stimulusWrapper,
|
|
69
|
-
tabIndex: "-1"
|
|
69
|
+
tabIndex: "-1",
|
|
70
|
+
hideOverlay: this.props.isQuizContentLocked
|
|
70
71
|
}, /*#__PURE__*/React.createElement("div", {
|
|
71
72
|
className: styles.stimulus
|
|
72
73
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -84,10 +85,13 @@ export var StimulusShow = (_dec = themeable(theme, styles), _dec(_class = (_temp
|
|
|
84
85
|
scrollKey: this.props.scrollKey,
|
|
85
86
|
shouldDisableDragHandle: this.props.shouldDisableDragHandle,
|
|
86
87
|
switchOnEditing: this.props.switchOnEditing,
|
|
87
|
-
shouldFocusOnMount: this.props.shouldFocusOnMount
|
|
88
|
+
shouldFocusOnMount: this.props.shouldFocusOnMount,
|
|
89
|
+
shouldDisableCopy: this.props.isQuizContentLocked,
|
|
90
|
+
shouldRenderEdit: !this.props.isQuizContentLocked,
|
|
91
|
+
shouldRenderDelete: !this.props.isQuizContentLocked
|
|
88
92
|
})), /*#__PURE__*/React.createElement("div", {
|
|
89
93
|
role: "presentation",
|
|
90
|
-
onClick: this.switchOnEditing,
|
|
94
|
+
onClick: this.props.isQuizContentLocked ? null : this.switchOnEditing,
|
|
91
95
|
className: styles.stimulusContent
|
|
92
96
|
}, /*#__PURE__*/React.createElement(StimulusShowInfo, {
|
|
93
97
|
stimulus: this.props.stimulus
|
|
@@ -101,6 +105,7 @@ export var StimulusShow = (_dec = themeable(theme, styles), _dec(_class = (_temp
|
|
|
101
105
|
connectDragSource: PropTypes.func.isRequired,
|
|
102
106
|
displayPosition: PropTypes.number.isRequired,
|
|
103
107
|
isBankedContent: PropTypes.bool,
|
|
108
|
+
isQuizContentLocked: PropTypes.bool.isRequired,
|
|
104
109
|
openDeleteStimulusModal: PropTypes.func.isRequired,
|
|
105
110
|
quizEntries: ImmutablePropTypes.listOf(ImmutablePropTypes.record).isRequired,
|
|
106
111
|
quizEntry: ImmutablePropTypes.record.isRequired,
|
|
@@ -111,6 +116,7 @@ export var StimulusShow = (_dec = themeable(theme, styles), _dec(_class = (_temp
|
|
|
111
116
|
shouldFocusOnMount: PropTypes.bool.isRequired
|
|
112
117
|
}, _class2.defaultProps = {
|
|
113
118
|
isBankedContent: false,
|
|
119
|
+
isQuizContentLocked: false,
|
|
114
120
|
scrollKey: '',
|
|
115
121
|
shouldDisableDragHandle: false,
|
|
116
122
|
shouldFocusOnMount: false
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EVENT_RESPONSE, QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT } from "./eventTypes.js";
|
|
1
|
+
import { EVENT_RESPONSE, QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT } from "./eventTypes.js";
|
|
2
2
|
export var assembleKinesisConfig = function assembleKinesisConfig(apiConfig) {
|
|
3
3
|
return Object.assign({
|
|
4
4
|
apiVersion: '2013-12-02'
|
|
@@ -19,7 +19,8 @@ export var eventStreamConfig = function eventStreamConfig(defaultStreamConfig, s
|
|
|
19
19
|
eventTypes: {
|
|
20
20
|
RESPONSE: EVENT_RESPONSE,
|
|
21
21
|
SESSION_STARTED_OR_RESUMED_EVENT: SESSION_STARTED_OR_RESUMED_EVENT,
|
|
22
|
-
QUIZ_SUBMISSION_EVENT: QUIZ_SUBMISSION_EVENT
|
|
22
|
+
QUIZ_SUBMISSION_EVENT: QUIZ_SUBMISSION_EVENT,
|
|
23
|
+
RCE_EVENT: RCE_EVENT
|
|
23
24
|
},
|
|
24
25
|
stream: stream
|
|
25
26
|
});
|
|
@@ -34,4 +34,5 @@ export var RESPONSE = eventType(function (data) {
|
|
|
34
34
|
});
|
|
35
35
|
export var EVENT_RESPONSE = eventType();
|
|
36
36
|
export var SESSION_STARTED_OR_RESUMED_EVENT = eventType();
|
|
37
|
-
export var QUIZ_SUBMISSION_EVENT = eventType();
|
|
37
|
+
export var QUIZ_SUBMISSION_EVENT = eventType();
|
|
38
|
+
export var RCE_EVENT = eventType();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Map } from 'immutable';
|
|
2
|
+
import { SET_RCE_ERROR } from '@instructure/quiz-common';
|
|
3
|
+
|
|
4
|
+
var setRceError = function setRceError(state, payload) {
|
|
5
|
+
return state.set('rceError', payload);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export default (function () {
|
|
9
|
+
var state = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : Map();
|
|
10
|
+
var action = arguments.length > 1 ? arguments[1] : void 0;
|
|
11
|
+
|
|
12
|
+
switch (action.type) {
|
|
13
|
+
case SET_RCE_ERROR:
|
|
14
|
+
return setRceError(state, action.payload);
|
|
15
|
+
|
|
16
|
+
default:
|
|
17
|
+
return state;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
@@ -6,14 +6,18 @@ import React, { useEffect, useState } from 'react';
|
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import { connect } from "../../common/react-redux.js";
|
|
8
8
|
import store from "../../reduxStore.js";
|
|
9
|
+
import { setRCEError } from "../actions/rce.js";
|
|
9
10
|
import isNewRCEEnabled from "./rceChecker.js";
|
|
10
11
|
import { QuizzesSpinner as Spinner } from "../components/shared/spinner/Spinner.js";
|
|
11
12
|
import { RceConfigContext, RceConfigKeys } from '@instructure/quiz-common';
|
|
12
13
|
import { addError } from "../actions/alerts.js";
|
|
14
|
+
import t from '@instructure/quiz-i18n/es/format-message';
|
|
15
|
+
import { extractTextFromHtml } from '@instructure/quiz-interactions';
|
|
16
|
+
import { isDuringQuizTake } from "./windowChecks.js";
|
|
13
17
|
|
|
14
18
|
var _ref4 = /*#__PURE__*/React.createElement(Spinner, null);
|
|
15
19
|
|
|
16
|
-
var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
20
|
+
export var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
17
21
|
var _useState = useState(props.rcsJwt),
|
|
18
22
|
_useState2 = _slicedToArray(_useState, 2),
|
|
19
23
|
jwt = _useState2[0],
|
|
@@ -34,10 +38,10 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
|
34
38
|
};
|
|
35
39
|
|
|
36
40
|
var refreshToken = /*#__PURE__*/function () {
|
|
37
|
-
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(setTokenFn) {
|
|
41
|
+
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(setTokenFn, questionStem) {
|
|
38
42
|
var _response$json;
|
|
39
43
|
|
|
40
|
-
var response, refreshedToken;
|
|
44
|
+
var response, refreshedToken, normalizedStem, extractedText;
|
|
41
45
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
42
46
|
while (1) {
|
|
43
47
|
switch (_context.prev = _context.next) {
|
|
@@ -59,18 +63,23 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
|
59
63
|
refreshedToken = response === null || response === void 0 ? void 0 : (_response$json = response.json) === null || _response$json === void 0 ? void 0 : _response$json.token; // inst-redux-service-middleware response structure
|
|
60
64
|
|
|
61
65
|
if (refreshedToken) {
|
|
62
|
-
_context.next =
|
|
66
|
+
_context.next = 13;
|
|
63
67
|
break;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
handleErrorFunc('Unable to refresh RCS token');
|
|
71
|
+
normalizedStem = questionStem !== null && questionStem !== void 0 ? questionStem : 'Unknown stem';
|
|
72
|
+
extractedText = extractTextFromHtml(normalizedStem);
|
|
73
|
+
setErrorIfDuringTaking(t('Error while answering "{stem}": Full functionality of the Rich Content Editor may not have been available to the user.', {
|
|
74
|
+
stem: extractedText
|
|
75
|
+
}));
|
|
67
76
|
return _context.abrupt("return");
|
|
68
77
|
|
|
69
|
-
case
|
|
78
|
+
case 13:
|
|
70
79
|
setJwt(refreshedToken);
|
|
71
80
|
setTokenFn(refreshedToken);
|
|
72
81
|
|
|
73
|
-
case
|
|
82
|
+
case 15:
|
|
74
83
|
case "end":
|
|
75
84
|
return _context.stop();
|
|
76
85
|
}
|
|
@@ -78,7 +87,7 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
|
78
87
|
}, _callee);
|
|
79
88
|
}));
|
|
80
89
|
|
|
81
|
-
return function refreshToken(_x) {
|
|
90
|
+
return function refreshToken(_x, _x2) {
|
|
82
91
|
return _ref.apply(this, arguments);
|
|
83
92
|
};
|
|
84
93
|
}();
|
|
@@ -92,20 +101,28 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
|
92
101
|
|
|
93
102
|
return {
|
|
94
103
|
rcs: hasAllPropsForRcs() && canvasConfig ? (_ref2 = {}, _defineProperty(_ref2, RceConfigKeys.useNewRce, props.useNewRce), _defineProperty(_ref2, RceConfigKeys.canvasUserId, props.canvasUserId), _defineProperty(_ref2, RceConfigKeys.contextId, props.contextId), _defineProperty(_ref2, RceConfigKeys.contextType, props.contextType), _defineProperty(_ref2, RceConfigKeys.rcsHost, props.rcsHost), _defineProperty(_ref2, RceConfigKeys.rcsJwt, jwt), _defineProperty(_ref2, RceConfigKeys.rcsJwtRefreshFn, refreshToken), _defineProperty(_ref2, RceConfigKeys.canvasConfig, canvasConfig), _ref2) : null,
|
|
95
|
-
rendererEnhancement: (_rendererEnhancement = {}, _defineProperty(_rendererEnhancement, RceConfigKeys.handleError, handleErrorFunc), _defineProperty(_rendererEnhancement, RceConfigKeys.
|
|
104
|
+
rendererEnhancement: (_rendererEnhancement = {}, _defineProperty(_rendererEnhancement, RceConfigKeys.handleError, handleErrorFunc), _defineProperty(_rendererEnhancement, RceConfigKeys.canvasOrigin, props.canvasOrigin), _rendererEnhancement)
|
|
96
105
|
};
|
|
97
106
|
};
|
|
98
107
|
|
|
108
|
+
var setErrorIfDuringTaking = function setErrorIfDuringTaking(errorMessage) {
|
|
109
|
+
if (!isDuringQuizTake()) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
props.setRCEError(errorMessage);
|
|
114
|
+
};
|
|
115
|
+
|
|
99
116
|
useEffect(function () {
|
|
100
117
|
_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
101
|
-
var
|
|
118
|
+
var host, base, url, response, json;
|
|
102
119
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
103
120
|
while (1) {
|
|
104
121
|
switch (_context2.prev = _context2.next) {
|
|
105
122
|
case 0:
|
|
106
123
|
_context2.prev = 0;
|
|
107
124
|
|
|
108
|
-
if (
|
|
125
|
+
if (props.useNewRce) {
|
|
109
126
|
_context2.next = 3;
|
|
110
127
|
break;
|
|
111
128
|
}
|
|
@@ -113,41 +130,56 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
|
113
130
|
return _context2.abrupt("return");
|
|
114
131
|
|
|
115
132
|
case 3:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
133
|
+
if (hasAllPropsForRcs()) {
|
|
134
|
+
_context2.next = 6;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
setErrorIfDuringTaking(t('Error: Full functionality of the Rich Content Editor may not have been available to the user.'));
|
|
139
|
+
return _context2.abrupt("return");
|
|
140
|
+
|
|
141
|
+
case 6:
|
|
142
|
+
host = props.rcsHost;
|
|
143
|
+
base = host.match(/^https?:\/\//) ? host : "".concat(window.location.protocol, "//").concat(host);
|
|
144
|
+
url = new URL('/api/rceConfig', base);
|
|
145
|
+
url.searchParams.append('contextType', props.contextType);
|
|
146
|
+
url.searchParams.append('contextId', props.contextId);
|
|
147
|
+
_context2.next = 13;
|
|
148
|
+
return fetch(url.href, {
|
|
119
149
|
headers: {
|
|
120
150
|
'Authorization': "Bearer ".concat(props.rcsJwt)
|
|
121
151
|
}
|
|
122
152
|
});
|
|
123
153
|
|
|
124
|
-
case
|
|
154
|
+
case 13:
|
|
125
155
|
response = _context2.sent;
|
|
126
|
-
_context2.next =
|
|
156
|
+
_context2.next = 16;
|
|
127
157
|
return response.json();
|
|
128
158
|
|
|
129
|
-
case
|
|
159
|
+
case 16:
|
|
130
160
|
json = _context2.sent;
|
|
131
161
|
setCanvasConfig(json);
|
|
132
|
-
|
|
162
|
+
setErrorIfDuringTaking(null);
|
|
163
|
+
_context2.next = 25;
|
|
133
164
|
break;
|
|
134
165
|
|
|
135
|
-
case
|
|
136
|
-
_context2.prev =
|
|
166
|
+
case 21:
|
|
167
|
+
_context2.prev = 21;
|
|
137
168
|
_context2.t0 = _context2["catch"](0);
|
|
138
169
|
setCanvasConfig(null);
|
|
170
|
+
setErrorIfDuringTaking(t('Error: Full functionality of the Rich Content Editor including accessibility features may not have been available to the user.'));
|
|
139
171
|
|
|
140
|
-
case
|
|
141
|
-
_context2.prev =
|
|
172
|
+
case 25:
|
|
173
|
+
_context2.prev = 25;
|
|
142
174
|
setCanvasConfigLoading(false);
|
|
143
|
-
return _context2.finish(
|
|
175
|
+
return _context2.finish(25);
|
|
144
176
|
|
|
145
|
-
case
|
|
177
|
+
case 28:
|
|
146
178
|
case "end":
|
|
147
179
|
return _context2.stop();
|
|
148
180
|
}
|
|
149
181
|
}
|
|
150
|
-
}, _callee2, null, [[0,
|
|
182
|
+
}, _callee2, null, [[0, 21, 25, 28]]);
|
|
151
183
|
}))();
|
|
152
184
|
}, [props.useNewRce]);
|
|
153
185
|
if (!props.useNewRce) return /*#__PURE__*/React.createElement(React.Fragment, null, props.children);
|
|
@@ -155,17 +187,17 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
|
|
|
155
187
|
value: getConfig()
|
|
156
188
|
}, props.children);
|
|
157
189
|
};
|
|
158
|
-
|
|
159
190
|
RceConfigProviderComponent.propTypes = {
|
|
160
191
|
children: PropTypes.node.isRequired,
|
|
161
192
|
useNewRce: PropTypes.bool.isRequired,
|
|
193
|
+
setRCEError: PropTypes.func.isRequired,
|
|
162
194
|
contextId: PropTypes.string,
|
|
163
195
|
contextType: PropTypes.string,
|
|
164
196
|
canvasUserId: PropTypes.string,
|
|
165
197
|
rcsHost: PropTypes.string,
|
|
166
198
|
rcsJwt: PropTypes.string,
|
|
167
199
|
rcsJwtRefreshFn: PropTypes.func,
|
|
168
|
-
|
|
200
|
+
canvasOrigin: PropTypes.string
|
|
169
201
|
};
|
|
170
202
|
RceConfigProviderComponent.defaultProps = {
|
|
171
203
|
contextId: null,
|
|
@@ -174,7 +206,7 @@ RceConfigProviderComponent.defaultProps = {
|
|
|
174
206
|
rcsHost: null,
|
|
175
207
|
rcsJwt: null,
|
|
176
208
|
rcsJwtRefreshFn: null,
|
|
177
|
-
|
|
209
|
+
canvasOrigin: null
|
|
178
210
|
};
|
|
179
211
|
|
|
180
212
|
var mapStateToProps = function mapStateToProps() {
|
|
@@ -183,5 +215,8 @@ var mapStateToProps = function mapStateToProps() {
|
|
|
183
215
|
};
|
|
184
216
|
};
|
|
185
217
|
|
|
186
|
-
var
|
|
218
|
+
var mapDispatchToProps = {
|
|
219
|
+
setRCEError: setRCEError
|
|
220
|
+
};
|
|
221
|
+
var RceConfigProvider = connect(mapStateToProps, mapDispatchToProps)(RceConfigProviderComponent);
|
|
187
222
|
export { RceConfigProvider };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT } from '@instructure/quiz-common';
|
|
1
|
+
import { QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT } from '@instructure/quiz-common';
|
|
2
2
|
import { getBrowserSessionId } from "../selectors/taking.js";
|
|
3
3
|
import { getActiveQuizSession } from "../selectors/quizSessions.js";
|
|
4
|
-
var whitelist = [QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT];
|
|
4
|
+
var whitelist = [QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT];
|
|
5
5
|
export function serializeEvent(action, store) {
|
|
6
6
|
var type = action.type;
|
|
7
7
|
|
|
@@ -11,4 +11,10 @@ export var onTablet = function onTablet() {
|
|
|
11
11
|
var windowObj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : window;
|
|
12
12
|
var mediaQueryString = media['tablet-break-point'];
|
|
13
13
|
return !onPhone(windowObj) && windowObj.matchMedia(mediaQueryString).matches;
|
|
14
|
+
};
|
|
15
|
+
export var isDuringQuizTake = function isDuringQuizTake() {
|
|
16
|
+
var windowObj = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : window;
|
|
17
|
+
var locationPath = windowObj.location.pathname;
|
|
18
|
+
var patternOfQuizTakingPath = /taking\/\d+\/take/;
|
|
19
|
+
return !!locationPath.match(patternOfQuizTakingPath);
|
|
14
20
|
};
|
package/es/configureStore.js
CHANGED
|
@@ -44,6 +44,7 @@ import ui from "./common/reducers/ui.js";
|
|
|
44
44
|
import upload from "./common/reducers/upload.js";
|
|
45
45
|
import qtiImports from "./common/reducers/qtiImports.js";
|
|
46
46
|
import printing from "./common/reducers/printing.js";
|
|
47
|
+
import rce from "./common/reducers/rce.js";
|
|
47
48
|
import dragAndDrop from "./common/reducers/dragAndDrop.js";
|
|
48
49
|
import sharedBanks from "./common/reducers/sharedBanks.js";
|
|
49
50
|
export function configureStore(_ref) {
|
|
@@ -110,7 +111,8 @@ export function configureStore(_ref) {
|
|
|
110
111
|
tagAssociations: tagAssociations,
|
|
111
112
|
taking: taking,
|
|
112
113
|
ui: ui,
|
|
113
|
-
upload: upload
|
|
114
|
+
upload: upload,
|
|
115
|
+
rce: rce
|
|
114
116
|
});
|
|
115
117
|
return createStoreWithMiddlewareApplied(rootReducer, initialState);
|
|
116
118
|
}
|
package/es/index.js
CHANGED
|
@@ -113,6 +113,7 @@ export { showError, hideError, clearErrorsShowing } from "./common/actions/error
|
|
|
113
113
|
export { changeItemState, changeQuizEntryPoints, changeQuizEntryProperties, clearModifications, moveTemporaryQuizEntry, changeQuizOutcomeAlignmentSetGuid, changeFudgePoints, sessionItemResultsModification } from "./common/actions/modifications.js";
|
|
114
114
|
export { previousQuestion, editResponse, previewResponse, setCurrentSessionItemPosition, clearFocusCurrentSessionItem } from "./common/actions/taking.js";
|
|
115
115
|
export { scrollToItem } from "./common/actions/scrolling.js";
|
|
116
|
+
export { reportRCEEvent } from "./common/actions/rce.js";
|
|
116
117
|
export { toggleSidebar } from "./common/actions/sidebar.js";
|
|
117
118
|
export { newHoverPosition } from "./common/actions/dragAndDrop.js";
|
|
118
119
|
export { set, setActiveCalculatorId } from "./common/actions/ui.js";
|
|
@@ -129,6 +130,7 @@ export { getItemById } from "./common/selectors/items.js";
|
|
|
129
130
|
export { fileUploading } from "./common/selectors/calls.js";
|
|
130
131
|
export { isTimeUp, getTimerData, getResponseDataByPosition } from "./common/selectors/taking.js";
|
|
131
132
|
export { getActiveCalculatorId } from "./common/selectors/ui.js";
|
|
133
|
+
export { getRCEError } from "./common/selectors/rce.js";
|
|
132
134
|
export { getQuizSessionById, getActiveQuizSession, getBacktrackingIsAllowed, isOneQuestionAtATime } from "./common/selectors/quizSessions.js";
|
|
133
135
|
export { getGradingSessionItems } from "./common/selectors/sessionItems.js";
|
|
134
136
|
export { getGradingSessionItemResults } from "./common/selectors/sessionItemResults.js"; // Records
|