@instructure/quiz-core 17.46.2-rc.12 → 17.46.2-rc.13

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 (27) hide show
  1. package/es/banks/components/AddToBankModal/index.js +6 -0
  2. package/es/banks/components/AddToBankModal/presenter.js +128 -6
  3. package/es/banks/components/BankEntry/presenter.js +4 -3
  4. package/es/building/api/items.js +21 -5
  5. package/es/building/api/stimuli.js +21 -5
  6. package/es/building/components/resources/quizEntry/QuizEntryEdit/presenter.js +1 -0
  7. package/es/common/actions/config.js +7 -1
  8. package/es/common/components/ConfirmationModal/presenter.js +1 -1
  9. package/es/common/components/SDKApp/index.js +10 -2
  10. package/es/common/components/resources/entry/EntrySave/index.js +11 -5
  11. package/es/common/components/resources/entry/EntrySave/presenter.js +95 -21
  12. package/es/common/components/resources/stimulus/StimulusEdit/presenter.js +1 -0
  13. package/es/common/reducers/config.js +4 -1
  14. package/lib/banks/components/AddToBankModal/index.js +9 -0
  15. package/lib/banks/components/AddToBankModal/presenter.js +135 -6
  16. package/lib/banks/components/BankEntry/presenter.js +4 -3
  17. package/lib/building/api/items.js +23 -5
  18. package/lib/building/api/stimuli.js +23 -5
  19. package/lib/building/components/resources/quizEntry/QuizEntryEdit/presenter.js +1 -0
  20. package/lib/common/actions/config.js +8 -0
  21. package/lib/common/components/ConfirmationModal/presenter.js +1 -1
  22. package/lib/common/components/SDKApp/index.js +9 -1
  23. package/lib/common/components/resources/entry/EntrySave/index.js +15 -2
  24. package/lib/common/components/resources/entry/EntrySave/presenter.js +96 -21
  25. package/lib/common/components/resources/stimulus/StimulusEdit/presenter.js +1 -0
  26. package/lib/common/reducers/config.js +3 -0
  27. package/package.json +9 -9
@@ -1,6 +1,8 @@
1
1
  import { connect } from "../../../common/react-redux.js";
2
2
  import { createBank } from "../../api/banks.js";
3
3
  import { createBankEntry } from "../../api/bankEntries.js";
4
+ import { checkItemShareability } from "../../../building/api/items.js";
5
+ import { checkStimulusShareability } from "../../../building/api/stimuli.js";
4
6
  import AddToBankModal from "./presenter.js";
5
7
  import * as modalActions from "../../../common/actions/modal.js";
6
8
  import { disassociateEntry } from "../../../common/actions/banks.js";
@@ -8,10 +10,14 @@ import * as uiActions from "../../../common/actions/ui.js";
8
10
  import Bank from "../../../common/records/Bank.js";
9
11
  import { ADD_TO_BANK_MODAL_BANK_SELECTION, ADD_TO_BANK_MODAL } from '@instructure/quiz-common';
10
12
  import { getModalTrigger } from "../../../common/util/modalHelpers.js";
