@instructure/quiz-core 17.46.2-rc.7 → 17.47.1-rc.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 (36) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/es/banks/components/AddToBankModal/index.js +6 -0
  3. package/es/banks/components/AddToBankModal/presenter.js +128 -6
  4. package/es/banks/components/BankEntry/presenter.js +4 -3
  5. package/es/building/api/items.js +21 -5
  6. package/es/building/api/stimuli.js +21 -5
  7. package/es/building/components/resources/quizEntry/QuizEntryEdit/presenter.js +1 -0
  8. package/es/common/actions/config.js +7 -1
  9. package/es/common/components/ApiFeatureFlagInitializer/index.js +36 -0
  10. package/es/common/components/ConfirmationModal/presenter.js +1 -1
  11. package/es/common/{util → components/RceConfigProvider}/RceConfigProvider.js +66 -51
  12. package/es/common/components/SDKApp/index.js +14 -7
  13. package/es/common/components/resources/entry/EntrySave/index.js +11 -5
  14. package/es/common/components/resources/entry/EntrySave/presenter.js +95 -21
  15. package/es/common/components/resources/stimulus/StimulusEdit/presenter.js +1 -0
  16. package/es/common/reducers/config.js +4 -1
  17. package/es/common/util/rceChecker.js +1 -1
  18. package/es/common/util/windowChecks.js +4 -1
  19. package/lib/banks/components/AddToBankModal/index.js +9 -0
  20. package/lib/banks/components/AddToBankModal/presenter.js +135 -6
  21. package/lib/banks/components/BankEntry/presenter.js +4 -3
  22. package/lib/building/api/items.js +23 -5
  23. package/lib/building/api/stimuli.js +23 -5
  24. package/lib/building/components/resources/quizEntry/QuizEntryEdit/presenter.js +1 -0
  25. package/lib/common/actions/config.js +8 -0
  26. package/lib/common/components/ApiFeatureFlagInitializer/index.js +53 -0
  27. package/lib/common/components/ConfirmationModal/presenter.js +1 -1
  28. package/lib/common/{util → components/RceConfigProvider}/RceConfigProvider.js +66 -51
  29. package/lib/common/components/SDKApp/index.js +17 -10
  30. package/lib/common/components/resources/entry/EntrySave/index.js +15 -2
  31. package/lib/common/components/resources/entry/EntrySave/presenter.js +96 -21
  32. package/lib/common/components/resources/stimulus/StimulusEdit/presenter.js +1 -0
  33. package/lib/common/reducers/config.js +3 -0
  34. package/lib/common/util/rceChecker.js +1 -1
  35. package/lib/common/util/windowChecks.js +8 -2
  36. package/package.json +10 -10
@@ -9,6 +9,10 @@ Object.defineProperty(exports, "__esModule", {
9
9
  });
10
10
  exports.default = exports.AddToBankModal = void 0;
11
11
 
12
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
13
+
14
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
15
+
12
16
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13
17
 
14
18
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
@@ -37,11 +41,36 @@ var _Bank = _interopRequireDefault(require("../../../common/records/Bank.js"));
37
41
 
38
42
  var _index = _interopRequireDefault(require("../../../common/components/resources/BankSelection/index.js"));
39
43
 
44
+ var _uiSpinner = require("@instructure/ui-spinner");
45
+
46
+ var _uiText = require("@instructure/ui-text");
47
+
48
+ var _uiIcons = require("@instructure/ui-icons");
49
+
50
+ var _uiView = require("@instructure/ui-view");
51
+
52
+ var _uiFlex = require("@instructure/ui-flex");
53
+
40
54
  var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
41
55
 
42
56
  var _quizCommon = require("@instructure/quiz-common");
43
57
 
