@instructure/quiz-core 22.10.2 → 22.11.1

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 (43) hide show
  1. package/es/banks/api/banks.js +18 -97
  2. package/es/banks/components/SharingModal/index.js +6 -3
  3. package/es/banks/components/SharingModal/presenter.js +207 -131
  4. package/es/building/api/items.js +120 -24
  5. package/es/building/api/quizEntries.js +78 -15
  6. package/es/building/components/resources/quizEntry/QuizEntryShow/presenter.js +11 -2
  7. package/es/common/actions/sharedBanks.js +13 -1
  8. package/es/common/actions/sharingModal.js +7 -0
  9. package/es/common/components/resources/quiz/AddContent/Body/index.js +1 -1
  10. package/es/common/components/resources/quiz/AddContent/Body/presenter.js +129 -141
  11. package/es/common/components/resources/quiz/AddContent/Modal/presenter.js +59 -72
  12. package/es/common/components/resources/quiz/AddContent/Popover/presenter.js +126 -119
  13. package/es/common/components/shared/InteractionTypes/index.js +1 -4
  14. package/es/common/components/shared/InteractionTypes/presenter.js +1 -3
  15. package/es/common/middleware/sharedBanksMiddleware.js +243 -0
  16. package/es/common/records/Item.js +2 -1
  17. package/es/common/records/QuizEntry.js +7 -0
  18. package/es/common/reducers/sharingModal.js +17 -0
  19. package/es/common/util/useRemoteComponent.js +127 -0
  20. package/es/configureStore.js +4 -1
  21. package/es/index.js +3 -2
  22. package/lib/banks/api/banks.js +17 -96
  23. package/lib/banks/components/SharingModal/index.js +5 -2
  24. package/lib/banks/components/SharingModal/presenter.js +205 -129
  25. package/lib/building/api/items.js +120 -23
  26. package/lib/building/api/quizEntries.js +78 -14
  27. package/lib/building/components/resources/quizEntry/QuizEntryShow/presenter.js +10 -1
  28. package/lib/common/actions/sharedBanks.js +13 -1
  29. package/lib/common/actions/sharingModal.js +13 -0
  30. package/lib/common/components/resources/quiz/AddContent/Body/index.js +1 -1
  31. package/lib/common/components/resources/quiz/AddContent/Body/presenter.js +132 -141
  32. package/lib/common/components/resources/quiz/AddContent/Modal/presenter.js +59 -74
  33. package/lib/common/components/resources/quiz/AddContent/Popover/presenter.js +127 -119
  34. package/lib/common/components/shared/InteractionTypes/index.js +1 -4
  35. package/lib/common/components/shared/InteractionTypes/presenter.js +1 -3
  36. package/lib/common/middleware/sharedBanksMiddleware.js +250 -0
  37. package/lib/common/records/Item.js +2 -1
  38. package/lib/common/records/QuizEntry.js +7 -0
  39. package/lib/common/reducers/sharingModal.js +23 -0
  40. package/lib/common/util/useRemoteComponent.js +134 -0
  41. package/lib/configureStore.js +4 -1
  42. package/lib/index.js +22 -0
  43. package/package.json +8 -8
