@instructure/quiz-core 17.41.1-rc.2 → 17.41.1-rc.20

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 (41) hide show
  1. package/es/building/components/resources/ActionButtons/presenter.js +2 -1
  2. package/es/building/components/resources/quizEntry/QuizEntry/presenter.js +4 -1
  3. package/es/building/components/resources/quizEntry/QuizEntryShow/index.js +1 -0
  4. package/es/building/components/resources/quizEntry/QuizEntryShow/presenter.js +15 -4
  5. package/es/common/actions/rce.js +17 -0
  6. package/es/common/components/SDKApp/index.js +2 -2
  7. package/es/common/components/resources/stimulus/Stimulus/index.js +1 -0
  8. package/es/common/components/resources/stimulus/Stimulus/presenter.js +20 -7
  9. package/es/common/components/resources/stimulus/StimulusShow/index.js +9 -3
  10. package/es/common/kinesis/config.js +3 -2
  11. package/es/common/kinesis/eventTypes.js +2 -1
  12. package/es/common/reducers/rce.js +19 -0
  13. package/es/common/selectors/rce.js +3 -0
  14. package/es/common/util/RceConfigProvider.js +63 -27
  15. package/es/common/util/serializeEvent.js +2 -2
  16. package/es/common/util/windowChecks.js +6 -0
  17. package/es/configureStore.js +3 -1
  18. package/es/index.js +2 -0
  19. package/es/moderating/components/events/Event.js +7 -1
  20. package/es/moderating/components/events/RCEEvent.js +34 -0
  21. package/lib/building/components/resources/ActionButtons/presenter.js +2 -1
  22. package/lib/building/components/resources/quizEntry/QuizEntry/presenter.js +4 -1
  23. package/lib/building/components/resources/quizEntry/QuizEntryShow/index.js +1 -0
  24. package/lib/building/components/resources/quizEntry/QuizEntryShow/presenter.js +15 -4
  25. package/lib/common/actions/rce.js +30 -0
  26. package/lib/common/components/SDKApp/index.js +2 -2
  27. package/lib/common/components/resources/stimulus/Stimulus/index.js +1 -0
  28. package/lib/common/components/resources/stimulus/Stimulus/presenter.js +20 -7
  29. package/lib/common/components/resources/stimulus/StimulusShow/index.js +9 -3
  30. package/lib/common/kinesis/config.js +2 -1
  31. package/lib/common/kinesis/eventTypes.js +4 -2
  32. package/lib/common/reducers/rce.js +29 -0
  33. package/lib/common/selectors/rce.js +12 -0
  34. package/lib/common/util/RceConfigProvider.js +68 -26
  35. package/lib/common/util/serializeEvent.js +1 -1
  36. package/lib/common/util/windowChecks.js +11 -2
  37. package/lib/configureStore.js +4 -1
  38. package/lib/index.js +18 -0
  39. package/lib/moderating/components/events/Event.js +7 -0
  40. package/lib/moderating/components/events/RCEEvent.js +53 -0
  41. package/package.json +10 -10
@@ -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],
@@ -37,7 +41,7 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
37
41
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(setTokenFn) {
38
42
  var _response$json;
39
43
 
40
- var response, refreshedToken;
44
+ var response, refreshedToken, stemPlaceholder, extractedText;
41
45
  return _regeneratorRuntime.wrap(function _callee$(_context) {
42
46
  while (1) {
43
47
  switch (_context.prev = _context.next) {
@@ -59,18 +63,24 @@ 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
- handleErrorFunc('Unable to refresh RCS token');
70
+ handleErrorFunc('Unable to refresh RCS token'); // TODO: provide question context for this function so it can actually get the question stem / instruction text
71
+
72
+ stemPlaceholder = 'Example question stem text';
73
+ extractedText = extractTextFromHtml(stemPlaceholder);
74
+ setErrorIfDuringTaking(t('Error while answering: {stem}: Full functionality of the Rich Content Editor may not have been available to the user.', {
75
+ stem: extractedText
76
+ }));
67
77
  return _context.abrupt("return");
68
78
 
69
- case 10:
79
+ case 13:
70
80
  setJwt(refreshedToken);
71
81
  setTokenFn(refreshedToken);
72
82
 
73
- case 12:
83
+ case 15:
74
84
  case "end":
75
85
  return _context.stop();
76
86
  }
@@ -92,20 +102,28 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
92
102
 
93
103
  return {
94
104
  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)
105
+ rendererEnhancement: (_rendererEnhancement = {}, _defineProperty(_rendererEnhancement, RceConfigKeys.handleError, handleErrorFunc), _defineProperty(_rendererEnhancement, RceConfigKeys.canvasOrigin, props.canvasOrigin), _rendererEnhancement)
96
106
  };
97
107
  };
98
108
 
109
+ var setErrorIfDuringTaking = function setErrorIfDuringTaking(errorMessage) {
110
+ if (!isDuringQuizTake()) {
111
+ return;
112
+ }
113
+
114
+ props.setRCEError(errorMessage);
115
+ };
116
+
99
117
  useEffect(function () {
100
118
  _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
101
- var endpoint, response, json;
119
+ var host, base, url, response, json;
102
120
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
103
121
  while (1) {
104
122
  switch (_context2.prev = _context2.next) {
105
123
  case 0:
106
124
  _context2.prev = 0;
107
125
 
108
- if (!(!props.useNewRce || !hasAllPropsForRcs())) {
126
+ if (props.useNewRce) {
109
127
  _context2.next = 3;
110
128
  break;
111
129
  }
@@ -113,41 +131,56 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
113
131
  return _context2.abrupt("return");
114
132
 
115
133
  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, {
134
+ if (hasAllPropsForRcs()) {
135
+ _context2.next = 6;
136
+ break;
137
+ }
138
+
139
+ setErrorIfDuringTaking(t('Error: Full functionality of the Rich Content Editor may not have been available to the user.'));
140
+ return _context2.abrupt("return");
141
+
142
+ case 6:
143
+ host = props.rcsHost;
144
+ base = host.match(/^https?:\/\//) ? host : "".concat(window.location.protocol, "//").concat(host);
145
+ url = new URL('/api/rceConfig', base);
146
+ url.searchParams.append('contextType', props.contextType);
147
+ url.searchParams.append('contextId', props.contextId);
148
+ _context2.next = 13;
149
+ return fetch(url.href, {
119
150
  headers: {
120
151
  'Authorization': "Bearer ".concat(props.rcsJwt)
121
152
  }
122
153
  });
123
154
 
124
- case 6:
155
+ case 13:
125
156
  response = _context2.sent;
126
- _context2.next = 9;
157
+ _context2.next = 16;
127
158
  return response.json();
128
159
 
129
- case 9:
160
+ case 16:
130
161
  json = _context2.sent;
131
162
  setCanvasConfig(json);
132
- _context2.next = 16;
163
+ setErrorIfDuringTaking(null);
164
+ _context2.next = 25;
133
165
  break;
134
166
 
135
- case 13:
136
- _context2.prev = 13;
167
+ case 21:
168
+ _context2.prev = 21;
137
169
  _context2.t0 = _context2["catch"](0);
138
170
  setCanvasConfig(null);
171
+ setErrorIfDuringTaking(t('Error: Full functionality of the Rich Content Editor including accessibility features may not have been available to the user.'));
139
172
 
140
- case 16:
141
- _context2.prev = 16;
173
+ case 25:
174
+ _context2.prev = 25;
142
175
  setCanvasConfigLoading(false);
143
- return _context2.finish(16);
176
+ return _context2.finish(25);
144
177
 
145
- case 19:
178
+ case 28:
146
179
  case "end":
147
180
  return _context2.stop();
148
181
  }
149
182
  }
150
- }, _callee2, null, [[0, 13, 16, 19]]);
183
+ }, _callee2, null, [[0, 21, 25, 28]]);
151
184
  }))();