13
+ import { featureOn } from "../../../common/util/featureCheck.js";
11
14
  export function mapStateToProps(state, props) {
12
15
  var selectedBankOption = state.getIn(['ui', ADD_TO_BANK_MODAL_BANK_SELECTION]);
13
16
  var selectedBank = selectedBankOption && new Bank(state.getIn(['banks', selectedBankOption]));
14
17
  return {
18
+ canvasOrigin: state.getIn(['config', 'canvasOrigin']),
19
+ checkBankedContentShareabilityEnabled: featureOn('check_banked_content_shareability'),
20
+ checkContentShareability: props.entryType === 'Item' ? checkItemShareability : checkStimulusShareability,
15
21
  selectedBank: selectedBank,
16
22
  modalTrigger: getModalTrigger(state),
17
23
  modalOpen: state.getIn(['modal', 'isOpen']) === [ADD_TO_BANK_MODAL, props.entryType, props.entryId].join(':')
@@ -1,3 +1,5 @@
1
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
1
3
  import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2
4
  import _createClass from "@babel/runtime/helpers/esm/createClass";
3
5
  import _inherits from "@babel/runtime/helpers/esm/inherits";
@@ -12,10 +14,30 @@ import { RadioInputGroup, RadioInput } from '@instructure/ui-radio-input';
12
14
  import { ScreenReaderContent } from '@instructure/ui-a11y-content';
13
15
  import Bank from "../../../common/records/Bank.js";
14
16
  import BankSelection from "../../../common/components/resources/BankSelection/index.js";
17
+ import { Spinner } from '@instructure/ui-spinner';
18
+ import { Text } from '@instructure/ui-text';
19
+ import { IconCheckLine, IconNoLine, IconWarningLine } from '@instructure/ui-icons';
20
+ import { View } from '@instructure/ui-view';
21
+ import { Flex } from '@instructure/ui-flex';
15
22
  import t from '@instructure/quiz-i18n/es/format-message';
16
23
  import { Modal, ModalHeader, ModalBody, ModalFooter, ADD_TO_BANK_MODAL_BANK_SELECTION, XSMALL_SIDE_MARGIN } from '@instructure/quiz-common';
17
24
 
18
- var _ref = /*#__PURE__*/React.createElement("br", null);
25
+ var _ref2 = /*#__PURE__*/React.createElement(IconCheckLine, {
26
+ color: "success"
27
+ });
28
+
29
+ var _ref3 = /*#__PURE__*/React.createElement(Flex.Item, {
30
+ padding: "0 small 0 0"
31
+ }, /*#__PURE__*/React.createElement(IconNoLine, {
32
+ color: "error",
33
+ size: "small"
34
+ }));
35
+
36
+ var _ref4 = /*#__PURE__*/React.createElement(IconWarningLine, {
37
+ color: "warning"
38
+ });
39
+
40
+ var _ref5 = /*#__PURE__*/React.createElement("br", null);
19
41
 
20
42
  export var AddToBankModal = /*#__PURE__*/function (_Component) {
21
43
  _inherits(AddToBankModal, _Component);
@@ -34,6 +56,7 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
34
56
  _this = _super.call.apply(_super, [this].concat(args));
35
57
  _this.state = {
36
58
  bankType: 'existing',
59
+ contentShareable: 'loading',
37
60
  newBankTitle: ''
38
61
  };
39
62
 
@@ -98,6 +121,65 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
98
121
  }
99
122
 
100
123
  _createClass(AddToBankModal, [{
124
+ key: "componentDidUpdate",
125
+ value: function componentDidUpdate(prevProps) {
126
+ var _this2 = this;
127
+
128
+ var _this$props = this.props,
129
+ canvasOrigin = _this$props.canvasOrigin,
130
+ checkBankedContentShareabilityEnabled = _this$props.checkBankedContentShareabilityEnabled,
131
+ modalOpen = _this$props.modalOpen,
132
+ checkContentShareability = _this$props.checkContentShareability,
133
+ workingEntry = _this$props.workingEntry;
134
+
135
+ if (checkBankedContentShareabilityEnabled && modalOpen && !prevProps.modalOpen) {
136
+ this.setState({
137
+ contentShareable: 'loading'
138
+ });
139
+ checkContentShareability(workingEntry, canvasOrigin).then(function () {
140
+ _this2.setState({
141
+ contentShareable: 'true'
142
+ });
143
+ }).catch( /*#__PURE__*/function () {
144
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(err) {
145
+ var _err$response, _err$response2;
146
+
147
+ var body;
148
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
149
+ while (1) {
150
+ switch (_context.prev = _context.next) {
151
+ case 0:
152
+ _context.next = 2;
153
+ return (_err$response = err.response) === null || _err$response === void 0 ? void 0 : _err$response.json();
154
+
155
+ case 2:
156
+ body = _context.sent;
157
+
158
+ if (((_err$response2 = err.response) === null || _err$response2 === void 0 ? void 0 : _err$response2.status) === 400 && body.shareable === false) {
159
+ _this2.setState({
160
+ contentShareable: 'false'
161
+ });
162
+ } else {
163
+ _this2.setState({
164
+ contentShareable: 'unknown'
165
+ });
166
+ }
167
+
168
+ case 4:
169
+ case "end":
170
+ return _context.stop();
171
+ }
172
+ }
173
+ }, _callee);
174
+ }));
175
+
176
+ return function (_x) {
177
+ return _ref.apply(this, arguments);
178
+ };
179
+ }());
180
+ }
181
+ }
182
+ }, {
101
183
  key: "cancelButton",
102
184
  value: function cancelButton() {
103
185
  return /*#__PURE__*/React.createElement(Button, {
@@ -110,8 +192,11 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
110
192
  value: function addToBankButton() {
111
193
  var _this$state = this.state,
112
194
  bankType = _this$state.bankType,
113
- newBankTitle = _this$state.newBankTitle;
114
- var disabled = bankType === 'existing' && !this.props.selectedBank || bankType === 'new' && (!newBankTitle || !newBankTitle.trim());
195
+ newBankTitle = _this$state.newBankTitle,
196
+ contentShareable = _this$state.contentShareable;
197
+ var checkBankedContentShareabilityEnabled = this.props.checkBankedContentShareabilityEnabled;
198
+ var contentShareableLoading = contentShareable === 'loading';
199
+ var disabled = bankType === 'existing' && !this.props.selectedBank || bankType === 'new' && (!newBankTitle || !newBankTitle.trim()) || checkBankedContentShareabilityEnabled && contentShareableLoading;
115
200
  return /*#__PURE__*/React.createElement(Button, {
116
201
  type: "button",
117
202
  variant: "primary",
@@ -119,7 +204,7 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
119
204
  disabled: disabled,
120
205
  margin: XSMALL_SIDE_MARGIN,
121
206
  "data-automation": "sdk-add-to-bank-button"
122
- }, t('Add'));
207
+ }, checkBankedContentShareabilityEnabled && !contentShareableLoading && contentShareable !== 'true' ? t('Add anyway') : t('Add'));
123
208
  }
124
209
  }, {
125
210
  key: "renderBankTypeContent",
@@ -139,6 +224,37 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
139
224
  type: "text"
140
225
  });