@@ -0,0 +1,127 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
2
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
3
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
4
+ // @ts-check
5
+ import { useCallback, useEffect, useRef, useState } from 'react';
6
+ import t from '@instructure/quiz-i18n/es/format-message';
7
+
8
+ /**
9
+ * Custom hook to load and render a remote component asynchronously.
10
+ *
11
+ * @param {() => Promise<{
12
+ * render: (container: HTMLElement, props: unknown) => void,
13
+ * unmount?: () => void
14
+ * }>} loadRemoteModule - A function that returns a promise resolving to the remote component module
15
+ * @param {unknown | undefined} props - Props to pass to the remote component when rendering
16
+ * @param {boolean} enabled - Whether the remote component should be loaded and rendered
17
+ *
18
+ * @returns {{
19
+ * containerRef: React.MutableRefObject<HTMLDivElement | null>,
20
+ * componentActivityState: 'idle' | 'pending' | 'success' | 'error',
21
+ * componentError: Error | null,
22
+ * unmount: () => void
23
+ * }} An object containing the container ref and unmount function
24
+ */
25
+ export function useRemoteComponent(loadRemoteModule, props) {
26
+ var enabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
27
+ var mountCancelled = useRef(false);
28
+ var _useState = useState(/** @type {'idle' | 'pending' | 'success' | 'error'} */'idle'),
29
+ _useState2 = _slicedToArray(_useState, 2),
30
+ componentActivityState = _useState2[0],
31
+ setComponentActivityState = _useState2[1];
32
+ var _useState3 = useState(/** @type {Error | null} */null),
33
+ _useState4 = _slicedToArray(_useState3, 2),
34
+ componentError = _useState4[0],
35
+ setComponentError = _useState4[1];
36
+
37
+ /**
38
+ * @type {React.MutableRefObject<{
39
+ * render: (container: HTMLElement, props: unknown) => void,
40
+ * unmount?: () => void
41
+ * } | null>}
42
+ */
43
+ var remoteModuleRef = useRef(null);
44
+
45
+ /**
46
+ * @type {React.MutableRefObject<HTMLDivElement | null>}
47
+ */
48
+ var containerRef = useRef(null);
49
+
50
+ // Note: This workflow can be converted to a TanStack Query hook in the future.
51
+ useEffect(function () {
52
+ if (loadRemoteModule == null || !enabled || componentActivityState === 'error') {
53
+ return;
54
+ }
55
+ mountCancelled.current = false;
56
+ setComponentActivityState('idle');
57
+ function loadModule() {
58
+ return _loadModule.apply(this, arguments);
59
+ }
60
+ function _loadModule() {
61
+ _loadModule = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
62
+ var module;
63
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
64
+ while (1) switch (_context.prev = _context.next) {
65
+ case 0:
66
+ _context.prev = 0;
67
+ if (!remoteModuleRef.current) {
68
+ _context.next = 4;
69
+ break;
70
+ }
71
+ setComponentActivityState('success');
72
+ return _context.abrupt("return", remoteModuleRef.current);
73
+ case 4:
74
+ setComponentActivityState('pending');
75
+ _context.next = 7;
76
+ return loadRemoteModule();
77
+ case 7:
78
+ module = _context.sent;
79
+ setComponentActivityState('success');
80
+ return _context.abrupt("return", module);
81
+ case 12:
82
+ _context.prev = 12;
83
+ _context.t0 = _context["catch"](0);
84
+ setComponentActivityState('error');
85
+ setComponentError(new Error(t('Failed to load remote module: {error}', {
86
+ error: _context.t0
87
+ })));
88
+ case 16:
89
+ case "end":
90
+ return _context.stop();
91
+ }
92
+ }, _callee, null, [[0, 12]]);
93
+ }));
94
+ return _loadModule.apply(this, arguments);
95
+ }
96
+ loadModule().then(function (module) {
97
+ if (module) {
98
+ remoteModuleRef.current = module;
99
+ }
100
+ var container = containerRef.current;
101
+ if (container == null || module == null || mountCancelled.current) {
102
+ return;
103
+ }
104
+ module.render(container, props);
105
+ });
106
+ return function () {
107
+ mountCancelled.current = true;
108
+ };
109
+ }, [loadRemoteModule, props, enabled]);
110
+ var unmount = useCallback(function () {
111
+ var _module$unmount;
112
+ if (mountCancelled.current || !containerRef.current) {
113
+ return;
114
+ }
115
+ var module = remoteModuleRef.current;
116
+ if (!module) {
117
+ return;
118
+ }
119
+ (_module$unmount = module.unmount) === null || _module$unmount === void 0 || _module$unmount.call(module);
120
+ }, []);
121
+ return {
122
+ containerRef: containerRef,
123
+ componentActivityState: componentActivityState,
124
+ componentError: componentError,
125
+ unmount: unmount
126
+ };
127
+ }
@@ -11,6 +11,7 @@ import alertTimerMiddleware from './common/middleware/alertTimerMiddleware';
11
11
  import crossDomainMessagingMiddleware from './common/middleware/crossDomainMessagingMiddleware';
12
12
  import eventLoggerMiddlewareCreator from './common/middleware/eventLoggerMiddleware';
13
13
  import { createQuizTimerWebSocketMiddleware } from './common/middleware/quizTimerWebSocketMiddleware';
14
+ import { createSharedBanksMiddleware } from './common/middleware/sharedBanksMiddleware';
14
15
 
15
16
  // reducers
16
17
  import alerts from './common/reducers/alerts';