44
- var _ref = /*#__PURE__*/_react.default.createElement("br", null);
58
+ var _ref2 = /*#__PURE__*/_react.default.createElement(_uiIcons.IconCheckLine, {
59
+ color: "success"
60
+ });
61
+
62
+ var _ref3 = /*#__PURE__*/_react.default.createElement(_uiFlex.Flex.Item, {
63
+ padding: "0 small 0 0"
64
+ }, /*#__PURE__*/_react.default.createElement(_uiIcons.IconNoLine, {
65
+ color: "error",
66
+ size: "small"
67
+ }));
68
+
69
+ var _ref4 = /*#__PURE__*/_react.default.createElement(_uiIcons.IconWarningLine, {
70
+ color: "warning"
71
+ });
72
+
73
+ var _ref5 = /*#__PURE__*/_react.default.createElement("br", null);
45
74
 
46
75
  var AddToBankModal = /*#__PURE__*/function (_Component) {
47
76
  (0, _inherits2.default)(AddToBankModal, _Component);
@@ -60,6 +89,7 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
60
89
  _this = _super.call.apply(_super, [this].concat(args));
61
90
  _this.state = {
62
91
  bankType: 'existing',
92
+ contentShareable: 'loading',
63
93
  newBankTitle: ''
64
94
  };
65
95
 
@@ -124,6 +154,65 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
124
154
  }
125
155
 
126
156
  (0, _createClass2.default)(AddToBankModal, [{
157
+ key: "componentDidUpdate",
158
+ value: function componentDidUpdate(prevProps) {
159
+ var _this2 = this;
160
+
161
+ var _this$props = this.props,
162
+ canvasOrigin = _this$props.canvasOrigin,
163
+ checkBankedContentShareabilityEnabled = _this$props.checkBankedContentShareabilityEnabled,
164
+ modalOpen = _this$props.modalOpen,
165
+ checkContentShareability = _this$props.checkContentShareability,
166
+ workingEntry = _this$props.workingEntry;
167
+
168
+ if (checkBankedContentShareabilityEnabled && modalOpen && !prevProps.modalOpen) {
169
+ this.setState({
170
+ contentShareable: 'loading'
171
+ });
172
+ checkContentShareability(workingEntry, canvasOrigin).then(function () {
173
+ _this2.setState({
174
+ contentShareable: 'true'
175
+ });
176
+ }).catch( /*#__PURE__*/function () {
177
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(err) {
178
+ var _err$response, _err$response2;
179
+
180
+ var body;
181
+ return _regenerator.default.wrap(function _callee$(_context) {
182
+ while (1) {
183
+ switch (_context.prev = _context.next) {
184
+ case 0:
185
+ _context.next = 2;
186
+ return (_err$response = err.response) === null || _err$response === void 0 ? void 0 : _err$response.json();
187
+
188
+ case 2:
189
+ body = _context.sent;
190
+
191
+ if (((_err$response2 = err.response) === null || _err$response2 === void 0 ? void 0 : _err$response2.status) === 400 && body.shareable === false) {
192
+ _this2.setState({
193
+ contentShareable: 'false'
194
+ });
195
+ } else {
196
+ _this2.setState({
197
+ contentShareable: 'unknown'
198
+ });
199
+ }
200
+
201
+ case 4:
202
+ case "end":
203
+ return _context.stop();
204
+ }
205
+ }
206
+ }, _callee);
207
+ }));
208
+
209
+ return function (_x) {
210
+ return _ref.apply(this, arguments);
211
+ };
212
+ }());
213
+ }
214
+ }
215
+ }, {
127
216
  key: "cancelButton",
128
217
  value: function cancelButton() {
129
218
  return /*#__PURE__*/_react.default.createElement(_uiButtons.Button, {
@@ -136,8 +225,11 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
136
225
  value: function addToBankButton() {
137
226
  var _this$state = this.state,
138
227
  bankType = _this$state.bankType,
139
- newBankTitle = _this$state.newBankTitle;
140
- var disabled = bankType === 'existing' && !this.props.selectedBank || bankType === 'new' && (!newBankTitle || !newBankTitle.trim());
228
+ newBankTitle = _this$state.newBankTitle,
229
+ contentShareable = _this$state.contentShareable;
230
+ var checkBankedContentShareabilityEnabled = this.props.checkBankedContentShareabilityEnabled;
231
+ var contentShareableLoading = contentShareable === 'loading';
232
+ var disabled = bankType === 'existing' && !this.props.selectedBank || bankType === 'new' && (!newBankTitle || !newBankTitle.trim()) || checkBankedContentShareabilityEnabled && contentShareableLoading;
141
233
  return /*#__PURE__*/_react.default.createElement(_uiButtons.Button, {
142
234
  type: "button",
143
235
  variant: "primary",
@@ -145,7 +237,7 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
145
237
  disabled: disabled,
146
238
  margin: _quizCommon.XSMALL_SIDE_MARGIN,
147
239
  "data-automation": "sdk-add-to-bank-button"
148
- }, (0, _formatMessage.default)('Add'));
240
+ }, checkBankedContentShareabilityEnabled && !contentShareableLoading && contentShareable !== 'true' ? (0, _formatMessage.default)('Add anyway') : (0, _formatMessage.default)('Add'));
149
241
  }
150
242
  }, {
151
243
  key: "renderBankTypeContent",
@@ -165,6 +257,37 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
165
257
  type: "text"
166
258
  });
