@instructure/quiz-core 21.0.0 → 21.0.1-rc.11

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 (71) hide show
  1. package/es/banks/components/BankEntry/presenter.js +2 -2
  2. package/es/banks/components/BanksList/presenter.js +1 -1
  3. package/es/banks/components/SharingModal/presenter.js +2 -2
  4. package/es/building/components/layout/header/BuildingButtons/theme.js +1 -1
  5. package/es/building/components/resources/quizEntry/QuizEntryEdit/Footer/presenter.js +2 -2
  6. package/es/building/components/resources/quizEntry/QuizEntryEdit/presenter.js +2 -2
  7. package/es/common/actions/taking.js +3 -2
  8. package/es/common/components/PrintFontSizeModal/presenter.js +2 -2
  9. package/es/common/components/SDKApp/index.js +4 -4
  10. package/es/common/components/layout/navbar/theme.js +1 -1
  11. package/es/common/components/resources/entry/EntrySave/presenter.js +2 -2
  12. package/es/common/components/resources/stimulus/StimulusEditInfo/index.js +5 -1
  13. package/es/common/components/resources/stimulus/StimulusEditInfo/presenter.js +15 -2
  14. package/es/common/components/resources/stimulus/StimulusShow/index.js +1 -1
  15. package/es/common/components/shared/Card/CardWrapper/theme.js +1 -1
  16. package/es/common/components/shared/PaginatedCollection/presenter.js +2 -2
  17. package/es/common/components/shared/TimeUnitsInput/index.js +2 -2
  18. package/es/common/components/shared/functionality/makeEditable.js +2 -2
  19. package/es/common/reducers/taking.js +5 -1
  20. package/es/common/selectors/taking.js +3 -0
  21. package/es/common/util/getClientIpAddress.js +35 -0
  22. package/es/common/util/serializeEvent.js +4 -2
  23. package/es/index.js +2 -3
  24. package/es/moderating/components/events/Event.js +27 -10
  25. package/es/moderating/components/events/ResponseEvent.js +24 -7
  26. package/es/moderating/components/events/SessionStartEvent.js +16 -15
  27. package/es/moderating/components/events/SessionSubmitEvent.js +42 -0
  28. package/es/moderating/components/resources/AccommodationsModal/ExtraTimeMultiplier/index.js +2 -2
  29. package/es/moderating/components/resources/EventDetails.js +43 -0
  30. package/es/moderating/components/resources/SessionBreachAlert.js +10 -0
  31. package/es/moderating/components/resources/util/checkIsBreach.js +28 -0
  32. package/es/moderating/components/resources/util/extractSessionData.js +20 -0
  33. package/es/reporting/components/resources/QuizAndItemAnalysis/presenter.js +2 -2
  34. package/es/reporting/components/resources/common/propTypes.js +14 -0
  35. package/es/taking/api/taking.js +26 -3
  36. package/lib/banks/components/BankEntry/presenter.js +2 -2
  37. package/lib/banks/components/BanksList/presenter.js +1 -1
  38. package/lib/banks/components/SharingModal/presenter.js +2 -2
  39. package/lib/building/components/layout/header/BuildingButtons/theme.js +1 -1
  40. package/lib/building/components/resources/quizEntry/QuizEntryEdit/Footer/presenter.js +2 -2
  41. package/lib/building/components/resources/quizEntry/QuizEntryEdit/presenter.js +2 -2
  42. package/lib/common/actions/taking.js +3 -2
  43. package/lib/common/components/PrintFontSizeModal/presenter.js +2 -2
  44. package/lib/common/components/SDKApp/index.js +4 -4
  45. package/lib/common/components/layout/navbar/theme.js +1 -1
  46. package/lib/common/components/resources/entry/EntrySave/presenter.js +2 -2
  47. package/lib/common/components/resources/stimulus/StimulusEditInfo/index.js +5 -1
  48. package/lib/common/components/resources/stimulus/StimulusEditInfo/presenter.js +15 -2
  49. package/lib/common/components/resources/stimulus/StimulusShow/index.js +1 -1
  50. package/lib/common/components/shared/Card/CardWrapper/theme.js +1 -1
  51. package/lib/common/components/shared/PaginatedCollection/presenter.js +2 -2
  52. package/lib/common/components/shared/TimeUnitsInput/index.js +2 -2
  53. package/lib/common/components/shared/functionality/makeEditable.js +2 -2
  54. package/lib/common/reducers/taking.js +5 -1
  55. package/lib/common/selectors/taking.js +5 -1
  56. package/lib/common/util/getClientIpAddress.js +43 -0
  57. package/lib/common/util/serializeEvent.js +3 -1
  58. package/lib/index.js +15 -0
  59. package/lib/moderating/components/events/Event.js +26 -9
  60. package/lib/moderating/components/events/ResponseEvent.js +25 -7
  61. package/lib/moderating/components/events/SessionStartEvent.js +16 -15
  62. package/lib/moderating/components/events/SessionSubmitEvent.js +52 -0
  63. package/lib/moderating/components/resources/AccommodationsModal/ExtraTimeMultiplier/index.js +2 -2
  64. package/lib/moderating/components/resources/EventDetails.js +51 -0
  65. package/lib/moderating/components/resources/SessionBreachAlert.js +18 -0
  66. package/lib/moderating/components/resources/util/checkIsBreach.js +36 -0
  67. package/lib/moderating/components/resources/util/extractSessionData.js +28 -0
  68. package/lib/reporting/components/resources/QuizAndItemAnalysis/presenter.js +2 -2
  69. package/lib/reporting/components/resources/common/propTypes.js +18 -2
  70. package/lib/taking/api/taking.js +26 -3
  71. package/package.json +34 -33
