dce-reactkit 3.4.0-beta.1 → 3.4.0-beta.3

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/dist/esm/index.js CHANGED
@@ -293,7 +293,7 @@ const ModalButtonTypeToLabelAndVariant = {
293
293
  /*------------------------------------------------------------------------*/
294
294
  /* Style */
295
295
  /*------------------------------------------------------------------------*/
296
- const style$9 = `
296
+ const style$8 = `
297
297
  .Modal-backdrop {
298
298
  position: fixed;
299
299
  top: 0;
@@ -467,7 +467,7 @@ const Modal = (props) => {
467
467
  left: 0,
468
468
  right: 0,
469
469
  } },
470
- React__default.createElement("style", null, style$9),
470
+ React__default.createElement("style", null, style$8),
471
471
  React__default.createElement("div", { className: `Modal-backdrop ${backdropAnimationClass}`, style: {
472
472
  zIndex: 5000000003,
473
473
  }, onClick: () => __awaiter$1(void 0, void 0, void 0, function* () {
@@ -563,7 +563,7 @@ const getSendRequest = () => __awaiter$1(void 0, void 0, void 0, function* () {
563
563
  yield initialized;
564
564
  // Error if no send request function
565
565
  if (timedOut) {
566
- showFatalError$1(new ErrorWithCode$1('Could not send a request because the request needed to be sent before dce-reactkit was properly initialized. Perhaps dce-reactkit was not initialized with initClient.', ReactKitErrorCode$3.NoCACCLSendRequestFunction));
566
+ showFatalError(new ErrorWithCode$1('Could not send a request because the request needed to be sent before dce-reactkit was properly initialized. Perhaps dce-reactkit was not initialized with initClient.', ReactKitErrorCode$3.NoCACCLSendRequestFunction));
567
567
  // Return dummy function that never resolves
568
568
  return (() => {
569
569
  return new Promise(() => { });
@@ -602,12 +602,12 @@ const initClient = (opts) => {
602
602
  };
603
603
 
604
604
  // Keep track of whether or not session expiry has already been handled
605
- let sessionAlreadyExpired$1 = false;
605
+ let sessionAlreadyExpired = false;
606
606
  /*------------------------------------------------------------------------*/
607
607
  /* Stub Logic */
608
608
  /*------------------------------------------------------------------------*/
609
609
  // Stored stub responses
610
- const stubResponses$1 = {};
610
+ const stubResponses = {};
611
611
  /**
612
612
  * Add a stub response
613
613
  * @author Gabe Abrams
@@ -625,10 +625,10 @@ const _setStubResponse = (opts) => {
625
625
  const errorMessage = ((_b = opts.errorMessage) !== null && _b !== void 0 ? _b : 'An unknown error has occurred.');
626
626
  const errorCode = ((_c = opts.errorCode) !== null && _c !== void 0 ? _c : ReactKitErrorCode$3.NoCode);
627
627
  // Store to stub responses
628
- if (!stubResponses$1[method]) {
629
- stubResponses$1[method] = {};
628
+ if (!stubResponses[method]) {
629
+ stubResponses[method] = {};
630
630
  }
631
- stubResponses$1[method][path] = ((opts.errorMessage || opts.errorCode)
631
+ stubResponses[method][path] = ((opts.errorMessage || opts.errorCode)
632
632
  ? {
633
633
  success: false,
634
634
  errorMessage,
@@ -651,15 +651,15 @@ const _setStubResponse = (opts) => {
651
651
  * @param [opts.params] - query/body parameters to include
652
652
  * @returns response from server
653
653
  */
654
- const visitServerEndpoint$1 = (opts) => __awaiter$1(void 0, void 0, void 0, function* () {
654
+ const visitServerEndpoint = (opts) => __awaiter$1(void 0, void 0, void 0, function* () {
655
655
  var _a, _b, _c;
656
656
  const method = ((_a = opts.method) !== null && _a !== void 0 ? _a : 'GET');
657
657
  // Handle stubs
658
- const stubResponse = (_b = stubResponses$1[method]) === null || _b === void 0 ? void 0 : _b[opts.path];
658
+ const stubResponse = (_b = stubResponses[method]) === null || _b === void 0 ? void 0 : _b[opts.path];
659
659
  if (stubResponse) {
660
660
  // Remove from list
661
661
  try {
662
- stubResponses$1[method][opts.path] = undefined;
662
+ stubResponses[method][opts.path] = undefined;
663
663
  }
664
664
  catch (err) {
665
665
  // Ignore
@@ -686,13 +686,13 @@ const visitServerEndpoint$1 = (opts) => __awaiter$1(void 0, void 0, void 0, func
686
686
  // Session expired
687
687
  if (response.body.code === ReactKitErrorCode$3.SessionExpired) {
688
688
  // Skip notice if session was already expired
689
- if (sessionAlreadyExpired$1) {
689
+ if (sessionAlreadyExpired) {
690
690
  // Never return (browser is already reloading)
691
691
  yield new Promise(() => {
692
692
  // Promise that never returns
693
693
  });
694
694
  }
695
- sessionAlreadyExpired$1 = true;
695
+ sessionAlreadyExpired = true;
696
696
  // Show session expiration message
697
697
  {
698
698
  // Fallback to alert
@@ -721,7 +721,7 @@ const visitServerEndpoint$1 = (opts) => __awaiter$1(void 0, void 0, void 0, func
721
721
  */
722
722
  const logClientEvent = (opts) => __awaiter$1(void 0, void 0, void 0, function* () {
723
723
  var _a, _b, _c, _d, _e, _f, _g;
724
- return visitServerEndpoint$1({
724
+ return visitServerEndpoint({
725
725
  path: LOG_ROUTE_PATH,
726
726
  method: 'POST',
727
727
  params: {
@@ -771,7 +771,7 @@ let onAlertClosed;
771
771
  * @param title the title text to display at the top of the alert
772
772
  * @param text the text to display in the alert
773
773
  */
774
- const alert$2 = (title, text) => __awaiter$1(void 0, void 0, void 0, function* () {
774
+ const alert$1 = (title, text) => __awaiter$1(void 0, void 0, void 0, function* () {
775
775
  // Fallback if alert not available
776
776
  if (!setAlertInfo) {
777
777
  window.alert(`${title}\n\n${text}`);
@@ -843,7 +843,7 @@ let setFatalErrorTitle;
843
843
  * @param error the error to show
844
844
  * @param [errorTitle] title of the error box
845
845
  */
846
- const showFatalError$1 = (error, errorTitle = 'An Error Occurred') => {
846
+ const showFatalError = (error, errorTitle = 'An Error Occurred') => {
847
847
  var _a, _b;
848
848
  // Determine message and code
849
849
  const message = (typeof error === 'string'
@@ -866,7 +866,7 @@ const showFatalError$1 = (error, errorTitle = 'An Error Occurred') => {
866
866
  });
867
867
  // Handle case where app hasn't loaded
868
868
  if (!setFatalErrorMessage || !setFatalErrorCode) {
869
- alert$2(errorTitle, `${message} (code: ${code}). Please contact support.`);
869
+ alert$1(errorTitle, `${message} (code: ${code}). Please contact support.`);
870
870
  return undefined;
871
871
  }
872
872
  // Use setters
@@ -971,7 +971,7 @@ const AppWrapper = (props) => {
971
971
  /*------------------------------------------------------------------------*/
972
972
  /* Style */
973
973
  /*------------------------------------------------------------------------*/
974
- const style$8 = `
974
+ const style$7 = `
975
975
  /* Container fades in */
976
976
  .LoadingSpinner-container {
977
977
  animation-name: LoadingSpinner-container-fade-in;
@@ -1043,13 +1043,13 @@ const style$8 = `
1043
1043
  /*------------------------------------------------------------------------*/
1044
1044
  /* Component */
1045
1045
  /*------------------------------------------------------------------------*/
1046
- const LoadingSpinner$1 = () => {
1046
+ const LoadingSpinner = () => {
1047
1047
  /*------------------------------------------------------------------------*/
1048
1048
  /* Render */
1049
1049
  /*------------------------------------------------------------------------*/
1050
1050
  // Add all four blips to a container
1051
1051
  return (React__default.createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
1052
- React__default.createElement("style", null, style$8),
1052
+ React__default.createElement("style", null, style$7),
1053
1053
  React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-1 me-1" }),
1054
1054
  React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-2 me-1" }),
1055
1055
  React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-3 me-1" }),
@@ -1063,7 +1063,7 @@ const LoadingSpinner$1 = () => {
1063
1063
  /*------------------------------------------------------------------------*/
1064
1064
  /* Style */
1065
1065
  /*------------------------------------------------------------------------*/
1066
- const style$7 = `
1066
+ const style$6 = `
1067
1067
  /* Tab Box */
1068
1068
  .TabBox-box {
1069
1069
  /* Light Border */
@@ -1143,7 +1143,7 @@ const TabBox = (props) => {
1143
1143
  /*----------------------------------------*/
1144
1144
  // Full UI
1145
1145
  return (React__default.createElement("div", { className: `TabBox-container ${noBottomMargin ? '' : 'mb-2'}` },
1146
- React__default.createElement("style", null, style$7),
1146
+ React__default.createElement("style", null, style$6),
1147
1147
  React__default.createElement("div", { className: "TabBox-title-container" },
1148
1148
  React__default.createElement("div", { className: "TabBox-title" }, title)),
1149
1149
  React__default.createElement("div", { className: `TabBox-box ps-2 pt-2 pe-2 ${noBottomPadding ? '' : 'pb-2'}` },
@@ -1157,7 +1157,7 @@ const TabBox = (props) => {
1157
1157
  /*------------------------------------------------------------------------*/
1158
1158
  /* Component */
1159
1159
  /*------------------------------------------------------------------------*/
1160
- const RadioButton$1 = (props) => {
1160
+ const RadioButton = (props) => {
1161
1161
  /*------------------------------------------------------------------------*/
1162
1162
  /* Setup */
1163
1163
  /*------------------------------------------------------------------------*/
@@ -1185,7 +1185,7 @@ const RadioButton$1 = (props) => {
1185
1185
  /*------------------------------------------------------------------------*/
1186
1186
  /* Component */
1187
1187
  /*------------------------------------------------------------------------*/
1188
- const CheckboxButton$1 = (props) => {
1188
+ const CheckboxButton = (props) => {
1189
1189
  /*------------------------------------------------------------------------*/
1190
1190
  /* Setup */
1191
1191
  /*------------------------------------------------------------------------*/
@@ -1222,7 +1222,7 @@ const CheckboxButton$1 = (props) => {
1222
1222
  /*------------------------------------------------------------------------*/
1223
1223
  /* Component */
1224
1224
  /*------------------------------------------------------------------------*/
1225
- const ButtonInputGroup$1 = (props) => {
1225
+ const ButtonInputGroup = (props) => {
1226
1226
  /*------------------------------------------------------------------------*/
1227
1227
  /* Setup */
1228
1228
  /*------------------------------------------------------------------------*/
@@ -1464,7 +1464,7 @@ const SimpleDateChooser = (props) => {
1464
1464
  /*------------------------------------------------------------------------*/
1465
1465
  /* Style */
1466
1466
  /*------------------------------------------------------------------------*/
1467
- const style$6 = `
1467
+ const style$5 = `
1468
1468
  .Drawer-container {
1469
1469
  margin-left: 1rem;
1470
1470
  margin-right: 1rem;
@@ -1498,7 +1498,7 @@ const Drawer = (props) => {
1498
1498
  return (React__default.createElement("div", { className: "Drawer-container", style: {
1499
1499
  backgroundColor: (customBackgroundColor !== null && customBackgroundColor !== void 0 ? customBackgroundColor : undefined),
1500
1500
  } },
1501
- React__default.createElement("style", null, style$6),
1501
+ React__default.createElement("style", null, style$5),
1502
1502
  children));
1503
1503
  };
1504
1504
 
@@ -1836,13 +1836,13 @@ const PopPendingMark = (props) => {
1836
1836
  */
1837
1837
  /* ------------- Actions ------------ */
1838
1838
  // Types of actions
1839
- var ActionType$7;
1839
+ var ActionType$8;
1840
1840
  (function (ActionType) {
1841
1841
  // Indicate that the text was recently copied
1842
1842
  ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
1843
1843
  // Clear the status
1844
1844
  ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
1845
- })(ActionType$7 || (ActionType$7 = {}));
1845
+ })(ActionType$8 || (ActionType$8 = {}));
1846
1846
  /**
1847
1847
  * Reducer that executes actions
1848
1848
  * @author Gabe Abrams
@@ -1851,12 +1851,12 @@ var ActionType$7;
1851
1851
  */
1852
1852
  const reducer$6 = (state, action) => {
1853
1853
  switch (action.type) {
1854
- case ActionType$7.IndicateRecentlyCopied: {
1854
+ case ActionType$8.IndicateRecentlyCopied: {
1855
1855
  return {
1856
1856
  recentlyCopied: true,
1857
1857
  };
1858
1858
  }
1859
- case ActionType$7.ClearRecentlyCopiedStatus: {
1859
+ case ActionType$8.ClearRecentlyCopiedStatus: {
1860
1860
  return {
1861
1861
  recentlyCopied: false,
1862
1862
  };
@@ -1898,17 +1898,17 @@ const CopiableBox = (props) => {
1898
1898
  yield navigator.clipboard.writeText(text);
1899
1899
  }
1900
1900
  catch (err) {
1901
- return alert$2('Unable to copy', 'Oops! We couldn\'t copy that to the clipboard. Please copy the text manually.');
1901
+ return alert$1('Unable to copy', 'Oops! We couldn\'t copy that to the clipboard. Please copy the text manually.');
1902
1902
  }
1903
1903
  // Show copied notice
1904
1904
  dispatch({
1905
- type: ActionType$7.IndicateRecentlyCopied,
1905
+ type: ActionType$8.IndicateRecentlyCopied,
1906
1906
  });
1907
1907
  // Wait a moment
1908
1908
  yield waitMs(4000);
1909
1909
  // Hide copied notice
1910
1910
  dispatch({
1911
- type: ActionType$7.ClearRecentlyCopiedStatus,
1911
+ type: ActionType$8.ClearRecentlyCopiedStatus,
1912
1912
  });
1913
1913
  });
1914
1914
  /*------------------------------------------------------------------------*/
@@ -1964,11 +1964,11 @@ const CopiableBox = (props) => {
1964
1964
  */
1965
1965
  /* ------------- Actions ------------ */
1966
1966
  // Types of actions
1967
- var ActionType$6;
1967
+ var ActionType$7;
1968
1968
  (function (ActionType) {
1969
1969
  // Toggle whether a child are being shown
1970
1970
  ActionType["ToggleChild"] = "toggle-child";
1971
- })(ActionType$6 || (ActionType$6 = {}));
1971
+ })(ActionType$7 || (ActionType$7 = {}));
1972
1972
  /**
1973
1973
  * Reducer that executes actions
1974
1974
  * @author Gabe Abrams
@@ -1977,7 +1977,7 @@ var ActionType$6;
1977
1977
  */
1978
1978
  const reducer$5 = (state, action) => {
1979
1979
  switch (action.type) {
1980
- case ActionType$6.ToggleChild: {
1980
+ case ActionType$7.ToggleChild: {
1981
1981
  return Object.assign(Object.assign({}, state), { childExpanded: Object.assign(Object.assign({}, state.childExpanded), { [String(action.id)]: !state.childExpanded[String(action.id)] }) });
1982
1982
  }
1983
1983
  default: {
@@ -2096,12 +2096,12 @@ const NestableItemList = (props) => {
2096
2096
  backgroundColor: 'transparent',
2097
2097
  }, type: "button", onClick: () => {
2098
2098
  dispatch({
2099
- type: ActionType$6.ToggleChild,
2099
+ type: ActionType$7.ToggleChild,
2100
2100
  id: item.id,
2101
2101
  });
2102
2102
  }, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}` },
2103
2103
  React__default.createElement(FontAwesomeIcon, { icon: childExpanded[item.id] ? faChevronDown : faChevronRight })))),
2104
- React__default.createElement(CheckboxButton$1, { className: `NestableItemList-CheckboxButton-${item.id}`, text: item.name, checked: item.isGroup ? allChecked(item.children) : item.checked, dashed: item.isGroup ? !noneChecked(item.children) : false, onChanged: (checked) => {
2104
+ React__default.createElement(CheckboxButton, { className: `NestableItemList-CheckboxButton-${item.id}`, text: item.name, checked: item.isGroup ? allChecked(item.children) : item.checked, dashed: item.isGroup ? !noneChecked(item.children) : false, onChanged: (checked) => {
2105
2105
  onChanged(changeChecked(item.id, checked, items));
2106
2106
  }, ariaLabel: `Select ${item.name}`, checkedVariant: Variant$3.Light }),
2107
2107
  (item.isGroup && childExpanded[item.id]) && (React__default.createElement("div", { className: "NestableItemList-children-container", style: {
@@ -2371,7 +2371,7 @@ var SortType;
2371
2371
  })(SortType || (SortType = {}));
2372
2372
  /* ------------- Actions ------------ */
2373
2373
  // Types of actions
2374
- var ActionType$5;
2374
+ var ActionType$6;
2375
2375
  (function (ActionType) {
2376
2376
  // Toggle sort column param
2377
2377
  ActionType["ToggleSortColumn"] = "toggle-sort-column";
@@ -2383,7 +2383,7 @@ var ActionType$5;
2383
2383
  ActionType["ShowAllColumns"] = "show-all-columns";
2384
2384
  // Hide all columns
2385
2385
  ActionType["HideAllColumns"] = "hide-all-columns";
2386
- })(ActionType$5 || (ActionType$5 = {}));
2386
+ })(ActionType$6 || (ActionType$6 = {}));
2387
2387
  /**
2388
2388
  * Reducer that executes actions
2389
2389
  * @author Gabe Abrams
@@ -2392,7 +2392,7 @@ var ActionType$5;
2392
2392
  */
2393
2393
  const reducer$4 = (state, action) => {
2394
2394
  switch (action.type) {
2395
- case ActionType$5.ToggleSortColumn: {
2395
+ case ActionType$6.ToggleSortColumn: {
2396
2396
  if (action.param !== state.sortColumnParam) {
2397
2397
  // Different column param
2398
2398
  return Object.assign(Object.assign({}, state), { sortColumnParam: action.param, sortType: SortType.Ascending });
@@ -2404,22 +2404,22 @@ const reducer$4 = (state, action) => {
2404
2404
  // Stop sorting by column
2405
2405
  return Object.assign(Object.assign({}, state), { sortColumnParam: undefined, sortType: SortType.Ascending });
2406
2406
  }
2407
- case ActionType$5.UpdateColumnVisibility: {
2407
+ case ActionType$6.UpdateColumnVisibility: {
2408
2408
  const { columnVisibilityMap } = state;
2409
2409
  columnVisibilityMap[action.param] = action.visible;
2410
2410
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2411
2411
  }
2412
- case ActionType$5.ToggleColVisCusModalVisibility: {
2412
+ case ActionType$6.ToggleColVisCusModalVisibility: {
2413
2413
  return Object.assign(Object.assign({}, state), { columnVisibilityCustomizationModalVisible: !state.columnVisibilityCustomizationModalVisible });
2414
2414
  }
2415
- case ActionType$5.ShowAllColumns: {
2415
+ case ActionType$6.ShowAllColumns: {
2416
2416
  const { columnVisibilityMap } = state;
2417
2417
  Object.keys(columnVisibilityMap).forEach((param) => {
2418
2418
  columnVisibilityMap[param] = true;
2419
2419
  });
2420
2420
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2421
2421
  }
2422
- case ActionType$5.HideAllColumns: {
2422
+ case ActionType$6.HideAllColumns: {
2423
2423
  const { columnVisibilityMap } = state;
2424
2424
  Object.keys(columnVisibilityMap).forEach((param) => {
2425
2425
  columnVisibilityMap[param] = false;
@@ -2486,16 +2486,16 @@ const IntelliTable = (props) => {
2486
2486
  return !isSelected;
2487
2487
  }));
2488
2488
  if (noColumnsSelected) {
2489
- return alert$2('Choose at least one column', 'To continue, you have to choose at least one column to show');
2489
+ return alert$1('Choose at least one column', 'To continue, you have to choose at least one column to show');
2490
2490
  }
2491
2491
  dispatch({
2492
- type: ActionType$5.ToggleColVisCusModalVisibility,
2492
+ type: ActionType$6.ToggleColVisCusModalVisibility,
2493
2493
  });
2494
2494
  }, okayVariant: Variant$3.Light },
2495
2495
  columns.map((column) => {
2496
- return (React__default.createElement(CheckboxButton$1, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, className: "mb-2", text: column.title, onChanged: (checked) => {
2496
+ return (React__default.createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, className: "mb-2", text: column.title, onChanged: (checked) => {
2497
2497
  dispatch({
2498
- type: ActionType$5.UpdateColumnVisibility,
2498
+ type: ActionType$6.UpdateColumnVisibility,
2499
2499
  param: column.param,
2500
2500
  visible: checked,
2501
2501
  });
@@ -2504,12 +2504,12 @@ const IntelliTable = (props) => {
2504
2504
  React__default.createElement("div", { className: "mt-3" }, "Or you can:"),
2505
2505
  React__default.createElement("button", { type: "button", id: `IntelliTable-${id}-select-all-columns`, className: "btn btn-secondary me-2", "aria-label": `show all columns in the ${title} table`, onClick: () => {
2506
2506
  dispatch({
2507
- type: ActionType$5.ShowAllColumns,
2507
+ type: ActionType$6.ShowAllColumns,
2508
2508
  });
2509
2509
  } }, "Select All"),
2510
2510
  React__default.createElement("button", { type: "button", id: `IntelliTable-${id}-select-none-columns`, className: "btn btn-secondary", "aria-label": `hide all columns in the ${title} table`, onClick: () => {
2511
2511
  dispatch({
2512
- type: ActionType$5.HideAllColumns,
2512
+ type: ActionType$6.HideAllColumns,
2513
2513
  });
2514
2514
  } }, "Deselect All")));
2515
2515
  }
@@ -2560,7 +2560,7 @@ const IntelliTable = (props) => {
2560
2560
  React__default.createElement("div", null,
2561
2561
  React__default.createElement("button", { type: "button", id: `IntelliTable-${id}-sort-by-${column.param}-button`, className: `btn btn-${sortingByThisColumn ? 'light' : 'secondary'} btn-sm ms-1 ps-1 pe-1 pt-0 pb-0`, "aria-label": sortButtonAriaLabel, onClick: () => {
2562
2562
  dispatch({
2563
- type: ActionType$5.ToggleSortColumn,
2563
+ type: ActionType$6.ToggleSortColumn,
2564
2564
  param: column.param,
2565
2565
  });
2566
2566
  } },
@@ -2749,7 +2749,7 @@ const IntelliTable = (props) => {
2749
2749
  React__default.createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: filename, csv: csv }),
2750
2750
  React__default.createElement("button", { type: "button", className: "btn btn-secondary ms-2", "aria-label": `show panel for customizing which columns show in table ${title}`, id: `IntelliTable-${id}-show-column-customization-modal`, onClick: () => {
2751
2751
  dispatch({
2752
- type: ActionType$5.ToggleColVisCusModalVisibility,
2752
+ type: ActionType$6.ToggleColVisCusModalVisibility,
2753
2753
  });
2754
2754
  } },
2755
2755
  "Show/Hide Cols",
@@ -3115,7 +3115,7 @@ const genHumanReadableName = (machineReadableName) => {
3115
3115
  };
3116
3116
  /* ------------- Actions ------------ */
3117
3117
  // Types of actions
3118
- var ActionType$4;
3118
+ var ActionType$5;
3119
3119
  (function (ActionType) {
3120
3120
  // Show the loading bar
3121
3121
  ActionType["StartLoading"] = "start-loading";
@@ -3137,7 +3137,7 @@ var ActionType$4;
3137
3137
  ActionType["UpdateActionErrorFilterState"] = "update-action-error-filter-state";
3138
3138
  // Update the advanced filter state
3139
3139
  ActionType["UpdateAdvancedFilterState"] = "update-advanced-filter-state";
3140
- })(ActionType$4 || (ActionType$4 = {}));
3140
+ })(ActionType$5 || (ActionType$5 = {}));
3141
3141
  /**
3142
3142
  * Reducer that executes actions
3143
3143
  * @author Gabe Abrams
@@ -3146,36 +3146,36 @@ var ActionType$4;
3146
3146
  */
3147
3147
  const reducer$3 = (state, action) => {
3148
3148
  switch (action.type) {
3149
- case ActionType$4.StartLoading: {
3149
+ case ActionType$5.StartLoading: {
3150
3150
  return Object.assign(Object.assign({}, state), { loading: true });
3151
3151
  }
3152
- case ActionType$4.FinishLoading: {
3152
+ case ActionType$5.FinishLoading: {
3153
3153
  return Object.assign(Object.assign({}, state), { loading: false, logMap: action.logMap });
3154
3154
  }
3155
- case ActionType$4.ToggleFilterDrawer: {
3155
+ case ActionType$5.ToggleFilterDrawer: {
3156
3156
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: (state.expandedFilterDrawer === action.filterDrawer
3157
3157
  ? undefined // hide
3158
3158
  : action.filterDrawer) });
3159
3159
  }
3160
- case ActionType$4.HideFilterDrawer: {
3160
+ case ActionType$5.HideFilterDrawer: {
3161
3161
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: undefined });
3162
3162
  }
3163
- case ActionType$4.ResetFilters: {
3163
+ case ActionType$5.ResetFilters: {
3164
3164
  return Object.assign(Object.assign({}, state), { dateFilterState: action.initDateFilterState, contextFilterState: action.initContextFilterState, tagFilterState: action.initTagFilterState, actionErrorFilterState: action.initActionErrorFilterState, advancedFilterState: action.initAdvancedFilterState });
3165
3165
  }
3166
- case ActionType$4.UpdateDateFilterState: {
3166
+ case ActionType$5.UpdateDateFilterState: {
3167
3167
  return Object.assign(Object.assign({}, state), { dateFilterState: action.dateFilterState });
3168
3168
  }
3169
- case ActionType$4.UpdateContextFilterState: {
3169
+ case ActionType$5.UpdateContextFilterState: {
3170
3170
  return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
3171
3171
  }
3172
- case ActionType$4.UpdateTagFilterState: {
3172
+ case ActionType$5.UpdateTagFilterState: {
3173
3173
  return Object.assign(Object.assign({}, state), { tagFilterState: action.tagFilterState });
3174
3174
  }
3175
- case ActionType$4.UpdateActionErrorFilterState: {
3175
+ case ActionType$5.UpdateActionErrorFilterState: {
3176
3176
  return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
3177
3177
  }
3178
- case ActionType$4.UpdateAdvancedFilterState: {
3178
+ case ActionType$5.UpdateAdvancedFilterState: {
3179
3179
  return Object.assign(Object.assign({}, state), { advancedFilterState: action.advancedFilterState });
3180
3180
  }
3181
3181
  default: {
@@ -3355,7 +3355,7 @@ const LogReviewer = (props) => {
3355
3355
  const handleDateRangeUpdated = (newDateFilterState) => __awaiter$1(void 0, void 0, void 0, function* () {
3356
3356
  // Update state
3357
3357
  dispatch({
3358
- type: ActionType$4.UpdateDateFilterState,
3358
+ type: ActionType$5.UpdateDateFilterState,
3359
3359
  dateFilterState: newDateFilterState,
3360
3360
  });
3361
3361
  // Check which year/month combos we need to load
@@ -3366,7 +3366,7 @@ const LogReviewer = (props) => {
3366
3366
  }
3367
3367
  // Start loading
3368
3368
  dispatch({
3369
- type: ActionType$4.StartLoading,
3369
+ type: ActionType$5.StartLoading,
3370
3370
  });
3371
3371
  // Load required months
3372
3372
  try {
@@ -3374,7 +3374,7 @@ const LogReviewer = (props) => {
3374
3374
  // Destructure
3375
3375
  const { year, month } = toLoad[i];
3376
3376
  // Load
3377
- const logs = yield visitServerEndpoint$1({
3377
+ const logs = yield visitServerEndpoint({
3378
3378
  path: `${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/${year}/months/${month}`,
3379
3379
  method: 'GET',
3380
3380
  });
@@ -3386,11 +3386,11 @@ const LogReviewer = (props) => {
3386
3386
  }
3387
3387
  }
3388
3388
  catch (err) {
3389
- return showFatalError$1(err);
3389
+ return showFatalError(err);
3390
3390
  }
3391
3391
  // Finish loading
3392
3392
  dispatch({
3393
- type: ActionType$4.FinishLoading,
3393
+ type: ActionType$5.FinishLoading,
3394
3394
  logMap,
3395
3395
  });
3396
3396
  });
@@ -3416,7 +3416,7 @@ const LogReviewer = (props) => {
3416
3416
  /* ------------- Loading ------------ */
3417
3417
  if (loading) {
3418
3418
  body = (React__default.createElement("div", { className: "text-center p-5" },
3419
- React__default.createElement(LoadingSpinner$1, null)));
3419
+ React__default.createElement(LoadingSpinner, null)));
3420
3420
  }
3421
3421
  /* ------------ Review UI ----------- */
3422
3422
  if (!loading) {
@@ -3429,7 +3429,7 @@ const LogReviewer = (props) => {
3429
3429
  React__default.createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
3430
3430
  React__default.createElement("button", { type: "button", id: "LogReviewer-toggle-date-filter-drawer", className: `btn btn-${FilterDrawer.Date === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle date filter drawer", onClick: () => {
3431
3431
  dispatch({
3432
- type: ActionType$4.ToggleFilterDrawer,
3432
+ type: ActionType$5.ToggleFilterDrawer,
3433
3433
  filterDrawer: FilterDrawer.Date,
3434
3434
  });
3435
3435
  } },
@@ -3437,7 +3437,7 @@ const LogReviewer = (props) => {
3437
3437
  "Date"),
3438
3438
  React__default.createElement("button", { type: "button", id: "LogReviewer-toggle-context-filter-drawer", className: `btn btn-${FilterDrawer.Context === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle context filter drawer", onClick: () => {
3439
3439
  dispatch({
3440
- type: ActionType$4.ToggleFilterDrawer,
3440
+ type: ActionType$5.ToggleFilterDrawer,
3441
3441
  filterDrawer: FilterDrawer.Context,
3442
3442
  });
3443
3443
  } },
@@ -3445,7 +3445,7 @@ const LogReviewer = (props) => {
3445
3445
  "Context"),
3446
3446
  (LogMetadata.Tag && Object.keys(LogMetadata.Tag).length > 0) && (React__default.createElement("button", { type: "button", id: "LogReviewer-toggle-tag-filter-drawer", className: `btn btn-${FilterDrawer.Tag === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle tag filter drawer", onClick: () => {
3447
3447
  dispatch({
3448
- type: ActionType$4.ToggleFilterDrawer,
3448
+ type: ActionType$5.ToggleFilterDrawer,
3449
3449
  filterDrawer: FilterDrawer.Tag,
3450
3450
  });
3451
3451
  } },
@@ -3453,7 +3453,7 @@ const LogReviewer = (props) => {
3453
3453
  "Tag")),
3454
3454
  React__default.createElement("button", { type: "button", id: "LogReviewer-toggle-action-filter-drawer", className: `btn btn-${FilterDrawer.Action === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle action and error filter drawer", onClick: () => {
3455
3455
  dispatch({
3456
- type: ActionType$4.ToggleFilterDrawer,
3456
+ type: ActionType$5.ToggleFilterDrawer,
3457
3457
  filterDrawer: FilterDrawer.Action,
3458
3458
  });
3459
3459
  } },
@@ -3461,7 +3461,7 @@ const LogReviewer = (props) => {
3461
3461
  "Action"),
3462
3462
  React__default.createElement("button", { type: "button", id: "LogReviewer-toggle-advanced-filter-drawer", className: `btn btn-${FilterDrawer.Advanced === expandedFilterDrawer ? 'warning' : 'light'} me-2`, "aria-label": "toggle advanced filter drawer", onClick: () => {
3463
3463
  dispatch({
3464
- type: ActionType$4.ToggleFilterDrawer,
3464
+ type: ActionType$5.ToggleFilterDrawer,
3465
3465
  filterDrawer: FilterDrawer.Advanced,
3466
3466
  });
3467
3467
  } },
@@ -3469,7 +3469,7 @@ const LogReviewer = (props) => {
3469
3469
  "Advanced"),
3470
3470
  React__default.createElement("button", { type: "button", id: "LogReviewer-reset-filters-button", className: "btn btn-light", "aria-label": "reset filters", onClick: () => {
3471
3471
  dispatch({
3472
- type: ActionType$4.ResetFilters,
3472
+ type: ActionType$5.ResetFilters,
3473
3473
  initActionErrorFilterState,
3474
3474
  initAdvancedFilterState,
3475
3475
  initContextFilterState,
@@ -3499,7 +3499,7 @@ const LogReviewer = (props) => {
3499
3499
  || (year === dateFilterState.startDate.year
3500
3500
  && month === dateFilterState.startDate.month
3501
3501
  && day < dateFilterState.startDate.day)) {
3502
- return alert$2('Invalid Start Date', 'The start date cannot be before the end date.');
3502
+ return alert$1('Invalid Start Date', 'The start date cannot be before the end date.');
3503
3503
  }
3504
3504
  dateFilterState.endDate = { month, day, year };
3505
3505
  handleDateRangeUpdated(dateFilterState);
@@ -3591,7 +3591,7 @@ const LogReviewer = (props) => {
3591
3591
  }
3592
3592
  });
3593
3593
  dispatch({
3594
- type: ActionType$4.UpdateContextFilterState,
3594
+ type: ActionType$5.UpdateContextFilterState,
3595
3595
  contextFilterState,
3596
3596
  });
3597
3597
  } }));
@@ -3603,10 +3603,10 @@ const LogReviewer = (props) => {
3603
3603
  React__default.createElement("div", { className: "d-flex gap-1 flex-wrap" }, Object.keys((_d = LogMetadata.Tag) !== null && _d !== void 0 ? _d : {})
3604
3604
  .map((tag) => {
3605
3605
  const description = genHumanReadableName(tag);
3606
- return (React__default.createElement(CheckboxButton$1, { key: tag, id: `LogReviewer-tag-${tag}-checkbox`, text: description, ariaLabel: `require that logs be tagged with "${description}" or any other selected tag`, checked: tagFilterState[tag], onChanged: (checked) => {
3606
+ return (React__default.createElement(CheckboxButton, { key: tag, id: `LogReviewer-tag-${tag}-checkbox`, text: description, ariaLabel: `require that logs be tagged with "${description}" or any other selected tag`, checked: tagFilterState[tag], onChanged: (checked) => {
3607
3607
  tagFilterState[tag] = checked;
3608
3608
  dispatch({
3609
- type: ActionType$4.UpdateTagFilterState,
3609
+ type: ActionType$5.UpdateTagFilterState,
3610
3610
  tagFilterState,
3611
3611
  });
3612
3612
  } }));
@@ -3616,47 +3616,47 @@ const LogReviewer = (props) => {
3616
3616
  // Create filter UI
3617
3617
  filterDrawer = (React__default.createElement(React__default.Fragment, null,
3618
3618
  React__default.createElement(TabBox, { title: "Log Type" },
3619
- React__default.createElement(RadioButton$1, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
3619
+ React__default.createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
3620
3620
  actionErrorFilterState.type = undefined;
3621
3621
  dispatch({
3622
- type: ActionType$4.UpdateActionErrorFilterState,
3622
+ type: ActionType$5.UpdateActionErrorFilterState,
3623
3623
  actionErrorFilterState,
3624
3624
  });
3625
3625
  }, ariaLabel: "show logs of all types", selected: actionErrorFilterState.type === undefined }),
3626
- React__default.createElement(RadioButton$1, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
3626
+ React__default.createElement(RadioButton, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
3627
3627
  actionErrorFilterState.type = LogType$1.Action;
3628
3628
  dispatch({
3629
- type: ActionType$4.UpdateActionErrorFilterState,
3629
+ type: ActionType$5.UpdateActionErrorFilterState,
3630
3630
  actionErrorFilterState,
3631
3631
  });
3632
3632
  }, ariaLabel: "only show action logs", selected: actionErrorFilterState.type === LogType$1.Action }),
3633
- React__default.createElement(RadioButton$1, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
3633
+ React__default.createElement(RadioButton, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
3634
3634
  actionErrorFilterState.type = LogType$1.Error;
3635
3635
  dispatch({
3636
- type: ActionType$4.UpdateActionErrorFilterState,
3636
+ type: ActionType$5.UpdateActionErrorFilterState,
3637
3637
  actionErrorFilterState,
3638
3638
  });
3639
3639
  }, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
3640
3640
  (actionErrorFilterState.type === undefined
3641
3641
  || actionErrorFilterState.type === LogType$1.Action) && (React__default.createElement(TabBox, { title: "Action Log Details" },
3642
- React__default.createElement(ButtonInputGroup$1, { label: "Action", className: "mb-2", wrapButtonsAndAddGaps: true }, Object.keys(LogAction$1)
3642
+ React__default.createElement(ButtonInputGroup, { label: "Action", className: "mb-2", wrapButtonsAndAddGaps: true }, Object.keys(LogAction$1)
3643
3643
  .map((action) => {
3644
3644
  const description = genHumanReadableName(action);
3645
- return (React__default.createElement(CheckboxButton$1, { key: action, id: `LogReviewer-action-${action}-checkbox`, text: description, ariaLabel: `include logs with action type "${description}" in results`, noMarginOnRight: true, checked: actionErrorFilterState.action[action], onChanged: (checked) => {
3645
+ return (React__default.createElement(CheckboxButton, { key: action, id: `LogReviewer-action-${action}-checkbox`, text: description, ariaLabel: `include logs with action type "${description}" in results`, noMarginOnRight: true, checked: actionErrorFilterState.action[action], onChanged: (checked) => {
3646
3646
  actionErrorFilterState.action[action] = checked;
3647
3647
  dispatch({
3648
- type: ActionType$4.UpdateActionErrorFilterState,
3648
+ type: ActionType$5.UpdateActionErrorFilterState,
3649
3649
  actionErrorFilterState,
3650
3650
  });
3651
3651
  } }));
3652
3652
  })),
3653
- React__default.createElement(ButtonInputGroup$1, { label: "Target", wrapButtonsAndAddGaps: true }, Object.keys(targetMap)
3653
+ React__default.createElement(ButtonInputGroup, { label: "Target", wrapButtonsAndAddGaps: true }, Object.keys(targetMap)
3654
3654
  .map((target) => {
3655
3655
  const description = genHumanReadableName(target);
3656
- return (React__default.createElement(CheckboxButton$1, { key: target, id: `LogReviewer-target-${target}-checkbox`, text: description, ariaLabel: `include logs with target "${description}" in results`, checked: actionErrorFilterState.target[target], noMarginOnRight: true, onChanged: (checked) => {
3656
+ return (React__default.createElement(CheckboxButton, { key: target, id: `LogReviewer-target-${target}-checkbox`, text: description, ariaLabel: `include logs with target "${description}" in results`, checked: actionErrorFilterState.target[target], noMarginOnRight: true, onChanged: (checked) => {
3657
3657
  actionErrorFilterState.target[target] = checked;
3658
3658
  dispatch({
3659
- type: ActionType$4.UpdateActionErrorFilterState,
3659
+ type: ActionType$5.UpdateActionErrorFilterState,
3660
3660
  actionErrorFilterState,
3661
3661
  });
3662
3662
  } }));
@@ -3668,7 +3668,7 @@ const LogReviewer = (props) => {
3668
3668
  React__default.createElement("input", { type: "text", className: "form-control", "aria-label": "query for error message", value: actionErrorFilterState.errorMessage, placeholder: "e.g. undefined is not a function", onChange: (e) => {
3669
3669
  actionErrorFilterState.errorMessage = e.target.value;
3670
3670
  dispatch({
3671
- type: ActionType$4.UpdateActionErrorFilterState,
3671
+ type: ActionType$5.UpdateActionErrorFilterState,
3672
3672
  actionErrorFilterState,
3673
3673
  });
3674
3674
  } })),
@@ -3679,7 +3679,7 @@ const LogReviewer = (props) => {
3679
3679
  .trim()
3680
3680
  .toUpperCase());
3681
3681
  dispatch({
3682
- type: ActionType$4.UpdateActionErrorFilterState,
3682
+ type: ActionType$5.UpdateActionErrorFilterState,
3683
3683
  actionErrorFilterState,
3684
3684
  });
3685
3685
  } }))))));
@@ -3693,7 +3693,7 @@ const LogReviewer = (props) => {
3693
3693
  React__default.createElement("input", { type: "text", className: "form-control", "aria-label": "query for user first name", value: advancedFilterState.userFirstName, placeholder: "e.g. Divardo", onChange: (e) => {
3694
3694
  advancedFilterState.userFirstName = e.target.value;
3695
3695
  dispatch({
3696
- type: ActionType$4.UpdateAdvancedFilterState,
3696
+ type: ActionType$5.UpdateAdvancedFilterState,
3697
3697
  advancedFilterState,
3698
3698
  });
3699
3699
  } })),
@@ -3702,7 +3702,7 @@ const LogReviewer = (props) => {
3702
3702
  React__default.createElement("input", { type: "text", className: "form-control", "aria-label": "query for user last name", value: advancedFilterState.userLastName, placeholder: "e.g. Calicci", onChange: (e) => {
3703
3703
  advancedFilterState.userLastName = e.target.value;
3704
3704
  dispatch({
3705
- type: ActionType$4.UpdateAdvancedFilterState,
3705
+ type: ActionType$5.UpdateAdvancedFilterState,
3706
3706
  advancedFilterState,
3707
3707
  });
3708
3708
  } })),
@@ -3712,7 +3712,7 @@ const LogReviewer = (props) => {
3712
3712
  advancedFilterState.userEmail = ((e.target.value)
3713
3713
  .trim());
3714
3714
  dispatch({
3715
- type: ActionType$4.UpdateAdvancedFilterState,
3715
+ type: ActionType$5.UpdateAdvancedFilterState,
3716
3716
  advancedFilterState,
3717
3717
  });
3718
3718
  } })),
@@ -3726,29 +3726,29 @@ const LogReviewer = (props) => {
3726
3726
  .trim());
3727
3727
  }
3728
3728
  dispatch({
3729
- type: ActionType$4.UpdateAdvancedFilterState,
3729
+ type: ActionType$5.UpdateAdvancedFilterState,
3730
3730
  advancedFilterState,
3731
3731
  });
3732
3732
  } })),
3733
- React__default.createElement(ButtonInputGroup$1, { label: "Role" },
3734
- React__default.createElement(CheckboxButton$1, { text: "Students", onChanged: (checked) => {
3733
+ React__default.createElement(ButtonInputGroup, { label: "Role" },
3734
+ React__default.createElement(CheckboxButton, { text: "Students", onChanged: (checked) => {
3735
3735
  advancedFilterState.includeLearners = checked;
3736
3736
  dispatch({
3737
- type: ActionType$4.UpdateAdvancedFilterState,
3737
+ type: ActionType$5.UpdateAdvancedFilterState,
3738
3738
  advancedFilterState,
3739
3739
  });
3740
3740
  }, checked: advancedFilterState.includeLearners, ariaLabel: "show logs from students" }),
3741
- React__default.createElement(CheckboxButton$1, { text: "Teaching Team Members", onChanged: (checked) => {
3741
+ React__default.createElement(CheckboxButton, { text: "Teaching Team Members", onChanged: (checked) => {
3742
3742
  advancedFilterState.includeTTMs = checked;
3743
3743
  dispatch({
3744
- type: ActionType$4.UpdateAdvancedFilterState,
3744
+ type: ActionType$5.UpdateAdvancedFilterState,
3745
3745
  advancedFilterState,
3746
3746
  });
3747
3747
  }, checked: advancedFilterState.includeTTMs, ariaLabel: "show logs from teaching team members" }),
3748
- React__default.createElement(CheckboxButton$1, { text: "Admins", onChanged: (checked) => {
3748
+ React__default.createElement(CheckboxButton, { text: "Admins", onChanged: (checked) => {
3749
3749
  advancedFilterState.includeAdmins = checked;
3750
3750
  dispatch({
3751
- type: ActionType$4.UpdateAdvancedFilterState,
3751
+ type: ActionType$5.UpdateAdvancedFilterState,
3752
3752
  advancedFilterState,
3753
3753
  });
3754
3754
  }, checked: advancedFilterState.includeAdmins, ariaLabel: "show logs from admins" }))),
@@ -3758,7 +3758,7 @@ const LogReviewer = (props) => {
3758
3758
  React__default.createElement("input", { type: "text", className: "form-control", "aria-label": "query for course name", value: advancedFilterState.courseName, placeholder: "e.g. GLC 200", onChange: (e) => {
3759
3759
  advancedFilterState.courseName = e.target.value;
3760
3760
  dispatch({
3761
- type: ActionType$4.UpdateAdvancedFilterState,
3761
+ type: ActionType$5.UpdateAdvancedFilterState,
3762
3762
  advancedFilterState,
3763
3763
  });
3764
3764
  } })),
@@ -3772,53 +3772,53 @@ const LogReviewer = (props) => {
3772
3772
  .trim());
3773
3773
  }
3774
3774
  dispatch({
3775
- type: ActionType$4.UpdateAdvancedFilterState,
3775
+ type: ActionType$5.UpdateAdvancedFilterState,
3776
3776
  advancedFilterState,
3777
3777
  });
3778
3778
  } }))),
3779
3779
  React__default.createElement(TabBox, { title: "Device" },
3780
- React__default.createElement(ButtonInputGroup$1, { label: "Device Type" },
3781
- React__default.createElement(RadioButton$1, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
3780
+ React__default.createElement(ButtonInputGroup, { label: "Device Type" },
3781
+ React__default.createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
3782
3782
  advancedFilterState.isMobile = undefined;
3783
3783
  dispatch({
3784
- type: ActionType$4.UpdateAdvancedFilterState,
3784
+ type: ActionType$5.UpdateAdvancedFilterState,
3785
3785
  advancedFilterState,
3786
3786
  });
3787
3787
  } }),
3788
- React__default.createElement(RadioButton$1, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
3788
+ React__default.createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
3789
3789
  advancedFilterState.isMobile = true;
3790
3790
  dispatch({
3791
- type: ActionType$4.UpdateAdvancedFilterState,
3791
+ type: ActionType$5.UpdateAdvancedFilterState,
3792
3792
  advancedFilterState,
3793
3793
  });
3794
3794
  } }),
3795
- React__default.createElement(RadioButton$1, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
3795
+ React__default.createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
3796
3796
  advancedFilterState.isMobile = false;
3797
3797
  dispatch({
3798
- type: ActionType$4.UpdateAdvancedFilterState,
3798
+ type: ActionType$5.UpdateAdvancedFilterState,
3799
3799
  advancedFilterState,
3800
3800
  });
3801
3801
  }, noMarginOnRight: true }))),
3802
3802
  React__default.createElement(TabBox, { title: "Source" },
3803
- React__default.createElement(ButtonInputGroup$1, { label: "Source Type" },
3804
- React__default.createElement(RadioButton$1, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
3803
+ React__default.createElement(ButtonInputGroup, { label: "Source Type" },
3804
+ React__default.createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
3805
3805
  advancedFilterState.source = undefined;
3806
3806
  dispatch({
3807
- type: ActionType$4.UpdateAdvancedFilterState,
3807
+ type: ActionType$5.UpdateAdvancedFilterState,
3808
3808
  advancedFilterState,
3809
3809
  });
3810
3810
  } }),
3811
- React__default.createElement(RadioButton$1, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
3811
+ React__default.createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
3812
3812
  advancedFilterState.source = LogSource$1.Client;
3813
3813
  dispatch({
3814
- type: ActionType$4.UpdateAdvancedFilterState,
3814
+ type: ActionType$5.UpdateAdvancedFilterState,
3815
3815
  advancedFilterState,
3816
3816
  });
3817
3817
  } }),
3818
- React__default.createElement(RadioButton$1, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
3818
+ React__default.createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
3819
3819
  advancedFilterState.source = LogSource$1.Server;
3820
3820
  dispatch({
3821
- type: ActionType$4.UpdateAdvancedFilterState,
3821
+ type: ActionType$5.UpdateAdvancedFilterState,
3822
3822
  advancedFilterState,
3823
3823
  });
3824
3824
  }, noMarginOnRight: true })),
@@ -3829,7 +3829,7 @@ const LogReviewer = (props) => {
3829
3829
  advancedFilterState.courseName = ((e.target.value)
3830
3830
  .trim());
3831
3831
  dispatch({
3832
- type: ActionType$4.UpdateAdvancedFilterState,
3832
+ type: ActionType$5.UpdateAdvancedFilterState,
3833
3833
  advancedFilterState,
3834
3834
  });
3835
3835
  } })),
@@ -3839,7 +3839,7 @@ const LogReviewer = (props) => {
3839
3839
  advancedFilterState.courseName = ((e.target.value)
3840
3840
  .trim());
3841
3841
  dispatch({
3842
- type: ActionType$4.UpdateAdvancedFilterState,
3842
+ type: ActionType$5.UpdateAdvancedFilterState,
3843
3843
  advancedFilterState,
3844
3844
  });
3845
3845
  } })))))));
@@ -4129,1427 +4129,464 @@ const LogReviewer = (props) => {
4129
4129
  React__default.createElement("div", { className: "LogReviewer-contents" }, body))));
4130
4130
  };
4131
4131
 
4132
- /******************************************************************************
4133
- Copyright (c) Microsoft Corporation.
4134
-
4135
- Permission to use, copy, modify, and/or distribute this software for any
4136
- purpose with or without fee is hereby granted.
4137
-
4138
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
4139
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
4140
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
4141
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
4142
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
4143
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
4144
- PERFORMANCE OF THIS SOFTWARE.
4145
- ***************************************************************************** */
4146
-
4147
- function __awaiter(thisArg, _arguments, P, generator) {
4148
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4149
- return new (P || (P = Promise))(function (resolve, reject) {
4150
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
4151
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
4152
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
4153
- step((generator = generator.apply(thisArg, _arguments || [])).next());
4154
- });
4155
- }
4156
-
4157
- // Highest error code = DRK10
4158
4132
  /**
4159
- * List of error codes built into the react kit
4160
- * @author Gabe Abrams
4133
+ * Options for field types
4134
+ * @author Yuen Ler Chow
4161
4135
  */
4162
- var ReactKitErrorCode;
4163
- (function (ReactKitErrorCode) {
4164
- ReactKitErrorCode["NoResponse"] = "DRK1";
4165
- ReactKitErrorCode["NoCode"] = "DRK2";
4166
- ReactKitErrorCode["SessionExpired"] = "DRK3";
4167
- ReactKitErrorCode["MissingParameter"] = "DRK4";
4168
- ReactKitErrorCode["InvalidParameter"] = "DRK5";
4169
- ReactKitErrorCode["WrongCourse"] = "DRK6";
4170
- ReactKitErrorCode["NoCACCLSendRequestFunction"] = "DRK7";
4171
- ReactKitErrorCode["NoCACCLGetLaunchInfoFunction"] = "DRK8";
4172
- ReactKitErrorCode["NotTTM"] = "DRK9";
4173
- ReactKitErrorCode["NotAdmin"] = "DRK10";
4174
- })(ReactKitErrorCode || (ReactKitErrorCode = {}));
4175
- var ReactKitErrorCode$1 = ReactKitErrorCode;
4136
+ var DBEntryFieldType;
4137
+ (function (DBEntryFieldType) {
4138
+ // A string input field
4139
+ DBEntryFieldType["String"] = "String";
4140
+ // A number input field
4141
+ DBEntryFieldType["Number"] = "Number";
4142
+ // input field with subfields that are also DBEntryFields
4143
+ DBEntryFieldType["Object"] = "Object";
4144
+ // list of strings input field
4145
+ DBEntryFieldType["StringArray"] = "StringArray";
4146
+ // list of numbers input field
4147
+ DBEntryFieldType["NumberArray"] = "NumberArray";
4148
+ })(DBEntryFieldType || (DBEntryFieldType = {}));
4149
+ var DBEntryFieldType$1 = DBEntryFieldType;
4176
4150
 
4177
- /**
4178
- * Types of buttons in the modal
4179
- * @author Gabe Abrams
4180
- */
4181
- var ModalButtonType;
4182
- (function (ModalButtonType) {
4183
- ModalButtonType["Okay"] = "okay";
4184
- ModalButtonType["Cancel"] = "cancel";
4185
- ModalButtonType["Yes"] = "yes";
4186
- ModalButtonType["No"] = "no";
4187
- ModalButtonType["Abandon"] = "abandon";
4188
- ModalButtonType["GoBack"] = "goBack";
4189
- ModalButtonType["Continue"] = "continue";
4190
- ModalButtonType["ImSure"] = "imSure";
4191
- ModalButtonType["Delete"] = "delete";
4192
- ModalButtonType["Confirm"] = "confirm";
4193
- })(ModalButtonType || (ModalButtonType = {}));
4194
- var ModalButtonType$1 = ModalButtonType;
4151
+ function _extends() {
4152
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
4153
+ for (var i = 1; i < arguments.length; i++) {
4154
+ var source = arguments[i];
4155
+ for (var key in source) {
4156
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
4157
+ target[key] = source[key];
4158
+ }
4159
+ }
4160
+ }
4161
+ return target;
4162
+ };
4163
+ return _extends.apply(this, arguments);
4164
+ }
4195
4165
 
4196
- /**
4197
- * Types of modals
4198
- * @author Gabe Abrams
4199
- */
4200
- var ModalType;
4201
- (function (ModalType) {
4202
- ModalType["Okay"] = "okay";
4203
- ModalType["OkayCancel"] = "okay-cancel";
4204
- ModalType["YesNo"] = "yes-no";
4205
- ModalType["YesNoCancel"] = "yes-no-cancel";
4206
- ModalType["AbandonGoBack"] = "abandon-goBack";
4207
- ModalType["ImSureCancel"] = "imSure-cancel";
4208
- ModalType["DeleteCancel"] = "delete-cancel";
4209
- ModalType["ConfirmCancel"] = "confirm-cancel";
4210
- ModalType["NoButtons"] = "-";
4211
- })(ModalType || (ModalType = {}));
4212
- var ModalType$1 = ModalType;
4166
+ function _typeof(obj) {
4167
+ "@babel/helpers - typeof";
4213
4168
 
4214
- /**
4215
- * Bootstrap variants
4216
- * @author Gabe Abrams
4217
- */
4218
- var Variant;
4219
- (function (Variant) {
4220
- Variant["Primary"] = "primary";
4221
- Variant["Secondary"] = "secondary";
4222
- Variant["Success"] = "success";
4223
- Variant["Warning"] = "warning";
4224
- Variant["Info"] = "info";
4225
- Variant["Danger"] = "danger";
4226
- Variant["Light"] = "light";
4227
- Variant["Dark"] = "dark";
4228
- })(Variant || (Variant = {}));
4229
- var Variant$1 = Variant;
4169
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
4170
+ return typeof obj;
4171
+ } : function (obj) {
4172
+ return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
4173
+ }, _typeof(obj);
4174
+ }
4230
4175
 
4231
- /**
4232
- * Modal sizes
4233
- * @author Gabe Abrams
4234
- */
4235
- var ModalSize;
4236
- (function (ModalSize) {
4237
- ModalSize["Small"] = "sm";
4238
- ModalSize["Medium"] = "md";
4239
- ModalSize["Large"] = "lg";
4240
- ModalSize["ExtraLarge"] = "xl";
4241
- })(ModalSize || (ModalSize = {}));
4242
- // Modal type to list of buttons
4243
- ({
4244
- [ModalType$1.Okay]: [
4245
- ModalButtonType$1.Okay,
4246
- ],
4247
- [ModalType$1.OkayCancel]: [
4248
- ModalButtonType$1.Okay,
4249
- ModalButtonType$1.Cancel,
4250
- ],
4251
- [ModalType$1.YesNo]: [
4252
- ModalButtonType$1.Yes,
4253
- ModalButtonType$1.No,
4254
- ],
4255
- [ModalType$1.YesNoCancel]: [
4256
- ModalButtonType$1.Yes,
4257
- ModalButtonType$1.No,
4258
- ModalButtonType$1.Cancel,
4259
- ],
4260
- [ModalType$1.AbandonGoBack]: [
4261
- ModalButtonType$1.Abandon,
4262
- ModalButtonType$1.GoBack,
4263
- ],
4264
- [ModalType$1.ImSureCancel]: [
4265
- ModalButtonType$1.ImSure,
4266
- ModalButtonType$1.Cancel,
4267
- ],
4268
- [ModalType$1.DeleteCancel]: [
4269
- ModalButtonType$1.Delete,
4270
- ModalButtonType$1.Cancel,
4271
- ],
4272
- [ModalType$1.ConfirmCancel]: [
4273
- ModalButtonType$1.Confirm,
4274
- ModalButtonType$1.Cancel,
4275
- ],
4276
- });
4277
- // Button type styling and labels
4278
- ({
4279
- [ModalButtonType$1.Okay]: {
4280
- label: 'Okay',
4281
- variant: Variant$1.Dark,
4282
- },
4283
- [ModalButtonType$1.Cancel]: {
4284
- label: 'Cancel',
4285
- variant: Variant$1.Secondary,
4286
- },
4287
- [ModalButtonType$1.Yes]: {
4288
- label: 'Yes',
4289
- variant: Variant$1.Dark,
4290
- },
4291
- [ModalButtonType$1.No]: {
4292
- label: 'No',
4293
- variant: Variant$1.Secondary,
4294
- },
4295
- [ModalButtonType$1.Abandon]: {
4296
- label: 'Abandon Changes',
4297
- variant: Variant$1.Warning,
4298
- },
4299
- [ModalButtonType$1.GoBack]: {
4300
- label: 'Go Back',
4301
- variant: Variant$1.Secondary,
4302
- },
4303
- [ModalButtonType$1.Continue]: {
4304
- label: 'Continue',
4305
- variant: Variant$1.Dark,
4306
- },
4307
- [ModalButtonType$1.ImSure]: {
4308
- label: 'I am sure',
4309
- variant: Variant$1.Warning,
4310
- },
4311
- [ModalButtonType$1.Delete]: {
4312
- label: 'Yes, Delete',
4313
- variant: Variant$1.Danger,
4314
- },
4315
- [ModalButtonType$1.Confirm]: {
4316
- label: 'Confirm',
4317
- variant: Variant$1.Dark,
4318
- },
4319
- });
4176
+ function _toPrimitive(input, hint) {
4177
+ if (_typeof(input) !== "object" || input === null) return input;
4178
+ var prim = input[Symbol.toPrimitive];
4179
+ if (prim !== undefined) {
4180
+ var res = prim.call(input, hint || "default");
4181
+ if (_typeof(res) !== "object") return res;
4182
+ throw new TypeError("@@toPrimitive must return a primitive value.");
4183
+ }
4184
+ return (hint === "string" ? String : Number)(input);
4185
+ }
4320
4186
 
4321
- /**
4322
- * An error with a code
4323
- * @author Gabe Abrams
4324
- */
4325
- class ErrorWithCode extends Error {
4326
- constructor(message, code) {
4327
- super(message);
4328
- this.name = 'ErrorWithCode';
4329
- this.code = code;
4330
- }
4187
+ function _toPropertyKey(arg) {
4188
+ var key = _toPrimitive(arg, "string");
4189
+ return _typeof(key) === "symbol" ? key : String(key);
4331
4190
  }
4332
- /**
4333
- * Send a request using caccl's send request feature
4334
- * @author Gabe Abrams
4335
- * @param opts send request options
4336
- * @returns send request response
4337
- */
4338
- const cacclSendRequest = (opts) => __awaiter(void 0, void 0, void 0, function* () {
4339
- // Make sure send request has been passed in
4340
- {
4341
- throw new ErrorWithCode(`\nThe request could not be sent because the AppWrapper component does not have a copy of sendRequest from CACCL.\nIf you are currently writing tests for your app, this means you did not properly stub the server response.\nMethod: ${opts.method}\nPath: ${opts.path}\n\n`, ReactKitErrorCode$1.NoCACCLSendRequestFunction);
4342
- }
4343
- });
4344
- /**
4345
- * Show an alert modal with an "Okay" button
4346
- * @author Gabe Abrams
4347
- * @param title the title text to display at the top of the alert
4348
- * @param text the text to display in the alert
4349
- */
4350
- const alert$1 = (title, text) => __awaiter(void 0, void 0, void 0, function* () {
4351
- // Fallback if alert not available
4352
- {
4353
- window.alert(`${title}\n\n${text}`);
4354
- return undefined;
4355
- }
4356
- });
4357
- /**
4358
- * Show a fatal error message
4359
- * @author Gabe Abrams
4360
- * @param error the error to show
4361
- * @param [errorTitle] title of the error box
4362
- */
4363
- const showFatalError = (error, errorTitle = 'An Error Occurred') => {
4364
- var _a, _b;
4365
- // Determine message and code
4366
- const message = (typeof error === 'string'
4367
- ? error.trim()
4368
- : String((_a = error.message) !== null && _a !== void 0 ? _a : 'An unknown error occurred.'));
4369
- const code = (typeof error === 'string'
4370
- ? ReactKitErrorCode$1.NoCode
4371
- : String((_b = error.code) !== null && _b !== void 0 ? _b : ReactKitErrorCode$1.NoCode));
4372
- // Handle case where app hasn't loaded
4373
- {
4374
- alert$1(errorTitle, `${message} (code: ${code}). Please contact support.`);
4375
- return undefined;
4376
- }
4377
- };
4378
4191
 
4379
- /**
4380
- * Loading spinner/indicator
4381
- * @author Gabe Abrams
4382
- */
4383
- /*------------------------------------------------------------------------*/
4384
- /* Style */
4385
- /*------------------------------------------------------------------------*/
4386
- const style$5 = `
4387
- /* Container fades in */
4388
- .LoadingSpinner-container {
4389
- animation-name: LoadingSpinner-container-fade-in;
4390
- animation-duration: 0.3s;
4391
- animation-delay: 0.4s;
4392
- animation-fill-mode: both;
4393
- animation-timing-function: ease-out;
4192
+ function _defineProperty(obj, key, value) {
4193
+ key = _toPropertyKey(key);
4194
+ if (key in obj) {
4195
+ Object.defineProperty(obj, key, {
4196
+ value: value,
4197
+ enumerable: true,
4198
+ configurable: true,
4199
+ writable: true
4200
+ });
4201
+ } else {
4202
+ obj[key] = value;
4203
+ }
4204
+ return obj;
4394
4205
  }
4395
- @keyframes LoadingSpinner-container-fade-in {
4396
- 0% {
4397
- opacity: 0;
4206
+
4207
+ function ownKeys(object, enumerableOnly) {
4208
+ var keys = Object.keys(object);
4209
+ if (Object.getOwnPropertySymbols) {
4210
+ var symbols = Object.getOwnPropertySymbols(object);
4211
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
4212
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
4213
+ })), keys.push.apply(keys, symbols);
4398
4214
  }
4399
- 100% {
4400
- opacity: 1;
4215
+ return keys;
4216
+ }
4217
+ function _objectSpread2(target) {
4218
+ for (var i = 1; i < arguments.length; i++) {
4219
+ var source = null != arguments[i] ? arguments[i] : {};
4220
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
4221
+ _defineProperty(target, key, source[key]);
4222
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
4223
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
4224
+ });
4401
4225
  }
4226
+ return target;
4402
4227
  }
4403
4228
 
4404
- /* Blips */
4405
- .LoadingSpinner-blip-1,
4406
- .LoadingSpinner-blip-2,
4407
- .LoadingSpinner-blip-3,
4408
- .LoadingSpinner-blip-4 {
4409
- font-size: 1.8rem;
4410
- opacity: 0.6;
4411
- margin-top: 1rem;
4412
- margin-bottom: 1rem;
4229
+ function _classCallCheck(instance, Constructor) {
4230
+ if (!(instance instanceof Constructor)) {
4231
+ throw new TypeError("Cannot call a class as a function");
4232
+ }
4413
4233
  }
4414
4234
 
4415
- /* First Blip */
4416
- .LoadingSpinner-blip-1 {
4417
- animation: LoadingSpinner-pop-animation 2s infinite;
4235
+ function _defineProperties(target, props) {
4236
+ for (var i = 0; i < props.length; i++) {
4237
+ var descriptor = props[i];
4238
+ descriptor.enumerable = descriptor.enumerable || false;
4239
+ descriptor.configurable = true;
4240
+ if ("value" in descriptor) descriptor.writable = true;
4241
+ Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
4242
+ }
4243
+ }
4244
+ function _createClass(Constructor, protoProps, staticProps) {
4245
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
4246
+ if (staticProps) _defineProperties(Constructor, staticProps);
4247
+ Object.defineProperty(Constructor, "prototype", {
4248
+ writable: false
4249
+ });
4250
+ return Constructor;
4418
4251
  }
4419
4252
 
4420
- /* Second Blip */
4421
- .LoadingSpinner-blip-2 {
4422
- animation: LoadingSpinner-pop-animation 2s infinite;
4423
- -webkit-animation-delay: 0.1s;
4424
- animation-delay: 0.1s;
4253
+ function _setPrototypeOf(o, p) {
4254
+ _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
4255
+ o.__proto__ = p;
4256
+ return o;
4257
+ };
4258
+ return _setPrototypeOf(o, p);
4425
4259
  }
4426
4260
 
4427
- /* Third Blip */
4428
- .LoadingSpinner-blip-3 {
4429
- animation: LoadingSpinner-pop-animation 2s infinite;
4430
- animation-delay: 0.2s;
4261
+ function _inherits(subClass, superClass) {
4262
+ if (typeof superClass !== "function" && superClass !== null) {
4263
+ throw new TypeError("Super expression must either be null or a function");
4264
+ }
4265
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
4266
+ constructor: {
4267
+ value: subClass,
4268
+ writable: true,
4269
+ configurable: true
4270
+ }
4271
+ });
4272
+ Object.defineProperty(subClass, "prototype", {
4273
+ writable: false
4274
+ });
4275
+ if (superClass) _setPrototypeOf(subClass, superClass);
4431
4276
  }
4432
4277
 
4433
- /* Fourth Blip */
4434
- .LoadingSpinner-blip-4 {
4435
- animation: LoadingSpinner-pop-animation 2s infinite;
4436
- animation-delay: 0.3s;
4278
+ function _getPrototypeOf(o) {
4279
+ _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
4280
+ return o.__proto__ || Object.getPrototypeOf(o);
4281
+ };
4282
+ return _getPrototypeOf(o);
4437
4283
  }
4438
4284
 
4439
- /* Pop Animation for Each Blip */
4440
- @keyframes LoadingSpinner-pop-animation {
4441
- 0% {
4442
- transform: scale(1.0);
4443
- }
4444
- 10% {
4445
- transform: scale(1.5);
4285
+ function _isNativeReflectConstruct() {
4286
+ if (typeof Reflect === "undefined" || !Reflect.construct) return false;
4287
+ if (Reflect.construct.sham) return false;
4288
+ if (typeof Proxy === "function") return true;
4289
+ try {
4290
+ Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
4291
+ return true;
4292
+ } catch (e) {
4293
+ return false;
4446
4294
  }
4447
- 30% {
4448
- transform: scale(1.0);
4295
+ }
4296
+
4297
+ function _assertThisInitialized(self) {
4298
+ if (self === void 0) {
4299
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
4449
4300
  }
4450
- 100% {
4451
- transform: scale(1.0);
4301
+ return self;
4302
+ }
4303
+
4304
+ function _possibleConstructorReturn(self, call) {
4305
+ if (call && (_typeof(call) === "object" || typeof call === "function")) {
4306
+ return call;
4307
+ } else if (call !== void 0) {
4308
+ throw new TypeError("Derived constructors may only return object or undefined");
4452
4309
  }
4310
+ return _assertThisInitialized(self);
4453
4311
  }
4454
- `;
4455
- /*------------------------------------------------------------------------*/
4456
- /* Component */
4457
- /*------------------------------------------------------------------------*/
4458
- const LoadingSpinner = () => {
4459
- /*------------------------------------------------------------------------*/
4460
- /* Render */
4461
- /*------------------------------------------------------------------------*/
4462
- // Add all four blips to a container
4463
- return (React__default.createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
4464
- React__default.createElement("style", null, style$5),
4465
- React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-1 me-1" }),
4466
- React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-2 me-1" }),
4467
- React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-3 me-1" }),
4468
- React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-4" })));
4469
- };
4470
4312
 
4471
- /**
4472
- * A radio selection button
4473
- * @author Gabe Abrams
4474
- */
4475
- /*------------------------------------------------------------------------*/
4476
- /* Component */
4477
- /*------------------------------------------------------------------------*/
4478
- const RadioButton = (props) => {
4479
- /*------------------------------------------------------------------------*/
4480
- /* Setup */
4481
- /*------------------------------------------------------------------------*/
4482
- /* -------------- Props ------------- */
4483
- const { text, onSelected, ariaLabel, title, selected, id, noMarginOnRight, selectedVariant = Variant$1.Secondary, unselectedVariant = Variant$1.Light, small, } = props;
4484
- /*------------------------------------------------------------------------*/
4485
- /* Render */
4486
- /*------------------------------------------------------------------------*/
4487
- /*----------------------------------------*/
4488
- /* Main UI */
4489
- /*----------------------------------------*/
4490
- return (React__default.createElement("button", { type: "button", id: id, title: title, className: `btn btn-${selected ? selectedVariant : unselectedVariant}${selected ? ' selected' : ''}${small ? ' btn-sm' : ''} m-0${noMarginOnRight ? '' : ' me-1'}`, "aria-label": `${ariaLabel}${selected ? ': currently selected' : ''}`, onClick: () => {
4491
- if (!selected) {
4492
- onSelected();
4493
- }
4494
- } },
4495
- React__default.createElement(FontAwesomeIcon, { icon: selected ? faDotCircle : faCircle$1, className: "me-1" }),
4496
- text));
4497
- };
4313
+ function _createSuper(Derived) {
4314
+ var hasNativeReflectConstruct = _isNativeReflectConstruct();
4315
+ return function _createSuperInternal() {
4316
+ var Super = _getPrototypeOf(Derived),
4317
+ result;
4318
+ if (hasNativeReflectConstruct) {
4319
+ var NewTarget = _getPrototypeOf(this).constructor;
4320
+ result = Reflect.construct(Super, arguments, NewTarget);
4321
+ } else {
4322
+ result = Super.apply(this, arguments);
4323
+ }
4324
+ return _possibleConstructorReturn(this, result);
4325
+ };
4326
+ }
4498
4327
 
4499
- /**
4500
- * A checkbox button
4501
- * @author Gabe Abrams
4502
- */
4503
- /*------------------------------------------------------------------------*/
4504
- /* Component */
4505
- /*------------------------------------------------------------------------*/
4506
- const CheckboxButton = (props) => {
4507
- /*------------------------------------------------------------------------*/
4508
- /* Setup */
4509
- /*------------------------------------------------------------------------*/
4510
- /* -------------- Props ------------- */
4511
- const { text, onChanged, ariaLabel, title, checked, id, className, noMarginOnRight, checkedVariant = Variant$1.Secondary, uncheckedVariant = Variant$1.Light, small, dashed, } = props;
4512
- /*------------------------------------------------------------------------*/
4513
- /* Render */
4514
- /*------------------------------------------------------------------------*/
4515
- /*----------------------------------------*/
4516
- /* Main UI */
4517
- /*----------------------------------------*/
4518
- // Determine the icon
4519
- let icon;
4520
- if (checked) {
4521
- icon = faCheckSquare;
4328
+ function _arrayLikeToArray(arr, len) {
4329
+ if (len == null || len > arr.length) len = arr.length;
4330
+ for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
4331
+ return arr2;
4332
+ }
4333
+
4334
+ function _arrayWithoutHoles(arr) {
4335
+ if (Array.isArray(arr)) return _arrayLikeToArray(arr);
4336
+ }
4337
+
4338
+ function _iterableToArray(iter) {
4339
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
4340
+ }
4341
+
4342
+ function _unsupportedIterableToArray(o, minLen) {
4343
+ if (!o) return;
4344
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
4345
+ var n = Object.prototype.toString.call(o).slice(8, -1);
4346
+ if (n === "Object" && o.constructor) n = o.constructor.name;
4347
+ if (n === "Map" || n === "Set") return Array.from(o);
4348
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
4349
+ }
4350
+
4351
+ function _nonIterableSpread() {
4352
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
4353
+ }
4354
+
4355
+ function _toConsumableArray(arr) {
4356
+ return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
4357
+ }
4358
+
4359
+ /*
4360
+
4361
+ Based off glamor's StyleSheet, thanks Sunil ❤️
4362
+
4363
+ high performance StyleSheet for css-in-js systems
4364
+
4365
+ - uses multiple style tags behind the scenes for millions of rules
4366
+ - uses `insertRule` for appending in production for *much* faster performance
4367
+
4368
+ // usage
4369
+
4370
+ import { StyleSheet } from '@emotion/sheet'
4371
+
4372
+ let styleSheet = new StyleSheet({ key: '', container: document.head })
4373
+
4374
+ styleSheet.insert('#box { border: 1px solid red; }')
4375
+ - appends a css rule into the stylesheet
4376
+
4377
+ styleSheet.flush()
4378
+ - empties the stylesheet of all its contents
4379
+
4380
+ */
4381
+ // $FlowFixMe
4382
+ function sheetForTag(tag) {
4383
+ if (tag.sheet) {
4384
+ // $FlowFixMe
4385
+ return tag.sheet;
4386
+ } // this weirdness brought to you by firefox
4387
+
4388
+ /* istanbul ignore next */
4389
+
4390
+
4391
+ for (var i = 0; i < document.styleSheets.length; i++) {
4392
+ if (document.styleSheets[i].ownerNode === tag) {
4393
+ // $FlowFixMe
4394
+ return document.styleSheets[i];
4522
4395
  }
4523
- else {
4524
- icon = (dashed
4525
- ? faSquareMinus
4526
- : faSquare);
4396
+ }
4397
+ }
4398
+
4399
+ function createStyleElement(options) {
4400
+ var tag = document.createElement('style');
4401
+ tag.setAttribute('data-emotion', options.key);
4402
+
4403
+ if (options.nonce !== undefined) {
4404
+ tag.setAttribute('nonce', options.nonce);
4405
+ }
4406
+
4407
+ tag.appendChild(document.createTextNode(''));
4408
+ tag.setAttribute('data-s', '');
4409
+ return tag;
4410
+ }
4411
+
4412
+ var StyleSheet = /*#__PURE__*/function () {
4413
+ // Using Node instead of HTMLElement since container may be a ShadowRoot
4414
+ function StyleSheet(options) {
4415
+ var _this = this;
4416
+
4417
+ this._insertTag = function (tag) {
4418
+ var before;
4419
+
4420
+ if (_this.tags.length === 0) {
4421
+ if (_this.insertionPoint) {
4422
+ before = _this.insertionPoint.nextSibling;
4423
+ } else if (_this.prepend) {
4424
+ before = _this.container.firstChild;
4425
+ } else {
4426
+ before = _this.before;
4427
+ }
4428
+ } else {
4429
+ before = _this.tags[_this.tags.length - 1].nextSibling;
4430
+ }
4431
+
4432
+ _this.container.insertBefore(tag, before);
4433
+
4434
+ _this.tags.push(tag);
4435
+ };
4436
+
4437
+ this.isSpeedy = options.speedy === undefined ? process.env.NODE_ENV === 'production' : options.speedy;
4438
+ this.tags = [];
4439
+ this.ctr = 0;
4440
+ this.nonce = options.nonce; // key is the value of the data-emotion attribute, it's used to identify different sheets
4441
+
4442
+ this.key = options.key;
4443
+ this.container = options.container;
4444
+ this.prepend = options.prepend;
4445
+ this.insertionPoint = options.insertionPoint;
4446
+ this.before = null;
4447
+ }
4448
+
4449
+ var _proto = StyleSheet.prototype;
4450
+
4451
+ _proto.hydrate = function hydrate(nodes) {
4452
+ nodes.forEach(this._insertTag);
4453
+ };
4454
+
4455
+ _proto.insert = function insert(rule) {
4456
+ // the max length is how many rules we have per style tag, it's 65000 in speedy mode
4457
+ // it's 1 in dev because we insert source maps that map a single rule to a location
4458
+ // and you can only have one source map per style tag
4459
+ if (this.ctr % (this.isSpeedy ? 65000 : 1) === 0) {
4460
+ this._insertTag(createStyleElement(this));
4527
4461
  }
4528
- // Create the button
4529
- return (React__default.createElement("button", { type: "button", id: id, title: title, className: `CheckboxButton-status-${checked ? 'checked' : 'unchecked'} ${dashed ? 'CheckboxButton-dashed ' : ''}btn btn-${checked ? checkedVariant : uncheckedVariant}${checked ? ' selected' : ''}${small ? ' btn-sm' : ''} m-0${noMarginOnRight ? '' : ' me-1'} ${className !== null && className !== void 0 ? className : ''}`, "aria-label": `${ariaLabel}${checked ? ': currently checked' : ''}`, onClick: () => {
4530
- onChanged(!checked);
4531
- } },
4532
- React__default.createElement(FontAwesomeIcon, { icon: icon, className: "me-1" }),
4533
- text));
4534
- };
4462
+
4463
+ var tag = this.tags[this.tags.length - 1];
4464
+
4465
+ if (process.env.NODE_ENV !== 'production') {
4466
+ var isImportRule = rule.charCodeAt(0) === 64 && rule.charCodeAt(1) === 105;
4467
+
4468
+ if (isImportRule && this._alreadyInsertedOrderInsensitiveRule) {
4469
+ // this would only cause problem in speedy mode
4470
+ // but we don't want enabling speedy to affect the observable behavior
4471
+ // so we report this error at all times
4472
+ console.error("You're attempting to insert the following rule:\n" + rule + '\n\n`@import` rules must be before all other types of rules in a stylesheet but other rules have already been inserted. Please ensure that `@import` rules are before all other rules.');
4473
+ }
4474
+ this._alreadyInsertedOrderInsensitiveRule = this._alreadyInsertedOrderInsensitiveRule || !isImportRule;
4475
+ }
4476
+
4477
+ if (this.isSpeedy) {
4478
+ var sheet = sheetForTag(tag);
4479
+
4480
+ try {
4481
+ // this is the ultrafast version, works across browsers
4482
+ // the big drawback is that the css won't be editable in devtools
4483
+ sheet.insertRule(rule, sheet.cssRules.length);
4484
+ } catch (e) {
4485
+ if (process.env.NODE_ENV !== 'production' && !/:(-moz-placeholder|-moz-focus-inner|-moz-focusring|-ms-input-placeholder|-moz-read-write|-moz-read-only|-ms-clear|-ms-expand|-ms-reveal){/.test(rule)) {
4486
+ console.error("There was a problem inserting the following rule: \"" + rule + "\"", e);
4487
+ }
4488
+ }
4489
+ } else {
4490
+ tag.appendChild(document.createTextNode(rule));
4491
+ }
4492
+
4493
+ this.ctr++;
4494
+ };
4495
+
4496
+ _proto.flush = function flush() {
4497
+ // $FlowFixMe
4498
+ this.tags.forEach(function (tag) {
4499
+ return tag.parentNode && tag.parentNode.removeChild(tag);
4500
+ });
4501
+ this.tags = [];
4502
+ this.ctr = 0;
4503
+
4504
+ if (process.env.NODE_ENV !== 'production') {
4505
+ this._alreadyInsertedOrderInsensitiveRule = false;
4506
+ }
4507
+ };
4508
+
4509
+ return StyleSheet;
4510
+ }();
4511
+
4512
+ var MS = '-ms-';
4513
+ var MOZ = '-moz-';
4514
+ var WEBKIT = '-webkit-';
4515
+
4516
+ var COMMENT = 'comm';
4517
+ var RULESET = 'rule';
4518
+ var DECLARATION = 'decl';
4519
+ var IMPORT = '@import';
4520
+ var KEYFRAMES = '@keyframes';
4521
+ var LAYER = '@layer';
4535
4522
 
4536
4523
  /**
4537
- * Input group with a title and space for buttons
4538
- * @author Gabe Abrams
4524
+ * @param {number}
4525
+ * @return {number}
4539
4526
  */
4540
- /*------------------------------------------------------------------------*/
4541
- /* Component */
4542
- /*------------------------------------------------------------------------*/
4543
- const ButtonInputGroup = (props) => {
4544
- /*------------------------------------------------------------------------*/
4545
- /* Setup */
4546
- /*------------------------------------------------------------------------*/
4547
- /* -------------- Props ------------- */
4548
- // Destructure all props
4549
- const { label, minLabelWidth, children, } = props;
4550
- /*------------------------------------------------------------------------*/
4551
- /* Render */
4552
- /*------------------------------------------------------------------------*/
4553
- /*----------------------------------------*/
4554
- /* Main UI */
4555
- /*----------------------------------------*/
4556
- return (React__default.createElement("div", { className: "input-group" },
4557
- React__default.createElement("div", { className: "input-group-prepend d-flex w-100" },
4558
- React__default.createElement("span", { className: "input-group-text", style: {
4559
- minWidth: (minLabelWidth !== null && minLabelWidth !== void 0 ? minLabelWidth : undefined),
4560
- borderTopRightRadius: 0,
4561
- borderBottomRightRadius: 0,
4562
- } }, label),
4563
- React__default.createElement("span", { className: "input-group-text flex-grow-1 rounded-right", style: {
4564
- backgroundColor: 'white',
4565
- borderTopLeftRadius: 0,
4566
- borderBottomLeftRadius: 0,
4567
- borderLeftWidth: 0,
4568
- } }, children))));
4569
- };
4527
+ var abs = Math.abs;
4570
4528
 
4571
4529
  /**
4572
- * Copiable text box
4573
- * @author Gabe Abrams
4530
+ * @param {number}
4531
+ * @return {string}
4574
4532
  */
4575
- /* ------------- Actions ------------ */
4576
- // Types of actions
4577
- var ActionType$1$1;
4578
- (function (ActionType) {
4579
- // Indicate that the text was recently copied
4580
- ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
4581
- // Clear the status
4582
- ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
4583
- })(ActionType$1$1 || (ActionType$1$1 = {}));
4533
+ var from = String.fromCharCode;
4584
4534
 
4585
4535
  /**
4586
- * Reusable nested item picker
4587
- * @author Yuen Ler Chow
4536
+ * @param {object}
4537
+ * @return {object}
4588
4538
  */
4589
- /* ------------- Actions ------------ */
4590
- // Types of actions
4591
- var ActionType$3;
4592
- (function (ActionType) {
4593
- // Toggle whether the children are being shown
4594
- ActionType["ToggleItems"] = "toggle-items";
4595
- })(ActionType$3 || (ActionType$3 = {}));
4539
+ var assign = Object.assign;
4596
4540
 
4597
- // Keep track of whether or not session expiry has already been handled
4598
- let sessionAlreadyExpired = false;
4599
- /*------------------------------------------------------------------------*/
4600
- /* Stub Logic */
4601
- /*------------------------------------------------------------------------*/
4602
- // Stored stub responses
4603
- const stubResponses = {};
4604
- /*------------------------------------------------------------------------*/
4605
- /* Main */
4606
- /*------------------------------------------------------------------------*/
4607
4541
  /**
4608
- * Visit an endpoint on the server [for client only]
4609
- * @author Gabe Abrams
4610
- * @param opts object containing all arguments
4611
- * @param opts.path - the path of the server endpoint
4612
- * @param [opts.method=GET] - the method of the endpoint
4613
- * @param [opts.params] - query/body parameters to include
4614
- * @returns response from server
4542
+ * @param {string} value
4543
+ * @param {number} length
4544
+ * @return {number}
4615
4545
  */
4616
- const visitServerEndpoint = (opts) => __awaiter(void 0, void 0, void 0, function* () {
4617
- var _a, _b, _c;
4618
- const method = ((_a = opts.method) !== null && _a !== void 0 ? _a : 'GET');
4619
- // Handle stubs
4620
- const stubResponse = (_b = stubResponses[method]) === null || _b === void 0 ? void 0 : _b[opts.path];
4621
- if (stubResponse) {
4622
- // Remove from list
4623
- try {
4624
- stubResponses[method][opts.path] = undefined;
4625
- }
4626
- catch (err) {
4627
- // Ignore
4628
- }
4629
- // Success
4630
- if (stubResponse.success) {
4631
- return stubResponse.body;
4632
- }
4633
- // Error
4634
- throw new ErrorWithCode(stubResponse.errorMessage, stubResponse.errorCode);
4635
- }
4636
- // Send the request
4637
- const response = yield cacclSendRequest({
4638
- path: opts.path,
4639
- method: (_c = opts.method) !== null && _c !== void 0 ? _c : 'GET',
4640
- params: opts.params,
4641
- });
4642
- // Check for failure
4643
- if (!response || !response.body) {
4644
- throw new ErrorWithCode('We didn\'t get a response from the server. Please check your internet connection.', ReactKitErrorCode$1.NoResponse);
4645
- }
4646
- if (!response.body.success) {
4647
- // Session expired
4648
- if (response.body.code === ReactKitErrorCode$1.SessionExpired) {
4649
- // Skip notice if session was already expired
4650
- if (sessionAlreadyExpired) {
4651
- // Never return (browser is already reloading)
4652
- yield new Promise(() => {
4653
- // Promise that never returns
4654
- });
4655
- }
4656
- sessionAlreadyExpired = true;
4657
- // Show session expiration message
4658
- {
4659
- // Fallback to alert
4660
- // eslint-disable-next-line no-alert
4661
- alert('Your session has expired. Please start over.');
4662
- }
4663
- // Never return (don't continue execution)
4664
- yield new Promise(() => {
4665
- // Promise that never returns
4666
- });
4667
- }
4668
- // Other errors
4669
- throw new ErrorWithCode((response.body.message
4670
- || 'An unknown error occurred. Please contact an admin.'), (response.body.code
4671
- || ReactKitErrorCode$1.NoCode));
4672
- }
4673
- // Success! Extract the body
4674
- const { body } = response.body;
4675
- // Return
4676
- return body;
4677
- });
4546
+ function hash (value, length) {
4547
+ return charat(value, 0) ^ 45 ? (((((((length << 2) ^ charat(value, 0)) << 2) ^ charat(value, 1)) << 2) ^ charat(value, 2)) << 2) ^ charat(value, 3) : 0
4548
+ }
4678
4549
 
4679
- // Import custom error
4680
- // Stored copy of caccl functions
4681
- let _cacclGetLaunchInfo$1;
4682
- /*------------------------------------------------------------------------*/
4683
- /* Helpers */
4684
- /*------------------------------------------------------------------------*/
4685
4550
  /**
4686
- * Get launch info via CACCL
4687
- * @author Gabe Abrams
4688
- * @param req express request object
4689
- * @returns object { launched, launchInfo }
4551
+ * @param {string} value
4552
+ * @return {string}
4690
4553
  */
4691
- const cacclGetLaunchInfo$1 = (req) => {
4692
- {
4693
- throw new ErrorWithCode('Could not get launch info because server was not initialized with dce-reactkit\'s initServer function', ReactKitErrorCode$1.NoCACCLGetLaunchInfoFunction);
4694
- }
4695
- };
4554
+ function trim (value) {
4555
+ return value.trim()
4556
+ }
4696
4557
 
4697
4558
  /**
4698
- * Server-side API param types
4699
- * @author Gabe Abrams
4559
+ * @param {string} value
4560
+ * @param {RegExp} pattern
4561
+ * @return {string?}
4700
4562
  */
4701
- var ParamType;
4702
- (function (ParamType) {
4703
- ParamType["Boolean"] = "boolean";
4704
- ParamType["BooleanOptional"] = "boolean-optional";
4705
- ParamType["Float"] = "float";
4706
- ParamType["FloatOptional"] = "float-optional";
4707
- ParamType["Int"] = "int";
4708
- ParamType["IntOptional"] = "int-optional";
4709
- ParamType["JSON"] = "json";
4710
- ParamType["JSONOptional"] = "json-optional";
4711
- ParamType["String"] = "string";
4712
- ParamType["StringOptional"] = "string-optional";
4713
- })(ParamType || (ParamType = {}));
4714
- var ParamType$1 = ParamType;
4563
+ function match (value, pattern) {
4564
+ return (value = pattern.exec(value)) ? value[0] : value
4565
+ }
4715
4566
 
4716
- // Import shared types
4717
4567
  /**
4718
- * Handle an error and respond to the client
4719
- * @author Gabe Abrams
4720
- * @param res express response
4721
- * @param error error info
4722
- * @param opts.err the error to send to the client
4723
- * or the error message
4724
- * @param [opts.code] an error code (only used if err.code is not
4725
- * included)
4726
- * @param [opts.status=500] the https status code to use
4727
- * defined)
4568
+ * @param {string} value
4569
+ * @param {(string|RegExp)} pattern
4570
+ * @param {string} replacement
4571
+ * @return {string}
4728
4572
  */
4729
- const handleError$1 = (res, error) => {
4730
- // Get the error message
4731
- let message;
4732
- if (error && error.message) {
4733
- message = (error.message || 'An unknown error occurred.');
4734
- }
4735
- else if (typeof error === 'string') {
4736
- message = (error.trim().length > 0
4737
- ? error
4738
- : 'An unknown error occurred.');
4739
- }
4740
- else {
4741
- message = 'An unknown error occurred.';
4742
- }
4743
- // Get the error code
4744
- const code = (error.code || ReactKitErrorCode$1.NoCode);
4745
- // Get the status code
4746
- const status = (error.status || 500);
4747
- // Respond to user
4748
- res
4749
- // Set the http status code
4750
- .status(status)
4751
- // Send a JSON response
4752
- .json({
4753
- // Error message
4754
- message,
4755
- // Error code
4756
- code,
4757
- // Success = false flag so client can detect server-side errors
4758
- success: false,
4759
- });
4760
- return undefined;
4761
- };
4573
+ function replace (value, pattern, replacement) {
4574
+ return value.replace(pattern, replacement)
4575
+ }
4762
4576
 
4763
4577
  /**
4764
- * Send successful API response
4765
- * @author Gabe Abrams
4766
- * @param res express response
4767
- * @param body the body of the response to send to the client
4578
+ * @param {string} value
4579
+ * @param {string} search
4580
+ * @return {number}
4768
4581
  */
4769
- const handleSuccess$1 = (res, body) => {
4770
- // Send a http 200 json response
4771
- res.json({
4772
- // Include the body as a parameter
4773
- body,
4774
- // Success = true flag so client can detect successful responses
4775
- success: true,
4776
- });
4777
- return undefined;
4778
- };
4582
+ function indexof (value, search) {
4583
+ return value.indexOf(search)
4584
+ }
4779
4585
 
4780
4586
  /**
4781
- * Generate an express API route handler
4782
- * @author Gabe Abrams
4783
- * @param opts object containing all arguments
4784
- * @param opts.paramTypes map containing the types for each parameter that is
4785
- * included in the request (map: param name => type)
4786
- * @param opts.handler function that processes the request
4787
- * @returns express route handler that takes the following arguments:
4788
- * params (map: param name => value), handleSuccess (function for handling
4789
- * successful requests), handleError (function for handling failed requests),
4790
- * req (express request object), res (express response object),
4791
- * next (express next function). Params also has userId, userFirstName,
4792
- * userLastName, isLearner, isTTM, isAdmin, and any other variables that
4793
- * are directly added to the session
4794
- */
4795
- const genRouteHandler$1 = (opts) => {
4796
- // Return a route handler
4797
- return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
4798
- var _a, _b;
4799
- // Output params
4800
- const output = {};
4801
- /*----------------------------------------*/
4802
- /* Parse Params */
4803
- /*----------------------------------------*/
4804
- // Process items one by one
4805
- const paramList = Object.entries((_a = opts.paramTypes) !== null && _a !== void 0 ? _a : {});
4806
- for (let i = 0; i < paramList.length; i++) {
4807
- const [name, type] = paramList[i];
4808
- // Find the value as a string
4809
- const value = (req.params[name]
4810
- || req.query[name]
4811
- || req.body[name]);
4812
- // Parse
4813
- if (type === ParamType$1.Boolean || type === ParamType$1.BooleanOptional) {
4814
- // Boolean
4815
- // Handle case where value doesn't exist
4816
- if (value === undefined) {
4817
- if (type === ParamType$1.BooleanOptional) {
4818
- output[name] = undefined;
4819
- }
4820
- else {
4821
- return handleError$1(res, {
4822
- message: `Parameter ${name} is required, but it was not included.`,
4823
- code: ReactKitErrorCode$1.MissingParameter,
4824
- status: 422,
4825
- });
4826
- }
4827
- }
4828
- else {
4829
- // Value exists
4830
- // Simplify value
4831
- const simpleVal = (String(value)
4832
- .trim()
4833
- .toLowerCase());
4834
- // Parse
4835
- output[name] = ([
4836
- 'true',
4837
- 'yes',
4838
- 'y',
4839
- '1',
4840
- 't',
4841
- ].indexOf(simpleVal) >= 0);
4842
- }
4843
- }
4844
- else if (type === ParamType$1.Float || type === ParamType$1.FloatOptional) {
4845
- // Float
4846
- // Handle case where value doesn't exist
4847
- if (value === undefined) {
4848
- if (type === ParamType$1.FloatOptional) {
4849
- output[name] = undefined;
4850
- }
4851
- else {
4852
- return handleError$1(res, {
4853
- message: `Parameter ${name} is required, but it was not included.`,
4854
- code: ReactKitErrorCode$1.MissingParameter,
4855
- status: 422,
4856
- });
4857
- }
4858
- }
4859
- else if (!Number.isNaN(Number.parseFloat(String(value)))) {
4860
- // Value is a number
4861
- output[name] = Number.parseFloat(String(value));
4862
- }
4863
- else {
4864
- // Issue!
4865
- return handleError$1(res, {
4866
- message: `Request data was malformed: ${name} was not a valid float.`,
4867
- code: ReactKitErrorCode$1.InvalidParameter,
4868
- status: 422,
4869
- });
4870
- }
4871
- }
4872
- else if (type === ParamType$1.Int || type === ParamType$1.IntOptional) {
4873
- // Int
4874
- // Handle case where value doesn't exist
4875
- if (value === undefined) {
4876
- if (type === ParamType$1.IntOptional) {
4877
- output[name] = undefined;
4878
- }
4879
- else {
4880
- return handleError$1(res, {
4881
- message: `Parameter ${name} is required, but it was not included.`,
4882
- code: ReactKitErrorCode$1.MissingParameter,
4883
- status: 422,
4884
- });
4885
- }
4886
- }
4887
- else if (!Number.isNaN(Number.parseInt(String(value), 10))) {
4888
- // Value is a number
4889
- output[name] = Number.parseInt(String(value), 10);
4890
- }
4891
- else {
4892
- // Issue!
4893
- return handleError$1(res, {
4894
- message: `Request data was malformed: ${name} was not a valid int.`,
4895
- code: ReactKitErrorCode$1.InvalidParameter,
4896
- status: 422,
4897
- });
4898
- }
4899
- }
4900
- else if (type === ParamType$1.JSON || type === ParamType$1.JSONOptional) {
4901
- // Stringified JSON
4902
- // Handle case where value doesn't exist
4903
- if (value === undefined) {
4904
- if (type === ParamType$1.JSONOptional) {
4905
- output[name] = undefined;
4906
- }
4907
- else {
4908
- return handleError$1(res, {
4909
- message: `Parameter ${name} is required, but it was not included.`,
4910
- code: ReactKitErrorCode$1.MissingParameter,
4911
- status: 422,
4912
- });
4913
- }
4914
- }
4915
- else {
4916
- // Value exists
4917
- // Parse
4918
- try {
4919
- output[name] = JSON.parse(String(value));
4920
- }
4921
- catch (err) {
4922
- return handleError$1(res, {
4923
- message: `Request data was malformed: ${name} was not a valid JSON payload.`,
4924
- code: ReactKitErrorCode$1.InvalidParameter,
4925
- status: 422,
4926
- });
4927
- }
4928
- }
4929
- }
4930
- else if (type === ParamType$1.String || type === ParamType$1.StringOptional) {
4931
- // String
4932
- // Handle case where value doesn't exist
4933
- if (value === undefined) {
4934
- if (type === ParamType$1.StringOptional) {
4935
- output[name] = undefined;
4936
- }
4937
- else {
4938
- return handleError$1(res, {
4939
- message: `Parameter ${name} is required, but it was not included.`,
4940
- code: ReactKitErrorCode$1.MissingParameter,
4941
- status: 422,
4942
- });
4943
- }
4944
- }
4945
- else {
4946
- // Value exists
4947
- // Leave as is
4948
- output[name] = value;
4949
- }
4950
- }
4951
- else {
4952
- // No valid data type
4953
- return handleError$1(res, {
4954
- message: `An internal error occurred: we could not determine the type of ${name}.`,
4955
- code: ReactKitErrorCode$1.InvalidParameter,
4956
- status: 422,
4957
- });
4958
- }
4959
- }
4960
- /*----------------------------------------*/
4961
- /* Launch Info */
4962
- /*----------------------------------------*/
4963
- // Get launch info
4964
- const { launched, launchInfo } = cacclGetLaunchInfo$1(req);
4965
- if (!launched || !launchInfo) {
4966
- return handleError$1(res, {
4967
- message: 'Your session has expired. Please refresh the page and try again.',
4968
- code: ReactKitErrorCode$1.SessionExpired,
4969
- status: 440,
4970
- });
4971
- }
4972
- // Error if user info cannot be found
4973
- if (!launchInfo.userId
4974
- || !launchInfo.userFirstName
4975
- || !launchInfo.userLastName
4976
- || (launchInfo.notInCourse
4977
- && !launchInfo.isAdmin)
4978
- || (!launchInfo.isTTM
4979
- && !launchInfo.isLearner
4980
- && !launchInfo.isAdmin)) {
4981
- return handleError$1(res, {
4982
- message: 'Your session was invalid. Please refresh the page and try again.',
4983
- code: ReactKitErrorCode$1.SessionExpired,
4984
- status: 440,
4985
- });
4986
- }
4987
- // Add launch info to output
4988
- output.userId = launchInfo.userId;
4989
- output.userFirstName = launchInfo.userFirstName;
4990
- output.userLastName = launchInfo.userLastName;
4991
- output.userEmail = launchInfo.userEmail;
4992
- output.isLearner = !!launchInfo.isLearner;
4993
- output.isTTM = !!launchInfo.isTTM;
4994
- output.isAdmin = !!launchInfo.isAdmin;
4995
- output.courseId = ((_b = output.courseId) !== null && _b !== void 0 ? _b : launchInfo.courseId);
4996
- output.courseName = launchInfo.contextLabel;
4997
- // Add other session variables
4998
- Object.keys(req.session).forEach((propName) => {
4999
- // Skip if prop already in output
5000
- if (output[propName] !== undefined) {
5001
- return;
5002
- }
5003
- // Add to output
5004
- const value = req.session[propName];
5005
- if (typeof value === 'string'
5006
- || typeof value === 'boolean'
5007
- || typeof value === 'number') {
5008
- output[propName] = value;
5009
- }
5010
- });
5011
- /*----------------------------------------*/
5012
- /* Require Course Consistency */
5013
- /*----------------------------------------*/
5014
- // Make sure the user actually launched from the appropriate course
5015
- if (output.courseId
5016
- && launchInfo.courseId
5017
- && output.courseId !== launchInfo.courseId
5018
- && !output.isTTM
5019
- && !output.isAdmin) {
5020
- // Course of interest is not the launch course
5021
- return handleError$1(res, {
5022
- message: 'You switched sessions by opening this app in another tab. Please refresh the page and try again.',
5023
- code: ReactKitErrorCode$1.WrongCourse,
5024
- status: 401,
5025
- });
5026
- }
5027
- /*----------------------------------------*/
5028
- /* Require Proper Permissions */
5029
- /*----------------------------------------*/
5030
- // Add TTM endpoint security
5031
- if (
5032
- // This is a TTM endpoint
5033
- req.path.startsWith('/api/ttm')
5034
- // User is not a TTM
5035
- && (
5036
- // User is not a TTM
5037
- !output.isTTM
5038
- // User is not an admin
5039
- && !output.isAdmin)) {
5040
- // User does not have access
5041
- return handleError$1(res, {
5042
- message: 'This action is only allowed if you are a teaching team member for the course. Please go back to Canvas, log in as a teaching team member, and try again.',
5043
- code: ReactKitErrorCode$1.NotTTM,
5044
- status: 401,
5045
- });
5046
- }
5047
- // Add Admin endpoint security
5048
- if (
5049
- // This is an admin endpoint
5050
- req.path.startsWith('/api/admin')
5051
- // User is not an admin
5052
- && !output.isAdmin) {
5053
- // User does not have access
5054
- return handleError$1(res, {
5055
- message: 'This action is only allowed if you are a Canvas admin. Please go back to Canvas, log in as an admin, and try again.',
5056
- code: ReactKitErrorCode$1.NotAdmin,
5057
- status: 401,
5058
- });
5059
- }
5060
- /*------------------------------------------------------------------------*/
5061
- /* Call handler */
5062
- /*------------------------------------------------------------------------*/
5063
- try {
5064
- const results = yield opts.handler({
5065
- params: output,
5066
- req,
5067
- res,
5068
- next,
5069
- });
5070
- // Send results to client
5071
- handleSuccess$1(res, results !== null && results !== void 0 ? results : undefined);
5072
- }
5073
- catch (err) {
5074
- // Send error to client
5075
- handleError$1(res, err);
5076
- }
5077
- });
5078
- };
5079
-
5080
- /**
5081
- * Days of the week
5082
- * @author Gabe Abrams
5083
- */
5084
- var DayOfWeek$2;
5085
- (function (DayOfWeek) {
5086
- DayOfWeek["Monday"] = "m";
5087
- DayOfWeek["Tuesday"] = "t";
5088
- DayOfWeek["Wednesday"] = "w";
5089
- DayOfWeek["Thursday"] = "r";
5090
- DayOfWeek["Friday"] = "f";
5091
- DayOfWeek["Saturday"] = "s";
5092
- DayOfWeek["Sunday"] = "u";
5093
- })(DayOfWeek$2 || (DayOfWeek$2 = {}));
5094
-
5095
- /**
5096
- * Options for field types
5097
- * @author Yuen Ler Chow
5098
- */
5099
- var DBEntryFieldType;
5100
- (function (DBEntryFieldType) {
5101
- // A string input field
5102
- DBEntryFieldType["String"] = "String";
5103
- // A number input field
5104
- DBEntryFieldType["Number"] = "Number";
5105
- // input field with subfields that are also DBEntryFields
5106
- DBEntryFieldType["Object"] = "Object";
5107
- // list of strings input field
5108
- DBEntryFieldType["StringArray"] = "StringArray";
5109
- // list of numbers input field
5110
- DBEntryFieldType["NumberArray"] = "NumberArray";
5111
- })(DBEntryFieldType || (DBEntryFieldType = {}));
5112
- var DBEntryFieldType$1 = DBEntryFieldType;
5113
-
5114
- function _extends() {
5115
- _extends = Object.assign ? Object.assign.bind() : function (target) {
5116
- for (var i = 1; i < arguments.length; i++) {
5117
- var source = arguments[i];
5118
- for (var key in source) {
5119
- if (Object.prototype.hasOwnProperty.call(source, key)) {
5120
- target[key] = source[key];
5121
- }
5122
- }
5123
- }
5124
- return target;
5125
- };
5126
- return _extends.apply(this, arguments);
5127
- }
5128
-
5129
- function _typeof(obj) {
5130
- "@babel/helpers - typeof";
5131
-
5132
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
5133
- return typeof obj;
5134
- } : function (obj) {
5135
- return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
5136
- }, _typeof(obj);
5137
- }
5138
-
5139
- function _toPrimitive(input, hint) {
5140
- if (_typeof(input) !== "object" || input === null) return input;
5141
- var prim = input[Symbol.toPrimitive];
5142
- if (prim !== undefined) {
5143
- var res = prim.call(input, hint || "default");
5144
- if (_typeof(res) !== "object") return res;
5145
- throw new TypeError("@@toPrimitive must return a primitive value.");
5146
- }
5147
- return (hint === "string" ? String : Number)(input);
5148
- }
5149
-
5150
- function _toPropertyKey(arg) {
5151
- var key = _toPrimitive(arg, "string");
5152
- return _typeof(key) === "symbol" ? key : String(key);
5153
- }
5154
-
5155
- function _defineProperty(obj, key, value) {
5156
- key = _toPropertyKey(key);
5157
- if (key in obj) {
5158
- Object.defineProperty(obj, key, {
5159
- value: value,
5160
- enumerable: true,
5161
- configurable: true,
5162
- writable: true
5163
- });
5164
- } else {
5165
- obj[key] = value;
5166
- }
5167
- return obj;
5168
- }
5169
-
5170
- function ownKeys(object, enumerableOnly) {
5171
- var keys = Object.keys(object);
5172
- if (Object.getOwnPropertySymbols) {
5173
- var symbols = Object.getOwnPropertySymbols(object);
5174
- enumerableOnly && (symbols = symbols.filter(function (sym) {
5175
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
5176
- })), keys.push.apply(keys, symbols);
5177
- }
5178
- return keys;
5179
- }
5180
- function _objectSpread2(target) {
5181
- for (var i = 1; i < arguments.length; i++) {
5182
- var source = null != arguments[i] ? arguments[i] : {};
5183
- i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
5184
- _defineProperty(target, key, source[key]);
5185
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
5186
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
5187
- });
5188
- }
5189
- return target;
5190
- }
5191
-
5192
- function _classCallCheck(instance, Constructor) {
5193
- if (!(instance instanceof Constructor)) {
5194
- throw new TypeError("Cannot call a class as a function");
5195
- }
5196
- }
5197
-
5198
- function _defineProperties(target, props) {
5199
- for (var i = 0; i < props.length; i++) {
5200
- var descriptor = props[i];
5201
- descriptor.enumerable = descriptor.enumerable || false;
5202
- descriptor.configurable = true;
5203
- if ("value" in descriptor) descriptor.writable = true;
5204
- Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
5205
- }
5206
- }
5207
- function _createClass(Constructor, protoProps, staticProps) {
5208
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
5209
- if (staticProps) _defineProperties(Constructor, staticProps);
5210
- Object.defineProperty(Constructor, "prototype", {
5211
- writable: false
5212
- });
5213
- return Constructor;
5214
- }
5215
-
5216
- function _setPrototypeOf(o, p) {
5217
- _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
5218
- o.__proto__ = p;
5219
- return o;
5220
- };
5221
- return _setPrototypeOf(o, p);
5222
- }
5223
-
5224
- function _inherits(subClass, superClass) {
5225
- if (typeof superClass !== "function" && superClass !== null) {
5226
- throw new TypeError("Super expression must either be null or a function");
5227
- }
5228
- subClass.prototype = Object.create(superClass && superClass.prototype, {
5229
- constructor: {
5230
- value: subClass,
5231
- writable: true,
5232
- configurable: true
5233
- }
5234
- });
5235
- Object.defineProperty(subClass, "prototype", {
5236
- writable: false
5237
- });
5238
- if (superClass) _setPrototypeOf(subClass, superClass);
5239
- }
5240
-
5241
- function _getPrototypeOf(o) {
5242
- _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
5243
- return o.__proto__ || Object.getPrototypeOf(o);
5244
- };
5245
- return _getPrototypeOf(o);
5246
- }
5247
-
5248
- function _isNativeReflectConstruct() {
5249
- if (typeof Reflect === "undefined" || !Reflect.construct) return false;
5250
- if (Reflect.construct.sham) return false;
5251
- if (typeof Proxy === "function") return true;
5252
- try {
5253
- Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
5254
- return true;
5255
- } catch (e) {
5256
- return false;
5257
- }
5258
- }
5259
-
5260
- function _assertThisInitialized(self) {
5261
- if (self === void 0) {
5262
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
5263
- }
5264
- return self;
5265
- }
5266
-
5267
- function _possibleConstructorReturn(self, call) {
5268
- if (call && (_typeof(call) === "object" || typeof call === "function")) {
5269
- return call;
5270
- } else if (call !== void 0) {
5271
- throw new TypeError("Derived constructors may only return object or undefined");
5272
- }
5273
- return _assertThisInitialized(self);
5274
- }
5275
-
5276
- function _createSuper(Derived) {
5277
- var hasNativeReflectConstruct = _isNativeReflectConstruct();
5278
- return function _createSuperInternal() {
5279
- var Super = _getPrototypeOf(Derived),
5280
- result;
5281
- if (hasNativeReflectConstruct) {
5282
- var NewTarget = _getPrototypeOf(this).constructor;
5283
- result = Reflect.construct(Super, arguments, NewTarget);
5284
- } else {
5285
- result = Super.apply(this, arguments);
5286
- }
5287
- return _possibleConstructorReturn(this, result);
5288
- };
5289
- }
5290
-
5291
- function _arrayLikeToArray(arr, len) {
5292
- if (len == null || len > arr.length) len = arr.length;
5293
- for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
5294
- return arr2;
5295
- }
5296
-
5297
- function _arrayWithoutHoles(arr) {
5298
- if (Array.isArray(arr)) return _arrayLikeToArray(arr);
5299
- }
5300
-
5301
- function _iterableToArray(iter) {
5302
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
5303
- }
5304
-
5305
- function _unsupportedIterableToArray(o, minLen) {
5306
- if (!o) return;
5307
- if (typeof o === "string") return _arrayLikeToArray(o, minLen);
5308
- var n = Object.prototype.toString.call(o).slice(8, -1);
5309
- if (n === "Object" && o.constructor) n = o.constructor.name;
5310
- if (n === "Map" || n === "Set") return Array.from(o);
5311
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
5312
- }
5313
-
5314
- function _nonIterableSpread() {
5315
- throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
5316
- }
5317
-
5318
- function _toConsumableArray(arr) {
5319
- return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
5320
- }
5321
-
5322
- /*
5323
-
5324
- Based off glamor's StyleSheet, thanks Sunil ❤️
5325
-
5326
- high performance StyleSheet for css-in-js systems
5327
-
5328
- - uses multiple style tags behind the scenes for millions of rules
5329
- - uses `insertRule` for appending in production for *much* faster performance
5330
-
5331
- // usage
5332
-
5333
- import { StyleSheet } from '@emotion/sheet'
5334
-
5335
- let styleSheet = new StyleSheet({ key: '', container: document.head })
5336
-
5337
- styleSheet.insert('#box { border: 1px solid red; }')
5338
- - appends a css rule into the stylesheet
5339
-
5340
- styleSheet.flush()
5341
- - empties the stylesheet of all its contents
5342
-
5343
- */
5344
- // $FlowFixMe
5345
- function sheetForTag(tag) {
5346
- if (tag.sheet) {
5347
- // $FlowFixMe
5348
- return tag.sheet;
5349
- } // this weirdness brought to you by firefox
5350
-
5351
- /* istanbul ignore next */
5352
-
5353
-
5354
- for (var i = 0; i < document.styleSheets.length; i++) {
5355
- if (document.styleSheets[i].ownerNode === tag) {
5356
- // $FlowFixMe
5357
- return document.styleSheets[i];
5358
- }
5359
- }
5360
- }
5361
-
5362
- function createStyleElement(options) {
5363
- var tag = document.createElement('style');
5364
- tag.setAttribute('data-emotion', options.key);
5365
-
5366
- if (options.nonce !== undefined) {
5367
- tag.setAttribute('nonce', options.nonce);
5368
- }
5369
-
5370
- tag.appendChild(document.createTextNode(''));
5371
- tag.setAttribute('data-s', '');
5372
- return tag;
5373
- }
5374
-
5375
- var StyleSheet = /*#__PURE__*/function () {
5376
- // Using Node instead of HTMLElement since container may be a ShadowRoot
5377
- function StyleSheet(options) {
5378
- var _this = this;
5379
-
5380
- this._insertTag = function (tag) {
5381
- var before;
5382
-
5383
- if (_this.tags.length === 0) {
5384
- if (_this.insertionPoint) {
5385
- before = _this.insertionPoint.nextSibling;
5386
- } else if (_this.prepend) {
5387
- before = _this.container.firstChild;
5388
- } else {
5389
- before = _this.before;
5390
- }
5391
- } else {
5392
- before = _this.tags[_this.tags.length - 1].nextSibling;
5393
- }
5394
-
5395
- _this.container.insertBefore(tag, before);
5396
-
5397
- _this.tags.push(tag);
5398
- };
5399
-
5400
- this.isSpeedy = options.speedy === undefined ? process.env.NODE_ENV === 'production' : options.speedy;
5401
- this.tags = [];
5402
- this.ctr = 0;
5403
- this.nonce = options.nonce; // key is the value of the data-emotion attribute, it's used to identify different sheets
5404
-
5405
- this.key = options.key;
5406
- this.container = options.container;
5407
- this.prepend = options.prepend;
5408
- this.insertionPoint = options.insertionPoint;
5409
- this.before = null;
5410
- }
5411
-
5412
- var _proto = StyleSheet.prototype;
5413
-
5414
- _proto.hydrate = function hydrate(nodes) {
5415
- nodes.forEach(this._insertTag);
5416
- };
5417
-
5418
- _proto.insert = function insert(rule) {
5419
- // the max length is how many rules we have per style tag, it's 65000 in speedy mode
5420
- // it's 1 in dev because we insert source maps that map a single rule to a location
5421
- // and you can only have one source map per style tag
5422
- if (this.ctr % (this.isSpeedy ? 65000 : 1) === 0) {
5423
- this._insertTag(createStyleElement(this));
5424
- }
5425
-
5426
- var tag = this.tags[this.tags.length - 1];
5427
-
5428
- if (process.env.NODE_ENV !== 'production') {
5429
- var isImportRule = rule.charCodeAt(0) === 64 && rule.charCodeAt(1) === 105;
5430
-
5431
- if (isImportRule && this._alreadyInsertedOrderInsensitiveRule) {
5432
- // this would only cause problem in speedy mode
5433
- // but we don't want enabling speedy to affect the observable behavior
5434
- // so we report this error at all times
5435
- console.error("You're attempting to insert the following rule:\n" + rule + '\n\n`@import` rules must be before all other types of rules in a stylesheet but other rules have already been inserted. Please ensure that `@import` rules are before all other rules.');
5436
- }
5437
- this._alreadyInsertedOrderInsensitiveRule = this._alreadyInsertedOrderInsensitiveRule || !isImportRule;
5438
- }
5439
-
5440
- if (this.isSpeedy) {
5441
- var sheet = sheetForTag(tag);
5442
-
5443
- try {
5444
- // this is the ultrafast version, works across browsers
5445
- // the big drawback is that the css won't be editable in devtools
5446
- sheet.insertRule(rule, sheet.cssRules.length);
5447
- } catch (e) {
5448
- if (process.env.NODE_ENV !== 'production' && !/:(-moz-placeholder|-moz-focus-inner|-moz-focusring|-ms-input-placeholder|-moz-read-write|-moz-read-only|-ms-clear|-ms-expand|-ms-reveal){/.test(rule)) {
5449
- console.error("There was a problem inserting the following rule: \"" + rule + "\"", e);
5450
- }
5451
- }
5452
- } else {
5453
- tag.appendChild(document.createTextNode(rule));
5454
- }
5455
-
5456
- this.ctr++;
5457
- };
5458
-
5459
- _proto.flush = function flush() {
5460
- // $FlowFixMe
5461
- this.tags.forEach(function (tag) {
5462
- return tag.parentNode && tag.parentNode.removeChild(tag);
5463
- });
5464
- this.tags = [];
5465
- this.ctr = 0;
5466
-
5467
- if (process.env.NODE_ENV !== 'production') {
5468
- this._alreadyInsertedOrderInsensitiveRule = false;
5469
- }
5470
- };
5471
-
5472
- return StyleSheet;
5473
- }();
5474
-
5475
- var MS = '-ms-';
5476
- var MOZ = '-moz-';
5477
- var WEBKIT = '-webkit-';
5478
-
5479
- var COMMENT = 'comm';
5480
- var RULESET = 'rule';
5481
- var DECLARATION = 'decl';
5482
- var IMPORT = '@import';
5483
- var KEYFRAMES = '@keyframes';
5484
- var LAYER = '@layer';
5485
-
5486
- /**
5487
- * @param {number}
5488
- * @return {number}
5489
- */
5490
- var abs = Math.abs;
5491
-
5492
- /**
5493
- * @param {number}
5494
- * @return {string}
5495
- */
5496
- var from = String.fromCharCode;
5497
-
5498
- /**
5499
- * @param {object}
5500
- * @return {object}
5501
- */
5502
- var assign = Object.assign;
5503
-
5504
- /**
5505
- * @param {string} value
5506
- * @param {number} length
5507
- * @return {number}
5508
- */
5509
- function hash (value, length) {
5510
- return charat(value, 0) ^ 45 ? (((((((length << 2) ^ charat(value, 0)) << 2) ^ charat(value, 1)) << 2) ^ charat(value, 2)) << 2) ^ charat(value, 3) : 0
5511
- }
5512
-
5513
- /**
5514
- * @param {string} value
5515
- * @return {string}
5516
- */
5517
- function trim (value) {
5518
- return value.trim()
5519
- }
5520
-
5521
- /**
5522
- * @param {string} value
5523
- * @param {RegExp} pattern
5524
- * @return {string?}
5525
- */
5526
- function match (value, pattern) {
5527
- return (value = pattern.exec(value)) ? value[0] : value
5528
- }
5529
-
5530
- /**
5531
- * @param {string} value
5532
- * @param {(string|RegExp)} pattern
5533
- * @param {string} replacement
5534
- * @return {string}
5535
- */
5536
- function replace (value, pattern, replacement) {
5537
- return value.replace(pattern, replacement)
5538
- }
5539
-
5540
- /**
5541
- * @param {string} value
5542
- * @param {string} search
5543
- * @return {number}
5544
- */
5545
- function indexof (value, search) {
5546
- return value.indexOf(search)
5547
- }
5548
-
5549
- /**
5550
- * @param {string} value
5551
- * @param {number} index
5552
- * @return {number}
4587
+ * @param {string} value
4588
+ * @param {number} index
4589
+ * @return {number}
5553
4590
  */
5554
4591
  function charat (value, index) {
5555
4592
  return value.charCodeAt(index) | 0
@@ -40402,11 +39439,11 @@ var CreatableSelect$1 = CreatableSelect;
40402
39439
  // Import React
40403
39440
  /* ------------- Actions ------------ */
40404
39441
  // Types of actions
40405
- var ActionType$2;
39442
+ var ActionType$4;
40406
39443
  (function (ActionType) {
40407
39444
  // Update the input value
40408
39445
  ActionType["SetInputValue"] = "SetInputValue";
40409
- })(ActionType$2 || (ActionType$2 = {}));
39446
+ })(ActionType$4 || (ActionType$4 = {}));
40410
39447
  /**
40411
39448
  * Reducer that executes actions
40412
39449
  * @author Yuen Ler Chow
@@ -40415,7 +39452,7 @@ var ActionType$2;
40415
39452
  */
40416
39453
  const reducer$2 = (state, action) => {
40417
39454
  switch (action.type) {
40418
- case ActionType$2.SetInputValue: {
39455
+ case ActionType$4.SetInputValue: {
40419
39456
  return Object.assign(Object.assign({}, state), { inputValue: action.value });
40420
39457
  }
40421
39458
  default: {
@@ -40506,7 +39543,7 @@ const CreatableMultiselect = (props) => {
40506
39543
  }
40507
39544
  // resets text field to empty because the values have been added
40508
39545
  dispatch({
40509
- type: ActionType$2.SetInputValue,
39546
+ type: ActionType$4.SetInputValue,
40510
39547
  value: '',
40511
39548
  });
40512
39549
  };
@@ -40545,7 +39582,7 @@ const CreatableMultiselect = (props) => {
40545
39582
  else {
40546
39583
  // simply update the input value to the new input value
40547
39584
  dispatch({
40548
- type: ActionType$2.SetInputValue,
39585
+ type: ActionType$4.SetInputValue,
40549
39586
  value: newValue,
40550
39587
  });
40551
39588
  }
@@ -40596,13 +39633,13 @@ const style = `
40596
39633
  `;
40597
39634
  /* ------------- Actions ------------ */
40598
39635
  // Types of actions
40599
- var ActionType$1;
39636
+ var ActionType$3;
40600
39637
  (function (ActionType) {
40601
39638
  // Update the DBEntry
40602
39639
  ActionType["UpdateDBEntry"] = "UpdateDBEntry";
40603
39640
  // Start the save spinner
40604
39641
  ActionType["StartSave"] = "StartSave";
40605
- })(ActionType$1 || (ActionType$1 = {}));
39642
+ })(ActionType$3 || (ActionType$3 = {}));
40606
39643
  /**
40607
39644
  * Reducer that executes actions
40608
39645
  * @author Yuen Ler Chow
@@ -40611,10 +39648,10 @@ var ActionType$1;
40611
39648
  */
40612
39649
  const reducer$1 = (state, action) => {
40613
39650
  switch (action.type) {
40614
- case ActionType$1.UpdateDBEntry: {
39651
+ case ActionType$3.UpdateDBEntry: {
40615
39652
  return Object.assign(Object.assign({}, state), { entry: action.dbEntry });
40616
39653
  }
40617
- case ActionType$1.StartSave: {
39654
+ case ActionType$3.StartSave: {
40618
39655
  return Object.assign(Object.assign({}, state), { saving: true });
40619
39656
  }
40620
39657
  default: {
@@ -40651,7 +39688,7 @@ const AddOrEditDBEntry = (props) => {
40651
39688
  */
40652
39689
  const save = () => __awaiter$1(void 0, void 0, void 0, function* () {
40653
39690
  // Start the save loading indicator
40654
- dispatch({ type: ActionType$1.StartSave });
39691
+ dispatch({ type: ActionType$3.StartSave });
40655
39692
  // add all default values to the entry
40656
39693
  entryFields.forEach((field) => {
40657
39694
  if (field.defaultValue && !entry[field.objectKey]) {
@@ -40812,7 +39849,7 @@ const AddOrEditDBEntry = (props) => {
40812
39849
  return (React__default.createElement(RadioButton, { key: choice.value, text: choice.title, selected: entry[field.objectKey] === choice.value, onSelected: () => {
40813
39850
  entry[field.objectKey] = choice.value;
40814
39851
  dispatch({
40815
- type: ActionType$1.UpdateDBEntry,
39852
+ type: ActionType$3.UpdateDBEntry,
40816
39853
  dbEntry: entry,
40817
39854
  });
40818
39855
  }, ariaLabel: choice.title }));
@@ -40824,7 +39861,7 @@ const AddOrEditDBEntry = (props) => {
40824
39861
  React__default.createElement("input", { disabled: disabled, type: "text", className: "form-control", placeholder: field.placeholder, "aria-describedby": "AddOrEditDBEntry-form-name-label", value: entry[field.objectKey] || '', onChange: (e) => {
40825
39862
  entry[field.objectKey] = (e.target.value);
40826
39863
  dispatch({
40827
- type: ActionType$1.UpdateDBEntry,
39864
+ type: ActionType$3.UpdateDBEntry,
40828
39865
  dbEntry: entry,
40829
39866
  });
40830
39867
  } }))));
@@ -40837,7 +39874,7 @@ const AddOrEditDBEntry = (props) => {
40837
39874
  entry[field.objectKey] = (e.target.value
40838
39875
  .replace(/[^0-9]/g, ''));
40839
39876
  dispatch({
40840
- type: ActionType$1.UpdateDBEntry,
39877
+ type: ActionType$3.UpdateDBEntry,
40841
39878
  dbEntry: entry,
40842
39879
  });
40843
39880
  } }))));
@@ -40867,7 +39904,7 @@ const AddOrEditDBEntry = (props) => {
40867
39904
  }
40868
39905
  // Save
40869
39906
  dispatch({
40870
- type: ActionType$1.UpdateDBEntry,
39907
+ type: ActionType$3.UpdateDBEntry,
40871
39908
  dbEntry: entry,
40872
39909
  });
40873
39910
  }, ariaLabel: choice.title }));
@@ -40882,7 +39919,7 @@ const AddOrEditDBEntry = (props) => {
40882
39919
  // Update entry and save
40883
39920
  entry[field.objectKey] = values;
40884
39921
  dispatch({
40885
- type: ActionType$1.UpdateDBEntry,
39922
+ type: ActionType$3.UpdateDBEntry,
40886
39923
  dbEntry: entry,
40887
39924
  });
40888
39925
  } })))));
@@ -40895,7 +39932,7 @@ const AddOrEditDBEntry = (props) => {
40895
39932
  React__default.createElement(CreatableMultiselect, { disabled: disabled, type: DBEntryFieldType$1.NumberArray, values: entry[field.objectKey] || [], onChange: (values) => {
40896
39933
  entry[field.objectKey] = values;
40897
39934
  dispatch({
40898
- type: ActionType$1.UpdateDBEntry,
39935
+ type: ActionType$3.UpdateDBEntry,
40899
39936
  dbEntry: entry,
40900
39937
  });
40901
39938
  } })))));
@@ -40950,6 +39987,7 @@ const AddOrEditDBEntry = (props) => {
40950
39987
  * @author Yuen Ler Chow
40951
39988
  * @param collectionName the name of the collection
40952
39989
  * @param [adminsOnly] true if the endpoint is for admins only
39990
+ * @returns the endpoint path
40953
39991
  */
40954
39992
  const generateEndpointPath = (collectionName, adminsOnly) => {
40955
39993
  // Determine prefix based on whether the endpoint is for admins only
@@ -40964,7 +40002,7 @@ const generateEndpointPath = (collectionName, adminsOnly) => {
40964
40002
  */
40965
40003
  /* ------------- Actions ------------ */
40966
40004
  // Types of actions
40967
- var ActionType;
40005
+ var ActionType$2;
40968
40006
  (function (ActionType) {
40969
40007
  // Show adder
40970
40008
  ActionType["ShowAdder"] = "ShowAdder";
@@ -40978,7 +40016,7 @@ var ActionType;
40978
40016
  ActionType["StartDelete"] = "StartDelete";
40979
40017
  // Finish deletion process
40980
40018
  ActionType["FinishDelete"] = "FinishDelete";
40981
- })(ActionType || (ActionType = {}));
40019
+ })(ActionType$2 || (ActionType$2 = {}));
40982
40020
  /**
40983
40021
  * Reducer that executes actions
40984
40022
  * @author Yuen Ler Chow
@@ -40987,16 +40025,16 @@ var ActionType;
40987
40025
  */
40988
40026
  const reducer = (state, action) => {
40989
40027
  switch (action.type) {
40990
- case ActionType.FinishLoading: {
40028
+ case ActionType$2.FinishLoading: {
40991
40029
  return Object.assign(Object.assign({}, state), { loading: false, dbEntries: action.dbEntries });
40992
40030
  }
40993
- case ActionType.ShowAdder: {
40031
+ case ActionType$2.ShowAdder: {
40994
40032
  return Object.assign(Object.assign({}, state), { adding: true, dbEntryToEdit: undefined });
40995
40033
  }
40996
- case ActionType.ShowEditor: {
40034
+ case ActionType$2.ShowEditor: {
40997
40035
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: action.dbEntry });
40998
40036
  }
40999
- case ActionType.FinishAdd: {
40037
+ case ActionType$2.FinishAdd: {
41000
40038
  // Handle cancel
41001
40039
  const finishedEntry = action.dbEntry;
41002
40040
  if (!finishedEntry) {
@@ -41020,10 +40058,10 @@ const reducer = (state, action) => {
41020
40058
  // Update the state
41021
40059
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: undefined, dbEntries: updatedDbEntries });
41022
40060
  }
41023
- case ActionType.StartDelete: {
40061
+ case ActionType$2.StartDelete: {
41024
40062
  return Object.assign(Object.assign({}, state), { loading: true });
41025
40063
  }
41026
- case ActionType.FinishDelete: {
40064
+ case ActionType$2.FinishDelete: {
41027
40065
  return Object.assign(Object.assign({}, state), { loading: false,
41028
40066
  // Remove the deleted entry from the list
41029
40067
  dbEntries: state.dbEntries.filter((entry) => {
@@ -41075,22 +40113,22 @@ const DBEntryManagerPanel = (props) => {
41075
40113
  try {
41076
40114
  // Start loader
41077
40115
  dispatch({
41078
- type: ActionType.StartDelete,
40116
+ type: ActionType$2.StartDelete,
41079
40117
  });
41080
40118
  // Perform deletion
41081
- yield visitServerEndpoint$1({
40119
+ yield visitServerEndpoint({
41082
40120
  path: `${endpoint}/${entry[idPropName]}`,
41083
40121
  method: 'DELETE',
41084
40122
  });
41085
40123
  // Finish loader
41086
40124
  dispatch({
41087
- type: ActionType.FinishDelete,
40125
+ type: ActionType$2.FinishDelete,
41088
40126
  dbEntry: entry,
41089
40127
  idPropName,
41090
40128
  });
41091
40129
  }
41092
40130
  catch (err) {
41093
- return showFatalError$1(err);
40131
+ return showFatalError(err);
41094
40132
  }
41095
40133
  });
41096
40134
  /*------------------------------------------------------------------------*/
@@ -41104,7 +40142,7 @@ const DBEntryManagerPanel = (props) => {
41104
40142
  (() => __awaiter$1(void 0, void 0, void 0, function* () {
41105
40143
  // Load list of database entries
41106
40144
  try {
41107
- const data = yield visitServerEndpoint$1({
40145
+ const data = yield visitServerEndpoint({
41108
40146
  path: endpoint,
41109
40147
  method: 'GET',
41110
40148
  params: {
@@ -41113,12 +40151,12 @@ const DBEntryManagerPanel = (props) => {
41113
40151
  });
41114
40152
  // Save loaded data
41115
40153
  dispatch({
41116
- type: ActionType.FinishLoading,
40154
+ type: ActionType$2.FinishLoading,
41117
40155
  dbEntries: data,
41118
40156
  });
41119
40157
  }
41120
40158
  catch (err) {
41121
- return showFatalError$1(err);
40159
+ return showFatalError(err);
41122
40160
  }
41123
40161
  }))();
41124
40162
  }, []);
@@ -41131,7 +40169,7 @@ const DBEntryManagerPanel = (props) => {
41131
40169
  let body;
41132
40170
  /* ------------- Loading ------------ */
41133
40171
  if (loading) {
41134
- body = (React__default.createElement(LoadingSpinner$1, null));
40172
+ body = (React__default.createElement(LoadingSpinner, null));
41135
40173
  }
41136
40174
  /* ------------- List of entries ------------ */
41137
40175
  if (!loading && !adding && !dbEntryToEdit) {
@@ -41156,7 +40194,7 @@ const DBEntryManagerPanel = (props) => {
41156
40194
  React__default.createElement("span", { className: "d-none d-md-inline ms-1" }, "Remove")),
41157
40195
  !disableEdit && (React__default.createElement("button", { type: "button", id: `DBEntryManagerPanel-edit-with-id-${entry[idPropName]}`, className: "btn btn-primary", "aria-label": `edit db entry: ${entry[titlePropName]}`, onClick: () => {
41158
40196
  dispatch({
41159
- type: ActionType.ShowEditor,
40197
+ type: ActionType$2.ShowEditor,
41160
40198
  dbEntry: entry,
41161
40199
  });
41162
40200
  } },
@@ -41166,7 +40204,7 @@ const DBEntryManagerPanel = (props) => {
41166
40204
  React__default.createElement("div", { className: "d-grid" },
41167
40205
  React__default.createElement("button", { type: "button", id: "DBEntryManagerPanel-add-entry", className: "btn btn-lg btn-primary", "aria-label": `add a new ${itemName} entry to the list of entries`, onClick: () => {
41168
40206
  dispatch({
41169
- type: ActionType.ShowAdder,
40207
+ type: ActionType$2.ShowAdder,
41170
40208
  });
41171
40209
  } },
41172
40210
  React__default.createElement(FontAwesomeIcon, { icon: faPlus, className: "me-2" }),
@@ -41178,7 +40216,7 @@ const DBEntryManagerPanel = (props) => {
41178
40216
  if (!loading && (adding || dbEntryToEdit)) {
41179
40217
  body = (React__default.createElement(AddOrEditDBEntry, { saveEndpointPath: endpoint, validateEntry: validateEntry, modifyEntry: modifyEntry, entryFields: entryFields, dbEntryToEdit: dbEntryToEdit, idPropName: idPropName, entries: dbEntries, onFinished: (entry) => {
41180
40218
  dispatch({
41181
- type: ActionType.FinishAdd,
40219
+ type: ActionType$2.FinishAdd,
41182
40220
  dbEntry: entry,
41183
40221
  idPropName,
41184
40222
  });
@@ -41401,7 +40439,7 @@ const padZerosLeft = (num, numDigits) => {
41401
40439
  const LOG_REVIEW_STATUS_ROUTE = `${ROUTE_PATH_PREFIX}/logs/access_allowed`;
41402
40440
 
41403
40441
  // Stored copy of caccl functions
41404
- let _cacclGetLaunchInfo;
40442
+ let _cacclGetLaunchInfo$1;
41405
40443
  // Stored copy of dce-mango log collection
41406
40444
  let _logCollection;
41407
40445
  /*------------------------------------------------------------------------*/
@@ -41413,11 +40451,11 @@ let _logCollection;
41413
40451
  * @param req express request object
41414
40452
  * @returns object { launched, launchInfo }
41415
40453
  */
41416
- const cacclGetLaunchInfo = (req) => {
41417
- if (!_cacclGetLaunchInfo) {
40454
+ const cacclGetLaunchInfo$1 = (req) => {
40455
+ if (!_cacclGetLaunchInfo$1) {
41418
40456
  throw new ErrorWithCode$1('Could not get launch info because server was not initialized with dce-reactkit\'s initServer function', ReactKitErrorCode$3.NoCACCLGetLaunchInfoFunction);
41419
40457
  }
41420
- return _cacclGetLaunchInfo(req);
40458
+ return _cacclGetLaunchInfo$1(req);
41421
40459
  };
41422
40460
  /**
41423
40461
  * Get log collection
@@ -41449,7 +40487,7 @@ const internalGetLogCollection = () => {
41449
40487
  * to review logs
41450
40488
  */
41451
40489
  const initServer = (opts) => {
41452
- _cacclGetLaunchInfo = opts.getLaunchInfo;
40490
+ _cacclGetLaunchInfo$1 = opts.getLaunchInfo;
41453
40491
  _logCollection = opts.logCollection;
41454
40492
  /*----------------------------------------*/
41455
40493
  /* Logging */
@@ -41473,7 +40511,7 @@ const initServer = (opts) => {
41473
40511
  * @param {LogAction} [action] the type of action performed on the target
41474
40512
  * @returns {Log}
41475
40513
  */
41476
- opts.app.post(LOG_ROUTE_PATH, genRouteHandler({
40514
+ opts.app.post(LOG_ROUTE_PATH, genRouteHandler$1({
41477
40515
  paramTypes: {
41478
40516
  context: ParamType$3.String,
41479
40517
  subcontext: ParamType$3.String,
@@ -41562,7 +40600,7 @@ const initServer = (opts) => {
41562
40600
  * @author Gabe Abrams
41563
40601
  * @returns {boolean} true if user has access
41564
40602
  */
41565
- opts.app.get(LOG_REVIEW_STATUS_ROUTE, genRouteHandler({
40603
+ opts.app.get(LOG_REVIEW_STATUS_ROUTE, genRouteHandler$1({
41566
40604
  handler: ({ params }) => __awaiter$1(void 0, void 0, void 0, function* () {
41567
40605
  const { userId, isAdmin } = params;
41568
40606
  const canReview = yield canReviewLogs(userId, isAdmin);
@@ -41576,7 +40614,7 @@ const initServer = (opts) => {
41576
40614
  * @param {number} month the month to query (e.g. 1 = January)
41577
40615
  * @returns {Log[]} list of logs from the given month
41578
40616
  */
41579
- opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler({
40617
+ opts.app.get(`${LOG_REVIEW_ROUTE_PATH_PREFIX}/years/:year/months/:month`, genRouteHandler$1({
41580
40618
  paramTypes: {
41581
40619
  year: ParamType$3.Int,
41582
40620
  month: ParamType$3.Int,
@@ -41613,7 +40651,7 @@ const initServer = (opts) => {
41613
40651
  * @param [opts.status=500] the https status code to use
41614
40652
  * defined)
41615
40653
  */
41616
- const handleError = (res, error) => {
40654
+ const handleError$1 = (res, error) => {
41617
40655
  // Get the error message
41618
40656
  let message;
41619
40657
  if (error && error.message) {
@@ -41653,7 +40691,7 @@ const handleError = (res, error) => {
41653
40691
  * @param res express response
41654
40692
  * @param body the body of the response to send to the client
41655
40693
  */
41656
- const handleSuccess = (res, body) => {
40694
+ const handleSuccess$1 = (res, body) => {
41657
40695
  // Send a http 200 json response
41658
40696
  res.json({
41659
40697
  // Include the body as a parameter
@@ -41919,7 +40957,7 @@ const parseUserAgent = (userAgent) => {
41919
40957
  * userLastName, isLearner, isTTM, isAdmin, and any other variables that
41920
40958
  * are directly added to the session, if the user does have a session.
41921
40959
  */
41922
- const genRouteHandler = (opts) => {
40960
+ const genRouteHandler$1 = (opts) => {
41923
40961
  // Return a route handler
41924
40962
  return (req, res, next) => __awaiter$1(void 0, void 0, void 0, function* () {
41925
40963
  var _a, _b;
@@ -41945,7 +40983,7 @@ const genRouteHandler = (opts) => {
41945
40983
  output[name] = undefined;
41946
40984
  }
41947
40985
  else {
41948
- return handleError(res, {
40986
+ return handleError$1(res, {
41949
40987
  message: `Parameter ${name} is required, but it was not included.`,
41950
40988
  code: ReactKitErrorCode$3.MissingParameter,
41951
40989
  status: 422,
@@ -41976,7 +41014,7 @@ const genRouteHandler = (opts) => {
41976
41014
  output[name] = undefined;
41977
41015
  }
41978
41016
  else {
41979
- return handleError(res, {
41017
+ return handleError$1(res, {
41980
41018
  message: `Parameter ${name} is required, but it was not included.`,
41981
41019
  code: ReactKitErrorCode$3.MissingParameter,
41982
41020
  status: 422,
@@ -41989,7 +41027,7 @@ const genRouteHandler = (opts) => {
41989
41027
  }
41990
41028
  else {
41991
41029
  // Issue!
41992
- return handleError(res, {
41030
+ return handleError$1(res, {
41993
41031
  message: `Request data was malformed: ${name} was not a valid float.`,
41994
41032
  code: ReactKitErrorCode$3.InvalidParameter,
41995
41033
  status: 422,
@@ -42004,7 +41042,7 @@ const genRouteHandler = (opts) => {
42004
41042
  output[name] = undefined;
42005
41043
  }
42006
41044
  else {
42007
- return handleError(res, {
41045
+ return handleError$1(res, {
42008
41046
  message: `Parameter ${name} is required, but it was not included.`,
42009
41047
  code: ReactKitErrorCode$3.MissingParameter,
42010
41048
  status: 422,
@@ -42017,7 +41055,7 @@ const genRouteHandler = (opts) => {
42017
41055
  }
42018
41056
  else {
42019
41057
  // Issue!
42020
- return handleError(res, {
41058
+ return handleError$1(res, {
42021
41059
  message: `Request data was malformed: ${name} was not a valid int.`,
42022
41060
  code: ReactKitErrorCode$3.InvalidParameter,
42023
41061
  status: 422,
@@ -42032,7 +41070,7 @@ const genRouteHandler = (opts) => {
42032
41070
  output[name] = undefined;
42033
41071
  }
42034
41072
  else {
42035
- return handleError(res, {
41073
+ return handleError$1(res, {
42036
41074
  message: `Parameter ${name} is required, but it was not included.`,
42037
41075
  code: ReactKitErrorCode$3.MissingParameter,
42038
41076
  status: 422,
@@ -42046,7 +41084,7 @@ const genRouteHandler = (opts) => {
42046
41084
  output[name] = JSON.parse(String(value));
42047
41085
  }
42048
41086
  catch (err) {
42049
- return handleError(res, {
41087
+ return handleError$1(res, {
42050
41088
  message: `Request data was malformed: ${name} was not a valid JSON payload.`,
42051
41089
  code: ReactKitErrorCode$3.InvalidParameter,
42052
41090
  status: 422,
@@ -42062,7 +41100,7 @@ const genRouteHandler = (opts) => {
42062
41100
  output[name] = undefined;
42063
41101
  }
42064
41102
  else {
42065
- return handleError(res, {
41103
+ return handleError$1(res, {
42066
41104
  message: `Parameter ${name} is required, but it was not included.`,
42067
41105
  code: ReactKitErrorCode$3.MissingParameter,
42068
41106
  status: 422,
@@ -42077,7 +41115,7 @@ const genRouteHandler = (opts) => {
42077
41115
  }
42078
41116
  else {
42079
41117
  // No valid data type
42080
- return handleError(res, {
41118
+ return handleError$1(res, {
42081
41119
  message: `An internal error occurred: we could not determine the type of ${name}.`,
42082
41120
  code: ReactKitErrorCode$3.InvalidParameter,
42083
41121
  status: 422,
@@ -42088,13 +41126,13 @@ const genRouteHandler = (opts) => {
42088
41126
  /* Launch Info */
42089
41127
  /*----------------------------------------*/
42090
41128
  // Get launch info
42091
- const { launched, launchInfo } = cacclGetLaunchInfo(req);
41129
+ const { launched, launchInfo } = cacclGetLaunchInfo$1(req);
42092
41130
  if (
42093
41131
  // Not launched
42094
41132
  (!launched || !launchInfo)
42095
41133
  // Not skipping the session check
42096
41134
  && !opts.skipSessionCheck) {
42097
- return handleError(res, {
41135
+ return handleError$1(res, {
42098
41136
  message: 'Your session has expired. Please refresh the page and try again.',
42099
41137
  code: ReactKitErrorCode$3.SessionExpired,
42100
41138
  status: 401,
@@ -42114,7 +41152,7 @@ const genRouteHandler = (opts) => {
42114
41152
  && !launchInfo.isAdmin))
42115
41153
  // Not skipping the session check
42116
41154
  && !opts.skipSessionCheck) {
42117
- return handleError(res, {
41155
+ return handleError$1(res, {
42118
41156
  message: 'Your session was invalid. Please refresh the page and try again.',
42119
41157
  code: ReactKitErrorCode$3.SessionExpired,
42120
41158
  status: 401,
@@ -42173,7 +41211,7 @@ const genRouteHandler = (opts) => {
42173
41211
  && !output.isTTM
42174
41212
  && !output.isAdmin) {
42175
41213
  // Course of interest is not the launch course
42176
- return handleError(res, {
41214
+ return handleError$1(res, {
42177
41215
  message: 'You switched sessions by opening this app in another tab. Please refresh the page and try again.',
42178
41216
  code: ReactKitErrorCode$3.WrongCourse,
42179
41217
  status: 401,
@@ -42193,7 +41231,7 @@ const genRouteHandler = (opts) => {
42193
41231
  // User is not an admin
42194
41232
  && !output.isAdmin)) {
42195
41233
  // User does not have access
42196
- return handleError(res, {
41234
+ return handleError$1(res, {
42197
41235
  message: 'This action is only allowed if you are a teaching team member for the course. Please go back to Canvas, log in as a teaching team member, and try again.',
42198
41236
  code: ReactKitErrorCode$3.NotTTM,
42199
41237
  status: 401,
@@ -42206,7 +41244,7 @@ const genRouteHandler = (opts) => {
42206
41244
  // User is not an admin
42207
41245
  && !output.isAdmin) {
42208
41246
  // User does not have access
42209
- return handleError(res, {
41247
+ return handleError$1(res, {
42210
41248
  message: 'This action is only allowed if you are a Canvas admin. Please go back to Canvas, log in as an admin, and try again.',
42211
41249
  code: ReactKitErrorCode$3.NotAdmin,
42212
41250
  status: 401,
@@ -42424,13 +41462,13 @@ const genRouteHandler = (opts) => {
42424
41462
  });
42425
41463
  // Send results to client (only if next wasn't called)
42426
41464
  if (!responseSent) {
42427
- return handleSuccess(res, results !== null && results !== void 0 ? results : undefined);
41465
+ return handleSuccess$1(res, results !== null && results !== void 0 ? results : undefined);
42428
41466
  }
42429
41467
  }
42430
41468
  catch (err) {
42431
41469
  // Send error to client (only if next wasn't called)
42432
41470
  if (!responseSent) {
42433
- handleError(res, err);
41471
+ handleError$1(res, err);
42434
41472
  // Log server-side error
42435
41473
  logServerEvent({
42436
41474
  context: LogBuiltInMetadata.Context.ServerEndpointError,
@@ -42596,143 +41634,786 @@ const parallelLimit = (taskFunctions, limit) => __awaiter$1(void 0, void 0, void
42596
41634
  });
42597
41635
 
42598
41636
  /**
42599
- * Initialize a log collection given the dce-mango Collection class
41637
+ * Initialize a log collection given the dce-mango Collection class
41638
+ * @author Gabe Abrams
41639
+ * @param Collection the Collection class from dce-mango
41640
+ * @returns initialized logCollection
41641
+ */
41642
+ const initLogCollection = (Collection) => {
41643
+ return new Collection('Log', {
41644
+ uniqueIndexKey: 'id',
41645
+ indexKeys: [
41646
+ 'courseId',
41647
+ 'context',
41648
+ 'subcontext',
41649
+ 'tags',
41650
+ ],
41651
+ });
41652
+ };
41653
+
41654
+ // Cache user's ability
41655
+ let canReview = undefined;
41656
+ /**
41657
+ * Check if the current user can review logs
41658
+ * @author Gabe Abrams
41659
+ * @returns true if current user can review logs
41660
+ */
41661
+ const canReviewLogs = () => __awaiter$1(void 0, void 0, void 0, function* () {
41662
+ // If cached, use that value
41663
+ if (canReview !== undefined) {
41664
+ return canReview;
41665
+ }
41666
+ // Ask on server
41667
+ try {
41668
+ canReview = !!(yield visitServerEndpoint({
41669
+ path: LOG_REVIEW_STATUS_ROUTE,
41670
+ method: 'GET',
41671
+ }));
41672
+ }
41673
+ catch (err) {
41674
+ canReview = false;
41675
+ }
41676
+ return canReview;
41677
+ });
41678
+
41679
+ /**
41680
+ * For every element in an array, extract the value of a prop
41681
+ * (e.g. for all user objects, extract their ages and put that into a new
41682
+ * ages array)
41683
+ * @author Gabe Abrams
41684
+ * @param arr the array of objects to operate on
41685
+ * @param prop the property to extract from each object
41686
+ * @returns new array containing the corresponding values, in order, of each
41687
+ * object in the original array
41688
+ */
41689
+ const extractProp = (arr, prop) => {
41690
+ return arr.map((item) => {
41691
+ return item[prop];
41692
+ });
41693
+ };
41694
+
41695
+ // Import shared helpers
41696
+ /**
41697
+ * Compare two arrays of objects by only comparing the values in a specific
41698
+ * property (e.g. compare user arrays by comparing their user.id values)
41699
+ * @author Gabe Abrams
41700
+ * @param a the first array
41701
+ * @param b the second array
41702
+ * @param prop the property to compare with
41703
+ * @returns true if the arrays contain the same objects as determined by
41704
+ * the values associated with each object's prop
41705
+ */
41706
+ const compareArraysByProp = (a, b, prop) => {
41707
+ // Extract values for comparison
41708
+ const aVals = new Set(extractProp(a, prop));
41709
+ const bVals = new Set(extractProp(b, prop));
41710
+ // Compare sizes first
41711
+ if (aVals.size !== bVals.size) {
41712
+ return false;
41713
+ }
41714
+ // Same number of items. Make sure every object in aVals appears in bVals
41715
+ // (if so, they should be equivalent since the sizes are the same)
41716
+ // > Create map of items in bVals
41717
+ const inBVals = {}; // item => true if in bVals
41718
+ Array.from(bVals.values()).forEach((item) => {
41719
+ inBVals[item] = true;
41720
+ });
41721
+ // > Loop through aVals and make sure every item is in bVals
41722
+ return Array.from(aVals.values()).every((item) => {
41723
+ return inBVals[item];
41724
+ });
41725
+ };
41726
+
41727
+ /**
41728
+ * Get current time info in local time
41729
+ * @author Gabe Abrams
41730
+ * @param [dateOrTimestamp=now] the date to get info on or a ms since epoch timestamp
41731
+ * @returns object with timestamp (ms since epoch) and numbers
41732
+ * corresponding to time values for year, month, day, hour, hour12, minute, isPM
41733
+ * where hour is in 24hr time and hour12 is in 12hr time.
41734
+ */
41735
+ const getLocalTimeInfo = (dateOrTimestamp) => {
41736
+ // Create a time string
41737
+ let d;
41738
+ if (!dateOrTimestamp) {
41739
+ // Use now
41740
+ d = new Date();
41741
+ }
41742
+ else if (typeof dateOrTimestamp === 'number') {
41743
+ // Convert to date
41744
+ d = new Date(dateOrTimestamp);
41745
+ }
41746
+ else {
41747
+ // Already a date
41748
+ d = dateOrTimestamp;
41749
+ }
41750
+ // Create all time numbers
41751
+ const timestamp = d.getTime();
41752
+ const year = d.getFullYear();
41753
+ const month = d.getMonth() + 1;
41754
+ const day = d.getDate();
41755
+ const hour = d.getHours();
41756
+ const isPM = hour >= 12;
41757
+ let hour12 = hour % 12;
41758
+ if (hour12 === 0) {
41759
+ hour12 = 12;
41760
+ }
41761
+ const minute = d.getMinutes();
41762
+ // Return
41763
+ return {
41764
+ timestamp,
41765
+ year,
41766
+ month,
41767
+ day,
41768
+ hour,
41769
+ hour12,
41770
+ isPM,
41771
+ minute,
41772
+ };
41773
+ };
41774
+
41775
+ /******************************************************************************
41776
+ Copyright (c) Microsoft Corporation.
41777
+
41778
+ Permission to use, copy, modify, and/or distribute this software for any
41779
+ purpose with or without fee is hereby granted.
41780
+
41781
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
41782
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
41783
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
41784
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41785
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
41786
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41787
+ PERFORMANCE OF THIS SOFTWARE.
41788
+ ***************************************************************************** */
41789
+
41790
+ function __awaiter(thisArg, _arguments, P, generator) {
41791
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
41792
+ return new (P || (P = Promise))(function (resolve, reject) {
41793
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
41794
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41795
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41796
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
41797
+ });
41798
+ }
41799
+
41800
+ // Highest error code = DRK10
41801
+ /**
41802
+ * List of error codes built into the react kit
41803
+ * @author Gabe Abrams
41804
+ */
41805
+ var ReactKitErrorCode;
41806
+ (function (ReactKitErrorCode) {
41807
+ ReactKitErrorCode["NoResponse"] = "DRK1";
41808
+ ReactKitErrorCode["NoCode"] = "DRK2";
41809
+ ReactKitErrorCode["SessionExpired"] = "DRK3";
41810
+ ReactKitErrorCode["MissingParameter"] = "DRK4";
41811
+ ReactKitErrorCode["InvalidParameter"] = "DRK5";
41812
+ ReactKitErrorCode["WrongCourse"] = "DRK6";
41813
+ ReactKitErrorCode["NoCACCLSendRequestFunction"] = "DRK7";
41814
+ ReactKitErrorCode["NoCACCLGetLaunchInfoFunction"] = "DRK8";
41815
+ ReactKitErrorCode["NotTTM"] = "DRK9";
41816
+ ReactKitErrorCode["NotAdmin"] = "DRK10";
41817
+ })(ReactKitErrorCode || (ReactKitErrorCode = {}));
41818
+ var ReactKitErrorCode$1 = ReactKitErrorCode;
41819
+
41820
+ /**
41821
+ * Types of buttons in the modal
41822
+ * @author Gabe Abrams
41823
+ */
41824
+ var ModalButtonType;
41825
+ (function (ModalButtonType) {
41826
+ ModalButtonType["Okay"] = "okay";
41827
+ ModalButtonType["Cancel"] = "cancel";
41828
+ ModalButtonType["Yes"] = "yes";
41829
+ ModalButtonType["No"] = "no";
41830
+ ModalButtonType["Abandon"] = "abandon";
41831
+ ModalButtonType["GoBack"] = "goBack";
41832
+ ModalButtonType["Continue"] = "continue";
41833
+ ModalButtonType["ImSure"] = "imSure";
41834
+ ModalButtonType["Delete"] = "delete";
41835
+ ModalButtonType["Confirm"] = "confirm";
41836
+ })(ModalButtonType || (ModalButtonType = {}));
41837
+ var ModalButtonType$1 = ModalButtonType;
41838
+
41839
+ /**
41840
+ * Types of modals
41841
+ * @author Gabe Abrams
41842
+ */
41843
+ var ModalType;
41844
+ (function (ModalType) {
41845
+ ModalType["Okay"] = "okay";
41846
+ ModalType["OkayCancel"] = "okay-cancel";
41847
+ ModalType["YesNo"] = "yes-no";
41848
+ ModalType["YesNoCancel"] = "yes-no-cancel";
41849
+ ModalType["AbandonGoBack"] = "abandon-goBack";
41850
+ ModalType["ImSureCancel"] = "imSure-cancel";
41851
+ ModalType["DeleteCancel"] = "delete-cancel";
41852
+ ModalType["ConfirmCancel"] = "confirm-cancel";
41853
+ ModalType["NoButtons"] = "-";
41854
+ })(ModalType || (ModalType = {}));
41855
+ var ModalType$1 = ModalType;
41856
+
41857
+ /**
41858
+ * Bootstrap variants
41859
+ * @author Gabe Abrams
41860
+ */
41861
+ var Variant;
41862
+ (function (Variant) {
41863
+ Variant["Primary"] = "primary";
41864
+ Variant["Secondary"] = "secondary";
41865
+ Variant["Success"] = "success";
41866
+ Variant["Warning"] = "warning";
41867
+ Variant["Info"] = "info";
41868
+ Variant["Danger"] = "danger";
41869
+ Variant["Light"] = "light";
41870
+ Variant["Dark"] = "dark";
41871
+ })(Variant || (Variant = {}));
41872
+ var Variant$1 = Variant;
41873
+
41874
+ /**
41875
+ * Modal sizes
41876
+ * @author Gabe Abrams
41877
+ */
41878
+ var ModalSize;
41879
+ (function (ModalSize) {
41880
+ ModalSize["Small"] = "sm";
41881
+ ModalSize["Medium"] = "md";
41882
+ ModalSize["Large"] = "lg";
41883
+ ModalSize["ExtraLarge"] = "xl";
41884
+ })(ModalSize || (ModalSize = {}));
41885
+ // Modal type to list of buttons
41886
+ ({
41887
+ [ModalType$1.Okay]: [
41888
+ ModalButtonType$1.Okay,
41889
+ ],
41890
+ [ModalType$1.OkayCancel]: [
41891
+ ModalButtonType$1.Okay,
41892
+ ModalButtonType$1.Cancel,
41893
+ ],
41894
+ [ModalType$1.YesNo]: [
41895
+ ModalButtonType$1.Yes,
41896
+ ModalButtonType$1.No,
41897
+ ],
41898
+ [ModalType$1.YesNoCancel]: [
41899
+ ModalButtonType$1.Yes,
41900
+ ModalButtonType$1.No,
41901
+ ModalButtonType$1.Cancel,
41902
+ ],
41903
+ [ModalType$1.AbandonGoBack]: [
41904
+ ModalButtonType$1.Abandon,
41905
+ ModalButtonType$1.GoBack,
41906
+ ],
41907
+ [ModalType$1.ImSureCancel]: [
41908
+ ModalButtonType$1.ImSure,
41909
+ ModalButtonType$1.Cancel,
41910
+ ],
41911
+ [ModalType$1.DeleteCancel]: [
41912
+ ModalButtonType$1.Delete,
41913
+ ModalButtonType$1.Cancel,
41914
+ ],
41915
+ [ModalType$1.ConfirmCancel]: [
41916
+ ModalButtonType$1.Confirm,
41917
+ ModalButtonType$1.Cancel,
41918
+ ],
41919
+ });
41920
+ // Button type styling and labels
41921
+ ({
41922
+ [ModalButtonType$1.Okay]: {
41923
+ label: 'Okay',
41924
+ variant: Variant$1.Dark,
41925
+ },
41926
+ [ModalButtonType$1.Cancel]: {
41927
+ label: 'Cancel',
41928
+ variant: Variant$1.Secondary,
41929
+ },
41930
+ [ModalButtonType$1.Yes]: {
41931
+ label: 'Yes',
41932
+ variant: Variant$1.Dark,
41933
+ },
41934
+ [ModalButtonType$1.No]: {
41935
+ label: 'No',
41936
+ variant: Variant$1.Secondary,
41937
+ },
41938
+ [ModalButtonType$1.Abandon]: {
41939
+ label: 'Abandon Changes',
41940
+ variant: Variant$1.Warning,
41941
+ },
41942
+ [ModalButtonType$1.GoBack]: {
41943
+ label: 'Go Back',
41944
+ variant: Variant$1.Secondary,
41945
+ },
41946
+ [ModalButtonType$1.Continue]: {
41947
+ label: 'Continue',
41948
+ variant: Variant$1.Dark,
41949
+ },
41950
+ [ModalButtonType$1.ImSure]: {
41951
+ label: 'I am sure',
41952
+ variant: Variant$1.Warning,
41953
+ },
41954
+ [ModalButtonType$1.Delete]: {
41955
+ label: 'Yes, Delete',
41956
+ variant: Variant$1.Danger,
41957
+ },
41958
+ [ModalButtonType$1.Confirm]: {
41959
+ label: 'Confirm',
41960
+ variant: Variant$1.Dark,
41961
+ },
41962
+ });
41963
+
41964
+ /**
41965
+ * An error with a code
41966
+ * @author Gabe Abrams
41967
+ */
41968
+ class ErrorWithCode extends Error {
41969
+ constructor(message, code) {
41970
+ super(message);
41971
+ this.name = 'ErrorWithCode';
41972
+ this.code = code;
41973
+ }
41974
+ }
41975
+
41976
+ /**
41977
+ * Copiable text box
41978
+ * @author Gabe Abrams
41979
+ */
41980
+ /* ------------- Actions ------------ */
41981
+ // Types of actions
41982
+ var ActionType$1;
41983
+ (function (ActionType) {
41984
+ // Indicate that the text was recently copied
41985
+ ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
41986
+ // Clear the status
41987
+ ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
41988
+ })(ActionType$1 || (ActionType$1 = {}));
41989
+
41990
+ /**
41991
+ * Reusable nested item picker
41992
+ * @author Yuen Ler Chow
41993
+ */
41994
+ /* ------------- Actions ------------ */
41995
+ // Types of actions
41996
+ var ActionType;
41997
+ (function (ActionType) {
41998
+ // Toggle whether the children are being shown
41999
+ ActionType["ToggleItems"] = "toggle-items";
42000
+ })(ActionType || (ActionType = {}));
42001
+
42002
+ // Import custom error
42003
+ // Stored copy of caccl functions
42004
+ let _cacclGetLaunchInfo;
42005
+ /*------------------------------------------------------------------------*/
42006
+ /* Helpers */
42007
+ /*------------------------------------------------------------------------*/
42008
+ /**
42009
+ * Get launch info via CACCL
42600
42010
  * @author Gabe Abrams
42601
- * @param Collection the Collection class from dce-mango
42602
- * @returns initialized logCollection
42011
+ * @param req express request object
42012
+ * @returns object { launched, launchInfo }
42603
42013
  */
42604
- const initLogCollection = (Collection) => {
42605
- return new Collection('Log', {
42606
- uniqueIndexKey: 'id',
42607
- indexKeys: [
42608
- 'courseId',
42609
- 'context',
42610
- 'subcontext',
42611
- 'tags',
42612
- ],
42613
- });
42014
+ const cacclGetLaunchInfo = (req) => {
42015
+ {
42016
+ throw new ErrorWithCode('Could not get launch info because server was not initialized with dce-reactkit\'s initServer function', ReactKitErrorCode$1.NoCACCLGetLaunchInfoFunction);
42017
+ }
42614
42018
  };
42615
42019
 
42616
- // Cache user's ability
42617
- let canReview = undefined;
42618
42020
  /**
42619
- * Check if the current user can review logs
42021
+ * Server-side API param types
42620
42022
  * @author Gabe Abrams
42621
- * @returns true if current user can review logs
42622
42023
  */
42623
- const canReviewLogs = () => __awaiter$1(void 0, void 0, void 0, function* () {
42624
- // If cached, use that value
42625
- if (canReview !== undefined) {
42626
- return canReview;
42024
+ var ParamType;
42025
+ (function (ParamType) {
42026
+ ParamType["Boolean"] = "boolean";
42027
+ ParamType["BooleanOptional"] = "boolean-optional";
42028
+ ParamType["Float"] = "float";
42029
+ ParamType["FloatOptional"] = "float-optional";
42030
+ ParamType["Int"] = "int";
42031
+ ParamType["IntOptional"] = "int-optional";
42032
+ ParamType["JSON"] = "json";
42033
+ ParamType["JSONOptional"] = "json-optional";
42034
+ ParamType["String"] = "string";
42035
+ ParamType["StringOptional"] = "string-optional";
42036
+ })(ParamType || (ParamType = {}));
42037
+ var ParamType$1 = ParamType;
42038
+
42039
+ // Import shared types
42040
+ /**
42041
+ * Handle an error and respond to the client
42042
+ * @author Gabe Abrams
42043
+ * @param res express response
42044
+ * @param error error info
42045
+ * @param opts.err the error to send to the client
42046
+ * or the error message
42047
+ * @param [opts.code] an error code (only used if err.code is not
42048
+ * included)
42049
+ * @param [opts.status=500] the https status code to use
42050
+ * defined)
42051
+ */
42052
+ const handleError = (res, error) => {
42053
+ // Get the error message
42054
+ let message;
42055
+ if (error && error.message) {
42056
+ message = (error.message || 'An unknown error occurred.');
42627
42057
  }
42628
- // Ask on server
42629
- try {
42630
- canReview = !!(yield visitServerEndpoint$1({
42631
- path: LOG_REVIEW_STATUS_ROUTE,
42632
- method: 'GET',
42633
- }));
42058
+ else if (typeof error === 'string') {
42059
+ message = (error.trim().length > 0
42060
+ ? error
42061
+ : 'An unknown error occurred.');
42634
42062
  }
42635
- catch (err) {
42636
- canReview = false;
42063
+ else {
42064
+ message = 'An unknown error occurred.';
42637
42065
  }
42638
- return canReview;
42639
- });
42066
+ // Get the error code
42067
+ const code = (error.code || ReactKitErrorCode$1.NoCode);
42068
+ // Get the status code
42069
+ const status = (error.status || 500);
42070
+ // Respond to user
42071
+ res
42072
+ // Set the http status code
42073
+ .status(status)
42074
+ // Send a JSON response
42075
+ .json({
42076
+ // Error message
42077
+ message,
42078
+ // Error code
42079
+ code,
42080
+ // Success = false flag so client can detect server-side errors
42081
+ success: false,
42082
+ });
42083
+ return undefined;
42084
+ };
42640
42085
 
42641
42086
  /**
42642
- * For every element in an array, extract the value of a prop
42643
- * (e.g. for all user objects, extract their ages and put that into a new
42644
- * ages array)
42087
+ * Send successful API response
42645
42088
  * @author Gabe Abrams
42646
- * @param arr the array of objects to operate on
42647
- * @param prop the property to extract from each object
42648
- * @returns new array containing the corresponding values, in order, of each
42649
- * object in the original array
42089
+ * @param res express response
42090
+ * @param body the body of the response to send to the client
42650
42091
  */
42651
- const extractProp = (arr, prop) => {
42652
- return arr.map((item) => {
42653
- return item[prop];
42092
+ const handleSuccess = (res, body) => {
42093
+ // Send a http 200 json response
42094
+ res.json({
42095
+ // Include the body as a parameter
42096
+ body,
42097
+ // Success = true flag so client can detect successful responses
42098
+ success: true,
42654
42099
  });
42100
+ return undefined;
42655
42101
  };
42656
42102
 
42657
- // Import shared helpers
42658
42103
  /**
42659
- * Compare two arrays of objects by only comparing the values in a specific
42660
- * property (e.g. compare user arrays by comparing their user.id values)
42104
+ * Generate an express API route handler
42661
42105
  * @author Gabe Abrams
42662
- * @param a the first array
42663
- * @param b the second array
42664
- * @param prop the property to compare with
42665
- * @returns true if the arrays contain the same objects as determined by
42666
- * the values associated with each object's prop
42106
+ * @param opts object containing all arguments
42107
+ * @param opts.paramTypes map containing the types for each parameter that is
42108
+ * included in the request (map: param name => type)
42109
+ * @param opts.handler function that processes the request
42110
+ * @returns express route handler that takes the following arguments:
42111
+ * params (map: param name => value), handleSuccess (function for handling
42112
+ * successful requests), handleError (function for handling failed requests),
42113
+ * req (express request object), res (express response object),
42114
+ * next (express next function). Params also has userId, userFirstName,
42115
+ * userLastName, isLearner, isTTM, isAdmin, and any other variables that
42116
+ * are directly added to the session
42667
42117
  */
42668
- const compareArraysByProp = (a, b, prop) => {
42669
- // Extract values for comparison
42670
- const aVals = new Set(extractProp(a, prop));
42671
- const bVals = new Set(extractProp(b, prop));
42672
- // Compare sizes first
42673
- if (aVals.size !== bVals.size) {
42674
- return false;
42675
- }
42676
- // Same number of items. Make sure every object in aVals appears in bVals
42677
- // (if so, they should be equivalent since the sizes are the same)
42678
- // > Create map of items in bVals
42679
- const inBVals = {}; // item => true if in bVals
42680
- Array.from(bVals.values()).forEach((item) => {
42681
- inBVals[item] = true;
42682
- });
42683
- // > Loop through aVals and make sure every item is in bVals
42684
- return Array.from(aVals.values()).every((item) => {
42685
- return inBVals[item];
42118
+ const genRouteHandler = (opts) => {
42119
+ // Return a route handler
42120
+ return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
42121
+ var _a, _b;
42122
+ // Output params
42123
+ const output = {};
42124
+ /*----------------------------------------*/
42125
+ /* Parse Params */
42126
+ /*----------------------------------------*/
42127
+ // Process items one by one
42128
+ const paramList = Object.entries((_a = opts.paramTypes) !== null && _a !== void 0 ? _a : {});
42129
+ for (let i = 0; i < paramList.length; i++) {
42130
+ const [name, type] = paramList[i];
42131
+ // Find the value as a string
42132
+ const value = (req.params[name]
42133
+ || req.query[name]
42134
+ || req.body[name]);
42135
+ // Parse
42136
+ if (type === ParamType$1.Boolean || type === ParamType$1.BooleanOptional) {
42137
+ // Boolean
42138
+ // Handle case where value doesn't exist
42139
+ if (value === undefined) {
42140
+ if (type === ParamType$1.BooleanOptional) {
42141
+ output[name] = undefined;
42142
+ }
42143
+ else {
42144
+ return handleError(res, {
42145
+ message: `Parameter ${name} is required, but it was not included.`,
42146
+ code: ReactKitErrorCode$1.MissingParameter,
42147
+ status: 422,
42148
+ });
42149
+ }
42150
+ }
42151
+ else {
42152
+ // Value exists
42153
+ // Simplify value
42154
+ const simpleVal = (String(value)
42155
+ .trim()
42156
+ .toLowerCase());
42157
+ // Parse
42158
+ output[name] = ([
42159
+ 'true',
42160
+ 'yes',
42161
+ 'y',
42162
+ '1',
42163
+ 't',
42164
+ ].indexOf(simpleVal) >= 0);
42165
+ }
42166
+ }
42167
+ else if (type === ParamType$1.Float || type === ParamType$1.FloatOptional) {
42168
+ // Float
42169
+ // Handle case where value doesn't exist
42170
+ if (value === undefined) {
42171
+ if (type === ParamType$1.FloatOptional) {
42172
+ output[name] = undefined;
42173
+ }
42174
+ else {
42175
+ return handleError(res, {
42176
+ message: `Parameter ${name} is required, but it was not included.`,
42177
+ code: ReactKitErrorCode$1.MissingParameter,
42178
+ status: 422,
42179
+ });
42180
+ }
42181
+ }
42182
+ else if (!Number.isNaN(Number.parseFloat(String(value)))) {
42183
+ // Value is a number
42184
+ output[name] = Number.parseFloat(String(value));
42185
+ }
42186
+ else {
42187
+ // Issue!
42188
+ return handleError(res, {
42189
+ message: `Request data was malformed: ${name} was not a valid float.`,
42190
+ code: ReactKitErrorCode$1.InvalidParameter,
42191
+ status: 422,
42192
+ });
42193
+ }
42194
+ }
42195
+ else if (type === ParamType$1.Int || type === ParamType$1.IntOptional) {
42196
+ // Int
42197
+ // Handle case where value doesn't exist
42198
+ if (value === undefined) {
42199
+ if (type === ParamType$1.IntOptional) {
42200
+ output[name] = undefined;
42201
+ }
42202
+ else {
42203
+ return handleError(res, {
42204
+ message: `Parameter ${name} is required, but it was not included.`,
42205
+ code: ReactKitErrorCode$1.MissingParameter,
42206
+ status: 422,
42207
+ });
42208
+ }
42209
+ }
42210
+ else if (!Number.isNaN(Number.parseInt(String(value), 10))) {
42211
+ // Value is a number
42212
+ output[name] = Number.parseInt(String(value), 10);
42213
+ }
42214
+ else {
42215
+ // Issue!
42216
+ return handleError(res, {
42217
+ message: `Request data was malformed: ${name} was not a valid int.`,
42218
+ code: ReactKitErrorCode$1.InvalidParameter,
42219
+ status: 422,
42220
+ });
42221
+ }
42222
+ }
42223
+ else if (type === ParamType$1.JSON || type === ParamType$1.JSONOptional) {
42224
+ // Stringified JSON
42225
+ // Handle case where value doesn't exist
42226
+ if (value === undefined) {
42227
+ if (type === ParamType$1.JSONOptional) {
42228
+ output[name] = undefined;
42229
+ }
42230
+ else {
42231
+ return handleError(res, {
42232
+ message: `Parameter ${name} is required, but it was not included.`,
42233
+ code: ReactKitErrorCode$1.MissingParameter,
42234
+ status: 422,
42235
+ });
42236
+ }
42237
+ }
42238
+ else {
42239
+ // Value exists
42240
+ // Parse
42241
+ try {
42242
+ output[name] = JSON.parse(String(value));
42243
+ }
42244
+ catch (err) {
42245
+ return handleError(res, {
42246
+ message: `Request data was malformed: ${name} was not a valid JSON payload.`,
42247
+ code: ReactKitErrorCode$1.InvalidParameter,
42248
+ status: 422,
42249
+ });
42250
+ }
42251
+ }
42252
+ }
42253
+ else if (type === ParamType$1.String || type === ParamType$1.StringOptional) {
42254
+ // String
42255
+ // Handle case where value doesn't exist
42256
+ if (value === undefined) {
42257
+ if (type === ParamType$1.StringOptional) {
42258
+ output[name] = undefined;
42259
+ }
42260
+ else {
42261
+ return handleError(res, {
42262
+ message: `Parameter ${name} is required, but it was not included.`,
42263
+ code: ReactKitErrorCode$1.MissingParameter,
42264
+ status: 422,
42265
+ });
42266
+ }
42267
+ }
42268
+ else {
42269
+ // Value exists
42270
+ // Leave as is
42271
+ output[name] = value;
42272
+ }
42273
+ }
42274
+ else {
42275
+ // No valid data type
42276
+ return handleError(res, {
42277
+ message: `An internal error occurred: we could not determine the type of ${name}.`,
42278
+ code: ReactKitErrorCode$1.InvalidParameter,
42279
+ status: 422,
42280
+ });
42281
+ }
42282
+ }
42283
+ /*----------------------------------------*/
42284
+ /* Launch Info */
42285
+ /*----------------------------------------*/
42286
+ // Get launch info
42287
+ const { launched, launchInfo } = cacclGetLaunchInfo(req);
42288
+ if (!launched || !launchInfo) {
42289
+ return handleError(res, {
42290
+ message: 'Your session has expired. Please refresh the page and try again.',
42291
+ code: ReactKitErrorCode$1.SessionExpired,
42292
+ status: 440,
42293
+ });
42294
+ }
42295
+ // Error if user info cannot be found
42296
+ if (!launchInfo.userId
42297
+ || !launchInfo.userFirstName
42298
+ || !launchInfo.userLastName
42299
+ || (launchInfo.notInCourse
42300
+ && !launchInfo.isAdmin)
42301
+ || (!launchInfo.isTTM
42302
+ && !launchInfo.isLearner
42303
+ && !launchInfo.isAdmin)) {
42304
+ return handleError(res, {
42305
+ message: 'Your session was invalid. Please refresh the page and try again.',
42306
+ code: ReactKitErrorCode$1.SessionExpired,
42307
+ status: 440,
42308
+ });
42309
+ }
42310
+ // Add launch info to output
42311
+ output.userId = launchInfo.userId;
42312
+ output.userFirstName = launchInfo.userFirstName;
42313
+ output.userLastName = launchInfo.userLastName;
42314
+ output.userEmail = launchInfo.userEmail;
42315
+ output.isLearner = !!launchInfo.isLearner;
42316
+ output.isTTM = !!launchInfo.isTTM;
42317
+ output.isAdmin = !!launchInfo.isAdmin;
42318
+ output.courseId = ((_b = output.courseId) !== null && _b !== void 0 ? _b : launchInfo.courseId);
42319
+ output.courseName = launchInfo.contextLabel;
42320
+ // Add other session variables
42321
+ Object.keys(req.session).forEach((propName) => {
42322
+ // Skip if prop already in output
42323
+ if (output[propName] !== undefined) {
42324
+ return;
42325
+ }
42326
+ // Add to output
42327
+ const value = req.session[propName];
42328
+ if (typeof value === 'string'
42329
+ || typeof value === 'boolean'
42330
+ || typeof value === 'number') {
42331
+ output[propName] = value;
42332
+ }
42333
+ });
42334
+ /*----------------------------------------*/
42335
+ /* Require Course Consistency */
42336
+ /*----------------------------------------*/
42337
+ // Make sure the user actually launched from the appropriate course
42338
+ if (output.courseId
42339
+ && launchInfo.courseId
42340
+ && output.courseId !== launchInfo.courseId
42341
+ && !output.isTTM
42342
+ && !output.isAdmin) {
42343
+ // Course of interest is not the launch course
42344
+ return handleError(res, {
42345
+ message: 'You switched sessions by opening this app in another tab. Please refresh the page and try again.',
42346
+ code: ReactKitErrorCode$1.WrongCourse,
42347
+ status: 401,
42348
+ });
42349
+ }
42350
+ /*----------------------------------------*/
42351
+ /* Require Proper Permissions */
42352
+ /*----------------------------------------*/
42353
+ // Add TTM endpoint security
42354
+ if (
42355
+ // This is a TTM endpoint
42356
+ req.path.startsWith('/api/ttm')
42357
+ // User is not a TTM
42358
+ && (
42359
+ // User is not a TTM
42360
+ !output.isTTM
42361
+ // User is not an admin
42362
+ && !output.isAdmin)) {
42363
+ // User does not have access
42364
+ return handleError(res, {
42365
+ message: 'This action is only allowed if you are a teaching team member for the course. Please go back to Canvas, log in as a teaching team member, and try again.',
42366
+ code: ReactKitErrorCode$1.NotTTM,
42367
+ status: 401,
42368
+ });
42369
+ }
42370
+ // Add Admin endpoint security
42371
+ if (
42372
+ // This is an admin endpoint
42373
+ req.path.startsWith('/api/admin')
42374
+ // User is not an admin
42375
+ && !output.isAdmin) {
42376
+ // User does not have access
42377
+ return handleError(res, {
42378
+ message: 'This action is only allowed if you are a Canvas admin. Please go back to Canvas, log in as an admin, and try again.',
42379
+ code: ReactKitErrorCode$1.NotAdmin,
42380
+ status: 401,
42381
+ });
42382
+ }
42383
+ /*------------------------------------------------------------------------*/
42384
+ /* Call handler */
42385
+ /*------------------------------------------------------------------------*/
42386
+ try {
42387
+ const results = yield opts.handler({
42388
+ params: output,
42389
+ req,
42390
+ res,
42391
+ next,
42392
+ });
42393
+ // Send results to client
42394
+ handleSuccess(res, results !== null && results !== void 0 ? results : undefined);
42395
+ }
42396
+ catch (err) {
42397
+ // Send error to client
42398
+ handleError(res, err);
42399
+ }
42686
42400
  });
42687
42401
  };
42688
42402
 
42689
42403
  /**
42690
- * Get current time info in local time
42404
+ * Days of the week
42691
42405
  * @author Gabe Abrams
42692
- * @param [dateOrTimestamp=now] the date to get info on or a ms since epoch timestamp
42693
- * @returns object with timestamp (ms since epoch) and numbers
42694
- * corresponding to time values for year, month, day, hour, hour12, minute, isPM
42695
- * where hour is in 24hr time and hour12 is in 12hr time.
42696
42406
  */
42697
- const getLocalTimeInfo = (dateOrTimestamp) => {
42698
- // Create a time string
42699
- let d;
42700
- if (!dateOrTimestamp) {
42701
- // Use now
42702
- d = new Date();
42703
- }
42704
- else if (typeof dateOrTimestamp === 'number') {
42705
- // Convert to date
42706
- d = new Date(dateOrTimestamp);
42707
- }
42708
- else {
42709
- // Already a date
42710
- d = dateOrTimestamp;
42711
- }
42712
- // Create all time numbers
42713
- const timestamp = d.getTime();
42714
- const year = d.getFullYear();
42715
- const month = d.getMonth() + 1;
42716
- const day = d.getDate();
42717
- const hour = d.getHours();
42718
- const isPM = hour >= 12;
42719
- let hour12 = hour % 12;
42720
- if (hour12 === 0) {
42721
- hour12 = 12;
42722
- }
42723
- const minute = d.getMinutes();
42724
- // Return
42725
- return {
42726
- timestamp,
42727
- year,
42728
- month,
42729
- day,
42730
- hour,
42731
- hour12,
42732
- isPM,
42733
- minute,
42734
- };
42735
- };
42407
+ var DayOfWeek$2;
42408
+ (function (DayOfWeek) {
42409
+ DayOfWeek["Monday"] = "m";
42410
+ DayOfWeek["Tuesday"] = "t";
42411
+ DayOfWeek["Wednesday"] = "w";
42412
+ DayOfWeek["Thursday"] = "r";
42413
+ DayOfWeek["Friday"] = "f";
42414
+ DayOfWeek["Saturday"] = "s";
42415
+ DayOfWeek["Sunday"] = "u";
42416
+ })(DayOfWeek$2 || (DayOfWeek$2 = {}));
42736
42417
 
42737
42418
  /**
42738
42419
  * Add all routes for the DBEditor
@@ -42750,7 +42431,7 @@ const addDBEditorEndpoints = (opts) => {
42750
42431
  * @author Yuen Ler Chow
42751
42432
  * @returns {any[]} the list of items in the collection
42752
42433
  */
42753
- app.get(endpointPath, genRouteHandler$1({
42434
+ app.get(endpointPath, genRouteHandler({
42754
42435
  paramTypes: {
42755
42436
  filterQuery: ParamType$1.JSONOptional,
42756
42437
  },
@@ -42766,7 +42447,7 @@ const addDBEditorEndpoints = (opts) => {
42766
42447
  * @author Yuen Ler Chow
42767
42448
  * @param {any} item the item to create
42768
42449
  */
42769
- app.post(endpointPath, genRouteHandler$1({
42450
+ app.post(endpointPath, genRouteHandler({
42770
42451
  paramTypes: {
42771
42452
  item: ParamType$1.JSON,
42772
42453
  },
@@ -42780,7 +42461,7 @@ const addDBEditorEndpoints = (opts) => {
42780
42461
  * Remove an item from the collection by id
42781
42462
  * @author Yuen Ler Chow
42782
42463
  */
42783
- app.delete(`${endpointPath}/:id`, genRouteHandler$1({
42464
+ app.delete(`${endpointPath}/:id`, genRouteHandler({
42784
42465
  paramTypes: {
42785
42466
  id: ParamType$1.String,
42786
42467
  },
@@ -42808,5 +42489,5 @@ var DayOfWeek;
42808
42489
  })(DayOfWeek || (DayOfWeek = {}));
42809
42490
  var DayOfWeek$1 = DayOfWeek;
42810
42491
 
42811
- export { AppWrapper, ButtonInputGroup$1 as ButtonInputGroup, CSVDownloadButton, CheckboxButton$1 as CheckboxButton, CopiableBox, DAY_IN_MS, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, DayOfWeek$1 as DayOfWeek, Drawer, DynamicWord, ErrorBox, ErrorWithCode$1 as ErrorWithCode, HOUR_IN_MS, IntelliTable, ItemPicker, LoadingSpinner$1 as LoadingSpinner, LogAction$1 as LogAction, LogBuiltInMetadata, LogReviewer, LogSource$1 as LogSource, LogType$1 as LogType, MINUTE_IN_MS, Modal, ModalButtonType$3 as ModalButtonType, ModalSize$2 as ModalSize, ModalType$3 as ModalType, ParamType$3 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton$1 as RadioButton, ReactKitErrorCode$3 as ReactKitErrorCode, SimpleDateChooser, TabBox, Variant$3 as Variant, abbreviate, addDBEditorEndpoints, alert$2 as alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, initClient, initLogCollection, initServer, isMobileOrTablet, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError$1 as showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, visitServerEndpoint$1 as visitServerEndpoint, waitMs };
42492
+ export { AppWrapper, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, DayOfWeek$1 as DayOfWeek, Drawer, DynamicWord, ErrorBox, ErrorWithCode$1 as ErrorWithCode, HOUR_IN_MS, IntelliTable, ItemPicker, LoadingSpinner, LogAction$1 as LogAction, LogBuiltInMetadata, LogReviewer, LogSource$1 as LogSource, LogType$1 as LogType, MINUTE_IN_MS, Modal, ModalButtonType$3 as ModalButtonType, ModalSize$2 as ModalSize, ModalType$3 as ModalType, ParamType$3 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$3 as ReactKitErrorCode, SimpleDateChooser, TabBox, Variant$3 as Variant, abbreviate, addDBEditorEndpoints, alert$1 as alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genRouteHandler$1 as genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError$1 as handleError, handleSuccess$1 as handleSuccess, initClient, initLogCollection, initServer, isMobileOrTablet, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, visitServerEndpoint, waitMs };
42812
42493
  //# sourceMappingURL=index.js.map