167
259
  }
260
+ }, {
261
+ key: "renderContentShareabilityMessage",
262
+ value: function renderContentShareabilityMessage() {
263
+ if (this.props.checkBankedContentShareabilityEnabled) {
264
+ var content = null;
265
+
266
+ if (this.state.contentShareable === 'loading') {
267
+ content = /*#__PURE__*/_react.default.createElement(_uiText.Text, null, /*#__PURE__*/_react.default.createElement(_uiSpinner.Spinner, {
268
+ size: "x-small",
269
+ renderTitle: (0, _formatMessage.default)('Checking content shareability...')
270
+ }), "\xA0", (0, _formatMessage.default)('Validating content...'));
271
+ } else if (this.state.contentShareable === 'true') {
272
+ content = /*#__PURE__*/_react.default.createElement(_uiText.Text, null, _ref2, "\xA0", (0, _formatMessage.default)('Good to go!'));
273
+ } else if (this.state.contentShareable === 'false') {
274
+ content = /*#__PURE__*/_react.default.createElement(_uiFlex.Flex, null, _ref3, /*#__PURE__*/_react.default.createElement(_uiFlex.Flex.Item, {
275
+ shouldShrink: true
276
+ }, /*#__PURE__*/_react.default.createElement(_uiText.Text, {
277
+ color: "error"
278
+ }, (0, _formatMessage.default)('You are attempting to add content containing course links which may not work when used in other courses.'))));
279
+ } else {
280
+ content = /*#__PURE__*/_react.default.createElement(_uiText.Text, {
281
+ color: "warning"
282
+ }, _ref4, "\xA0", (0, _formatMessage.default)('There was an error attempting to validate shareability.'));
283
+ }
284
+
285
+ return /*#__PURE__*/_react.default.createElement(_uiView.View, {
286
+ as: "div",
287
+ margin: "small 0 0 0"
288
+ }, content);
289
+ }
290
+ }
168
291
  }, {
169
292
  key: "renderContent",
170
293
  value: function renderContent() {
@@ -179,7 +302,7 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
179
302
  }), /*#__PURE__*/_react.default.createElement(_uiRadioInput.RadioInput, {
180
303
  value: "new",
181
304
  label: (0, _formatMessage.default)('New item bank')
182
- })), _ref, this.renderBankTypeContent());
305
+ })), _ref5, this.renderBankTypeContent(), this.renderContentShareabilityMessage());
183
306
  }