@@ -50,6 +51,7 @@ import qtiImports from './common/reducers/qtiImports';
50
51
  import printing from './common/reducers/printing';
51
52
  import rce from './common/reducers/rce';
52
53
  import analyses from './common/reducers/analyses';
54
+ import sharingModal from './common/reducers/sharingModal';
53
55
  import dragAndDrop from './common/reducers/dragAndDrop';
54
56
  import sharedBanks from './common/reducers/sharedBanks';
55
57
  export function configureStore(_ref) {
@@ -77,7 +79,7 @@ export function configureStore(_ref) {
77
79
  var getMiddleware = function getMiddleware(implementation, override) {
78
80
  return isTest && override ? override : implementation;
79
81
  };
80
- var middlewares = [getMiddleware(alertTimerMiddleware, middlewareOverrides.alertTimerMiddleware), getMiddleware(crossDomainMessagingMiddleware, middlewareOverrides.crossDomainMessagingMiddleware), getMiddleware(multi, middlewareOverrides.multiMiddleware), getMiddleware(eventLoggerMiddlewareCreator(), middlewareOverrides.kinesisMiddleware), getMiddleware(thunkMiddleware, middlewareOverrides.thunkMiddleware), getMiddleware(createQuizTimerWebSocketMiddleware(), middlewareOverrides.websocketMiddleware)];
82
+ var middlewares = [getMiddleware(alertTimerMiddleware, middlewareOverrides.alertTimerMiddleware), getMiddleware(crossDomainMessagingMiddleware, middlewareOverrides.crossDomainMessagingMiddleware), getMiddleware(multi, middlewareOverrides.multiMiddleware), getMiddleware(eventLoggerMiddlewareCreator(), middlewareOverrides.kinesisMiddleware), getMiddleware(thunkMiddleware, middlewareOverrides.thunkMiddleware), getMiddleware(createQuizTimerWebSocketMiddleware(), middlewareOverrides.websocketMiddleware), getMiddleware(createSharedBanksMiddleware(), middlewareOverrides.sharedBanksMiddleware)];
81
83
  var devMiddleware = [getMiddleware(loggerMiddleware, middlewareOverrides.logger)];
82
84
  if (inDevelopment) {
83
85
  middlewares.push.apply(middlewares, devMiddleware);
@@ -98,6 +100,7 @@ export function configureStore(_ref) {
98
100
  banks: banks,
99
101
  bankEntries: bankEntries,
100
102
  sharedBanks: sharedBanks,
103
+ sharingModal: sharingModal,
101
104
  calls: calls,
102
105
  config: configReducer,
103
106
  editing: editing,
package/es/index.js CHANGED
@@ -110,18 +110,19 @@ export { breakdownSeconds, HOUR_IN_SECONDS } from './common/components/shared/Fo
110
110
  export { sessionStore } from './common/util/sessionStore';
111
111
  export { printWithCss, ensureImagesLoaded } from './common/util/printUtils';
112
112
  export { ensureRCEContentIsLoaded } from './common/util/rceChecker';
113
+ export { useRemoteComponent } from './common/util/useRemoteComponent';
113
114
  export { applyComponentStyleOverride, withStyleOverrides, getThemeByKey, setThemeByKey, getActiveTheme, setActiveTheme } from '@instructure/quiz-common';
114
115
  export { getClientIpAddress } from './common/util/getClientIpAddress';
115
116
 
116
117
  // APIs
117
118
  export { createQuizEntryRegrade } from './grading/api/quizEntryRegrades';
118
119
  export { getQuizEntry } from './building/api/quizEntries';
119
- export { getItem } from './building/api/items';
120
+ export { getItem, createBulkItems } from './building/api/items';
120
121
  export { interactionFileUpload, setOneAtATimeType, quizBuildingSession, saveQuizChange, setBacktracking, setCalculatorType, setAllowClearMCSelection, setChoiceElimination, setFilterIpAddress, setIpFiltersApi, setIpFiltersUi, setQuizDefaultRceSettings, setQuizShuffleAnswers, setQuizDisableDocumentAccess, setQuizShuffleQuestions, setRequireStudentAccessCode, setStudentAccessCodeApi, setStudentAccessCodeUi, setQuizHasTimeLimit, setSessionTimeLimitInSecondsUi, setSessionTimeLimitInSecondsApi, setResultsFeedback, setResultsFeedbackEnabled, setQuizDetectMultipleSessions } from './building/api/quizzes';
121
122
  export { getExistingQuiz } from './common/api/quizzes';
122
123
  export { confirmSessionStartPage, submitStudentAccessCode, nextQuestion, submitQuiz } from './taking/api/taking';
123
124
  export { pinSessionItem } from './common/api/quizSessions';
124
- export { moveQuizEntry } from './building/api/quizEntries';
125
+ export { moveQuizEntry, createBulkQuizEntries } from './building/api/quizEntries';
125
126
  export { postQuizSessionResults } from './grading/api/updateResults';
126
127
  export { getQuizSession, submitOutstandingQuizSession, getQuizSessions } from './moderating/api/quizSessions';
127
128
  export { getQuizSessionEvents } from './moderating/api/quizSessionEvents';
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.getBanks = exports.getBank = exports.getAllBanks = exports.deleteBank = exports.createBankCloneJob = exports.createBank = void 0;
7
+ exports.getBanks = exports.getBank = exports.getAllBanks = exports.deleteBank = exports.createBankCloneJob = exports.createBank = exports.changeSharedBankLoading = void 0;
8
8
  exports.getExistingBankAndEntries = getExistingBankAndEntries;
9
9
  exports.updateSharedBankPermission = exports.updateBank = exports.simpleFetchBanks = exports.shareBank = exports.getSpecificBanks = exports.getSharedBanks = exports.getSharedBank = void 0;
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
@@ -16,6 +16,7 @@ var _callHandlers = require("../../common/api/callHandlers");
16
16
  var _bankEntries = require("../../common/actions/bankEntries");
17
17
  var _banks = require("../../common/actions/banks");
18
18
  var _sharedBanks = require("../../common/actions/sharedBanks");
19
+ var _sharingModal = require("../../common/actions/sharingModal");
19
20
  var _ui = require("../../common/actions/ui");
20
21
  var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/es/format-message"));
21
22
  var _helpers = require("../../common/api/helpers");
@@ -277,102 +278,22 @@ var getSharedBank = exports.getSharedBank = function getSharedBank(bankId, entit
277
278
  };
278
279
  };
279
280
  var getSharedBanks = exports.getSharedBanks = function getSharedBanks(bank, getUserInfo, getCourseInfo, getAccountInfo) {
280
- var url = "".concat(banksApiEndpoint, "/").concat(bank.id, "/shared_banks");
281
281
  return function (dispatch, getState) {
282
- var fetcher = new _Fetcher["default"]({
283
- onError: (0, _helpers.handleError)(dispatch, (0, _formatMessage["default"])('Failed to fetch shared banks.'))
284
- });
285
- return fetcher.get(url).then(function (sharedBanksInfo) {
286
- // if the API returns no data, we manually add the bank's creator to the response
287
- if (sharedBanksInfo.length === 0) {
288
- sharedBanksInfo.push({
289
- id: '-1',
290
- entity_type: _quizCommon.SHARED_WITH_USER,
291
- entity_id: bank.creator,
292
- permission: _quizCommon.CAN_EDIT,
293
- bank_id: bank.id
294
- });
295
- }
296
-
297
- // USERS
298
- var userSharedBanks = [];
299
- var userUuids = sharedBanksInfo.filter(function (sb) {
300
- return sb.entity_type === _quizCommon.SHARED_WITH_USER;
301
- }).map(function (sb) {
302
- return sb.entity_id;
303
- });
304
- getUserInfo(userUuids).then(function (usersInfo) {
305
- usersInfo.forEach(function (userInfo) {
306
- var sharedBankInfo = sharedBanksInfo.find(function (sb) {
307
- return sb.entity_type === _quizCommon.SHARED_WITH_USER && sb.entity_id === userInfo.uuid;
308
- });
309
- if (sharedBankInfo) {
310
- userSharedBanks.push({
311
- id: sharedBankInfo.id,
312
- entityType: sharedBankInfo.entity_type,
313
- entityId: sharedBankInfo.entity_id,
314
- title: userInfo.fullName,
315
- avatar: userInfo.avatar,
316
- permission: sharedBankInfo.permission,
317
- bankId: sharedBankInfo.bank_id
318
- });
319
- }
320
- });
321
- dispatch((0, _callHandlers.handleShareBanksResponse)(userSharedBanks));
322
- });
323
-
324
- // COURSES
325
- var courseSharedBanks = [];
326
- var courseUuids = sharedBanksInfo.filter(function (sb) {
327
- return sb.entity_type === _quizCommon.SHARED_WITH_COURSE;
328
- }).map(function (sb) {
329
- return sb.entity_id;
330
- });
331
- getCourseInfo(courseUuids).then(function (coursesInfo) {
332
- coursesInfo.forEach(function (courseInfo) {
333
- var sharedBankInfo = sharedBanksInfo.find(function (sb) {
334
- return sb.entity_type === _quizCommon.SHARED_WITH_COURSE && sb.entity_id === courseInfo.uuid;
335
- });
336
- if (sharedBankInfo) {
337
- courseSharedBanks.push({
338
- id: sharedBankInfo.id,
339
- entityType: sharedBankInfo.entity_type,
340
- entityId: sharedBankInfo.entity_id,
341
- title: courseInfo.title,
342
- permission: sharedBankInfo.permission,
343
- bankId: sharedBankInfo.bank_id
344
- });
345
- }
346
- });
347
- dispatch((0, _callHandlers.handleShareBanksResponse)(courseSharedBanks));
348
- });
349
-
350
- // ACCOUNTS
351
- var accountSharedBanks = [];
352
- var accountUuids = sharedBanksInfo.filter(function (sb) {
353
- return sb.entity_type === _quizCommon.SHARED_WITH_ACCOUNT;
354
- }).map(function (sb) {
355
- return sb.entity_id;
356
- });
357
- getAccountInfo(accountUuids).then(function (accountsInfo) {
358
- accountsInfo.forEach(function (accountInfo) {
359
- var sharedBankInfo = sharedBanksInfo.find(function (sb) {
360
- return sb.entity_type === _quizCommon.SHARED_WITH_ACCOUNT && sb.entity_id === accountInfo.uuid;
361
- });
362
- if (sharedBankInfo) {
363
- accountSharedBanks.push({
364
- id: sharedBankInfo.id,
365
- entityType: sharedBankInfo.entity_type,
366
- entityId: sharedBankInfo.entity_id,
367
- title: accountInfo.name,
368
- permission: sharedBankInfo.permission,
369
- bankId: sharedBankInfo.bank_id
370
- });
371
- }
372
- });
373
- dispatch((0, _callHandlers.handleShareBanksResponse)(accountSharedBanks));
374
- });
375
- });
282
+ var payload = {
283
+ bank: bank,
284
+ getUserInfo: getUserInfo,
285
+ getCourseInfo: getCourseInfo,
286
+ getAccountInfo: getAccountInfo
287
+ };
288
+ dispatch((0, _sharedBanks.getSharedBanksAction)(payload));
289
+ };
290
+ };
291
+ var changeSharedBankLoading = exports.changeSharedBankLoading = function changeSharedBankLoading(isLoading) {
292
+ return function (dispatch, getState) {
293
+ var payload = {
294
+ loading: isLoading
295
+ };
296
+ dispatch((0, _sharingModal.sharedBankLoadingAction)(payload));
376
297
  };
377
298
  };
378
299
  var updateSharedBankPermission = exports.updateSharedBankPermission = function updateSharedBankPermission(bankId, sharedBankId, permission) {
@@ -16,8 +16,10 @@ function mapStateToProps(state, ownProps) {
16
16
  var sharedBanks = state.get('sharedBanks', (0, _immutable.Map)()).filter(function (sharedBank) {
17
17
  return sharedBank.get('bankId') === ownProps.bank.id;
18
18
  }).toList();
19
+ var loading = state.getIn(['sharingModal', 'loading']);
19
20
  return {
20
- sharedBanks: sharedBanks
21
+ sharedBanks: sharedBanks,
22
+ loading: loading
21
23
  };
22
24
  }
23
25
  var mapDispatchToProps = {
@@ -27,6 +29,7 @@ var mapDispatchToProps = {
27
29
  getBank: _banks.getBank,
28
30
  removeSharedBank: _sharedBanks.removeSharedBank,
29
31
  updateBank: _banks.updateBank,
30
- withConfirm: _modal.withConfirm
32
+ withConfirm: _modal.withConfirm,
33
+ changeSharedBankLoading: _banks.changeSharedBankLoading
31
34
  };
32
35
  var _default = exports["default"] = (0, _redux.compose)((0, _reactRedux.connect)(mapStateToProps, mapDispatchToProps))(_presenter["default"]);