@@ -212,8 +212,8 @@ export var BankEntry = (_dec = withStyleOverrides(generateStyle, generateCompone
212
212
  this.props.setShouldClone(false);
213
213
  }
214
214
  }, {
215
- key: "componentWillMount",
216
- value: function componentWillMount() {
215
+ key: "UNSAFE_componentWillMount",
216
+ value: function UNSAFE_componentWillMount() {
217
217
  this.props.setShouldClone(false);
218
218
  }
219
219
  }, {
@@ -446,7 +446,7 @@ export var BanksList = (_dec = withStyleOverrides(generateStyle, generateCompone
446
446
  }, jsx(Table.Row, null, this.renderTableSortHeader('name', t('Name')), this.renderTableSortHeader('updated_at', t('Updated')), jsx(Table.ColHeader, {
447
447
  id: "header-num-questions",
448
448
  width: "1"
449
- }, t('Questions')), this.renderTableSortHeader('last_used', t('Last Used')), this.renderTableSortHeader('created_at', t('Created')), !this.props.isCompact && jsx(Table.ColHeader, {
449
+ }, t('Questions')), this.renderTableSortHeader('last_used', t('Last Used')), this.renderTableSortHeader('created_at', t('Created')), jsx(Table.ColHeader, {
450
450
  id: "header-option-links",
451
451
  width: "1"
452
452
  }, jsx(ScreenReaderContent, null, t('Bank option links'))))), jsx(Table.Body, null, (this.props.banks.toArray() || []).map(function (bank) {
@@ -329,8 +329,8 @@ export var SharingModalPresenter = (_dec = withStyleOverrides(generateStyle, gen
329
329
  });
330
330
  }
331
331
  }, {
332
- key: "componentWillReceiveProps",
333
- value: function componentWillReceiveProps(nextProps) {
332
+ key: "UNSAFE_componentWillReceiveProps",
333
+ value: function UNSAFE_componentWillReceiveProps(nextProps) {
334
334
  this.setState({
335
335
  accountPermission: nextProps.bank.accountPermission,
336
336
  shares: nextProps.sharedBanks
@@ -5,7 +5,7 @@ var generateComponentTheme = function generateComponentTheme(_ref) {
5
5
  return {
6
6
  quizSavingColor: colors.lightGray,
7
7
  quizSavingMargin: spacing.large,
8
- buttonsHolderMargin: spacing.xLarge,
8
+ buttonsHolderMargin: spacing.mediumSmall,
9
9
  menuIconMargin: spacing.xSmall,
10
10
  menuIconFontSize: typography.fontSizeLarge
11
11
  };
@@ -87,8 +87,8 @@ export var QuizEntryEditFooter = (_dec = withStyleOverrides(generateStyle, gener
87
87
  return _this;
88
88
  }
89
89
  _createClass(QuizEntryEditFooter, [{
90
- key: "componentWillReceiveProps",
91
- value: function componentWillReceiveProps(nextProps) {
90
+ key: "UNSAFE_componentWillReceiveProps",
91
+ value: function UNSAFE_componentWillReceiveProps(nextProps) {
92
92
  var points = this.getPoints(nextProps);
93
93
  this.setState({
94
94
  points: points,
@@ -276,8 +276,8 @@ var QuizEntryEdit = (_dec = withStyleOverrides(generateStyle, generateComponentT
276
276
  this.props.onEditQuizEntryToggle(this.props.quizEntry.id);
277
277
  }
278
278
  }, {
279
- key: "componentWillMount",
280
- value: function componentWillMount() {
279
+ key: "UNSAFE_componentWillMount",
280
+ value: function UNSAFE_componentWillMount() {
281
281
  this.props.setUi(SHOULD_CLONE_ITEM, false);
282
282
  }
283
283
  }, {
@@ -104,12 +104,13 @@ export var loadResumeData = function loadResumeData(resumeData) {
104
104
  payload: resumeData
105
105
  };
106
106
  };
107
- export var sessionStartOrResumeEvent = function sessionStartOrResumeEvent(userAgent) {
107
+ export var sessionStartOrResumeEvent = function sessionStartOrResumeEvent(userAgent, ipAddress) {
108
108
  return {
109
109
  type: SESSION_STARTED_OR_RESUMED_EVENT,
110
110
  payload: {
111
111
  userAgent: userAgent,
112
- browserSessionId: uuid()
112
+ browserSessionId: uuid(),
113
+ ipAddress: ipAddress
113
114
  }
114
115
  };
115
116
  };
@@ -85,8 +85,8 @@ export var PrintFontSizeModal = (_dec = withStyleOverrides(generateStyle, genera
85
85
  });
86
86
  }
87
87
  }, {
88
- key: "componentWillReceiveProps",
89
- value: function componentWillReceiveProps(nextProps) {
88
+ key: "UNSAFE_componentWillReceiveProps",
89
+ value: function UNSAFE_componentWillReceiveProps(nextProps) {
90
90
  this.setState({
91
91
  selectedFontSize: nextProps.persistedPrintFontSize || this.state.selectedFontSize,
92
92
  rememberTextSizeSetting: !!this.props.persistedPrintFontSize || this.state.rememberTextSizeSetting
@@ -65,8 +65,8 @@ export var SDKApp = (_dec = withStyleOverrides(generateStyle, null), _dec(_class
65
65
  return set('appContainer', selectors);
66
66
  }
67
67
  }, {
68
- key: "componentWillMount",
69
- value: function componentWillMount() {
68
+ key: "UNSAFE_componentWillMount",
69
+ value: function UNSAFE_componentWillMount() {
70
70
  var _this$props$rceConfig;
71
71
  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), setExternalAccountUuid(this.props.externalAccountUuid)]);
72
72
  if (this.props.itemBankSharingEnabled) {
@@ -84,8 +84,8 @@ export var SDKApp = (_dec = withStyleOverrides(generateStyle, null), _dec(_class
84
84
  !this.props.disableAlertLiveRegion && renderAlerts(this.store);
85
85
  }
86
86
  }, {
87
- key: "componentWillReceiveProps",
88
- value: function componentWillReceiveProps(newProps) {
87
+ key: "UNSAFE_componentWillReceiveProps",
88
+ value: function UNSAFE_componentWillReceiveProps(newProps) {
89
89
  var _newProps$rceConfig, _this$props$rceConfig2;
90
90
  if (newProps.apiEndpoint !== this.props.apiEndpoint) {
91
91
  this.store.dispatch(setAPIEndpoint(newProps.apiEndpoint));
@@ -2,7 +2,7 @@ var generateComponentTheme = function generateComponentTheme(_ref) {
2
2
  var breakpoints = _ref.breakpoints,
3
3
  colors = _ref.colors;
4
4
  return {
5
- backgroundColor: colors.porcelain,
5
+ backgroundColor: colors.white,
6
6
  phoneBreakPoint: breakpoints.medium
7
7
  };
8
8
  };
@@ -85,8 +85,8 @@ export var EntrySave = /*#__PURE__*/function (_Component) {
85
85
  return _this;
86
86
  }
87
87
  _createClass(EntrySave, [{
88
- key: "componentWillMount",
89
- value: function componentWillMount() {
88
+ key: "UNSAFE_componentWillMount",
89
+ value: function UNSAFE_componentWillMount() {
90
90
  this.props.switchOnEditing(this.props.initialFocusId);
91
91
  }
92
92
  }, {
@@ -2,12 +2,16 @@ import { bindActionCreators } from 'redux';
2
2
  import { connect } from "../../../../react-redux.js";
3
3
  import * as modificationActions from "../../../../actions/modifications.js";
4
4
  import { featureOn } from "../../../../../common/util/featureCheck.js";
5
+ import { getActiveQuizId, getQuizById } from "../../../../../common/selectors/quizzes.js";
5
6
  import StimulusEditInfo from "./presenter.js";
6
7
  function mapStateToProps(state, props) {
8
+ var quizId = getActiveQuizId(state);
9
+ var quiz = getQuizById(state, quizId);
7
10
  return {
8
11
  workingStimulus: props.stimulus.getWorkingInstance(),
9
12
  errorsShowing: state.getIn(['errorsShowing', props.guid], props.errorsShowing || false),
10
- stimulusOrientationEnabled: featureOn('customizable_stimulus_orientation')
13
+ stimulusOrientationEnabled: featureOn('customizable_stimulus_orientation'),
14
+ shuffleQuestionsEnabled: quiz.shuffleQuestions
11
15
  };
12
16
  }
13
17
  function mapDispatchToProps(dispatch) {
@@ -18,6 +18,7 @@ import { SimpleSelect, TextInput, TOP, withStyleOverrides, FormFieldGroup, FormF
18
18
  import t from '@instructure/quiz-i18n/es/format-message';
19
19
  import generateStyle from "./styles.js";
20
20
  import generateComponentTheme from "./theme.js";
21
+ import { Alert } from '@instructure/ui-alerts';
21
22
  var _ref3 = jsx(IconUpdownLine, {
22
23
  rotate: "90"
23
24
  });
@@ -96,6 +97,16 @@ export var StimulusEditInfo = (_dec = withStyleOverrides(generateStyle, generate
96
97
  value: "top"
97
98
  }, t('Questions below'))));
98
99
  }
100
+ }, {
101
+ key: "renderPassageAlert",
102
+ value: function renderPassageAlert(stimulus) {
103
+ if (!stimulus.passage || !this.props.shuffleQuestionsEnabled) {
104
+ return null;
105
+ }
106
+ return jsx(Alert, {
107
+ variant: "warning"
108
+ }, t('The passage sections may not appear in their original order due to the shuffle setting.'));
109
+ }
99
110
  }, {
100
111
  key: "renderInstructions",
101
112
  value: function renderInstructions(stimulus) {
@@ -146,7 +157,7 @@ export var StimulusEditInfo = (_dec = withStyleOverrides(generateStyle, generate
146
157
  }, jsx(Heading, {
147
158
  level: "h3",
148
159
  as: "h2"
149
- }, this.headerText(stimulus)), jsx("div", {
160
+ }, this.headerText(stimulus)), this.renderPassageAlert(stimulus), jsx("div", {
150
161
  css: this.props.styles.section
151
162
  }, jsx(TextInput, {
152
163
  messages: this.inputErrors('title'),
@@ -184,9 +195,11 @@ export var StimulusEditInfo = (_dec = withStyleOverrides(generateStyle, generate
184
195
  modifyStimulus: PropTypes.func.isRequired,
185
196
  setTitleRef: PropTypes.func,
186
197
  stimulusOrientationEnabled: PropTypes.bool.isRequired,
187
- styles: PropTypes.object
198
+ styles: PropTypes.object,
199
+ shuffleQuestionsEnabled: PropTypes.bool
188
200
  }, _StimulusEditInfo.defaultProps = {
189
201
  isBankedContent: false,
202
+ shuffleQuestionsEnabled: false,
190
203
  setTitleRef: function setTitleRef() {}
191
204
  }, _StimulusEditInfo)) || _class);
192
205
  export default StimulusEditInfo;
@@ -11,13 +11,13 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
11
11
  import { IconBankLine } from '@instructure/ui-icons';
12
12
  import { jsx } from '@instructure/emotion';
13
13
  import { Text } from '@instructure/ui-text';
14
+ import { Flex, withStyleOverrides } from '@instructure/quiz-common';
14
15
  import StimulusShowInfo from "../StimulusShowInfo/index.js";
15
16
  import ActionButtons from "../../../../../building/components/resources/ActionButtons/index.js";
16
17
  import t from '@instructure/quiz-i18n/es/format-message';
17
18
  import generateStyle from "./styles.js";
18
19
  import generateComponentTheme from "./theme.js";
19
20
  import Overlay from "../../../shared/overlay/index.js";
20
- import { Flex, withStyleOverrides } from '@instructure/quiz-common';
21
21
  var _ref = jsx(IconBankLine, null);
22
22
  export var StimulusShow = (_dec = withStyleOverrides(generateStyle, generateComponentTheme), _dec(_class = (_StimulusShow = /*#__PURE__*/function (_Component) {
23
23
  _inherits(StimulusShow, _Component);
@@ -3,7 +3,7 @@ var generateComponentTheme = function generateComponentTheme(_ref) {
3
3
  breakpoints = _ref.breakpoints,
4
4
  transitions = _ref.transitions;
5
5
  return {
6
- wrapperPadding: spacing.medium,
6
+ wrapperPadding: spacing.mediumSmall,
7
7
  wrapperTransitionDuration: transitions.duration,
8
8
  phoneBreakPoint: "max-width: ".concat(breakpoints.medium),
9
9
  phoneWrapperPadding: spacing.medium
@@ -54,8 +54,8 @@ export var PaginatedCollection = (_dec = withStyleOverrides(generateStyle, gener
54
54
  this.getPage(this.props.stateKey, this.props.currentPage, this.props.params);
55
55
  }
56
56
  }, {
57
- key: "componentWillReceiveProps",
58
- value: function componentWillReceiveProps(_ref) {
57
+ key: "UNSAFE_componentWillReceiveProps",
58
+ value: function UNSAFE_componentWillReceiveProps(_ref) {
59
59
  var merge = _ref.merge,
60
60
  params = _ref.params,
61
61
  set = _ref.set,
@@ -179,8 +179,8 @@ export var TimeUnitsInput = /*#__PURE__*/function (_Component) {
179
179
  return _this;
180
180
  }
181
181
  _createClass(TimeUnitsInput, [{
182
- key: "componentWillMount",
183
- value: function componentWillMount() {
182
+ key: "UNSAFE_componentWillMount",
183
+ value: function UNSAFE_componentWillMount() {
184
184
  var _breakdownSeconds5 = breakdownSeconds(this.props.timeInSeconds, this.props.includeDays),
185
185
  days = _breakdownSeconds5.days,
186
186
  hours = _breakdownSeconds5.hours,
@@ -55,8 +55,8 @@ var giveEditProps = function giveEditProps(ComposedComponent) {
55
55
  return _this;
56
56
  }
57
57
  _createClass(_Class, [{
58
- key: "componentWillMount",
59
- value: function componentWillMount() {
58
+ key: "UNSAFE_componentWillMount",
59
+ value: function UNSAFE_componentWillMount() {
60
60
  this._uniqId = uniqueId("".concat(ComposedComponent.displayName, "_"));
61
61
  }
62
62
  }, {
@@ -67,7 +67,11 @@ var loadResponses = function loadResponses(state, payload) {
67
67
  return payload.reduce(modifyResponse, state);
68
68
  };
69
69
  var markSessionStartedIdentifier = function markSessionStartedIdentifier(state, payload) {
70
- return state.get('browserSessionId') === payload.browserSessionId ? state : state.set('browserSessionId', payload.browserSessionId);
70
+ var needsUpdate = state.get('browserSessionId') !== payload.browserSessionId || state.get('ipAddress') !== payload.ipAddress;
71
+ return needsUpdate ? state.merge({
72
+ browserSessionId: payload.browserSessionId,
73
+ ipAddress: payload.ipAddress
74
+ }) : state;
71
75
  };
72
76
  var updateQuizSubmitFlag = function updateQuizSubmitFlag(state, payload) {
73
77
  return state.set('submitFlag', payload.value);
@@ -7,6 +7,9 @@ export var getCurrentSessionItemPosition = function getCurrentSessionItemPositio
7
7
  export var getBrowserSessionId = function getBrowserSessionId(state) {
8
8
  return state.getIn([path, 'browserSessionId']);
9
9
  };
10
+ export var getIpAddress = function getIpAddress(state) {
11
+ return state.getIn([path, 'ipAddress']);
12
+ };
10
13
  export var getTimerData = function getTimerData(state) {
11
14
  return state.getIn([path, 'timerData'], Map());
12
15
  };
@@ -0,0 +1,35 @@
1
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
3
+ import Fetcher from "./Fetcher.js";
4
+ export var getClientIpAddress = /*#__PURE__*/function () {
5
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(quizSessionId) {
6
+ var url, fetcher, _yield$fetcher$get, ip;
7
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
8
+ while (1) {
9
+ switch (_context.prev = _context.next) {
10
+ case 0:
11
+ _context.prev = 0;
12
+ url = "/api/quiz_sessions/".concat(quizSessionId, "/get_ip_address");
13
+ fetcher = new Fetcher();
14
+ _context.next = 5;
15
+ return fetcher.get(url);
16
+ case 5:
17
+ _yield$fetcher$get = _context.sent;
18
+ ip = _yield$fetcher$get.ip;
19
+ return _context.abrupt("return", ip);
20
+ case 10:
21
+ _context.prev = 10;
22
+ _context.t0 = _context["catch"](0);
23
+ console.error(_context.t0);
24
+ return _context.abrupt("return", null);
25
+ case 14:
26
+ case "end":
27
+ return _context.stop();
28
+ }
29
+ }
30
+ }, _callee, null, [[0, 10]]);
31
+ }));
32
+ return function getClientIpAddress(_x) {
33
+ return _ref.apply(this, arguments);
34
+ };
35
+ }();
@@ -1,5 +1,5 @@
1
1
  import { QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT, PAGE_BLURRED_EVENT, PAGE_FOCUSED_EVENT } from '@instructure/quiz-common';
2
- import { getBrowserSessionId } from "../selectors/taking.js";
2
+ import { getBrowserSessionId, getIpAddress } from "../selectors/taking.js";
3
3
  import { getActiveQuizSession } from "../selectors/quizSessions.js";
4
4
  var whitelist = [QUIZ_SUBMISSION_EVENT, RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT, PAGE_BLURRED_EVENT, PAGE_FOCUSED_EVENT];
5
5
  export function serializeEvent(action, store) {
@@ -10,8 +10,10 @@ export function serializeEvent(action, store) {
10
10
  var state = store.getState();
11
11
  var quizSession = getActiveQuizSession(state);
12
12
  var defaultEventData = {
13
+ userAgent: navigator.userAgent,
13
14
  browserSessionId: getBrowserSessionId(state),
14
- clientTimestamp: new Date()
15
+ clientTimestamp: new Date(),
16
+ ipAddress: getIpAddress(state)
15
17
  };
16
18
  var authoritativeData = {
17
19
  accountUuid: quizSession.accountUuid,
package/es/index.js CHANGED
@@ -107,8 +107,7 @@ export { sessionStore } from "./common/util/sessionStore.js";
107
107
  export { printWithCss, ensureImagesLoaded } from "./common/util/printUtils.js";
108
108
  export { ensureRCEContentIsLoaded } from "./common/util/rceChecker.js";
109
109
  export { applyComponentStyleOverride, withStyleOverrides, getThemeByKey, setThemeByKey, getActiveTheme, setActiveTheme } from '@instructure/quiz-common';
110
-
111
- // APIs
110
+ export { getClientIpAddress } from "./common/util/getClientIpAddress.js"; // APIs
112
111
  export { createQuizEntryRegrade } from "./grading/api/quizEntryRegrades.js";
113
112
  export { getQuizEntry } from "./building/api/quizEntries.js";
114
113
  export { getItem } from "./building/api/items.js";
@@ -146,7 +145,7 @@ import * as takingActionCreators from "./common/actions/taking.js";
146
145
  export { takingActionCreators };
147
146
 
148
147
  // Selectors
149
- export { getQuizById, getActiveQuizId, getQuizEntryById, isActiveQuizWorkingInstanceOneQuestionAtATime, getActiveQuiz } from "./common/selectors/quizzes.js";
148
+ export { getQuizById, getActiveQuizId, getQuizEntryById, getQuizEntriesByQuizId, isActiveQuizWorkingInstanceOneQuestionAtATime, getActiveQuiz } from "./common/selectors/quizzes.js";
150
149
  export { getItemById } from "./common/selectors/items.js";
151
150
  export { fileUploading } from "./common/selectors/calls.js";
152
151
  export { isTimeUp, getTimerData, getResponseDataByPosition } from "./common/selectors/taking.js";
@@ -6,14 +6,17 @@ var _Event;
6
6
  import React, { Component } from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import ImmutablePropTypes from 'react-immutable-proptypes';
9
- import { RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT, PAGE_BLURRED_EVENT, PAGE_FOCUSED_EVENT } from '@instructure/quiz-common';
9
+ import { RESPONSE, SESSION_STARTED_OR_RESUMED_EVENT, RCE_EVENT, PAGE_BLURRED_EVENT, PAGE_FOCUSED_EVENT, QUIZ_SUBMISSION_EVENT } from '@instructure/quiz-common';
10
10
  import { Table } from '@instructure/ui-table';
11
11
  import ElapsedTime from "../resources/ElapsedTime.js";
12
12
  import ResponseEvent from "./ResponseEvent.js";
13
13
  import SessionStartEvent from "./SessionStartEvent.js";
14
+ import { SessionSubmitEvent } from "./SessionSubmitEvent.js";
14
15
  import RCEEvent from "./RCEEvent.js";
15
16
  import PageBlurredEvent from "./PageBlurredEvent.js";
16
17
  import PageFocusedEvent from "./PageFocusedEvent.js";
18
+ import { extractSessionData } from "../resources/util/extractSessionData.js";
19
+ import { checkIsBreach } from "../resources/util/checkIsBreach.js";
17
20
  var _ref = /*#__PURE__*/React.createElement(PageBlurredEvent, null);
18
21
  var _ref2 = /*#__PURE__*/React.createElement(PageFocusedEvent, null);
19
22
  export var Event = /*#__PURE__*/function (_Component) {
@@ -25,26 +28,34 @@ export var Event = /*#__PURE__*/function (_Component) {
25
28
  }
26
29
  _createClass(Event, [{
27
30
  key: "renderResponseEvent",
28
- value: function renderResponseEvent(event) {
31
+ value: function renderResponseEvent(event, validationErrors, currentEventData) {
29
32
  var item = event.getItem();
30
33
  if (!item) {
31
34
  return null;
32
35
  } else {
33
36
  return /*#__PURE__*/React.createElement(ResponseEvent, {
34
37
  event: event,
35
- item: item
38
+ item: item,
39
+ validationErrors: validationErrors,
40
+ currentEventData: currentEventData
36
41
  });
37
42
  }
38
43
  }
39
44
  }, {
40
45
  key: "renderPayload",
41
- value: function renderPayload(event) {
46
+ value: function renderPayload(event, validationErrors, currentEventData) {
42
47
  switch (event.eventType) {
43
48
  case RESPONSE:
44
- return this.renderResponseEvent(event);
49
+ return this.renderResponseEvent(event, validationErrors, currentEventData);
45
50
  case SESSION_STARTED_OR_RESUMED_EVENT:
46
51
  return /*#__PURE__*/React.createElement(SessionStartEvent, {
47
- event: event
52
+ validationErrors: validationErrors,
53
+ currentEventData: currentEventData
54
+ });
55
+ case QUIZ_SUBMISSION_EVENT:
56
+ return /*#__PURE__*/React.createElement(SessionSubmitEvent, {
57
+ validationErrors: validationErrors,
58
+ currentEventData: currentEventData
48
59
  });
49
60
  case RCE_EVENT:
50
61
  return /*#__PURE__*/React.createElement(RCEEvent, {
@@ -64,8 +75,12 @@ export var Event = /*#__PURE__*/function (_Component) {
64
75
  value: function render() {
65
76
  var _this$props = this.props,
66
77
  event = _this$props.event,
67
- startTime = _this$props.startTime;
68
- var payloadNode = this.renderPayload(event);
78
+ startTime = _this$props.startTime,
79
+ firstEvent = _this$props.firstEvent;
80
+ var currentEventData = extractSessionData(event);
81
+ var firstEventData = extractSessionData(firstEvent);
82
+ var validationErrors = checkIsBreach(firstEventData, currentEventData);
83
+ var payloadNode = this.renderPayload(event, validationErrors, currentEventData);
69
84
  if (!payloadNode) return null;
70
85
  return /*#__PURE__*/React.createElement(Table.Row, null, /*#__PURE__*/React.createElement(Table.Cell, null, /*#__PURE__*/React.createElement(ElapsedTime, {
71
86
  eventTime: event.createdDate(),
@@ -82,10 +97,12 @@ Event.displayName = 'Row';
82
97
  Event.componentId = "Quizzes".concat(_Event.displayName);
83
98
  Event.propTypes = {
84
99
  event: ImmutablePropTypes.record,
85
- startTime: PropTypes.instanceOf(Date)
100
+ startTime: PropTypes.instanceOf(Date),
101
+ firstEvent: ImmutablePropTypes.record
86
102
  };
87
103
  Event.defaultProps = {
88
104
  event: void 0,
89
- startTime: void 0
105
+ startTime: void 0,
106
+ firstEvent: void 0
90
107
  };
91
108
  export default Event;
@@ -4,7 +4,7 @@ import _inherits from "@babel/runtime/helpers/esm/inherits";
4
4
  import _createSuper from "@babel/runtime/helpers/esm/createSuper";
5
5
  var _dec, _class, _ResponseEvent;
6
6
  /** @jsx jsx */
7
- import { Component } from 'react';
7
+ import React, { Component } from 'react';
8
8
  import ImmutablePropTypes from 'react-immutable-proptypes';
9
9
  import PropTypes from 'prop-types';
10
10
  import { IconImageSolid } from '@instructure/ui-icons';
@@ -14,9 +14,11 @@ import { ToggleDetails } from '@instructure/ui-toggle-details';
14
14
  import { jsx } from '@instructure/emotion';
15
15
  import t from '@instructure/quiz-i18n/es/format-message';
16
16
  import { extractTextFromHtml } from '@instructure/quiz-interactions';
17
+ import { EventDetails } from "../resources/EventDetails.js";
17
18
  import generateStyle from "./styles.js";
18
19
  import generateComponentTheme from "./theme.js";
19
20
  import { withStyleOverrides } from '@instructure/quiz-common';
21
+ import { sessionValidationErrorsPropType, eventDataPropType } from "../../../reporting/components/resources/common/propTypes.js";
20
22
  var imgRegex = /<img.*?src=['"](.+)['"]/g;
21
23
  export var ResponseEvent = (_dec = withStyleOverrides(generateStyle, generateComponentTheme), _dec(_class = (_ResponseEvent = /*#__PURE__*/function (_Component) {
22
24
  _inherits(ResponseEvent, _Component);
@@ -44,13 +46,16 @@ export var ResponseEvent = (_dec = withStyleOverrides(generateStyle, generateCom
44
46
  }, {
45
47
  key: "renderTextSummary",
46
48
  value: function renderTextSummary() {
49
+ var isBreach = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
47
50
  var strippedItemBody = extractTextFromHtml(this.itemBody);
48
51
  return jsx("span", null, this.hasMedia() && jsx(IconImageSolid, {
49
52
  css: this.props.styles.answerMediaIcon
50
- }), t('Answered question {position}: {question}', {
53
+ }), jsx(Text, {
54
+ color: isBreach ? 'danger' : 'primary'
55
+ }, t('Answered question {position}: {question}', {
51
56
  position: this.props.event.getIn(['eventData', 'position']),
52
57
  question: strippedItemBody
53
- }));
58
+ })));
54
59
  }
55
60
  }, {
56
61
  key: "renderMedia",
@@ -78,16 +83,26 @@ export var ResponseEvent = (_dec = withStyleOverrides(generateStyle, generateCom
78
83
  }, {
79
84
  key: "render",
80
85
  value: function render() {
86
+ var _this$props = this.props,
87
+ validationErrors = _this$props.validationErrors,
88
+ currentEventData = _this$props.currentEventData;
81
89
  var responseText = this.getReadableResponseText();
82
90
  if (responseText) {
83
91
  // If this returns falsey, then we know to just display the stem
84
92
  return jsx(ToggleDetails, {
85
- summary: this.renderTextSummary()
86
- }, this.renderMedia(), responseText);
93
+ summary: this.renderTextSummary(validationErrors.isBreach)
94
+ }, this.renderMedia(), jsx(EventDetails, {
95
+ currentEventData: currentEventData,
96
+ validationErrors: validationErrors,
97
+ answerValue: responseText
98
+ }));
87
99
  } else {
88
100
  return jsx(Text, {
89
101
  size: "small"
90
- }, this.renderTextSummary(), this.renderMedia());
102
+ }, this.renderTextSummary(validationErrors.isBreach), jsx(EventDetails, {
103
+ currentEventData: currentEventData,
104
+ validationErrors: validationErrors
105
+ }), this.renderMedia());
91
106
  }
92
107
  }
93
108
  }, {
@@ -101,6 +116,8 @@ export var ResponseEvent = (_dec = withStyleOverrides(generateStyle, generateCom
101
116
  }(Component), _ResponseEvent.displayName = 'ResponseEvent', _ResponseEvent.componentId = "Quizzes".concat(_ResponseEvent.displayName), _ResponseEvent.propTypes = {
102
117
  event: ImmutablePropTypes.record.isRequired,
103
118
  item: ImmutablePropTypes.record.isRequired,
104
- styles: PropTypes.object
119
+ styles: PropTypes.object,
120
+ validationErrors: sessionValidationErrorsPropType,
121
+ currentEventData: eventDataPropType
105
122
  }, _ResponseEvent)) || _class);
106
123
  export default ResponseEvent;
@@ -3,11 +3,11 @@ import _createClass from "@babel/runtime/helpers/esm/createClass";
3
3
  import _inherits from "@babel/runtime/helpers/esm/inherits";
4
4
  import _createSuper from "@babel/runtime/helpers/esm/createSuper";
5
5
  import React, { Component } from 'react';
6
- import ImmutablePropTypes from 'react-immutable-proptypes';
7
- import platform from 'platform';
6
+ import { EventDetails } from "../resources/EventDetails.js";
8
7
  import { ToggleDetails } from '@instructure/ui-toggle-details';
9
- import { Table } from '@instructure/ui-table';
10
8
  import t from '@instructure/quiz-i18n/es/format-message';
9
+ import { Text } from '@instructure/ui-text';
10
+ import { sessionValidationErrorsPropType, eventDataPropType } from "../../../reporting/components/resources/common/propTypes.js";
11
11
  export var SessionStartEvent = /*#__PURE__*/function (_Component) {
12
12
  _inherits(SessionStartEvent, _Component);
13
13
  var _super = _createSuper(SessionStartEvent);
@@ -18,24 +18,25 @@ export var SessionStartEvent = /*#__PURE__*/function (_Component) {
18
18
  _createClass(SessionStartEvent, [{
19
19
  key: "render",
20
20
  value: function render() {
21
- var event = this.props.event;
22
- var userPlatform = platform.parse(event.getIn(['eventData', 'userAgent']));
21
+ var _this$props = this.props,
22
+ validationErrors = _this$props.validationErrors,
23
+ currentEventData = _this$props.currentEventData;
24
+ var summary = /*#__PURE__*/React.createElement(Text, {
25
+ color: validationErrors.isBreach ? 'danger' : 'primary'
26
+ }, t('Session started'));
23
27
  return /*#__PURE__*/React.createElement(ToggleDetails, {
24
- summary: t('Session started')
25
- }, /*#__PURE__*/React.createElement(Table, {
26
- caption: t('System details')
27
- }, /*#__PURE__*/React.createElement(Table.Head, null, /*#__PURE__*/React.createElement(Table.Row, null, /*#__PURE__*/React.createElement(Table.ColHeader, {
28
- id: "system-details-attribute"
29
- }, t('attribute')), /*#__PURE__*/React.createElement(Table.ColHeader, {
30
- id: "system-details-value"
31
- }, t('value')))), /*#__PURE__*/React.createElement(Table.Body, null, /*#__PURE__*/React.createElement(Table.Row, null, /*#__PURE__*/React.createElement(Table.Cell, null, t('Browser')), /*#__PURE__*/React.createElement(Table.Cell, null, // eslint-disable-next-line react/jsx-no-literals
32
- "".concat(userPlatform.name, " ").concat(userPlatform.version))), /*#__PURE__*/React.createElement(Table.Row, null, /*#__PURE__*/React.createElement(Table.Cell, null, t('Operating System')), /*#__PURE__*/React.createElement(Table.Cell, null, userPlatform.os.toString())))));
28
+ summary: summary
29
+ }, /*#__PURE__*/React.createElement(EventDetails, {
30
+ currentEventData: currentEventData,
31
+ validationErrors: validationErrors
32
+ }));
33
33
  }
34
34
  }]);
35
35
  SessionStartEvent.displayName = "SessionStartEvent";
36
36
  return SessionStartEvent;
37
37
  }(Component);
38
38
  SessionStartEvent.propTypes = {
39
- event: ImmutablePropTypes.record.isRequired
39
+ validationErrors: sessionValidationErrorsPropType,
40
+ currentEventData: eventDataPropType
40
41
  };
41
42
  export default SessionStartEvent;
@@ -0,0 +1,42 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/esm/createClass";
3
+ import _inherits from "@babel/runtime/helpers/esm/inherits";
4
+ import _createSuper from "@babel/runtime/helpers/esm/createSuper";
5
+ import React, { Component } from 'react';
6
+ import t from '@instructure/quiz-i18n/es/format-message';
7
+ import { EventDetails } from "../resources/EventDetails.js";
8
+ import { ToggleDetails } from '@instructure/ui-toggle-details';
9
+ import { Text } from '@instructure/ui-text';
10
+ import { sessionValidationErrorsPropType, eventDataPropType } from "../../../reporting/components/resources/common/propTypes.js";
11
+ export var SessionSubmitEvent = /*#__PURE__*/function (_Component) {
12
+ _inherits(SessionSubmitEvent, _Component);
13
+ var _super = _createSuper(SessionSubmitEvent);
14
+ function SessionSubmitEvent() {
15
+ _classCallCheck(this, SessionSubmitEvent);
16
+ return _super.apply(this, arguments);
17
+ }
18
+ _createClass(SessionSubmitEvent, [{
19
+ key: "render",
20
+ value: function render() {
21
+ var _this$props = this.props,
22
+ validationErrors = _this$props.validationErrors,
23
+ currentEventData = _this$props.currentEventData;
24
+ var summary = /*#__PURE__*/React.createElement(Text, {
25
+ color: validationErrors.isBreach ? 'danger' : 'primary'
26
+ }, t('Session submitted'));
27
+ return /*#__PURE__*/React.createElement(ToggleDetails, {
28
+ summary: summary
29
+ }, /*#__PURE__*/React.createElement(EventDetails, {
30
+ currentEventData: currentEventData,
31
+ validationErrors: validationErrors
32
+ }));
33
+ }
34
+ }]);
35
+ SessionSubmitEvent.displayName = "SessionSubmitEvent";
36
+ return SessionSubmitEvent;
37
+ }(Component);
38
+ SessionSubmitEvent.propTypes = {
39
+ validationErrors: sessionValidationErrorsPropType,
40
+ currentEventData: eventDataPropType
41
+ };
42
+ export default SessionSubmitEvent;