184
307
  }, {
185
308
  key: "render",
@@ -207,6 +330,9 @@ var AddToBankModal = /*#__PURE__*/function (_Component) {
207
330
 
208
331
  exports.AddToBankModal = AddToBankModal;
209
332
  AddToBankModal.propTypes = {
333
+ canvasOrigin: _propTypes.default.string,
334
+ checkBankedContentShareabilityEnabled: _propTypes.default.bool,
335
+ checkContentShareability: _propTypes.default.func.isRequired,
210
336
  closeModal: _propTypes.default.func.isRequired,
211
337
  createBank: _propTypes.default.func.isRequired,
212
338
  createBankEntry: _propTypes.default.func.isRequired,
@@ -218,15 +344,18 @@ AddToBankModal.propTypes = {
218
344
  entryType: _propTypes.default.string.isRequired,
219
345
  // Resolve to the bank entry's entry, or create it if it does not yet exist.
220
346
  getEntry: _propTypes.default.func.isRequired,
347
+ handleValidationErrorsFromApi: _propTypes.default.func.isRequired,
221
348
  label: _propTypes.default.string.isRequired,
222
349
  modalOpen: _propTypes.default.bool.isRequired,
223
350
  onAdd: _propTypes.default.func,
224
351
  onContinue: _propTypes.default.func,
225
352
  selectedBank: _reactImmutableProptypes.default.record,
226
353
  uiSet: _propTypes.default.func.isRequired,
227
- handleValidationErrorsFromApi: _propTypes.default.func.isRequired
354
+ workingEntry: _reactImmutableProptypes.default.record.isRequired
228
355
  };
229
356
  AddToBankModal.defaultProps = {
357
+ canvasOrigin: '',
358
+ checkBankedContentShareabilityEnabled: false,
230
359
  onAdd: function onAdd() {},
231
360
  onContinue: function onContinue() {},
232
361
  selectedBank: null
@@ -245,17 +245,18 @@ var BankEntry = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _de
245
245
  return {
246
246
  cancelHandler: _this.navigateToBank,
247
247
  clearChanges: _this.clearChanges,
248
+ clearValidationErrorsFromApi: _this.clearValidationErrorsFromApi,
248
249
  contextUuid: null,
250
+ disableSubmit: Boolean(_this.state.validationErrorsFromApi && Object.values(_this.state.validationErrorsFromApi).length),
249
251
  entry: entry,
250
252
  guid: "".concat(_this.props.bankEntry.id, "_bank_entry_edit"),
251
253
  handleQuizEntryPointsChange: _this.handlePointsChange,
252
254
  parentId: _this.props.bankId,
253
255
  parentType: _quizCommon.PARENT_TYPE_BANK,
256
+ shouldValidateShareableContent: true,
254
257
  stimulus: entry,
255
258
  submitHandler: _this.submitHandler,
256
- validationErrorsFromApi: _this.state.validationErrorsFromApi,
257
- clearValidationErrorsFromApi: _this.clearValidationErrorsFromApi,
258
- disableSubmit: Boolean(_this.state.validationErrorsFromApi && Object.values(_this.state.validationErrorsFromApi).length)
259
+ validationErrorsFromApi: _this.state.validationErrorsFromApi
259
260
  };
260
261
  };
261
262
 
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.getItem = getItem;
9
+ exports.checkItemShareability = checkItemShareability;
9
10
  exports.createItem = createItem;
10
11
  exports.updateItem = updateItem;
11
12
 
@@ -50,6 +51,20 @@ function getItem(itemId) {
50
51
  };
51
52
  }
52
53
 
54
+ function checkItemShareability(item, canvasOrigin) {
55
+ var url = '/api/items/check_shareability';
56
+ var requestBody = JSON.stringify({
57
+ item: updateItemParams(item),
58
+ source_origin: canvasOrigin
59
+ });
60
+ var fetcher = new _Fetcher.default({
61
+ onError: function onError() {}
62
+ });
63
+ return fetcher.post(url, {
64
+ body: requestBody
65
+ });
66
+ }
67
+
53
68
  function createItem(item, parentId, parentType) {
54
69
  var parentItemId = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
55
70
  var resource = parentType === 'bank' ? 'banks' : 'quizzes';
@@ -157,10 +172,8 @@ function createItem(item, parentId, parentType) {
157
172
  // =====================
158
173
 
159
174
 
160
- function updateItem(item, parentId, parentType) {
161
- var resource = parentType === 'bank' ? 'banks' : 'quizzes';
162
- var url = "/api/".concat(resource, "/").concat(parentId, "/items/").concat(item.id);
163
- var itemData = {
175
+ function updateItemParams(item) {
176
+ return {
164
177
  item_body: item.itemBody,
165
178
  title: item.title,
166
179
  scoring_data: item.scoringData,
@@ -172,8 +185,13 @@ function updateItem(item, parentId, parentType) {
172
185
  calculator_type: item.calculatorType,
173
186
  answer_feedback: item.answerFeedback
174
187
  };
188
+ }
189
+
190
+ function updateItem(item, parentId, parentType) {
191
+ var resource = parentType === 'bank' ? 'banks' : 'quizzes';
192
+ var url = "/api/".concat(resource, "/").concat(parentId, "/items/").concat(item.id);
175
193
  var reqBody = JSON.stringify({
176
- item: itemData
194
+ item: updateItemParams(item)
177
195
  });
178
196
  return function (dispatch, getState) {
179
197
  var updateItemParams = {
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  });
8
8
  exports.createStimulus = createStimulus;
9
9
  exports.updateStimulus = updateStimulus;
10
+ exports.checkStimulusShareability = checkStimulusShareability;
10
11
 
11
12
  var _quizCommon = require("@instructure/quiz-common");
12
13
 
@@ -61,18 +62,21 @@ function createStimulus(stimulus, parentId, parentType) {
61
62
  // =====================
62
63
 
63
64
 
64
- function updateStimulus(stimulus, parentId, parentType) {
65
- var resource = parentType === 'bank' ? 'banks' : 'quizzes';
66
- var url = "/api/".concat(resource, "/").concat(parentId, "/stimuli/").concat(stimulus.id);
67
- var stimulusData = {
65
+ function updateStimulusParams(stimulus) {
66
+ return {
68
67
  orientation: stimulus.orientation,
69
68
  title: stimulus.title,
70
69
  instructions: stimulus.instructions,
71
70
  body: stimulus.body,
72
71
  source_url: stimulus.sourceUrl
73
72
  };
73
+ }
74
+
75
+ function updateStimulus(stimulus, parentId, parentType) {
76
+ var resource = parentType === 'bank' ? 'banks' : 'quizzes';
77
+ var url = "/api/".concat(resource, "/").concat(parentId, "/stimuli/").concat(stimulus.id);
74
78
  var reqBody = JSON.stringify({
75
- stimulus: stimulusData
79
+ stimulus: updateStimulusParams(stimulus)
76
80
  });
77
81
  return function (dispatch, getState) {
78
82
  var updateStimulusParams = {
@@ -89,4 +93,18 @@ function updateStimulus(stimulus, parentId, parentType) {
89
93
  return stimulusData;
90
94
  });
91
95
  };
96
+ }
97
+
98
+ function checkStimulusShareability(stimulus, canvasOrigin) {
99
+ var url = '/api/stimuli/check_shareability';
100
+ var requestBody = JSON.stringify({
101
+ stimulus: updateStimulusParams(stimulus),
102
+ source_origin: canvasOrigin
103
+ });
104
+ var fetcher = new _Fetcher.default({
105
+ onError: function onError() {}
106
+ });
107
+ return fetcher.post(url, {
108
+ body: requestBody
109
+ });
92
110
  }
@@ -424,6 +424,7 @@ var QuizEntryEdit = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles),
424
424
  onContinue: this.handleAddToBankContinue,
425
425
  onAdd: this.handleAddToBank,
426
426
  getEntry: this.getEntryForBank,
427
+ workingEntry: this.props.workingEntry,
427
428
  entryId: this.props.guid,
428
429
  entryType: this.props.quizEntry.entryType,
429
430
  handleValidationErrorsFromApi: this.props.handleValidationErrorsFromApi
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.setAPIEndpoint = setAPIEndpoint;
7
7
  exports.setUserToken = setUserToken;
8
+ exports.setCanvasOrigin = setCanvasOrigin;
8
9
 
9
10
  var _quizCommon = require("@instructure/quiz-common");
10
11
 
@@ -20,4 +21,11 @@ function setUserToken(token) {
20
21
  type: _quizCommon.SET_USER_TOKEN,
21
22
  payload: token
22
23
  };
24
+ }
25
+
26
+ function setCanvasOrigin(canvasHost) {
27
+ return {
28
+ type: _quizCommon.SET_CANVAS_ORIGIN,
29
+ payload: canvasHost
30
+ };
23
31
  }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.ApiFeatureFlagInitializer = exports.ApiFeatureFlagInitializerComponent = void 0;
9
+
10
+ var _react = _interopRequireWildcard(require("react"));
11
+
12
+ var _reactRedux = require("../../react-redux.js");
13
+
14
+ var _propTypes = require("prop-types");
15
+
16
+ var _features = require("../../api/features.js");
17
+
18
+ var _Spinner = require("../shared/spinner/Spinner.js");
19
+
20
+ var _index = require("../shared/Card/index.js");
21
+
22
+ var _ref = /*#__PURE__*/_react.default.createElement(_index.Card, {
23
+ wrapped: true
24
+ }, /*#__PURE__*/_react.default.createElement(_Spinner.QuizzesSpinner, null));
25
+
26
+ var ApiFeatureFlagInitializerComponent = function ApiFeatureFlagInitializerComponent(props) {
27
+ (0, _react.useEffect)(function () {
28
+ !props.loadedApiFeatures && props.getFeatures();
29
+ }, []);
30
+ return props.loadedApiFeatures ? props.children : _ref;
31
+ };
32
+
33
+ exports.ApiFeatureFlagInitializerComponent = ApiFeatureFlagInitializerComponent;
34
+ ApiFeatureFlagInitializerComponent.propTypes = {
35
+ children: _propTypes.node.isRequired,
36
+ getFeatures: _propTypes.func.isRequired,
37
+ loadedApiFeatures: _propTypes.bool
38
+ };
39
+ ApiFeatureFlagInitializerComponent.defaultProps = {
40
+ loadedApiFeatures: false
41
+ };
42
+
43
+ var mapStateToProps = function mapStateToProps(state, ownProps) {
44
+ return {
45
+ loadedApiFeatures: state.getIn(['ui', 'loadedApiFeatures']) || ownProps.loadedApiFeatures
46
+ };
47
+ };
48
+
49
+ var mapDispatchToProps = {
50
+ getFeatures: _features.getFeatures
51
+ };
52
+ var ApiFeatureFlagInitializer = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)(ApiFeatureFlagInitializerComponent);
53
+ exports.ApiFeatureFlagInitializer = ApiFeatureFlagInitializer;
@@ -105,7 +105,7 @@ var ConfirmationModal = /*#__PURE__*/function (_Component) {
105
105
  as: "h2",
106
106
  "data-automation": "sdk-confirmation-modal-heading"
107
107
  }, title || (0, _formatMessage.default)('Confirm')), /*#__PURE__*/_react.default.createElement(_uiButtons.CloseButton, {
108
- onClick: this.props.closeModal,
108
+ onClick: this.cancelAction,
109
109
  placement: "end",
110
110
  offset: "medium",
111
111
  screenReaderLabel: (0, _formatMessage.default)('Close')