@instructure/quiz-core 17.58.2-rc.7 → 17.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,27 @@
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.59.0](https://gerrit.instructure.com/quizzes-ui/compare/v17.58.1...v17.59.0) (2023-07-12)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **quiz-core:** Increase sidebar window resize test timeout ([0716a78](https://gerrit.instructure.com/quizzes-ui/commits/0716a7873da0fb869dd529065be9ad6fb5eceab7))
12
+
13
+
14
+ ### Features
15
+
16
+ * **Export:** add alert when export starts ([a1e4d07](https://gerrit.instructure.com/quizzes-ui/commits/a1e4d07d82fa8acf8cd4a11e5120e1c9a12d68b9))
17
+ * **itemanalysis:** item overview ([623c562](https://gerrit.instructure.com/quizzes-ui/commits/623c562cd0e8f4d89e5c5480e383e8c8ddc01546))
18
+ * **quizanalysis:** score distribution chart ([6f8fb67](https://gerrit.instructure.com/quizzes-ui/commits/6f8fb67283b864ad86c4591a16a7e38d880918ce))
19
+ * **Reports:** Add initial report card for the new analysis UI ([2291f06](https://gerrit.instructure.com/quizzes-ui/commits/2291f061ed85f10cd0648eef4a254b8b2975fb50))
20
+ * **Reports:** Show points possible next to certain metrics for item analysis ([8dccd4a](https://gerrit.instructure.com/quizzes-ui/commits/8dccd4adaa3fd5c6594e78f02b25acf7d3a03444))
21
+ * **sharing:** Add share checkbox on bank details ([a2806a2](https://gerrit.instructure.com/quizzes-ui/commits/a2806a24eb3fd90deeaf76b10b647ba9cfd9ed4a))
22
+
23
+
24
+
25
+
26
+
6
27
  ## [17.58.1](https://gerrit.instructure.com/quizzes-ui/compare/v17.58.0...v17.58.1) (2023-06-27)
7
28
 
8
29
  **Note:** Version bump only for package @instructure/quiz-core
@@ -11,6 +11,7 @@ import { clear, newActiveBankEntry, newActiveBank } from "../../common/actions/u
11
11
  import t from '@instructure/quiz-i18n/es/format-message';
12
12
  import { handleError } from "../../common/api/helpers.js";
13
13
  import { BANKS_BANK_PAGINATION, BANKS_BANK_ENTRY_PAGINATION, DELETE_BANK_CALL, UPDATE_BANK_CALL, CAN_EDIT, READ_ONLY, REMOVED_ACCESS, SHARED_WITH_USER, SHARED_WITH_COURSE } from '@instructure/quiz-common';
14
+ import { noop } from 'lodash';
14
15
  var banksApiEndpoint = '/api/banks';
15
16
  var DEFAULT_PAGE_SIZE = 100;
16
17
 
@@ -169,7 +170,8 @@ export var deleteBank = function deleteBank(bankId) {
169
170
  });
170
171
  };
171
172
  };
172
- export var shareBank = function shareBank(_shareBank, getUserInfo) {
173
+ export var shareBank = function shareBank(_shareBank) {
174
+ var getUserInfo = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : noop;
173
175
  var url = "".concat(banksApiEndpoint, "/").concat(_shareBank.bankId, "/shared_banks");
174
176
  return function (dispatch, getState) {
175
177
  var shareBankData = JSON.stringify({
@@ -213,6 +215,38 @@ export var shareBank = function shareBank(_shareBank, getUserInfo) {
213
215
  });
214
216
  };
215
217
  };
218
+ export var getSharedBank = function getSharedBank(bankId, entityType, entityId) {
219
+ var url = "".concat(banksApiEndpoint, "/").concat(bankId, "/shared_banks");
220
+ var params = {
221
+ entity_type: entityType,
222
+ entity_id: entityId
223
+ };
224
+ return function (dispatch, getState) {
225
+ var fetcher = new Fetcher({
226
+ onError: handleError(dispatch, t('Failed to fetch shared bank.'))
227
+ });
228
+ return fetcher.get(url, params).then(function (sharedBankInfo) {
229
+ // if the API returns no data, we manually add placeholder to the response
230
+ if (sharedBankInfo.length === 0) {
231
+ var placeholder = {
232
+ id: "notshared_".concat(bankId, "_").concat(entityId),
233
+ entityType: entityType,
234
+ entityId: entityId,
235
+ permission: REMOVED_ACCESS,
236
+ bankId: bankId
237
+ };
238
+ sharedBankInfo.push(placeholder);
239
+ }
240
+
241
+ dispatch(handleShareBanksResponse(sharedBankInfo));
242
+ }).catch(function (err) {
243
+ if (err.response.status === 401) {
244
+ dispatch(clear(BANKS_BANK_PAGINATION));
245
+ throw err;
246
+ }
247
+ });
248
+ };
249
+ };
216
250
  export var getSharedBanks = function getSharedBanks(bank, getUserInfo, getCourseInfo) {
217
251
  var url = "".concat(banksApiEndpoint, "/").concat(bank.id, "/shared_banks");
218
252
  var userSharedBanks = [];
@@ -3,18 +3,21 @@ import { Bank as BankPresenter } from "./presenter.js";
3
3
  import { connect } from "../../../common/react-redux.js";
4
4
  import BankRecord from "../../../common/records/Bank.js";
5
5
  import { getActiveQuiz } from "../../../common/selectors/quizzes.js";
6
- import { getBank } from "../../../banks/api/banks.js";
6
+ import { getBank, getSharedBank, shareBank, updateSharedBankPermission } from "../../../banks/api/banks.js";
7
7
  import { getBankEntries } from "../../../banks/api/bankEntries.js";
8
8
  import { createQuizEntry } from "../../../building/api/quizEntries.js";
9
- import { openModal } from "../../../common/actions/modal.js";
9
+ import { openModal, withConfirm } from "../../../common/actions/modal.js";
10
10
  import { BUILD_TRAY_POSITION, BUILD_TRAY_STIMULUS_ID } from '@instructure/quiz-common';
11
11
  import { screenreaderNotification } from "../../../common/actions/alerts.js";
12
12
  import { reset as resetSearch } from "../../../common/actions/bankSearch.js";
13
+ import { removeSharedBank } from "../../../common/actions/sharedBanks.js";
13
14
  import { featureOn } from "../../../common/util/featureCheck.js";
14
-
15
- function mapStateToProps(state, props) {
15
+ export function mapStateToProps(state, props) {
16
16
  var bank = new BankRecord(state.getIn(['banks', props.bankId]));
17
17
  var search = state.get('bankSearch', immutable.Map());
18
+ var courseSharedBank = state.get('sharedBanks', immutable.Map()).find(function (sharedBank) {
19
+ return sharedBank.get('bankId') === props.bankId && sharedBank.get('entityType') === props.scope.type && sharedBank.get('entityId') === props.scope.uuid;
20
+ });
18
21
  var activeQuiz = getActiveQuiz(state);
19
22
  var lockBlueprintContentEnabled = featureOn('lock_blueprint_content');
20
23
  var isQuizContentLocked = activeQuiz && activeQuiz.originalQuizLockedByBlueprint && lockBlueprintContentEnabled;
@@ -22,20 +25,26 @@ function mapStateToProps(state, props) {
22
25
  bank: bank,
23
26
  isQuizContentLocked: isQuizContentLocked,
24
27
  search: search,
28
+ courseSharedBank: courseSharedBank,
25
29
  useBankSearch: featureOn('item_bank_search'),
26
30
  position: state.getIn(['ui', BUILD_TRAY_POSITION]),
27
31
  stimulusId: state.getIn(['ui', BUILD_TRAY_STIMULUS_ID]),
28
- activeQuizId: state.getIn(['quizzes', 'activeQuizId'])
32
+ activeQuizId: state.getIn(['quizzes', 'activeQuizId']),
33
+ showShareBankFromTray: featureOn('share_bank_from_tray')
29
34
  };
30
35
  }
31
-
32
36
  var mapDispatchToProps = {
33
37
  addEntryToQuiz: createQuizEntry,
34
38
  getBank: getBank,
35
39
  getBankEntries: getBankEntries,
40
+ getSharedBank: getSharedBank,
36
41
  openModal: openModal,
42
+ removeSharedBank: removeSharedBank,
37
43
  resetSearch: resetSearch,
38
- screenreaderNotification: screenreaderNotification
44
+ screenreaderNotification: screenreaderNotification,
45
+ shareBank: shareBank,
46
+ updateSharedBankPermission: updateSharedBankPermission,
47
+ withConfirm: withConfirm
39
48
  };
40
49
  export var Bank = connect(mapStateToProps, mapDispatchToProps)(BankPresenter);
41
50
  export default Bank;
@@ -1,3 +1,6 @@
1
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
2
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
1
4
  import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2
5
  import _createClass from "@babel/runtime/helpers/esm/createClass";
3
6
  import _inherits from "@babel/runtime/helpers/esm/inherits";
@@ -10,12 +13,15 @@ import * as immutable from 'immutable';
10
13
  import debounce from 'lodash/debounce';
11
14
  import PropTypes from 'prop-types';
12
15
  import ImmutablePropTypes from 'react-immutable-proptypes';
16
+ import partial from 'lodash/partial';
13
17
  import { IconPlusLine } from '@instructure/ui-icons';
14
18
  import { BreadcrumbLink } from '@instructure/ui-breadcrumb';
15
19
  import { Button } from '@instructure/ui-buttons';
16
20
  import { Heading } from '@instructure/ui-heading';
17
21
  import { AccessibleContent } from '@instructure/ui-a11y-content';
18
22
  import { themeable } from '@instructure/ui-themeable';
23
+ import { Checkbox } from '@instructure/ui-checkbox';
24
+ import { View } from '@instructure/ui-view';
19
25
  import BankRecord from "../../../common/records/Bank.js";
20
26
  import Page from "../../../common/components/layout/Page/index.js";
21
27
  import PaginatedCollection from "../../../common/components/shared/PaginatedCollection/index.js";
@@ -27,7 +33,7 @@ import BankEntriesList from "../../../banks/components/BankEntriesList/index.js"
27
33
  import BankSearch from "../../../banks/components/BankSearch/index.js";
28
34
  import HeaderMenu from "../../../banks/components/HeaderMenu/index.js";
29
35
  import NavWrapper from "../NavWrapper/index.js";
30
- import { ADD_BANK_ENTRY_MODAL, BANKS_BANK_ENTRY_PAGINATION } from '@instructure/quiz-common';
36
+ import { ADD_BANK_ENTRY_MODAL, BANKS_BANK_ENTRY_PAGINATION, CAN_EDIT, REMOVED_ACCESS, READ_ONLY } from '@instructure/quiz-common';
31
37
  var styles = {
32
38
  componentId: 'fWUWr',
33
39
  template: function template(theme) {
@@ -56,6 +62,10 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
56
62
  }
57
63
 
58
64
  _this = _super.call.apply(_super, [this].concat(_args));
65
+ _this.state = {
66
+ sharedWithCourse: false,
67
+ shareWithCourseCheckboxDisabled: true
68
+ };
59
69
 
60
70
  _this.openAddBankEntryModal = function () {
61
71
  _this.props.openModal(ADD_BANK_ENTRY_MODAL, {
@@ -75,6 +85,74 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
75
85
  _this.createBankEntryButton = c;
76
86
  };
77
87
 
88
+ _this.toggleCheckbox = function () {
89
+ // disable until request resolves
90
+ _this.setState({
91
+ shareWithCourseCheckboxDisabled: true
92
+ });
93
+
94
+ _this.changeSharedPermissions();
95
+ };
96
+
97
+ _this.unshareBankWithCourse = /*#__PURE__*/function () {
98
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(sharedBank) {
99
+ var _this$props, updateSharedBankPermission, bankId, getSharedBank, scope;
100
+
101
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
102
+ while (1) {
103
+ switch (_context.prev = _context.next) {
104
+ case 0:
105
+ _this$props = _this.props, updateSharedBankPermission = _this$props.updateSharedBankPermission, bankId = _this$props.bankId, getSharedBank = _this$props.getSharedBank, scope = _this$props.scope;
106
+ _context.next = 3;
107
+ return updateSharedBankPermission(bankId, sharedBank.get('id'), REMOVED_ACCESS);
108
+
109
+ case 3:
110
+ getSharedBank(bankId, scope.type, scope.uuid).catch(function (err) {
111
+ // make sure the user still has access to the bank
112
+ if (err.response.status === 401) {
113
+ _this.props.navigateToBanks();
114
+ }
115
+ });
116
+
117
+ case 4:
118
+ case "end":
119
+ return _context.stop();
120
+ }
121
+ }
122
+ }, _callee);
123
+ }));
124
+
125
+ return function (_x) {
126
+ return _ref.apply(this, arguments);
127
+ };
128
+ }();
129
+
130
+ _this.translatedPermissionLevel = function (permission) {
131
+ var _CAN_EDIT$READ_ONLY$p;
132
+
133
+ return (_CAN_EDIT$READ_ONLY$p = {}, _defineProperty(_CAN_EDIT$READ_ONLY$p, CAN_EDIT, t('edit')), _defineProperty(_CAN_EDIT$READ_ONLY$p, READ_ONLY, t('view')), _CAN_EDIT$READ_ONLY$p)[permission];
134
+ };
135
+
136
+ _this.confirmUnshareBankWithCourse = function () {
137
+ var confirmText = t('You are about to remove { accessLevel } access for { entityTitle } to this bank.', {
138
+ accessLevel: _this.translatedPermissionLevel(_this.props.courseSharedBank.get('permission')),
139
+ entityTitle: _this.props.scope.title
140
+ });
141
+
142
+ _this.props.withConfirm(partial(_this.unshareBankWithCourse, _this.props.courseSharedBank), {
143
+ title: t('Unshare Bank with Course'),
144
+ text: confirmText,
145
+ continueText: t('Confirm'),
146
+ onCancel: _this.onCancelUnshareBankWithCourse
147
+ });
148
+ };
149
+
150
+ _this.onCancelUnshareBankWithCourse = function () {
151
+ _this.setState({
152
+ shareWithCourseCheckboxDisabled: false
153
+ });
154
+ };
155
+
78
156
  _this.addBankToQuiz = function () {
79
157
  var newEntry = QuizEntry.create({
80
158
  entryId: _this.props.bankId,
@@ -100,8 +178,8 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
100
178
  }, _this.renderNewBankEntryButton());
101
179
  };
102
180
 
103
- _this.announceResults = function (_ref) {
104
- var totalPages = _ref.totalPages;
181
+ _this.announceResults = function (_ref2) {
182
+ var totalPages = _ref2.totalPages;
105
183
  var message = t("{\n count, plural,\n =0 {No search results found}\n one {Displaying one page of results}\n other {Displaying # pages of results}\n }", {
106
184
  count: totalPages
107
185
  }); // Audibly announce when search results are ready.
@@ -115,10 +193,10 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
115
193
  _this.debouncedAnnounceResults = debounce(_this.announceResults, 1000);
116
194
 
117
195
  _this.getPage = function (page, search) {
118
- var _this$props = _this.props,
119
- getBankEntries = _this$props.getBankEntries,
120
- bankId = _this$props.bankId,
121
- useBankSearch = _this$props.useBankSearch;
196
+ var _this$props2 = _this.props,
197
+ getBankEntries = _this$props2.getBankEntries,
198
+ bankId = _this$props2.bankId,
199
+ useBankSearch = _this$props2.useBankSearch;
122
200
  var text = search.get('text');
123
201
  var interactionTypes = search.get('interactionTypes', immutable.Set()).toJS();
124
202
  var tagIds = search.get('tags', []).map(function (tag) {
@@ -173,19 +251,68 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
173
251
 
174
252
  if (this.props.onError) {
175
253
  this.props.getBank(this.props.bankId).catch(this.props.onError);
254
+
255
+ if (this.shouldRenderShareWithCourseCheckbox()) {
256
+ this.props.getSharedBank(this.props.bankId, this.props.scope.type, this.props.scope.uuid).catch(this.props.onError);
257
+ }
176
258
  } else {
177
259
  this.props.getBank(this.props.bankId);
260
+
261
+ if (this.shouldRenderShareWithCourseCheckbox()) {
262
+ this.props.getSharedBank(this.props.bankId, this.props.scope.type, this.props.scope.uuid);
263
+ }
264
+ } // when courseSharedBank is already loaded
265
+
266
+
267
+ if (this.props.courseSharedBank) {
268
+ this.setShareWithCourseCheckbox();
178
269
  }
179
270
  }
271
+ }, {
272
+ key: "componentDidUpdate",
273
+ value: function componentDidUpdate(prevProps) {
274
+ var _prevProps$courseShar, _this$props$courseSha;
275
+
276
+ var permissionChanged = ((_prevProps$courseShar = prevProps.courseSharedBank) === null || _prevProps$courseShar === void 0 ? void 0 : _prevProps$courseShar.get('permission')) !== ((_this$props$courseSha = this.props.courseSharedBank) === null || _this$props$courseSha === void 0 ? void 0 : _this$props$courseSha.get('permission'));
277
+
278
+ if (this.props.courseSharedBank && permissionChanged) {
279
+ this.setShareWithCourseCheckbox();
280
+ }
281
+ }
282
+ }, {
283
+ key: "setShareWithCourseCheckbox",
284
+ value: function setShareWithCourseCheckbox() {
285
+ if (this.props.courseSharedBank.get('permission') === REMOVED_ACCESS) {
286
+ this.setState({
287
+ sharedWithCourse: false,
288
+ shareWithCourseCheckboxDisabled: false
289
+ });
290
+ } else {
291
+ this.setState({
292
+ sharedWithCourse: true,
293
+ shareWithCourseCheckboxDisabled: false
294
+ });
295
+ }
296
+ }
297
+ }, {
298
+ key: "componentWillUnmount",
299
+ value: function componentWillUnmount() {
300
+ this.props.removeSharedBank(this.placeholderCourseSharedBankKey());
301
+ }
302
+ }, {
303
+ key: "placeholderCourseSharedBankKey",
304
+ value: function placeholderCourseSharedBankKey() {
305
+ return "notshared_".concat(this.props.bankId, "_").concat(this.props.scope.uuid);
306
+ }
180
307
  }, {
181
308
  key: "renderNav",
182
309
  value: function renderNav() {
183
- var _this$props2 = this.props,
184
- scope = _this$props2.scope,
185
- closeTray = _this$props2.closeTray,
186
- navigateToBanks = _this$props2.navigateToBanks,
187
- navigateToBuild = _this$props2.navigateToBuild,
188
- returnToUrl = _this$props2.returnToUrl;
310
+ var _this$props3 = this.props,
311
+ scope = _this$props3.scope,
312
+ closeTray = _this$props3.closeTray,
313
+ navigateToBanks = _this$props3.navigateToBanks,
314
+ navigateToBuild = _this$props3.navigateToBuild,
315
+ returnToUrl = _this$props3.returnToUrl;
189
316
  var isScopeEmpty = !Object.keys(scope).length;
190
317
  return /*#__PURE__*/React.createElement(NavWrapper, {
191
318
  closeTray: closeTray,
@@ -217,6 +344,50 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
217
344
  });
218
345
  }
219
346
  }
347
+ }, {
348
+ key: "changeSharedPermissions",
349
+ value: function changeSharedPermissions() {
350
+ if (this.props.bank.canEdit()) {
351
+ if (!this.state.sharedWithCourse) {
352
+ var shareBank = {
353
+ entityId: this.props.scope.uuid,
354
+ entityType: this.props.scope.type,
355
+ title: this.props.scope.title,
356
+ permission: READ_ONLY,
357
+ bankId: this.props.bankId
358
+ };
359
+ this.props.removeSharedBank(this.placeholderCourseSharedBankKey());
360
+ this.props.shareBank(shareBank);
361
+ } else {
362
+ this.confirmUnshareBankWithCourse();
363
+ }
364
+ }
365
+ }
366
+ }, {
367
+ key: "shouldRenderShareWithCourseCheckbox",
368
+ value: function shouldRenderShareWithCourseCheckbox() {
369
+ return this.props.showShareBankFromTray && this.props.scope.type === 'course' && this.props.scope.title && this.props.scope.uuid;
370
+ }
371
+ }, {
372
+ key: "renderCheckbox",
373
+ value: function renderCheckbox() {
374
+ if (!this.shouldRenderShareWithCourseCheckbox()) {
375
+ return null;
376
+ }
377
+
378
+ var label = t('Share with { courseName }', {
379
+ courseName: this.props.scope.title
380
+ });
381
+ return /*#__PURE__*/React.createElement(View, {
382
+ margin: "small 0",
383
+ as: "div"
384
+ }, /*#__PURE__*/React.createElement(Checkbox, {
385
+ checked: this.state.sharedWithCourse,
386
+ label: label,
387
+ onChange: this.toggleCheckbox,
388
+ disabled: this.props.bank.canEdit() ? this.state.shareWithCourseCheckboxDisabled : true
389
+ }));
390
+ }
220
391
  }, {
221
392
  key: "renderModals",
222
393
  value: function renderModals() {
@@ -292,7 +463,7 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
292
463
  value: function render() {
293
464
  return /*#__PURE__*/React.createElement(Page, null, this.renderModals(), this.renderNav(), /*#__PURE__*/React.createElement("div", {
294
465
  className: styles.content
295
- }, this.renderName(), /*#__PURE__*/React.createElement("div", {
466
+ }, this.renderName(), this.renderCheckbox(), /*#__PURE__*/React.createElement("div", {
296
467
  className: styles.topMenu
297
468
  }, this.renderTopLeftMenu(), this.renderTopRightMenu()), this.renderSearch(), /*#__PURE__*/React.createElement(PaginatedCollection, {
298
469
  empty: this.emptyLoadText(),
@@ -315,6 +486,7 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
315
486
  closeTray: PropTypes.func,
316
487
  getBank: PropTypes.func.isRequired,
317
488
  getBankEntries: PropTypes.func.isRequired,
489
+ getSharedBank: PropTypes.func.isRequired,
318
490
  isCompact: PropTypes.bool,
319
491
  isQuizContentLocked: PropTypes.bool.isRequired,
320
492
  navigateToBanks: PropTypes.func.isRequired,
@@ -323,20 +495,26 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
323
495
  // can be from consumer
324
496
  navigateToBuild: PropTypes.func,
325
497
  // from consumer
326
- scope: PropTypes.objectOf(PropTypes.shape({
498
+ scope: PropTypes.shape({
327
499
  type: PropTypes.string,
328
500
  uuid: PropTypes.string,
329
501
  title: PropTypes.string
330
- })),
502
+ }),
503
+ courseSharedBank: ImmutablePropTypes.map,
331
504
  returnToUrl: PropTypes.string,
332
505
  // from consumer
333
506
  onError: PropTypes.func,
334
507
  openModal: PropTypes.func.isRequired,
335
508
  position: PropTypes.number,
509
+ removeSharedBank: PropTypes.func.isRequired,
336
510
  resetSearch: PropTypes.func.isRequired,
337
511
  screenreaderNotification: PropTypes.func.isRequired,
338
512
  search: ImmutablePropTypes.map.isRequired,
339
- stimulusId: PropTypes.string
513
+ shareBank: PropTypes.func.isRequired,
514
+ stimulusId: PropTypes.string,
515
+ showShareBankFromTray: PropTypes.bool,
516
+ updateSharedBankPermission: PropTypes.func.isRequired,
517
+ withConfirm: PropTypes.func.isRequired
340
518
  }, _class2.defaultProps = {
341
519
  activeQuizId: null,
342
520
  addEntryToQuiz: null,
@@ -350,6 +528,8 @@ export var Bank = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
350
528
  stimulusId: null,
351
529
  scope: {},
352
530
  returnToUrl: null,
353
- isQuizContentLocked: false
531
+ isQuizContentLocked: false,
532
+ showShareBankFromTray: false,
533
+ courseSharedBank: null
354
534
  }, _temp)) || _class);
355
535
  export default Bank;
@@ -95,7 +95,8 @@ export var BanksTray = /*#__PURE__*/function (_Component) {
95
95
  closeTray: this.closeTray,
96
96
  bankId: activeBankId,
97
97
  navigateToBanks: this.clearActiveBank,
98
- navigateToBankEntry: this.props.newActiveBankEntry
98
+ navigateToBankEntry: this.props.newActiveBankEntry,
99
+ scope: this.props.itemBanksScope
99
100
  });
100
101
  }
101
102
  } else {
@@ -14,9 +14,9 @@ export var updateSharedBankPermission = function updateSharedBankPermission(shar
14
14
  }
15
15
  };
16
16
  };
17
- export var removeSharedBank = function removeSharedBank(bankId) {
17
+ export var removeSharedBank = function removeSharedBank(sharedBankId) {
18
18
  return {
19
19
  type: REMOVE_SHARED_BANK,
20
- payload: bankId
20
+ payload: sharedBankId
21
21
  };
22
22
  };
@@ -57,7 +57,7 @@ export var AnalysisMetric = (_dec = themeable(theme, styles), _dec(_class = (_te
57
57
  }(Component), _class2.propTypes = {
58
58
  metricKey: PropTypes.string.isRequired,
59
59
  label: PropTypes.string.isRequired,
60
- value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
60
+ value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.array]).isRequired,
61
61
  suffix: PropTypes.string
62
62
  }, _class2.defaultProps = {
63
63
  suffix: ''
@@ -9,23 +9,24 @@ var _dec, _class, _class2, _temp;
9
9
  import { Heading } from '@instructure/ui-heading';
10
10
  import React, { Component } from 'react';
11
11
  var styles = {
12
- componentId: 'dcJyB',
12
+ componentId: 'eLWCD',
13
13
  template: function template(theme) {
14
- return "\n\n.dcJyB_eDnN{display:flex;flex-basis:45%;flex-direction:column;overflow:hidden}\n\n.dcJyB_eKXQ{padding:".concat(theme.cardWrapperPadding || 'inherit', ";position:relative}\n\n.dcJyB_eIAv{display:flex;position:relative}\n\n.dcJyB_ePHw{flex-basis:91%;overflow:hidden;padding-bottom:10px;text-overflow:ellipsis;white-space:nowrap}\n\n.dcJyB_dzsH{overflow:visible;text-overflow:unset;white-space:normal}\n\n.dcJyB_byoJ{position:absolute;right:7px;top:-8px}\n\n.dcJyB_evBt{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}\n\n.dcJyB_pAQb{display:flex;flex-direction:column;height:60px}\n\n.dcJyB_zefc{display:flex;flex-basis:55%;justify-content:flex-end}\n\n.dcJyB_dPzc{flex-direction:column}\n\n.dcJyB_dPzc,.dcJyB_dzph{display:flex;flex-basis:100%}\n\n.dcJyB_dzph{align-items:flex-start;box-sizing:border-box;column-gap:5px;justify-content:space-between;padding:0 30px 0 25px}\n\n.dcJyB_eobd{padding-top:1rem}\n\n.dcJyB_NpIG{position:absolute;right:").concat(theme.viewPadding || 'inherit', ";top:").concat(theme.viewPadding || 'inherit', "}\n\n@media screen and (--tabletBreakPoint){.dcJyB_zefc{flex-basis:100%;justify-content:flex-start}.dcJyB_ePHw{flex-basis:94%}.dcJyB_eDnN{flex-basis:100%}.dcJyB_dzph{padding:0}.dcJyB_eDnN h3{padding-right:30px}.dcJyB_NpIG{right:17px}.dcJyB_eIAv{margin-bottom:20px}.dcJyB_byoJ{right:-7px}.dcJyB_dzph{flex-wrap:wrap}}");
14
+ return "\n\n.eLWCD_eDnN{display:flex;flex-basis:45%;flex-direction:column;overflow:hidden}\n\n.eLWCD_eKXQ{padding:".concat(theme.cardWrapperPadding || 'inherit', ";position:relative}\n\n.eLWCD_eoBe{font-size:").concat(theme.metricNumberContextFontSize || 'inherit', ";font-weight:").concat(theme.metricNumberContextFontWeight || 'inherit', "}\n\n.eLWCD_eIAv{display:flex;position:relative}\n\n.eLWCD_ePHw{flex-basis:91%;overflow:hidden;padding-bottom:10px;text-overflow:ellipsis;white-space:nowrap}\n\n.eLWCD_dzsH{overflow:visible;text-overflow:unset;white-space:normal}\n\n.eLWCD_byoJ{position:absolute;right:7px;top:-8px}\n\n.eLWCD_evBt{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}\n\n.eLWCD_pAQb{display:flex;flex-direction:column;height:60px}\n\n.eLWCD_zefc{display:flex;flex-basis:55%;justify-content:flex-end}\n\n.eLWCD_dPzc{flex-direction:column}\n\n.eLWCD_dPzc,.eLWCD_dzph{display:flex;flex-basis:100%}\n\n.eLWCD_dzph{align-items:flex-start;box-sizing:border-box;column-gap:5px;justify-content:space-between;padding:0 30px 0 25px}\n\n.eLWCD_eobd{padding-top:1rem}\n\n.eLWCD_NpIG{position:absolute;right:").concat(theme.viewPadding || 'inherit', ";top:").concat(theme.viewPadding || 'inherit', "}\n\n@media screen and (--tabletBreakPoint){.eLWCD_zefc{flex-basis:100%;justify-content:flex-start}.eLWCD_ePHw{flex-basis:94%}.eLWCD_eDnN{flex-basis:100%}.eLWCD_dzph{padding:0}.eLWCD_eDnN h3{padding-right:30px}.eLWCD_NpIG{right:17px}.eLWCD_eIAv{margin-bottom:20px}.eLWCD_byoJ{right:-7px}.eLWCD_dzph{flex-wrap:wrap}}");
15
15
  },
16
- 'heading': 'dcJyB_eDnN',
17
- 'cardWrapper': 'dcJyB_eKXQ',
18
- 'bodyPresentation': 'dcJyB_eIAv',
19
- 'bodyExcerpt': 'dcJyB_ePHw',
20
- 'bodyExcerptExpanded': 'dcJyB_dzsH',
21
- 'bodyExpandButtonWrapper': 'dcJyB_byoJ',
22
- 'innerWrapper': 'dcJyB_evBt',
23
- 'expandableInnerWrapper': 'dcJyB_pAQb',
24
- 'metricsWithControls': 'dcJyB_zefc',
25
- 'metricGroup': 'dcJyB_dPzc',
26
- 'metricsRow': 'dcJyB_dzph',
27
- 'metricsRowPaginated': 'dcJyB_eobd',
28
- 'itemCardToggleButtonWrapper': 'dcJyB_NpIG'
16
+ 'heading': 'eLWCD_eDnN',
17
+ 'cardWrapper': 'eLWCD_eKXQ',
18
+ 'metricNumberContext': 'eLWCD_eoBe',
19
+ 'bodyPresentation': 'eLWCD_eIAv',
20
+ 'bodyExcerpt': 'eLWCD_ePHw',
21
+ 'bodyExcerptExpanded': 'eLWCD_dzsH',
22
+ 'bodyExpandButtonWrapper': 'eLWCD_byoJ',
23
+ 'innerWrapper': 'eLWCD_evBt',
24
+ 'expandableInnerWrapper': 'eLWCD_pAQb',
25
+ 'metricsWithControls': 'eLWCD_zefc',
26
+ 'metricGroup': 'eLWCD_dPzc',
27
+ 'metricsRow': 'eLWCD_dzph',
28
+ 'metricsRowPaginated': 'eLWCD_eobd',
29
+ 'itemCardToggleButtonWrapper': 'eLWCD_NpIG'
29
30
  };
30
31
  import t from '@instructure/quiz-i18n/es/format-message';
31
32
  import ExpandButton from "../../../../../common/components/shared/ExpandButton/index.js";
@@ -129,10 +130,26 @@ export var NewItemAnalysis = (_dec = themeable(theme, styles), _dec(_class = (_t
129
130
  }));
130
131
  };
131
132
 
133
+ _this.calculateValueWithPointsPossible = function (metricKey, metricValue) {
134
+ var pointsPossible = _this.props.itemAnalysis.scores.points_possible;
135
+ return t.rich('{score, number}<s>/{possible, number} PTS</s>', {
136
+ s: function s(_ref) {
137
+ var children = _ref.children;
138
+ return /*#__PURE__*/React.createElement("span", {
139
+ key: metricKey,
140
+ className: styles.metricNumberContext
141
+ }, children);
142
+ },
143
+ score: metricValue,
144
+ possible: pointsPossible
145
+ });
146
+ };
147
+
132
148
  _this.renderExpanded = function () {
133
149
  var scores = _this.props.itemAnalysis.scores;
150
+ var classes = classnames(styles.metricsRow, styles.metricsRowPaginated);
134
151
  return /*#__PURE__*/React.createElement("div", {
135
- className: [styles.metricsRow, styles.metricsRowPaginated].join(' ')
152
+ className: classes
136
153
  }, /*#__PURE__*/React.createElement(AnalysisPopoverMetric, {
137
154
  metricKey: "pearson_correlation",
138
155
  label: t('Pearson Correlation Coefficient'),
@@ -202,11 +219,11 @@ export var NewItemAnalysis = (_dec = themeable(theme, styles), _dec(_class = (_t
202
219
  }), /*#__PURE__*/React.createElement(AnalysisMetric, {
203
220
  metricKey: "mean",
204
221
  label: t('Mean Earned Points'),
205
- value: t.number(scores.mean)
222
+ value: this.calculateValueWithPointsPossible('mean', scores.mean)
206
223
  }), /*#__PURE__*/React.createElement(AnalysisMetric, {
207
224
  metricKey: "median",
208
225
  label: t('Median Earned Points'),
209
- value: t.number(scores.median)
226
+ value: this.calculateValueWithPointsPossible('median', scores.median)
210
227
  }), /*#__PURE__*/React.createElement(AnalysisPopoverMetric, {
211
228
  metricKey: "discrimination_index",
212
229
  label: t('Discrimination Index'),
@@ -1,9 +1,12 @@
1
1
  export default function generator(_ref) {
2
2
  var spacing = _ref.spacing,
3
- breakpoints = _ref.breakpoints;
3
+ breakpoints = _ref.breakpoints,
4
+ typography = _ref.typography;
4
5
  return {
5
6
  tabletBreakPoint: "max-width: ".concat(breakpoints.large),
6
7
  cardWrapperPadding: spacing.medium,
7
- viewPadding: spacing.small
8
+ viewPadding: spacing.small,
9
+ metricNumberContextFontSize: typography.fontSizeMedium,
10
+ metricNumberContextFontWeight: typography.fontWeightNormal
8
11
  };
9
12
  }
@@ -5,7 +5,7 @@ var getSanitizedMetricValue = function getSanitizedMetricValue(value, suffix) {
5
5
  return t('N/A');
6
6
  }
7
7
 
8
- return value + (suffix ? suffix : '');
8
+ return suffix ? value + suffix : value;
9
9
  };
10
10
 
11
11
  export { getSanitizedMetricValue };
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
8
  exports.getExistingBankAndEntries = getExistingBankAndEntries;
9
- exports.updateSharedBankPermission = exports.getSharedBanks = exports.shareBank = exports.deleteBank = exports.updateBank = exports.createBank = exports.getBank = exports.getAllBanks = exports.getBanks = void 0;
9
+ exports.updateSharedBankPermission = exports.getSharedBanks = exports.getSharedBank = exports.shareBank = exports.deleteBank = exports.updateBank = exports.createBank = exports.getBank = exports.getAllBanks = exports.getBanks = void 0;
10
10
 
11
11
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
12
12
 
@@ -34,6 +34,8 @@ var _helpers = require("../../common/api/helpers.js");
34
34
 
35
35
  var _quizCommon = require("@instructure/quiz-common");
36
36
 
37
+ var _lodash = require("lodash");
38
+
37
39
  var banksApiEndpoint = '/api/banks';
38
40
  var DEFAULT_PAGE_SIZE = 100;
39
41
 
@@ -211,7 +213,8 @@ var deleteBank = function deleteBank(bankId) {
211
213
 
212
214
  exports.deleteBank = deleteBank;
213
215
 
214
- var shareBank = function shareBank(_shareBank, getUserInfo) {
216
+ var shareBank = function shareBank(_shareBank) {
217
+ var getUserInfo = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : _lodash.noop;
215
218
  var url = "".concat(banksApiEndpoint, "/").concat(_shareBank.bankId, "/shared_banks");
216
219
  return function (dispatch, getState) {
217
220
  var shareBankData = JSON.stringify({
@@ -258,6 +261,41 @@ var shareBank = function shareBank(_shareBank, getUserInfo) {
258
261
 
259
262
  exports.shareBank = shareBank;
260
263
 
264
+ var getSharedBank = function getSharedBank(bankId, entityType, entityId) {
265
+ var url = "".concat(banksApiEndpoint, "/").concat(bankId, "/shared_banks");
266
+ var params = {
267
+ entity_type: entityType,
268
+ entity_id: entityId
269
+ };
270
+ return function (dispatch, getState) {
271
+ var fetcher = new _Fetcher.default({
272
+ onError: (0, _helpers.handleError)(dispatch, (0, _formatMessage.default)('Failed to fetch shared bank.'))
273
+ });
274
+ return fetcher.get(url, params).then(function (sharedBankInfo) {
275
+ // if the API returns no data, we manually add placeholder to the response
276
+ if (sharedBankInfo.length === 0) {
277
+ var placeholder = {
278
+ id: "notshared_".concat(bankId, "_").concat(entityId),
279
+ entityType: entityType,
280
+ entityId: entityId,
281
+ permission: _quizCommon.REMOVED_ACCESS,
282
+ bankId: bankId
283
+ };
284
+ sharedBankInfo.push(placeholder);
285
+ }
286
+
287
+ dispatch((0, _callHandlers.handleShareBanksResponse)(sharedBankInfo));
288
+ }).catch(function (err) {
289
+ if (err.response.status === 401) {
290
+ dispatch((0, _ui.clear)(_quizCommon.BANKS_BANK_PAGINATION));
291
+ throw err;
292
+ }
293
+ });
294
+ };
295
+ };
296
+
297
+ exports.getSharedBank = getSharedBank;
298
+
261
299
  var getSharedBanks = function getSharedBanks(bank, getUserInfo, getCourseInfo) {
262
300
  var url = "".concat(banksApiEndpoint, "/").concat(bank.id, "/shared_banks");
263
301
  var userSharedBanks = [];
@@ -7,6 +7,7 @@ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWild
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
+ exports.mapStateToProps = mapStateToProps;
10
11
  exports.default = exports.Bank = void 0;
11
12
 
12
13
  var immutable = _interopRequireWildcard(require("immutable"));
@@ -33,11 +34,16 @@ var _alerts = require("../../../common/actions/alerts.js");
33
34
 
34
35
  var _bankSearch = require("../../../common/actions/bankSearch.js");
35
36
 
37
+ var _sharedBanks = require("../../../common/actions/sharedBanks.js");
38
+
36
39
  var _featureCheck = require("../../../common/util/featureCheck.js");
37
40
 
38
41
  function mapStateToProps(state, props) {
39
42
  var bank = new _Bank.default(state.getIn(['banks', props.bankId]));
40
43
  var search = state.get('bankSearch', immutable.Map());
44
+ var courseSharedBank = state.get('sharedBanks', immutable.Map()).find(function (sharedBank) {
45
+ return sharedBank.get('bankId') === props.bankId && sharedBank.get('entityType') === props.scope.type && sharedBank.get('entityId') === props.scope.uuid;
46
+ });
41
47
  var activeQuiz = (0, _quizzes.getActiveQuiz)(state);
42
48
  var lockBlueprintContentEnabled = (0, _featureCheck.featureOn)('lock_blueprint_content');
43
49
  var isQuizContentLocked = activeQuiz && activeQuiz.originalQuizLockedByBlueprint && lockBlueprintContentEnabled;
@@ -45,10 +51,12 @@ function mapStateToProps(state, props) {
45
51
  bank: bank,
46
52
  isQuizContentLocked: isQuizContentLocked,
47
53
  search: search,
54
+ courseSharedBank: courseSharedBank,
48
55
  useBankSearch: (0, _featureCheck.featureOn)('item_bank_search'),
49
56
  position: state.getIn(['ui', _quizCommon.BUILD_TRAY_POSITION]),
50
57
  stimulusId: state.getIn(['ui', _quizCommon.BUILD_TRAY_STIMULUS_ID]),
51
- activeQuizId: state.getIn(['quizzes', 'activeQuizId'])
58
+ activeQuizId: state.getIn(['quizzes', 'activeQuizId']),
59
+ showShareBankFromTray: (0, _featureCheck.featureOn)('share_bank_from_tray')
52
60
  };
53
61
  }
54
62
 
@@ -56,9 +64,14 @@ var mapDispatchToProps = {
56
64
  addEntryToQuiz: _quizEntries.createQuizEntry,
57
65
  getBank: _banks.getBank,
58
66
  getBankEntries: _bankEntries.getBankEntries,
67
+ getSharedBank: _banks.getSharedBank,
59
68
  openModal: _modal.openModal,
69
+ removeSharedBank: _sharedBanks.removeSharedBank,
60
70
  resetSearch: _bankSearch.reset,
61
- screenreaderNotification: _alerts.screenreaderNotification
71
+ screenreaderNotification: _alerts.screenreaderNotification,
72
+ shareBank: _banks.shareBank,
73
+ updateSharedBankPermission: _banks.updateSharedBankPermission,
74
+ withConfirm: _modal.withConfirm
62
75
  };
63
76
  var Bank = (0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps)(_presenter.Bank);
64
77
  exports.Bank = Bank;
@@ -9,6 +9,12 @@ Object.defineProperty(exports, "__esModule", {
9
9
  });
10
10
  exports.default = exports.Bank = void 0;
11
11
 
12
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
+
14
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
15
+
16
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
17
+
12
18
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13
19
 
14
20
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
@@ -27,6 +33,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
27
33
 
28
34
  var _reactImmutableProptypes = _interopRequireDefault(require("react-immutable-proptypes"));
29
35
 
36
+ var _partial = _interopRequireDefault(require("lodash/partial"));
37
+
30
38
  var _uiIcons = require("@instructure/ui-icons");
31
39
 
32
40
  var _uiBreadcrumb = require("@instructure/ui-breadcrumb");
@@ -39,6 +47,10 @@ var _uiA11yContent = require("@instructure/ui-a11y-content");
39
47
 
40
48
  var _uiThemeable = require("@instructure/ui-themeable");
41
49
 
50
+ var _uiCheckbox = require("@instructure/ui-checkbox");
51
+
52
+ var _uiView = require("@instructure/ui-view");
53
+
42
54
  var _Bank = _interopRequireDefault(require("../../../common/records/Bank.js"));
43
55
 
44
56
  var _index = _interopRequireDefault(require("../../../common/components/layout/Page/index.js"));
@@ -94,6 +106,10 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
94
106
  }
95
107
 
96
108
  _this = _super.call.apply(_super, [this].concat(_args));
109
+ _this.state = {
110
+ sharedWithCourse: false,
111
+ shareWithCourseCheckboxDisabled: true
112
+ };
97
113
 
98
114
  _this.openAddBankEntryModal = function () {
99
115
  _this.props.openModal(_quizCommon.ADD_BANK_ENTRY_MODAL, {
@@ -113,6 +129,74 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
113
129
  _this.createBankEntryButton = c;
114
130
  };
115
131
 
132
+ _this.toggleCheckbox = function () {
133
+ // disable until request resolves
134
+ _this.setState({
135
+ shareWithCourseCheckboxDisabled: true
136
+ });
137
+
138
+ _this.changeSharedPermissions();
139
+ };
140
+
141
+ _this.unshareBankWithCourse = /*#__PURE__*/function () {
142
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(sharedBank) {
143
+ var _this$props, updateSharedBankPermission, bankId, getSharedBank, scope;
144
+
145
+ return _regenerator.default.wrap(function _callee$(_context) {
146
+ while (1) {
147
+ switch (_context.prev = _context.next) {
148
+ case 0:
149
+ _this$props = _this.props, updateSharedBankPermission = _this$props.updateSharedBankPermission, bankId = _this$props.bankId, getSharedBank = _this$props.getSharedBank, scope = _this$props.scope;
150
+ _context.next = 3;
151
+ return updateSharedBankPermission(bankId, sharedBank.get('id'), _quizCommon.REMOVED_ACCESS);
152
+
153
+ case 3:
154
+ getSharedBank(bankId, scope.type, scope.uuid).catch(function (err) {
155
+ // make sure the user still has access to the bank
156
+ if (err.response.status === 401) {
157
+ _this.props.navigateToBanks();
158
+ }
159
+ });
160
+
161
+ case 4:
162
+ case "end":
163
+ return _context.stop();
164
+ }
165
+ }
166
+ }, _callee);
167
+ }));
168
+
169
+ return function (_x) {
170
+ return _ref.apply(this, arguments);
171
+ };
172
+ }();
173
+
174
+ _this.translatedPermissionLevel = function (permission) {
175
+ var _CAN_EDIT$READ_ONLY$p;
176
+
177
+ return (_CAN_EDIT$READ_ONLY$p = {}, (0, _defineProperty2.default)(_CAN_EDIT$READ_ONLY$p, _quizCommon.CAN_EDIT, (0, _formatMessage.default)('edit')), (0, _defineProperty2.default)(_CAN_EDIT$READ_ONLY$p, _quizCommon.READ_ONLY, (0, _formatMessage.default)('view')), _CAN_EDIT$READ_ONLY$p)[permission];
178
+ };
179
+
180
+ _this.confirmUnshareBankWithCourse = function () {
181
+ var confirmText = (0, _formatMessage.default)('You are about to remove { accessLevel } access for { entityTitle } to this bank.', {
182
+ accessLevel: _this.translatedPermissionLevel(_this.props.courseSharedBank.get('permission')),
183
+ entityTitle: _this.props.scope.title
184
+ });
185
+
186
+ _this.props.withConfirm((0, _partial.default)(_this.unshareBankWithCourse, _this.props.courseSharedBank), {
187
+ title: (0, _formatMessage.default)('Unshare Bank with Course'),
188
+ text: confirmText,
189
+ continueText: (0, _formatMessage.default)('Confirm'),
190
+ onCancel: _this.onCancelUnshareBankWithCourse
191
+ });
192
+ };
193
+
194
+ _this.onCancelUnshareBankWithCourse = function () {
195
+ _this.setState({
196
+ shareWithCourseCheckboxDisabled: false
197
+ });
198
+ };
199
+
116
200
  _this.addBankToQuiz = function () {
117
201
  var newEntry = _QuizEntry.default.create({
118
202
  entryId: _this.props.bankId,
@@ -138,8 +222,8 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
138
222
  }, _this.renderNewBankEntryButton());
139
223
  };
140
224
 
141
- _this.announceResults = function (_ref) {
142
- var totalPages = _ref.totalPages;
225
+ _this.announceResults = function (_ref2) {
226
+ var totalPages = _ref2.totalPages;
143
227
  var message = (0, _formatMessage.default)("{\n count, plural,\n =0 {No search results found}\n one {Displaying one page of results}\n other {Displaying # pages of results}\n }", {
144
228
  count: totalPages
145
229
  }); // Audibly announce when search results are ready.
@@ -153,10 +237,10 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
153
237
  _this.debouncedAnnounceResults = (0, _debounce.default)(_this.announceResults, 1000);
154
238
 
155
239
  _this.getPage = function (page, search) {
156
- var _this$props = _this.props,
157
- getBankEntries = _this$props.getBankEntries,
158
- bankId = _this$props.bankId,
159
- useBankSearch = _this$props.useBankSearch;
240
+ var _this$props2 = _this.props,
241
+ getBankEntries = _this$props2.getBankEntries,
242
+ bankId = _this$props2.bankId,
243
+ useBankSearch = _this$props2.useBankSearch;
160
244
  var text = search.get('text');
161
245
  var interactionTypes = search.get('interactionTypes', immutable.Set()).toJS();
162
246
  var tagIds = search.get('tags', []).map(function (tag) {
@@ -211,19 +295,68 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
211
295
 
212
296
  if (this.props.onError) {
213
297
  this.props.getBank(this.props.bankId).catch(this.props.onError);
298
+
299
+ if (this.shouldRenderShareWithCourseCheckbox()) {
300
+ this.props.getSharedBank(this.props.bankId, this.props.scope.type, this.props.scope.uuid).catch(this.props.onError);
301
+ }
214
302
  } else {
215
303
  this.props.getBank(this.props.bankId);
304
+
305
+ if (this.shouldRenderShareWithCourseCheckbox()) {
306
+ this.props.getSharedBank(this.props.bankId, this.props.scope.type, this.props.scope.uuid);
307
+ }
308
+ } // when courseSharedBank is already loaded
309
+
310
+
311
+ if (this.props.courseSharedBank) {
312
+ this.setShareWithCourseCheckbox();
216
313
  }
217
314
  }
315
+ }, {
316
+ key: "componentDidUpdate",
317
+ value: function componentDidUpdate(prevProps) {
318
+ var _prevProps$courseShar, _this$props$courseSha;
319
+
320
+ var permissionChanged = ((_prevProps$courseShar = prevProps.courseSharedBank) === null || _prevProps$courseShar === void 0 ? void 0 : _prevProps$courseShar.get('permission')) !== ((_this$props$courseSha = this.props.courseSharedBank) === null || _this$props$courseSha === void 0 ? void 0 : _this$props$courseSha.get('permission'));
321
+
322
+ if (this.props.courseSharedBank && permissionChanged) {
323
+ this.setShareWithCourseCheckbox();
324
+ }
325
+ }
326
+ }, {
327
+ key: "setShareWithCourseCheckbox",
328
+ value: function setShareWithCourseCheckbox() {
329
+ if (this.props.courseSharedBank.get('permission') === _quizCommon.REMOVED_ACCESS) {
330
+ this.setState({
331
+ sharedWithCourse: false,
332
+ shareWithCourseCheckboxDisabled: false
333
+ });
334
+ } else {
335
+ this.setState({
336
+ sharedWithCourse: true,
337
+ shareWithCourseCheckboxDisabled: false
338
+ });
339
+ }
340
+ }
341
+ }, {
342
+ key: "componentWillUnmount",
343
+ value: function componentWillUnmount() {
344
+ this.props.removeSharedBank(this.placeholderCourseSharedBankKey());
345
+ }
346
+ }, {
347
+ key: "placeholderCourseSharedBankKey",
348
+ value: function placeholderCourseSharedBankKey() {
349
+ return "notshared_".concat(this.props.bankId, "_").concat(this.props.scope.uuid);
350
+ }
218
351
  }, {
219
352
  key: "renderNav",
220
353
  value: function renderNav() {
221
- var _this$props2 = this.props,
222
- scope = _this$props2.scope,
223
- closeTray = _this$props2.closeTray,
224
- navigateToBanks = _this$props2.navigateToBanks,
225
- navigateToBuild = _this$props2.navigateToBuild,
226
- returnToUrl = _this$props2.returnToUrl;
354
+ var _this$props3 = this.props,
355
+ scope = _this$props3.scope,
356
+ closeTray = _this$props3.closeTray,
357
+ navigateToBanks = _this$props3.navigateToBanks,
358
+ navigateToBuild = _this$props3.navigateToBuild,
359
+ returnToUrl = _this$props3.returnToUrl;
227
360
  var isScopeEmpty = !Object.keys(scope).length;
228
361
  return /*#__PURE__*/_react.default.createElement(_index7.default, {
229
362
  closeTray: closeTray,
@@ -255,6 +388,50 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
255
388
  });
256
389
  }
257
390
  }
391
+ }, {
392
+ key: "changeSharedPermissions",
393
+ value: function changeSharedPermissions() {
394
+ if (this.props.bank.canEdit()) {
395
+ if (!this.state.sharedWithCourse) {
396
+ var shareBank = {
397
+ entityId: this.props.scope.uuid,
398
+ entityType: this.props.scope.type,
399
+ title: this.props.scope.title,
400
+ permission: _quizCommon.READ_ONLY,
401
+ bankId: this.props.bankId
402
+ };
403
+ this.props.removeSharedBank(this.placeholderCourseSharedBankKey());
404
+ this.props.shareBank(shareBank);
405
+ } else {
406
+ this.confirmUnshareBankWithCourse();
407
+ }
408
+ }
409
+ }
410
+ }, {
411
+ key: "shouldRenderShareWithCourseCheckbox",
412
+ value: function shouldRenderShareWithCourseCheckbox() {
413
+ return this.props.showShareBankFromTray && this.props.scope.type === 'course' && this.props.scope.title && this.props.scope.uuid;
414
+ }
415
+ }, {
416
+ key: "renderCheckbox",
417
+ value: function renderCheckbox() {
418
+ if (!this.shouldRenderShareWithCourseCheckbox()) {
419
+ return null;
420
+ }
421
+
422
+ var label = (0, _formatMessage.default)('Share with { courseName }', {
423
+ courseName: this.props.scope.title
424
+ });
425
+ return /*#__PURE__*/_react.default.createElement(_uiView.View, {
426
+ margin: "small 0",
427
+ as: "div"
428
+ }, /*#__PURE__*/_react.default.createElement(_uiCheckbox.Checkbox, {
429
+ checked: this.state.sharedWithCourse,
430
+ label: label,
431
+ onChange: this.toggleCheckbox,
432
+ disabled: this.props.bank.canEdit() ? this.state.shareWithCourseCheckboxDisabled : true
433
+ }));
434
+ }
258
435
  }, {
259
436
  key: "renderModals",
260
437
  value: function renderModals() {
@@ -330,7 +507,7 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
330
507
  value: function render() {
331
508
  return /*#__PURE__*/_react.default.createElement(_index.default, null, this.renderModals(), this.renderNav(), /*#__PURE__*/_react.default.createElement("div", {
332
509
  className: styles.content
333
- }, this.renderName(), /*#__PURE__*/_react.default.createElement("div", {
510
+ }, this.renderName(), this.renderCheckbox(), /*#__PURE__*/_react.default.createElement("div", {
334
511
  className: styles.topMenu
335
512
  }, this.renderTopLeftMenu(), this.renderTopRightMenu()), this.renderSearch(), /*#__PURE__*/_react.default.createElement(_index2.default, {
336
513
  empty: this.emptyLoadText(),
@@ -352,6 +529,7 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
352
529
  closeTray: _propTypes.default.func,
353
530
  getBank: _propTypes.default.func.isRequired,
354
531
  getBankEntries: _propTypes.default.func.isRequired,
532
+ getSharedBank: _propTypes.default.func.isRequired,
355
533
  isCompact: _propTypes.default.bool,
356
534
  isQuizContentLocked: _propTypes.default.bool.isRequired,
357
535
  navigateToBanks: _propTypes.default.func.isRequired,
@@ -360,20 +538,26 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
360
538
  // can be from consumer
361
539
  navigateToBuild: _propTypes.default.func,
362
540
  // from consumer
363
- scope: _propTypes.default.objectOf(_propTypes.default.shape({
541
+ scope: _propTypes.default.shape({
364
542
  type: _propTypes.default.string,
365
543
  uuid: _propTypes.default.string,
366
544
  title: _propTypes.default.string
367
- })),
545
+ }),
546
+ courseSharedBank: _reactImmutableProptypes.default.map,
368
547
  returnToUrl: _propTypes.default.string,
369
548
  // from consumer
370
549
  onError: _propTypes.default.func,
371
550
  openModal: _propTypes.default.func.isRequired,
372
551
  position: _propTypes.default.number,
552
+ removeSharedBank: _propTypes.default.func.isRequired,
373
553
  resetSearch: _propTypes.default.func.isRequired,
374
554
  screenreaderNotification: _propTypes.default.func.isRequired,
375
555
  search: _reactImmutableProptypes.default.map.isRequired,
376
- stimulusId: _propTypes.default.string
556
+ shareBank: _propTypes.default.func.isRequired,
557
+ stimulusId: _propTypes.default.string,
558
+ showShareBankFromTray: _propTypes.default.bool,
559
+ updateSharedBankPermission: _propTypes.default.func.isRequired,
560
+ withConfirm: _propTypes.default.func.isRequired
377
561
  }, _class2.defaultProps = {
378
562
  activeQuizId: null,
379
563
  addEntryToQuiz: null,
@@ -387,7 +571,9 @@ var Bank = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
387
571
  stimulusId: null,
388
572
  scope: {},
389
573
  returnToUrl: null,
390
- isQuizContentLocked: false
574
+ isQuizContentLocked: false,
575
+ showShareBankFromTray: false,
576
+ courseSharedBank: null
391
577
  }, _temp)) || _class);
392
578
  exports.Bank = Bank;
393
579
  var _default = Bank;
@@ -123,7 +123,8 @@ var BanksTray = /*#__PURE__*/function (_Component) {
123
123
  closeTray: this.closeTray,
124
124
  bankId: activeBankId,
125
125
  navigateToBanks: this.clearActiveBank,
126
- navigateToBankEntry: this.props.newActiveBankEntry
126
+ navigateToBankEntry: this.props.newActiveBankEntry,
127
+ scope: this.props.itemBanksScope
127
128
  });
128
129
  }
129
130
  } else {
@@ -28,10 +28,10 @@ var updateSharedBankPermission = function updateSharedBankPermission(sharedBankI
28
28
 
29
29
  exports.updateSharedBankPermission = updateSharedBankPermission;
30
30
 
31
- var removeSharedBank = function removeSharedBank(bankId) {
31
+ var removeSharedBank = function removeSharedBank(sharedBankId) {
32
32
  return {
33
33
  type: _quizCommon.REMOVE_SHARED_BANK,
34
- payload: bankId
34
+ payload: sharedBankId
35
35
  };
36
36
  };
37
37
 
@@ -75,7 +75,7 @@ var AnalysisMetric = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles)
75
75
  }(_react.Component), _class2.propTypes = {
76
76
  metricKey: _propTypes.default.string.isRequired,
77
77
  label: _propTypes.default.string.isRequired,
78
- value: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
78
+ value: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string, _propTypes.default.array]).isRequired,
79
79
  suffix: _propTypes.default.string
80
80
  }, _class2.defaultProps = {
81
81
  suffix: ''
@@ -50,23 +50,24 @@ var _interactionTypeMetadata = require("../../../../../common/util/interactionTy
50
50
  var _dec, _class, _class2, _temp;
51
51
 
52
52
  var styles = {
53
- componentId: 'dcJyB',
53
+ componentId: 'eLWCD',
54
54
  template: function template(theme) {
55
- return "\n\n.dcJyB_eDnN{display:flex;flex-basis:45%;flex-direction:column;overflow:hidden}\n\n.dcJyB_eKXQ{padding:".concat(theme.cardWrapperPadding || 'inherit', ";position:relative}\n\n.dcJyB_eIAv{display:flex;position:relative}\n\n.dcJyB_ePHw{flex-basis:91%;overflow:hidden;padding-bottom:10px;text-overflow:ellipsis;white-space:nowrap}\n\n.dcJyB_dzsH{overflow:visible;text-overflow:unset;white-space:normal}\n\n.dcJyB_byoJ{position:absolute;right:7px;top:-8px}\n\n.dcJyB_evBt{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}\n\n.dcJyB_pAQb{display:flex;flex-direction:column;height:60px}\n\n.dcJyB_zefc{display:flex;flex-basis:55%;justify-content:flex-end}\n\n.dcJyB_dPzc{flex-direction:column}\n\n.dcJyB_dPzc,.dcJyB_dzph{display:flex;flex-basis:100%}\n\n.dcJyB_dzph{align-items:flex-start;box-sizing:border-box;column-gap:5px;justify-content:space-between;padding:0 30px 0 25px}\n\n.dcJyB_eobd{padding-top:1rem}\n\n.dcJyB_NpIG{position:absolute;right:").concat(theme.viewPadding || 'inherit', ";top:").concat(theme.viewPadding || 'inherit', "}\n\n@media screen and (--tabletBreakPoint){.dcJyB_zefc{flex-basis:100%;justify-content:flex-start}.dcJyB_ePHw{flex-basis:94%}.dcJyB_eDnN{flex-basis:100%}.dcJyB_dzph{padding:0}.dcJyB_eDnN h3{padding-right:30px}.dcJyB_NpIG{right:17px}.dcJyB_eIAv{margin-bottom:20px}.dcJyB_byoJ{right:-7px}.dcJyB_dzph{flex-wrap:wrap}}");
55
+ return "\n\n.eLWCD_eDnN{display:flex;flex-basis:45%;flex-direction:column;overflow:hidden}\n\n.eLWCD_eKXQ{padding:".concat(theme.cardWrapperPadding || 'inherit', ";position:relative}\n\n.eLWCD_eoBe{font-size:").concat(theme.metricNumberContextFontSize || 'inherit', ";font-weight:").concat(theme.metricNumberContextFontWeight || 'inherit', "}\n\n.eLWCD_eIAv{display:flex;position:relative}\n\n.eLWCD_ePHw{flex-basis:91%;overflow:hidden;padding-bottom:10px;text-overflow:ellipsis;white-space:nowrap}\n\n.eLWCD_dzsH{overflow:visible;text-overflow:unset;white-space:normal}\n\n.eLWCD_byoJ{position:absolute;right:7px;top:-8px}\n\n.eLWCD_evBt{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}\n\n.eLWCD_pAQb{display:flex;flex-direction:column;height:60px}\n\n.eLWCD_zefc{display:flex;flex-basis:55%;justify-content:flex-end}\n\n.eLWCD_dPzc{flex-direction:column}\n\n.eLWCD_dPzc,.eLWCD_dzph{display:flex;flex-basis:100%}\n\n.eLWCD_dzph{align-items:flex-start;box-sizing:border-box;column-gap:5px;justify-content:space-between;padding:0 30px 0 25px}\n\n.eLWCD_eobd{padding-top:1rem}\n\n.eLWCD_NpIG{position:absolute;right:").concat(theme.viewPadding || 'inherit', ";top:").concat(theme.viewPadding || 'inherit', "}\n\n@media screen and (--tabletBreakPoint){.eLWCD_zefc{flex-basis:100%;justify-content:flex-start}.eLWCD_ePHw{flex-basis:94%}.eLWCD_eDnN{flex-basis:100%}.eLWCD_dzph{padding:0}.eLWCD_eDnN h3{padding-right:30px}.eLWCD_NpIG{right:17px}.eLWCD_eIAv{margin-bottom:20px}.eLWCD_byoJ{right:-7px}.eLWCD_dzph{flex-wrap:wrap}}");
56
56
  },
57
- 'heading': 'dcJyB_eDnN',
58
- 'cardWrapper': 'dcJyB_eKXQ',
59
- 'bodyPresentation': 'dcJyB_eIAv',
60
- 'bodyExcerpt': 'dcJyB_ePHw',
61
- 'bodyExcerptExpanded': 'dcJyB_dzsH',
62
- 'bodyExpandButtonWrapper': 'dcJyB_byoJ',
63
- 'innerWrapper': 'dcJyB_evBt',
64
- 'expandableInnerWrapper': 'dcJyB_pAQb',
65
- 'metricsWithControls': 'dcJyB_zefc',
66
- 'metricGroup': 'dcJyB_dPzc',
67
- 'metricsRow': 'dcJyB_dzph',
68
- 'metricsRowPaginated': 'dcJyB_eobd',
69
- 'itemCardToggleButtonWrapper': 'dcJyB_NpIG'
57
+ 'heading': 'eLWCD_eDnN',
58
+ 'cardWrapper': 'eLWCD_eKXQ',
59
+ 'metricNumberContext': 'eLWCD_eoBe',
60
+ 'bodyPresentation': 'eLWCD_eIAv',
61
+ 'bodyExcerpt': 'eLWCD_ePHw',
62
+ 'bodyExcerptExpanded': 'eLWCD_dzsH',
63
+ 'bodyExpandButtonWrapper': 'eLWCD_byoJ',
64
+ 'innerWrapper': 'eLWCD_evBt',
65
+ 'expandableInnerWrapper': 'eLWCD_pAQb',
66
+ 'metricsWithControls': 'eLWCD_zefc',
67
+ 'metricGroup': 'eLWCD_dPzc',
68
+ 'metricsRow': 'eLWCD_dzph',
69
+ 'metricsRowPaginated': 'eLWCD_eobd',
70
+ 'itemCardToggleButtonWrapper': 'eLWCD_NpIG'
70
71
  };
71
72
  var NewItemAnalysis = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_class = (_temp = _class2 = /*#__PURE__*/function (_Component) {
72
73
  (0, _inherits2.default)(NewItemAnalysis, _Component);
@@ -158,10 +159,26 @@ var NewItemAnalysis = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles
158
159
  }));
159
160
  };
160
161
 
162
+ _this.calculateValueWithPointsPossible = function (metricKey, metricValue) {
163
+ var pointsPossible = _this.props.itemAnalysis.scores.points_possible;
164
+ return _formatMessage.default.rich('{score, number}<s>/{possible, number} PTS</s>', {
165
+ s: function s(_ref) {
166
+ var children = _ref.children;
167
+ return /*#__PURE__*/_react.default.createElement("span", {
168
+ key: metricKey,
169
+ className: styles.metricNumberContext
170
+ }, children);
171
+ },
172
+ score: metricValue,
173
+ possible: pointsPossible
174
+ });
175
+ };
176
+
161
177
  _this.renderExpanded = function () {
162
178
  var scores = _this.props.itemAnalysis.scores;
179
+ var classes = (0, _classnames2.default)(styles.metricsRow, styles.metricsRowPaginated);
163
180
  return /*#__PURE__*/_react.default.createElement("div", {
164
- className: [styles.metricsRow, styles.metricsRowPaginated].join(' ')
181
+ className: classes
165
182
  }, /*#__PURE__*/_react.default.createElement(_index4.default, {
166
183
  metricKey: "pearson_correlation",
167
184
  label: (0, _formatMessage.default)('Pearson Correlation Coefficient'),
@@ -231,11 +248,11 @@ var NewItemAnalysis = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles
231
248
  }), /*#__PURE__*/_react.default.createElement(_index3.default, {
232
249
  metricKey: "mean",
233
250
  label: (0, _formatMessage.default)('Mean Earned Points'),
234
- value: _formatMessage.default.number(scores.mean)
251
+ value: this.calculateValueWithPointsPossible('mean', scores.mean)
235
252
  }), /*#__PURE__*/_react.default.createElement(_index3.default, {
236
253
  metricKey: "median",
237
254
  label: (0, _formatMessage.default)('Median Earned Points'),
238
- value: _formatMessage.default.number(scores.median)
255
+ value: this.calculateValueWithPointsPossible('median', scores.median)
239
256
  }), /*#__PURE__*/_react.default.createElement(_index4.default, {
240
257
  metricKey: "discrimination_index",
241
258
  label: (0, _formatMessage.default)('Discrimination Index'),
@@ -7,10 +7,13 @@ exports.default = generator;
7
7
 
8
8
  function generator(_ref) {
9
9
  var spacing = _ref.spacing,
10
- breakpoints = _ref.breakpoints;
10
+ breakpoints = _ref.breakpoints,
11
+ typography = _ref.typography;
11
12
  return {
12
13
  tabletBreakPoint: "max-width: ".concat(breakpoints.large),
13
14
  cardWrapperPadding: spacing.medium,
14
- viewPadding: spacing.small
15
+ viewPadding: spacing.small,
16
+ metricNumberContextFontSize: typography.fontSizeMedium,
17
+ metricNumberContextFontWeight: typography.fontWeightNormal
15
18
  };
16
19
  }
@@ -14,7 +14,7 @@ var getSanitizedMetricValue = function getSanitizedMetricValue(value, suffix) {
14
14
  return (0, _formatMessage.default)('N/A');
15
15
  }
16
16
 
17
- return value + (suffix ? suffix : '');
17
+ return suffix ? value + suffix : value;
18
18
  };
19
19
 
20
20
  exports.getSanitizedMetricValue = getSanitizedMetricValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/quiz-core",
3
- "version": "17.58.2-rc.7+623c562cd",
3
+ "version": "17.59.0",
4
4
  "license": "MIT",
5
5
  "description": "The Quiz React SDK by Instructure Inc.",
6
6
  "author": "Instructure, Inc. Engineering and Product Design",
@@ -41,11 +41,11 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@instructure/outcomes-ui": "^2.1.8",
44
- "@instructure/quiz-common": "17.58.2-rc.7+623c562cd",
45
- "@instructure/quiz-i18n": "17.58.2-rc.7+623c562cd",
46
- "@instructure/quiz-interactions": "17.58.2-rc.7+623c562cd",
47
- "@instructure/quiz-number-input": "17.58.2-rc.7+623c562cd",
48
- "@instructure/quiz-rce": "17.58.2-rc.7+623c562cd",
44
+ "@instructure/quiz-common": "^17.59.0",
45
+ "@instructure/quiz-i18n": "^17.59.0",
46
+ "@instructure/quiz-interactions": "^17.59.0",
47
+ "@instructure/quiz-number-input": "^17.59.0",
48
+ "@instructure/quiz-rce": "^17.59.0",
49
49
  "@instructure/ui-a11y-content": "^7.20.0",
50
50
  "@instructure/ui-alerts": "^7.20.0",
51
51
  "@instructure/ui-avatar": "^7.20.0",
@@ -106,7 +106,7 @@
106
106
  "eventemitter3": "^3.1.0",
107
107
  "humps": "^2.0.0",
108
108
  "immutable": "^3.8.1",
109
- "instructure-validations": "17.58.2-rc.7+623c562cd",
109
+ "instructure-validations": "^17.59.0",
110
110
  "ipaddr.js": "^1.5.4",
111
111
  "isomorphic-fetch": "^2.2.0",
112
112
  "isuuid": "^0.1.0",
@@ -137,7 +137,7 @@
137
137
  "uuid": "^3.2.1"
138
138
  },
139
139
  "devDependencies": {
140
- "@instructure/quiz-scripts": "17.58.1",
140
+ "@instructure/quiz-scripts": "^17.59.0",
141
141
  "@instructure/ui-axe-check": "^7.20.0",
142
142
  "@instructure/ui-babel-preset": "^7.20.0",
143
143
  "@instructure/ui-karma-config": "^7.20.0",
@@ -156,7 +156,7 @@
156
156
  "intl": "^1.2.4",
157
157
  "jquery": "^2.2.3",
158
158
  "most-subject": "^5.3.0",
159
- "quiz-presets": "17.58.2-rc.7+623c562cd",
159
+ "quiz-presets": "^17.59.0",
160
160
  "react": "^16.8.6",
161
161
  "react-addons-test-utils": "^15.6.2",
162
162
  "react-dom": "^16.8.6",
@@ -172,5 +172,5 @@
172
172
  "publishConfig": {
173
173
  "access": "public"
174
174
  },
175
- "gitHead": "623c562cd0e8f4d89e5c5480e383e8c8ddc01546"
175
+ "gitHead": "ce01a61066897195267a01a792262b8860aee224"
176
176
  }