141
226
  }
227
+ }, {
228
+ key: "renderContentShareabilityMessage",
229
+ value: function renderContentShareabilityMessage() {
230
+ if (this.props.checkBankedContentShareabilityEnabled) {
231
+ var content = null;
232
+
233
+ if (this.state.contentShareable === 'loading') {
234
+ content = /*#__PURE__*/React.createElement(Text, null, /*#__PURE__*/React.createElement(Spinner, {
235
+ size: "x-small",
236
+ renderTitle: t('Checking content shareability...')
237
+ }), "\xA0", t('Validating content...'));
238
+ } else if (this.state.contentShareable === 'true') {
239
+ content = /*#__PURE__*/React.createElement(Text, null, _ref2, "\xA0", t('Good to go!'));
240
+ } else if (this.state.contentShareable === 'false') {
241
+ content = /*#__PURE__*/React.createElement(Flex, null, _ref3, /*#__PURE__*/React.createElement(Flex.Item, {
242
+ shouldShrink: true
243
+ }, /*#__PURE__*/React.createElement(Text, {
244
+ color: "error"
245
+ }, t('You are attempting to add content containing course links which may not work when used in other courses.'))));
246
+ } else {
247
+ content = /*#__PURE__*/React.createElement(Text, {
248
+ color: "warning"
249
+ }, _ref4, "\xA0", t('There was an error attempting to validate shareability.'));
250
+ }
251
+
252
+ return /*#__PURE__*/React.createElement(View, {
253
+ as: "div",
254
+ margin: "small 0 0 0"
255
+ }, content);
256
+ }
257
+ }
142
258
  }, {
143
259
  key: "renderContent",
144
260
  value: function renderContent() {
@@ -153,7 +269,7 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
153
269
  }), /*#__PURE__*/React.createElement(RadioInput, {
154
270
  value: "new",
155
271
  label: t('New item bank')
156
- })), _ref, this.renderBankTypeContent());
272
+ })), _ref5, this.renderBankTypeContent(), this.renderContentShareabilityMessage());
157
273
  }
