@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.
Files changed (42) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/es/building/components/resources/ActionButtons/presenter.js +2 -1
  3. package/es/building/components/resources/quizEntry/QuizEntry/presenter.js +4 -1
  4. package/es/building/components/resources/quizEntry/QuizEntryShow/index.js +1 -0
  5. package/es/building/components/resources/quizEntry/QuizEntryShow/presenter.js +15 -4
  6. package/es/common/actions/rce.js +17 -0
  7. package/es/common/components/SDKApp/index.js +2 -2
  8. package/es/common/components/resources/stimulus/Stimulus/index.js +1 -0
  9. package/es/common/components/resources/stimulus/Stimulus/presenter.js +20 -7
  10. package/es/common/components/resources/stimulus/StimulusShow/index.js +9 -3
  11. package/es/common/kinesis/config.js +3 -2
  12. package/es/common/kinesis/eventTypes.js +2 -1
  13. package/es/common/reducers/rce.js +19 -0
  14. package/es/common/selectors/rce.js +3 -0
  15. package/es/common/util/RceConfigProvider.js +63 -28
  16. package/es/common/util/serializeEvent.js +2 -2
  17. package/es/common/util/windowChecks.js +6 -0
  18. package/es/configureStore.js +3 -1
  19. package/es/index.js +2 -0
  20. package/es/moderating/components/events/Event.js +7 -1
  21. package/es/moderating/components/events/RCEEvent.js +34 -0
  22. package/lib/building/components/resources/ActionButtons/presenter.js +2 -1
  23. package/lib/building/components/resources/quizEntry/QuizEntry/presenter.js +4 -1
  24. package/lib/building/components/resources/quizEntry/QuizEntryShow/index.js +1 -0
  25. package/lib/building/components/resources/quizEntry/QuizEntryShow/presenter.js +15 -4
  26. package/lib/common/actions/rce.js +30 -0
  27. package/lib/common/components/SDKApp/index.js +2 -2
  28. package/lib/common/components/resources/stimulus/Stimulus/index.js +1 -0
  29. package/lib/common/components/resources/stimulus/Stimulus/presenter.js +20 -7
  30. package/lib/common/components/resources/stimulus/StimulusShow/index.js +9 -3
  31. package/lib/common/kinesis/config.js +2 -1
  32. package/lib/common/kinesis/eventTypes.js +4 -2
  33. package/lib/common/reducers/rce.js +29 -0
  34. package/lib/common/selectors/rce.js +12 -0
  35. package/lib/common/util/RceConfigProvider.js +68 -27
  36. package/lib/common/util/serializeEvent.js +1 -1
  37. package/lib/common/util/windowChecks.js +11 -2
  38. package/lib/configureStore.js +4 -1
  39. package/lib/index.js +18 -0
  40. package/lib/moderating/components/events/Event.js +7 -0
  41. package/lib/moderating/components/events/RCEEvent.js +53 -0
  42. 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
- }; // Overlay gets tabIndex === "-1" so that the drag handle is tabbable before
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$props2 = this.props,
135
- stimulus = _this$props2.stimulus,
136
- stimulusOrientationEnabled = _this$props2.stimulusOrientationEnabled;
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
+ });
@@ -0,0 +1,3 @@
1
+ export var getRCEError = function getRCEError(state) {
2
+ return state.getIn(['rce', 'rceError'], null);
3
+ };
@@ -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 = 10;
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 10:
78
+ case 13:
70
79
  setJwt(refreshedToken);
71
80
  setTokenFn(refreshedToken);
72
81
 
73
- case 12:
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.documentServiceHost, props.documentServiceHost), _rendererEnhancement)
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 endpoint, response, json;
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 (!(!props.useNewRce || !hasAllPropsForRcs())) {
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
- endpoint = "".concat(props.rcsHost, "/api/rceConfig?contextType=").concat(props.contextType, "&contextId=").concat(props.contextId);
117
- _context2.next = 6;
118
- return fetch(endpoint, {
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 6:
154
+ case 13:
125
155
  response = _context2.sent;
126
- _context2.next = 9;
156
+ _context2.next = 16;
127
157
  return response.json();
128
158
 
129
- case 9:
159
+ case 16:
130
160
  json = _context2.sent;
131
161
  setCanvasConfig(json);
132
- _context2.next = 16;
162
+ setErrorIfDuringTaking(null);
163
+ _context2.next = 25;
133
164
  break;
134
165
 
135
- case 13:
136
- _context2.prev = 13;
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 16:
141
- _context2.prev = 16;
172
+ case 25:
173
+ _context2.prev = 25;
142
174
  setCanvasConfigLoading(false);
143
- return _context2.finish(16);
175
+ return _context2.finish(25);
144
176
 
145
- case 19:
177
+ case 28:
146
178
  case "end":
147
179
  return _context2.stop();
148
180
  }
149
181
  }
150
- }, _callee2, null, [[0, 13, 16, 19]]);
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
- documentServiceHost: PropTypes.string
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
- documentServiceHost: null
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 RceConfigProvider = connect(mapStateToProps)(RceConfigProviderComponent);
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
  };
@@ -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