152
185
  }, [props.useNewRce]);
153
186
  if (!props.useNewRce) return /*#__PURE__*/React.createElement(React.Fragment, null, props.children);
@@ -155,17 +188,17 @@ var RceConfigProviderComponent = function RceConfigProviderComponent(props) {
155
188
  value: getConfig()
156
189
  }, props.children);
157
190
  };
158
-
159
191
  RceConfigProviderComponent.propTypes = {
160
192
  children: PropTypes.node.isRequired,
161
193
  useNewRce: PropTypes.bool.isRequired,
194
+ setRCEError: PropTypes.func.isRequired,
162
195
  contextId: PropTypes.string,
163
196
  contextType: PropTypes.string,
164
197
  canvasUserId: PropTypes.string,
165
198
  rcsHost: PropTypes.string,
166
199
  rcsJwt: PropTypes.string,
167
200
  rcsJwtRefreshFn: PropTypes.func,
168
- documentServiceHost: PropTypes.string
201
+ canvasOrigin: PropTypes.string
169
202
  };
170
203
  RceConfigProviderComponent.defaultProps = {
171
204
  contextId: null,
@@ -174,7 +207,7 @@ RceConfigProviderComponent.defaultProps = {
174
207
  rcsHost: null,
175
208
  rcsJwt: null,
176
209
  rcsJwtRefreshFn: null,
177
- documentServiceHost: null
210
+ canvasOrigin: null
178
211
  };
179
212
 
180
213
  var mapStateToProps = function mapStateToProps() {
@@ -183,5 +216,8 @@ var mapStateToProps = function mapStateToProps() {
183
216
  };
184
217
  };
185
218
 
186
- var RceConfigProvider = connect(mapStateToProps)(RceConfigProviderComponent);
219
+ var mapDispatchToProps = {
220
+ setRCEError: setRCEError
221
+ };
222
+ var RceConfigProvider = connect(mapStateToProps, mapDispatchToProps)(RceConfigProviderComponent);
187
223
  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
@@ -5,11 +5,12 @@ import _createSuper from "@babel/runtime/helpers/esm/createSuper";
5
5
  import React, { Component } from 'react';
6
6
  import PropTypes from 'prop-types';
7
7
  import ImmutablePropTypes from 'react-immutable-proptypes';
8
- import { RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT } from '@instructure/quiz-common';
8
+ import { RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT } from '@instructure/quiz-common';
9
9
  import { Table } from '@instructure/ui-table';
10
10
  import ElapsedTime from "../resources/ElapsedTime.js";
11
11
  import ResponseEvent from "./ResponseEvent.js";
12
12
  import SessionStartEvent from "./SessionStartEvent.js";
13
+ import RCEEvent from "./RCEEvent.js";
13
14
  export var Event = /*#__PURE__*/function (_Component) {
14
15
  _inherits(Event, _Component);
15
16
 
@@ -48,6 +49,11 @@ export var Event = /*#__PURE__*/function (_Component) {
48
49
  event: event
49
50
  });
50
51
 
52
+ case RCE_EVENT:
53
+ return /*#__PURE__*/React.createElement(RCEEvent, {
54
+ event: event
55
+ });
56
+
51
57
  default:
52
58
  return null;
53
59
  // unknown event