158
274
  }, {
159
275
  key: "render",
@@ -180,6 +296,9 @@ export var AddToBankModal = /*#__PURE__*/function (_Component) {
180
296
  return AddToBankModal;
181
297
  }(Component);
182
298
  AddToBankModal.propTypes = {
299
+ canvasOrigin: PropTypes.string,
300
+ checkBankedContentShareabilityEnabled: PropTypes.bool,
301
+ checkContentShareability: PropTypes.func.isRequired,
183
302
  closeModal: PropTypes.func.isRequired,
184
303
  createBank: PropTypes.func.isRequired,
185
304
  createBankEntry: PropTypes.func.isRequired,
@@ -191,15 +310,18 @@ AddToBankModal.propTypes = {
191
310
  entryType: PropTypes.string.isRequired,
192
311
  // Resolve to the bank entry's entry, or create it if it does not yet exist.
193
312
  getEntry: PropTypes.func.isRequired,
313
+ handleValidationErrorsFromApi: PropTypes.func.isRequired,
194
314
  label: PropTypes.string.isRequired,
195
315
  modalOpen: PropTypes.bool.isRequired,
196
316
  onAdd: PropTypes.func,
197
317
  onContinue: PropTypes.func,
198
318
  selectedBank: ImmutablePropTypes.record,
199
319
  uiSet: PropTypes.func.isRequired,
200
- handleValidationErrorsFromApi: PropTypes.func.isRequired
320
+ workingEntry: ImmutablePropTypes.record.isRequired
201
321
  };
202
322
  AddToBankModal.defaultProps = {
323
+ canvasOrigin: '',
324
+ checkBankedContentShareabilityEnabled: false,
203
325
  onAdd: function onAdd() {},
204
326
  onContinue: function onContinue() {},
205
327
  selectedBank: null
@@ -193,17 +193,18 @@ export var BankEntry = (_dec = themeable(theme, styles), _dec(_class = (_temp =
193
193
  return {
194
194
  cancelHandler: _this.navigateToBank,
195
195
  clearChanges: _this.clearChanges,
196
+ clearValidationErrorsFromApi: _this.clearValidationErrorsFromApi,
196
197
  contextUuid: null,
198
+ disableSubmit: Boolean(_this.state.validationErrorsFromApi && Object.values(_this.state.validationErrorsFromApi).length),
197
199
  entry: entry,
198
200
  guid: "".concat(_this.props.bankEntry.id, "_bank_entry_edit"),
199
201
  handleQuizEntryPointsChange: _this.handlePointsChange,
200
202
  parentId: _this.props.bankId,
201
203
  parentType: PARENT_TYPE_BANK,
204
+ shouldValidateShareableContent: true,
202
205
  stimulus: entry,
203
206
  submitHandler: _this.submitHandler,
204
- validationErrorsFromApi: _this.state.validationErrorsFromApi,
205
- clearValidationErrorsFromApi: _this.clearValidationErrorsFromApi,
206
- disableSubmit: Boolean(_this.state.validationErrorsFromApi && Object.values(_this.state.validationErrorsFromApi).length)
207
+ validationErrorsFromApi: _this.state.validationErrorsFromApi
207
208
  };
208
209
  };
209
210
 
@@ -29,6 +29,19 @@ export function getItem(itemId) {
29
29
  });
30
30
  };
31
31
  }
32
+ export function checkItemShareability(item, canvasOrigin) {
33
+ var url = '/api/items/check_shareability';
34
+ var requestBody = JSON.stringify({
35
+ item: updateItemParams(item),
36
+ source_origin: canvasOrigin
37
+ });
38
+ var fetcher = new Fetcher({
39
+ onError: function onError() {}
40
+ });
41
+ return fetcher.post(url, {
42
+ body: requestBody
43
+ });
44
+ }
32
45
  export function createItem(item, parentId, parentType) {
33
46
  var parentItemId = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
34
47
  var resource = parentType === 'bank' ? 'banks' : 'quizzes';
@@ -135,10 +148,8 @@ export function createItem(item, parentId, parentType) {
135
148
  // =====================
136
149
  // =====================
137
150
 
138
- export function updateItem(item, parentId, parentType) {
139
- var resource = parentType === 'bank' ? 'banks' : 'quizzes';
140
- var url = "/api/".concat(resource, "/").concat(parentId, "/items/").concat(item.id);
141
- var itemData = {
151
+ function updateItemParams(item) {
152
+ return {
142
153
  item_body: item.itemBody,
143
154
  title: item.title,
144
155
  scoring_data: item.scoringData,
@@ -150,8 +161,13 @@ export function updateItem(item, parentId, parentType) {
150
161
  calculator_type: item.calculatorType,
151
162
  answer_feedback: item.answerFeedback
152
163
  };
164
+ }
165
+
166
+ export function updateItem(item, parentId, parentType) {
167
+ var resource = parentType === 'bank' ? 'banks' : 'quizzes';
168
+ var url = "/api/".concat(resource, "/").concat(parentId, "/items/").concat(item.id);
153
169
  var reqBody = JSON.stringify({
154
- item: itemData
170
+ item: updateItemParams(item)
155
171
  });
156
172
  return function (dispatch, getState) {
157
173
  var updateItemParams = {
@@ -45,18 +45,21 @@ export function createStimulus(stimulus, parentId, parentType) {
45
45
  // =====================
46
46
  // =====================
47
47
 
48
- export function updateStimulus(stimulus, parentId, parentType) {
49
- var resource = parentType === 'bank' ? 'banks' : 'quizzes';
50
- var url = "/api/".concat(resource, "/").concat(parentId, "/stimuli/").concat(stimulus.id);
51
- var stimulusData = {
48
+ function updateStimulusParams(stimulus) {
49
+ return {
52
50
  orientation: stimulus.orientation,
53
51
  title: stimulus.title,
54
52
  instructions: stimulus.instructions,
55
53
  body: stimulus.body,
56
54
  source_url: stimulus.sourceUrl
57
55
  };
56
+ }
57
+
58
+ export function updateStimulus(stimulus, parentId, parentType) {
59
+ var resource = parentType === 'bank' ? 'banks' : 'quizzes';
60
+ var url = "/api/".concat(resource, "/").concat(parentId, "/stimuli/").concat(stimulus.id);
58
61
  var reqBody = JSON.stringify({
59
- stimulus: stimulusData
62
+ stimulus: updateStimulusParams(stimulus)
60
63
  });
61
64
  return function (dispatch, getState) {
62
65
  var updateStimulusParams = {
@@ -73,4 +76,17 @@ export function updateStimulus(stimulus, parentId, parentType) {
73
76
  return stimulusData;
74
77
  });
75
78
  };
79
+ }
80
+ export function checkStimulusShareability(stimulus, canvasOrigin) {
81
+ var url = '/api/stimuli/check_shareability';
82
+ var requestBody = JSON.stringify({
83
+ stimulus: updateStimulusParams(stimulus),
84
+ source_origin: canvasOrigin
85
+ });
86
+ var fetcher = new Fetcher({
87
+ onError: function onError() {}
88
+ });
89
+ return fetcher.post(url, {
90
+ body: requestBody
91
+ });
76
92
  }
@@ -390,6 +390,7 @@ var QuizEntryEdit = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
390
390
  onContinue: this.handleAddToBankContinue,
391
391
  onAdd: this.handleAddToBank,
392
392
  getEntry: this.getEntryForBank,
393
+ workingEntry: this.props.workingEntry,
393
394
  entryId: this.props.guid,
394
395
  entryType: this.props.quizEntry.entryType,
395
396
  handleValidationErrorsFromApi: this.props.handleValidationErrorsFromApi
@@ -1,4 +1,4 @@
1
- import { SET_API_ENDPOINT, SET_USER_TOKEN } from '@instructure/quiz-common';
1
+ import { SET_API_ENDPOINT, SET_CANVAS_ORIGIN, SET_USER_TOKEN } from '@instructure/quiz-common';
2
2
  export function setAPIEndpoint(endpoint) {
3
3
  return {
4
4
  type: SET_API_ENDPOINT,
@@ -10,4 +10,10 @@ export function setUserToken(token) {
10
10
  type: SET_USER_TOKEN,
11
11
  payload: token
12
12
  };
13
+ }
14
+ export function setCanvasOrigin(canvasHost) {
15
+ return {
16
+ type: SET_CANVAS_ORIGIN,
17
+ payload: canvasHost
18
+ };
13
19
  }
@@ -83,7 +83,7 @@ export var ConfirmationModal = /*#__PURE__*/function (_Component) {
83
83
  as: "h2",
84
84
  "data-automation": "sdk-confirmation-modal-heading"
85
85
  }, title || t('Confirm')), /*#__PURE__*/React.createElement(CloseButton, {
86
- onClick: this.props.closeModal,
86
+ onClick: this.cancelAction,
87
87
  placement: "end",
88
88
  offset: "medium",
89
89
  screenReaderLabel: t('Close')
@@ -19,7 +19,7 @@ import store from "../../../reduxStore.js";
19
19
  import { getLocale } from '@instructure/quiz-common';
20
20
  import { getFeatures } from "../../api/features.js";
21
21
  import { set } from "../../actions/ui.js";
22
- import { setAPIEndpoint, setUserToken } from "../../actions/config.js";
22
+ import { setAPIEndpoint, setCanvasOrigin, setUserToken } from "../../actions/config.js";
23
23
  import { setContextUuid, setOutcomesEndpoint, setOutcomesToken } from "../../actions/outcomes.js";
24
24
  import { addFeatures, removeFeatures } from "../../actions/features.js";
25
25
  import renderAlerts from "../../util/renderAlerts.js";
@@ -78,7 +78,9 @@ export var SDKApp = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
78
78
  }, {
79
79
  key: "componentWillMount",
80
80
  value: function componentWillMount() {
81
- this.store.dispatch([setAPIEndpoint(this.props.apiEndpoint), this.setAppContainer(this.props.appContainer), setUserToken(this.props.userToken), setOutcomesEndpoint(this.props.outcomesEndpoint), setOutcomesToken(this.props.outcomesToken), setContextUuid(this.props.contextUuid)]);
81
+ var _this$props$rceConfig;
82
+
83
+ this.store.dispatch([setAPIEndpoint(this.props.apiEndpoint), setCanvasOrigin((_this$props$rceConfig = this.props.rceConfig) === null || _this$props$rceConfig === void 0 ? void 0 : _this$props$rceConfig.canvasOrigin), this.setAppContainer(this.props.appContainer), setUserToken(this.props.userToken), setOutcomesEndpoint(this.props.outcomesEndpoint), setOutcomesToken(this.props.outcomesToken), setContextUuid(this.props.contextUuid)]);
82
84
  this.store.dispatch(getFeatures());
83
85
 
84
86
  if (this.props.itemBankSharingEnabled) {
@@ -95,10 +97,16 @@ export var SDKApp = (_dec = themeable(theme, styles), _dec(_class = (_temp = _cl
95
97
  }, {
96
98
  key: "componentWillReceiveProps",
97
99
  value: function componentWillReceiveProps(newProps) {
100
+ var _newProps$rceConfig, _this$props$rceConfig2;
101
+
98
102
  if (newProps.apiEndpoint !== this.props.apiEndpoint) {
99
103
  this.store.dispatch(setAPIEndpoint(newProps.apiEndpoint));
100
104
  }
101
105
 
106
+ if (((_newProps$rceConfig = newProps.rceConfig) === null || _newProps$rceConfig === void 0 ? void 0 : _newProps$rceConfig.canvasOrigin) !== ((_this$props$rceConfig2 = this.props.rceConfig) === null || _this$props$rceConfig2 === void 0 ? void 0 : _this$props$rceConfig2.canvasOrigin)) {
107
+ this.store.dispatch(setCanvasOrigin(newProps.rceConfig.canvasOrigin));
108
+ }
109
+
102
110
  if (newProps.appContainer !== this.props.appContainer) {
103
111
  this.store.dispatch(this.setAppContainer(newProps.appContainer));
104
112
  }
@@ -1,23 +1,29 @@
1
1
  import { connect } from "../../../../react-redux.js";
2
+ import { checkItemShareability } from "../../../../../building/api/items.js";
3
+ import { checkStimulusShareability } from "../../../../../building/api/stimuli.js";
2
4
  import makeEditable from "../../../shared/functionality/makeEditable.js";
3
5
  import { showError, hideError } from "../../../../actions/errorsShowing.js";
4
6
  import { screenreaderNotification } from "../../../../actions/alerts.js";
5
7
  import { clearNextQuizEntry } from "../../../../actions/modifications.js";
8
+ import { withConfirm } from "../../../../actions/modal.js";
9
+ import { featureOn } from "../../../../util/featureCheck.js";
6
10
  import EntrySave from "./presenter.js";
7
-
8
- function mapStateToProps(state, props) {
11
+ export function mapStateToProps(state, props) {
9
12
  // Error Related:
10
13
  var workingEntry = props.entry.getWorkingInstance();
11
14
  var isValid = props.isValid !== void 0 ? props.isValid : workingEntry.isValid();
12
15
  return {
16
+ canvasOrigin: state.getIn(['config', 'canvasOrigin']),
17
+ checkBankedContentShareabilityEnabled: featureOn('check_banked_content_shareability'),
18
+ checkContentShareability: props.entry.isStimulus ? checkStimulusShareability : checkItemShareability,
13
19
  isValid: isValid
14
20
  };
15
21
  }
16
-
17
22
  var mapDispatchToProps = {
18
23
  clearNextQuizEntry: clearNextQuizEntry,
19
- showError: showError,
20
24
  hideError: hideError,
21
- screenreaderNotification: screenreaderNotification
25
+ screenreaderNotification: screenreaderNotification,
26
+ showError: showError,
27
+ withConfirm: withConfirm
22
28
  };
23
29
  export default makeEditable(connect(mapStateToProps, mapDispatchToProps)(EntrySave));
@@ -6,6 +6,7 @@ import _inherits from "@babel/runtime/helpers/esm/inherits";
6
6
  import _createSuper from "@babel/runtime/helpers/esm/createSuper";
7
7
  import React, { Component } from 'react';
8
8
  import PropTypes from 'prop-types';
9
+ import ImmutablePropTypes from 'react-immutable-proptypes';
9
10
  import { Button } from '@instructure/ui-buttons';
10
11
  import { View } from '@instructure/ui-view';
11
12
  import { API_INPUT_VALIDATION_ERROR } from '@instructure/quiz-common';
@@ -39,11 +40,75 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
39
40
  _this.props.screenreaderNotification(msg);
40
41
  };
41
42
 
43
+ _this.confirmShareableContent = function () {
44
+ var _this$props = _this.props,
45
+ canvasOrigin = _this$props.canvasOrigin,
46
+ checkContentShareability = _this$props.checkContentShareability,
47
+ entry = _this$props.entry,
48
+ withConfirm = _this$props.withConfirm;
49
+
50
+ _this.setState({
51
+ canSubmit: false
52
+ });
53
+
54
+ checkContentShareability(entry.getWorkingInstance(), canvasOrigin).then(function () {
55
+ _this.successfulSubmit();
56
+ }).catch( /*#__PURE__*/function () {
57
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(err) {
58
+ var _err$response, _err$response2;
59
+
60
+ var body, text;
61
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
62
+ while (1) {
63
+ switch (_context.prev = _context.next) {
64
+ case 0:
65
+ _context.next = 2;
66
+ return (_err$response = err.response) === null || _err$response === void 0 ? void 0 : _err$response.json();
67
+
68
+ case 2:
69
+ body = _context.sent;
70
+ text = t('There was an error attempting to validate shareability.');
71
+
72
+ if (((_err$response2 = err.response) === null || _err$response2 === void 0 ? void 0 : _err$response2.status) === 400 && body.shareable === false) {
73
+ text = t('You are attempting to save content containing course links which may not work when used in other courses.');
74
+ }
75
+
76
+ withConfirm(function () {
77
+ _this.successfulSubmit();
78
+ }, {
79
+ title: t('Are you sure?'),
80
+ text: text,
81
+ continueText: t('Save anyway'),
82
+ onCancel: function onCancel() {
83
+ _this.setState({
84
+ canSubmit: true
85
+ });
86
+ }
87
+ });
88
+
89
+ case 6:
90
+ case "end":
91
+ return _context.stop();
92
+ }
93
+ }
94
+ }, _callee);
95
+ }));
96
+
97
+ return function (_x) {
98
+ return _ref.apply(this, arguments);
99
+ };
100
+ }());
101
+ };
102
+
42
103
  _this.onSubmit = function (e) {
43
104
  e.preventDefault();
44
105
 
45
106
  if (_this.props.isValid) {
46
- _this.successfulSubmit();
107
+ if (_this.props.checkBankedContentShareabilityEnabled && _this.props.shouldValidateShareableContent) {
108
+ _this.confirmShareableContent();
109
+ } else {
110
+ _this.successfulSubmit();
111
+ }
47
112
  } else {
48
113
  _this.createScreenReaderNotification();
49
114
 
@@ -87,24 +152,24 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
87
152
  }, {
88
153
  key: "successfulSubmit",
89
154
  value: function () {
90
- var _successfulSubmit = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
155
+ var _successfulSubmit = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
91
156
  var validationResult;
92
- return _regeneratorRuntime.wrap(function _callee$(_context) {
157
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
93
158
  while (1) {
94
- switch (_context.prev = _context.next) {
159
+ switch (_context2.prev = _context2.next) {
95
160
  case 0:
96
161
  this.setState({
97
162
  canSubmit: false
98
163
  });
99
- _context.prev = 1;
100
- _context.next = 4;
164
+ _context2.prev = 1;
165
+ _context2.next = 4;
101
166
  return this.props.submitHandler();
102
167
 
103
168
  case 4:
104
- validationResult = _context.sent;
169
+ validationResult = _context2.sent;
105
170
 
106
171
  if (!(validationResult === API_INPUT_VALIDATION_ERROR)) {
107
- _context.next = 8;
172
+ _context2.next = 8;
108
173
  break;
109
174
  }
110
175
 
@@ -112,16 +177,16 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
112
177
  throw new Error('User input validation error received from API.');
113
178
 
114
179
  case 8:
115
- _context.next = 14;
180
+ _context2.next = 14;
116
181
  break;
117
182
 
118
183
  case 10:
119
- _context.prev = 10;
120
- _context.t0 = _context["catch"](1);
184
+ _context2.prev = 10;
185
+ _context2.t0 = _context2["catch"](1);
121
186
  this.setState({
122
187
  canSubmit: true
123
188
  });
124
- return _context.abrupt("return");
189
+ return _context2.abrupt("return");
125
190
 
126
191
  case 14:
127
192
  this.props.switchOffEditing();
@@ -130,10 +195,10 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
130
195
 
131
196
  case 17:
132
197
  case "end":
133
- return _context.stop();
198
+ return _context2.stop();
134
199
  }
135
200
  }
136
- }, _callee, this, [[1, 10]]);
201
+ }, _callee2, this, [[1, 10]]);
137
202
  }));
138
203
 
139
204
  function successfulSubmit() {
@@ -168,28 +233,37 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
168
233
  return EntrySave;
169
234
  }(Component);
170
235
  EntrySave.propTypes = {
171
- displayPosition: PropTypes.number,
172
- disableSubmit: PropTypes.bool,
173
- guid: PropTypes.string,
174
- submitHandler: PropTypes.func.isRequired,
175
236
  cancelHandler: PropTypes.func,
237
+ canvasOrigin: PropTypes.string,
238
+ checkBankedContentShareabilityEnabled: PropTypes.bool,
239
+ checkContentShareability: PropTypes.func.isRequired,
176
240
  clearChanges: PropTypes.func.isRequired,
177
241
  // From connected component
178
242
  clearNextQuizEntry: PropTypes.func.isRequired,
243
+ disableSubmit: PropTypes.bool,
244
+ displayPosition: PropTypes.number,
245
+ entry: ImmutablePropTypes.record.isRequired,
246
+ guid: PropTypes.string,
179
247
  hideError: PropTypes.func.isRequired,
248
+ initialFocusId: PropTypes.string,
180
249
  isValid: PropTypes.bool.isRequired,
181
250
  showError: PropTypes.func.isRequired,
182
251
  screenreaderNotification: PropTypes.func.isRequired,
252
+ shouldValidateShareableContent: PropTypes.bool,
253
+ submitHandler: PropTypes.func.isRequired,
183
254
  // from makescrollable / from props being passed in occasionally
184
255
  switchOnEditing: PropTypes.func.isRequired,
185
256
  switchOffEditing: PropTypes.func.isRequired,
186
- initialFocusId: PropTypes.string
257
+ withConfirm: PropTypes.func.isRequired
187
258
  };
188
259
  EntrySave.defaultProps = {
189
- displayPosition: null,
190
260
  cancelHandler: noop,
261
+ canvasOrigin: '',
262
+ checkBankedContentShareabilityEnabled: false,
263
+ displayPosition: null,
191
264
  disableSubmit: false,
192
265
  guid: null,
193
- initialFocusId: null
266
+ initialFocusId: null,
267
+ shouldValidateShareableContent: false
194
268
  };
195
269
  export default EntrySave;
@@ -376,6 +376,7 @@ export var StimulusEdit = (_dec = themeable(theme, styles), _dec(_class = (_temp
376
376
  onAdd: this.handleAddToBank,
377
377
  onContinue: this.handleAddToBankContinue,
378
378
  getEntry: this.getEntryForBank,
379
+ workingEntry: this.props.workingStimulus,
379
380
  entryId: this.props.guid,
380
381
  entryType: this.props.quizEntry.entryType
381
382
  });