dce-reactkit 3.5.3 → 3.5.5

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/cjs/index.js CHANGED
@@ -319,7 +319,7 @@ const ModalButtonTypeToLabelAndVariant = {
319
319
  /*------------------------------------------------------------------------*/
320
320
  /* Style */
321
321
  /*------------------------------------------------------------------------*/
322
- const style$8 = `
322
+ const style$9 = `
323
323
  .Modal-backdrop {
324
324
  position: fixed;
325
325
  top: 0;
@@ -493,7 +493,7 @@ const Modal = (props) => {
493
493
  left: 0,
494
494
  right: 0,
495
495
  } },
496
- React__default["default"].createElement("style", null, style$8),
496
+ React__default["default"].createElement("style", null, style$9),
497
497
  React__default["default"].createElement("div", { className: `Modal-backdrop ${backdropAnimationClass}`, style: {
498
498
  zIndex: 5000000003,
499
499
  }, onClick: () => __awaiter(void 0, void 0, void 0, function* () {
@@ -778,10 +778,10 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
778
778
  * @author Gabe Abrams
779
779
  */
780
780
  /*------------------------------------------------------------------------*/
781
- /* Static Helpers */
781
+ /* --------------------------- Static Helpers --------------------------- */
782
782
  /*------------------------------------------------------------------------*/
783
783
  /*----------------------------------------*/
784
- /* Alert */
784
+ /* ---------------- Alert --------------- */
785
785
  /*----------------------------------------*/
786
786
  // Stored copies of setters
787
787
  let setAlertInfo;
@@ -795,6 +795,7 @@ let onAlertClosed;
795
795
  const alert$1 = (title, text) => __awaiter(void 0, void 0, void 0, function* () {
796
796
  // Fallback if alert not available
797
797
  if (!setAlertInfo) {
798
+ // eslint-disable-next-line no-alert
798
799
  window.alert(`${title}\n\n${text}`);
799
800
  return undefined;
800
801
  }
@@ -812,7 +813,7 @@ const alert$1 = (title, text) => __awaiter(void 0, void 0, void 0, function* ()
812
813
  });
813
814
  });
814
815
  /*----------------------------------------*/
815
- /* Confirm */
816
+ /* --------------- Confirm -------------- */
816
817
  /*----------------------------------------*/
817
818
  // Stored copies of setters
818
819
  let setConfirmInfo;
@@ -835,6 +836,7 @@ let onConfirmClosed;
835
836
  const confirm = (title, text, opts) => __awaiter(void 0, void 0, void 0, function* () {
836
837
  // Fallback if confirm is not available
837
838
  if (!setConfirmInfo) {
839
+ // eslint-disable-next-line no-alert
838
840
  return window.confirm(`${title}\n\n${text}`);
839
841
  }
840
842
  // Return promise that resolves with result of confirmation
@@ -852,12 +854,14 @@ const confirm = (title, text, opts) => __awaiter(void 0, void 0, void 0, functio
852
854
  });
853
855
  });
854
856
  /*----------------------------------------*/
855
- /* Fatal Error */
857
+ /* ------------- Fatal Error ------------ */
856
858
  /*----------------------------------------*/
857
859
  // Stored copies of setters
858
860
  let setFatalErrorMessage;
859
861
  let setFatalErrorCode;
860
862
  let setFatalErrorTitle;
863
+ // Fatal error listeners
864
+ const fatalErrorHandlers = [];
861
865
  /**
862
866
  * Show a fatal error message
863
867
  * @author Gabe Abrams
@@ -873,6 +877,15 @@ const showFatalError = (error, errorTitle = 'An Error Occurred') => {
873
877
  const code = (typeof error === 'string'
874
878
  ? ReactKitErrorCode$1.NoCode
875
879
  : String((_b = error.code) !== null && _b !== void 0 ? _b : ReactKitErrorCode$1.NoCode));
880
+ // Call all fatal error listeners
881
+ try {
882
+ fatalErrorHandlers.forEach((handler) => {
883
+ handler();
884
+ });
885
+ }
886
+ catch (err) {
887
+ // Ignore listener errors
888
+ }
876
889
  // Add log
877
890
  logClientEvent({
878
891
  context: LogBuiltInMetadata.Context.ClientFatalError,
@@ -896,12 +909,19 @@ const showFatalError = (error, errorTitle = 'An Error Occurred') => {
896
909
  setFatalErrorTitle(errorTitle);
897
910
  return undefined;
898
911
  };
912
+ /**
913
+ * Add a handler for when a fatal error occurs
914
+ * @author Gabe Abrams
915
+ */
916
+ const addFatalErrorHandler = (handler) => {
917
+ fatalErrorHandlers.push(handler);
918
+ };
899
919
  /*------------------------------------------------------------------------*/
900
- /* Component */
920
+ /* ------------------------------ Component ----------------------------- */
901
921
  /*------------------------------------------------------------------------*/
902
922
  const AppWrapper = (props) => {
903
923
  /*------------------------------------------------------------------------*/
904
- /* Setup */
924
+ /* -------------------------------- Setup ------------------------------- */
905
925
  /*------------------------------------------------------------------------*/
906
926
  /* -------------- Props ------------- */
907
927
  const { children, dark, } = props;
@@ -922,10 +942,10 @@ const AppWrapper = (props) => {
922
942
  // Session expired
923
943
  const [sessionHasExpired, setSessionHasExpiredInner,] = React.useState(false);
924
944
  /*------------------------------------------------------------------------*/
925
- /* Render */
945
+ /* ------------------------------- Render ------------------------------- */
926
946
  /*------------------------------------------------------------------------*/
927
947
  /*----------------------------------------*/
928
- /* Modal */
948
+ /* ---------------- Modal --------------- */
929
949
  /*----------------------------------------*/
930
950
  // Modal that may be defined
931
951
  let modal;
@@ -949,7 +969,7 @@ const AppWrapper = (props) => {
949
969
  }, dontAllowBackdropExit: true }, confirmInfo.text));
950
970
  }
951
971
  /*----------------------------------------*/
952
- /* Views */
972
+ /* ---------------- Views --------------- */
953
973
  /*----------------------------------------*/
954
974
  // Body that will be filled with the current view
955
975
  let body;
@@ -975,7 +995,7 @@ const AppWrapper = (props) => {
975
995
  }
976
996
  /* --------------- App -------------- */
977
997
  if (!body) {
978
- body = (React__default["default"].createElement(React__default["default"].Fragment, null, children));
998
+ body = children;
979
999
  }
980
1000
  /*----------------------------------------*/
981
1001
  /* Main UI */
@@ -992,7 +1012,7 @@ const AppWrapper = (props) => {
992
1012
  /*------------------------------------------------------------------------*/
993
1013
  /* Style */
994
1014
  /*------------------------------------------------------------------------*/
995
- const style$7 = `
1015
+ const style$8 = `
996
1016
  /* Container fades in */
997
1017
  .LoadingSpinner-container {
998
1018
  animation-name: LoadingSpinner-container-fade-in;
@@ -1070,7 +1090,7 @@ const LoadingSpinner = () => {
1070
1090
  /*------------------------------------------------------------------------*/
1071
1091
  // Add all four blips to a container
1072
1092
  return (React__default["default"].createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
1073
- React__default["default"].createElement("style", null, style$7),
1093
+ React__default["default"].createElement("style", null, style$8),
1074
1094
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-1 me-1" }),
1075
1095
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-2 me-1" }),
1076
1096
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-3 me-1" }),
@@ -1084,7 +1104,7 @@ const LoadingSpinner = () => {
1084
1104
  /*------------------------------------------------------------------------*/
1085
1105
  /* Style */
1086
1106
  /*------------------------------------------------------------------------*/
1087
- const style$6 = `
1107
+ const style$7 = `
1088
1108
  /* Tab Box */
1089
1109
  .TabBox-box {
1090
1110
  /* Light Border */
@@ -1164,7 +1184,7 @@ const TabBox = (props) => {
1164
1184
  /*----------------------------------------*/
1165
1185
  // Full UI
1166
1186
  return (React__default["default"].createElement("div", { className: `TabBox-container ${noBottomMargin ? '' : 'mb-2'}` },
1167
- React__default["default"].createElement("style", null, style$6),
1187
+ React__default["default"].createElement("style", null, style$7),
1168
1188
  React__default["default"].createElement("div", { className: "TabBox-title-container" },
1169
1189
  React__default["default"].createElement("div", { className: "TabBox-title" }, title)),
1170
1190
  React__default["default"].createElement("div", { className: `TabBox-box ps-2 pt-2 pe-2 ${noBottomPadding ? '' : 'pb-2'}` },
@@ -1486,7 +1506,7 @@ const SimpleDateChooser = (props) => {
1486
1506
  /*------------------------------------------------------------------------*/
1487
1507
  /* Style */
1488
1508
  /*------------------------------------------------------------------------*/
1489
- const style$5 = `
1509
+ const style$6 = `
1490
1510
  .Drawer-container {
1491
1511
  margin-left: 1rem;
1492
1512
  margin-right: 1rem;
@@ -1520,7 +1540,7 @@ const Drawer = (props) => {
1520
1540
  return (React__default["default"].createElement("div", { className: "Drawer-container", style: {
1521
1541
  backgroundColor: (customBackgroundColor !== null && customBackgroundColor !== void 0 ? customBackgroundColor : undefined),
1522
1542
  } },
1523
- React__default["default"].createElement("style", null, style$5),
1543
+ React__default["default"].createElement("style", null, style$6),
1524
1544
  children));
1525
1545
  };
1526
1546
 
@@ -1531,7 +1551,7 @@ const Drawer = (props) => {
1531
1551
  /*------------------------------------------------------------------------*/
1532
1552
  /* Style */
1533
1553
  /*------------------------------------------------------------------------*/
1534
- const style$4 = `
1554
+ const style$5 = `
1535
1555
  .PopSuccessMark-outer-container {
1536
1556
  position: relative;
1537
1557
  display: inline-block;
@@ -1636,7 +1656,7 @@ const PopSuccessMark = (props) => {
1636
1656
  width: `${sizeRem}rem`,
1637
1657
  height: `${sizeRem}rem`,
1638
1658
  }, "aria-label": "checkmark indicating success" },
1639
- React__default["default"].createElement("style", null, style$4),
1659
+ React__default["default"].createElement("style", null, style$5),
1640
1660
  React__default["default"].createElement("div", { className: `PopSuccessMark-check-stroke-1 bg-${checkVariant}`, style: {
1641
1661
  borderRadius: `${sizeRem / 5}rem`,
1642
1662
  } }),
@@ -1652,7 +1672,7 @@ const PopSuccessMark = (props) => {
1652
1672
  /*------------------------------------------------------------------------*/
1653
1673
  /* Style */
1654
1674
  /*------------------------------------------------------------------------*/
1655
- const style$3 = `
1675
+ const style$4 = `
1656
1676
  .PopFailureMark-outer-container {
1657
1677
  position: relative;
1658
1678
  display: inline-block;
@@ -1756,7 +1776,7 @@ const PopFailureMark = (props) => {
1756
1776
  width: `${sizeRem}rem`,
1757
1777
  height: `${sizeRem}rem`,
1758
1778
  }, "aria-label": "mark indicating failure" },
1759
- React__default["default"].createElement("style", null, style$3),
1779
+ React__default["default"].createElement("style", null, style$4),
1760
1780
  React__default["default"].createElement("div", { className: `PopFailureMark-x-stroke-1 bg-${xVariant}`, style: {
1761
1781
  borderRadius: `${sizeRem / 5}rem`,
1762
1782
  } }),
@@ -1772,7 +1792,7 @@ const PopFailureMark = (props) => {
1772
1792
  /*------------------------------------------------------------------------*/
1773
1793
  /* Style */
1774
1794
  /*------------------------------------------------------------------------*/
1775
- const style$2 = `
1795
+ const style$3 = `
1776
1796
  .PopPendingMark-outer-container {
1777
1797
  position: relative;
1778
1798
  display: inline-block;
@@ -1845,7 +1865,7 @@ const PopPendingMark = (props) => {
1845
1865
  width: `${sizeRem}rem`,
1846
1866
  height: `${sizeRem}rem`,
1847
1867
  }, "aria-label": "mark indicating that the item is pending" },
1848
- React__default["default"].createElement("style", null, style$2),
1868
+ React__default["default"].createElement("style", null, style$3),
1849
1869
  React__default["default"].createElement("div", null,
1850
1870
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faHourglass, className: `PopPendingMark-hourglass text-${hourglassVariant}`, style: {
1851
1871
  fontSize: `${sizeRem * 0.6}rem`,
@@ -1858,27 +1878,27 @@ const PopPendingMark = (props) => {
1858
1878
  */
1859
1879
  /* ------------- Actions ------------ */
1860
1880
  // Types of actions
1861
- var ActionType$6;
1881
+ var ActionType$7;
1862
1882
  (function (ActionType) {
1863
1883
  // Indicate that the text was recently copied
1864
1884
  ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
1865
1885
  // Clear the status
1866
1886
  ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
1867
- })(ActionType$6 || (ActionType$6 = {}));
1887
+ })(ActionType$7 || (ActionType$7 = {}));
1868
1888
  /**
1869
1889
  * Reducer that executes actions
1870
1890
  * @author Gabe Abrams
1871
1891
  * @param state current state
1872
1892
  * @param action action to execute
1873
1893
  */
1874
- const reducer$6 = (state, action) => {
1894
+ const reducer$7 = (state, action) => {
1875
1895
  switch (action.type) {
1876
- case ActionType$6.IndicateRecentlyCopied: {
1896
+ case ActionType$7.IndicateRecentlyCopied: {
1877
1897
  return {
1878
1898
  recentlyCopied: true,
1879
1899
  };
1880
1900
  }
1881
- case ActionType$6.ClearRecentlyCopiedStatus: {
1901
+ case ActionType$7.ClearRecentlyCopiedStatus: {
1882
1902
  return {
1883
1903
  recentlyCopied: false,
1884
1904
  };
@@ -1904,7 +1924,7 @@ const CopiableBox = (props) => {
1904
1924
  recentlyCopied: false,
1905
1925
  };
1906
1926
  // Initialize state
1907
- const [state, dispatch] = React.useReducer(reducer$6, initialState);
1927
+ const [state, dispatch] = React.useReducer(reducer$7, initialState);
1908
1928
  // Destructure common state
1909
1929
  const { recentlyCopied, } = state;
1910
1930
  /*------------------------------------------------------------------------*/
@@ -1924,13 +1944,13 @@ const CopiableBox = (props) => {
1924
1944
  }
1925
1945
  // Show copied notice
1926
1946
  dispatch({
1927
- type: ActionType$6.IndicateRecentlyCopied,
1947
+ type: ActionType$7.IndicateRecentlyCopied,
1928
1948
  });
1929
1949
  // Wait a moment
1930
1950
  yield waitMs(4000);
1931
1951
  // Hide copied notice
1932
1952
  dispatch({
1933
- type: ActionType$6.ClearRecentlyCopiedStatus,
1953
+ type: ActionType$7.ClearRecentlyCopiedStatus,
1934
1954
  });
1935
1955
  });
1936
1956
  /*------------------------------------------------------------------------*/
@@ -1986,20 +2006,20 @@ const CopiableBox = (props) => {
1986
2006
  */
1987
2007
  /* ------------- Actions ------------ */
1988
2008
  // Types of actions
1989
- var ActionType$5;
2009
+ var ActionType$6;
1990
2010
  (function (ActionType) {
1991
2011
  // Toggle whether a child are being shown
1992
2012
  ActionType["ToggleChild"] = "toggle-child";
1993
- })(ActionType$5 || (ActionType$5 = {}));
2013
+ })(ActionType$6 || (ActionType$6 = {}));
1994
2014
  /**
1995
2015
  * Reducer that executes actions
1996
2016
  * @author Gabe Abrams
1997
2017
  * @param state current state
1998
2018
  * @param action action to execute
1999
2019
  */
2000
- const reducer$5 = (state, action) => {
2020
+ const reducer$6 = (state, action) => {
2001
2021
  switch (action.type) {
2002
- case ActionType$5.ToggleChild: {
2022
+ case ActionType$6.ToggleChild: {
2003
2023
  return Object.assign(Object.assign({}, state), { childExpanded: Object.assign(Object.assign({}, state.childExpanded), { [String(action.id)]: !state.childExpanded[String(action.id)] }) });
2004
2024
  }
2005
2025
  default: {
@@ -2028,7 +2048,7 @@ const NestableItemList = (props) => {
2028
2048
  childExpanded: initChildExpanded,
2029
2049
  };
2030
2050
  // Initialize state
2031
- const [state, dispatch] = React.useReducer(reducer$5, initialState);
2051
+ const [state, dispatch] = React.useReducer(reducer$6, initialState);
2032
2052
  // Destructure common state
2033
2053
  const { childExpanded, } = state;
2034
2054
  /*------------------------------------------------------------------------*/
@@ -2118,7 +2138,7 @@ const NestableItemList = (props) => {
2118
2138
  backgroundColor: 'transparent',
2119
2139
  }, type: "button", onClick: () => {
2120
2140
  dispatch({
2121
- type: ActionType$5.ToggleChild,
2141
+ type: ActionType$6.ToggleChild,
2122
2142
  id: item.id,
2123
2143
  });
2124
2144
  }, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}` },
@@ -2394,7 +2414,7 @@ var SortType;
2394
2414
  })(SortType || (SortType = {}));
2395
2415
  /* ------------- Actions ------------ */
2396
2416
  // Types of actions
2397
- var ActionType$4;
2417
+ var ActionType$5;
2398
2418
  (function (ActionType) {
2399
2419
  // Toggle sort column param
2400
2420
  ActionType["ToggleSortColumn"] = "toggle-sort-column";
@@ -2406,16 +2426,16 @@ var ActionType$4;
2406
2426
  ActionType["ShowAllColumns"] = "show-all-columns";
2407
2427
  // Hide all columns
2408
2428
  ActionType["HideAllColumns"] = "hide-all-columns";
2409
- })(ActionType$4 || (ActionType$4 = {}));
2429
+ })(ActionType$5 || (ActionType$5 = {}));
2410
2430
  /**
2411
2431
  * Reducer that executes actions
2412
2432
  * @author Gabe Abrams
2413
2433
  * @param state current state
2414
2434
  * @param action action to execute
2415
2435
  */
2416
- const reducer$4 = (state, action) => {
2436
+ const reducer$5 = (state, action) => {
2417
2437
  switch (action.type) {
2418
- case ActionType$4.ToggleSortColumn: {
2438
+ case ActionType$5.ToggleSortColumn: {
2419
2439
  if (action.param !== state.sortColumnParam) {
2420
2440
  // Different column param
2421
2441
  return Object.assign(Object.assign({}, state), { sortColumnParam: action.param, sortType: SortType.Ascending });
@@ -2427,22 +2447,22 @@ const reducer$4 = (state, action) => {
2427
2447
  // Stop sorting by column
2428
2448
  return Object.assign(Object.assign({}, state), { sortColumnParam: undefined, sortType: SortType.Ascending });
2429
2449
  }
2430
- case ActionType$4.UpdateColumnVisibility: {
2450
+ case ActionType$5.UpdateColumnVisibility: {
2431
2451
  const { columnVisibilityMap } = state;
2432
2452
  columnVisibilityMap[action.param] = action.visible;
2433
2453
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2434
2454
  }
2435
- case ActionType$4.ToggleColVisCusModalVisibility: {
2455
+ case ActionType$5.ToggleColVisCusModalVisibility: {
2436
2456
  return Object.assign(Object.assign({}, state), { columnVisibilityCustomizationModalVisible: !state.columnVisibilityCustomizationModalVisible });
2437
2457
  }
2438
- case ActionType$4.ShowAllColumns: {
2458
+ case ActionType$5.ShowAllColumns: {
2439
2459
  const { columnVisibilityMap } = state;
2440
2460
  Object.keys(columnVisibilityMap).forEach((param) => {
2441
2461
  columnVisibilityMap[param] = true;
2442
2462
  });
2443
2463
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2444
2464
  }
2445
- case ActionType$4.HideAllColumns: {
2465
+ case ActionType$5.HideAllColumns: {
2446
2466
  const { columnVisibilityMap } = state;
2447
2467
  Object.keys(columnVisibilityMap).forEach((param) => {
2448
2468
  columnVisibilityMap[param] = false;
@@ -2489,7 +2509,7 @@ const IntelliTable = (props) => {
2489
2509
  columnVisibilityCustomizationModalVisible: false,
2490
2510
  };
2491
2511
  // Initialize state
2492
- const [state, dispatch] = React.useReducer(reducer$4, initialState);
2512
+ const [state, dispatch] = React.useReducer(reducer$5, initialState);
2493
2513
  // Destructure common state
2494
2514
  const { sortColumnParam, sortType, columnVisibilityMap, columnVisibilityCustomizationModalVisible, } = state;
2495
2515
  /*------------------------------------------------------------------------*/
@@ -2512,13 +2532,13 @@ const IntelliTable = (props) => {
2512
2532
  return alert$1('Choose at least one column', 'To continue, you have to choose at least one column to show');
2513
2533
  }
2514
2534
  dispatch({
2515
- type: ActionType$4.ToggleColVisCusModalVisibility,
2535
+ type: ActionType$5.ToggleColVisCusModalVisibility,
2516
2536
  });
2517
2537
  }, okayVariant: Variant$1.Light },
2518
2538
  columns.map((column) => {
2519
2539
  return (React__default["default"].createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, className: "mb-2", text: column.title, onChanged: (checked) => {
2520
2540
  dispatch({
2521
- type: ActionType$4.UpdateColumnVisibility,
2541
+ type: ActionType$5.UpdateColumnVisibility,
2522
2542
  param: column.param,
2523
2543
  visible: checked,
2524
2544
  });
@@ -2527,12 +2547,12 @@ const IntelliTable = (props) => {
2527
2547
  React__default["default"].createElement("div", { className: "mt-3" }, "Or you can:"),
2528
2548
  React__default["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: () => {
2529
2549
  dispatch({
2530
- type: ActionType$4.ShowAllColumns,
2550
+ type: ActionType$5.ShowAllColumns,
2531
2551
  });
2532
2552
  } }, "Select All"),
2533
2553
  React__default["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: () => {
2534
2554
  dispatch({
2535
- type: ActionType$4.HideAllColumns,
2555
+ type: ActionType$5.HideAllColumns,
2536
2556
  });
2537
2557
  } }, "Deselect All")));
2538
2558
  }
@@ -2583,7 +2603,7 @@ const IntelliTable = (props) => {
2583
2603
  React__default["default"].createElement("div", null,
2584
2604
  React__default["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: () => {
2585
2605
  dispatch({
2586
- type: ActionType$4.ToggleSortColumn,
2606
+ type: ActionType$5.ToggleSortColumn,
2587
2607
  param: column.param,
2588
2608
  });
2589
2609
  } },
@@ -2772,7 +2792,7 @@ const IntelliTable = (props) => {
2772
2792
  React__default["default"].createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: filename, csv: csv }),
2773
2793
  React__default["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: () => {
2774
2794
  dispatch({
2775
- type: ActionType$4.ToggleColVisCusModalVisibility,
2795
+ type: ActionType$5.ToggleColVisCusModalVisibility,
2776
2796
  });
2777
2797
  } },
2778
2798
  "Show/Hide Cols",
@@ -2804,7 +2824,7 @@ var FilterDrawer;
2804
2824
  /*------------------------------------------------------------------------*/
2805
2825
  /* Style */
2806
2826
  /*------------------------------------------------------------------------*/
2807
- const style$1 = `
2827
+ const style$2 = `
2808
2828
  .LogReviewer-outer-container {
2809
2829
  /* Full Screen */
2810
2830
  display: inline-block;
@@ -3138,7 +3158,7 @@ const genHumanReadableName = (machineReadableName) => {
3138
3158
  };
3139
3159
  /* ------------- Actions ------------ */
3140
3160
  // Types of actions
3141
- var ActionType$3;
3161
+ var ActionType$4;
3142
3162
  (function (ActionType) {
3143
3163
  // Show the loading bar
3144
3164
  ActionType["StartLoading"] = "start-loading";
@@ -3160,45 +3180,45 @@ var ActionType$3;
3160
3180
  ActionType["UpdateActionErrorFilterState"] = "update-action-error-filter-state";
3161
3181
  // Update the advanced filter state
3162
3182
  ActionType["UpdateAdvancedFilterState"] = "update-advanced-filter-state";
3163
- })(ActionType$3 || (ActionType$3 = {}));
3183
+ })(ActionType$4 || (ActionType$4 = {}));
3164
3184
  /**
3165
3185
  * Reducer that executes actions
3166
3186
  * @author Gabe Abrams
3167
3187
  * @param state current state
3168
3188
  * @param action action to execute
3169
3189
  */
3170
- const reducer$3 = (state, action) => {
3190
+ const reducer$4 = (state, action) => {
3171
3191
  switch (action.type) {
3172
- case ActionType$3.StartLoading: {
3192
+ case ActionType$4.StartLoading: {
3173
3193
  return Object.assign(Object.assign({}, state), { loading: true });
3174
3194
  }
3175
- case ActionType$3.FinishLoading: {
3195
+ case ActionType$4.FinishLoading: {
3176
3196
  return Object.assign(Object.assign({}, state), { loading: false, logMap: action.logMap });
3177
3197
  }
3178
- case ActionType$3.ToggleFilterDrawer: {
3198
+ case ActionType$4.ToggleFilterDrawer: {
3179
3199
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: (state.expandedFilterDrawer === action.filterDrawer
3180
3200
  ? undefined // hide
3181
3201
  : action.filterDrawer) });
3182
3202
  }
3183
- case ActionType$3.HideFilterDrawer: {
3203
+ case ActionType$4.HideFilterDrawer: {
3184
3204
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: undefined });
3185
3205
  }
3186
- case ActionType$3.ResetFilters: {
3206
+ case ActionType$4.ResetFilters: {
3187
3207
  return Object.assign(Object.assign({}, state), { dateFilterState: action.initDateFilterState, contextFilterState: action.initContextFilterState, tagFilterState: action.initTagFilterState, actionErrorFilterState: action.initActionErrorFilterState, advancedFilterState: action.initAdvancedFilterState });
3188
3208
  }
3189
- case ActionType$3.UpdateDateFilterState: {
3209
+ case ActionType$4.UpdateDateFilterState: {
3190
3210
  return Object.assign(Object.assign({}, state), { dateFilterState: action.dateFilterState });
3191
3211
  }
3192
- case ActionType$3.UpdateContextFilterState: {
3212
+ case ActionType$4.UpdateContextFilterState: {
3193
3213
  return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
3194
3214
  }
3195
- case ActionType$3.UpdateTagFilterState: {
3215
+ case ActionType$4.UpdateTagFilterState: {
3196
3216
  return Object.assign(Object.assign({}, state), { tagFilterState: action.tagFilterState });
3197
3217
  }
3198
- case ActionType$3.UpdateActionErrorFilterState: {
3218
+ case ActionType$4.UpdateActionErrorFilterState: {
3199
3219
  return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
3200
3220
  }
3201
- case ActionType$3.UpdateAdvancedFilterState: {
3221
+ case ActionType$4.UpdateAdvancedFilterState: {
3202
3222
  return Object.assign(Object.assign({}, state), { advancedFilterState: action.advancedFilterState });
3203
3223
  }
3204
3224
  default: {
@@ -3327,7 +3347,7 @@ const LogReviewer = (props) => {
3327
3347
  advancedFilterState: initAdvancedFilterState,
3328
3348
  };
3329
3349
  // Initialize state
3330
- const [state, dispatch] = React.useReducer(reducer$3, initialState);
3350
+ const [state, dispatch] = React.useReducer(reducer$4, initialState);
3331
3351
  // Destructure common state
3332
3352
  const { loading, logMap, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, } = state;
3333
3353
  /*------------------------------------------------------------------------*/
@@ -3378,7 +3398,7 @@ const LogReviewer = (props) => {
3378
3398
  const handleDateRangeUpdated = (newDateFilterState) => __awaiter(void 0, void 0, void 0, function* () {
3379
3399
  // Update state
3380
3400
  dispatch({
3381
- type: ActionType$3.UpdateDateFilterState,
3401
+ type: ActionType$4.UpdateDateFilterState,
3382
3402
  dateFilterState: newDateFilterState,
3383
3403
  });
3384
3404
  // Check which year/month combos we need to load
@@ -3389,7 +3409,7 @@ const LogReviewer = (props) => {
3389
3409
  }
3390
3410
  // Start loading
3391
3411
  dispatch({
3392
- type: ActionType$3.StartLoading,
3412
+ type: ActionType$4.StartLoading,
3393
3413
  });
3394
3414
  // Load required months
3395
3415
  try {
@@ -3413,7 +3433,7 @@ const LogReviewer = (props) => {
3413
3433
  }
3414
3434
  // Finish loading
3415
3435
  dispatch({
3416
- type: ActionType$3.FinishLoading,
3436
+ type: ActionType$4.FinishLoading,
3417
3437
  logMap,
3418
3438
  });
3419
3439
  });
@@ -3452,7 +3472,7 @@ const LogReviewer = (props) => {
3452
3472
  React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
3453
3473
  React__default["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: () => {
3454
3474
  dispatch({
3455
- type: ActionType$3.ToggleFilterDrawer,
3475
+ type: ActionType$4.ToggleFilterDrawer,
3456
3476
  filterDrawer: FilterDrawer.Date,
3457
3477
  });
3458
3478
  } },
@@ -3460,7 +3480,7 @@ const LogReviewer = (props) => {
3460
3480
  "Date"),
3461
3481
  React__default["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: () => {
3462
3482
  dispatch({
3463
- type: ActionType$3.ToggleFilterDrawer,
3483
+ type: ActionType$4.ToggleFilterDrawer,
3464
3484
  filterDrawer: FilterDrawer.Context,
3465
3485
  });
3466
3486
  } },
@@ -3468,7 +3488,7 @@ const LogReviewer = (props) => {
3468
3488
  "Context"),
3469
3489
  (LogMetadata.Tag && Object.keys(LogMetadata.Tag).length > 0) && (React__default["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: () => {
3470
3490
  dispatch({
3471
- type: ActionType$3.ToggleFilterDrawer,
3491
+ type: ActionType$4.ToggleFilterDrawer,
3472
3492
  filterDrawer: FilterDrawer.Tag,
3473
3493
  });
3474
3494
  } },
@@ -3476,7 +3496,7 @@ const LogReviewer = (props) => {
3476
3496
  "Tag")),
3477
3497
  React__default["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: () => {
3478
3498
  dispatch({
3479
- type: ActionType$3.ToggleFilterDrawer,
3499
+ type: ActionType$4.ToggleFilterDrawer,
3480
3500
  filterDrawer: FilterDrawer.Action,
3481
3501
  });
3482
3502
  } },
@@ -3484,7 +3504,7 @@ const LogReviewer = (props) => {
3484
3504
  "Action"),
3485
3505
  React__default["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: () => {
3486
3506
  dispatch({
3487
- type: ActionType$3.ToggleFilterDrawer,
3507
+ type: ActionType$4.ToggleFilterDrawer,
3488
3508
  filterDrawer: FilterDrawer.Advanced,
3489
3509
  });
3490
3510
  } },
@@ -3492,7 +3512,7 @@ const LogReviewer = (props) => {
3492
3512
  "Advanced"),
3493
3513
  React__default["default"].createElement("button", { type: "button", id: "LogReviewer-reset-filters-button", className: "btn btn-light", "aria-label": "reset filters", onClick: () => {
3494
3514
  dispatch({
3495
- type: ActionType$3.ResetFilters,
3515
+ type: ActionType$4.ResetFilters,
3496
3516
  initActionErrorFilterState,
3497
3517
  initAdvancedFilterState,
3498
3518
  initContextFilterState,
@@ -3614,7 +3634,7 @@ const LogReviewer = (props) => {
3614
3634
  }
3615
3635
  });
3616
3636
  dispatch({
3617
- type: ActionType$3.UpdateContextFilterState,
3637
+ type: ActionType$4.UpdateContextFilterState,
3618
3638
  contextFilterState,
3619
3639
  });
3620
3640
  } }));
@@ -3629,7 +3649,7 @@ const LogReviewer = (props) => {
3629
3649
  return (React__default["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) => {
3630
3650
  tagFilterState[tag] = checked;
3631
3651
  dispatch({
3632
- type: ActionType$3.UpdateTagFilterState,
3652
+ type: ActionType$4.UpdateTagFilterState,
3633
3653
  tagFilterState,
3634
3654
  });
3635
3655
  } }));
@@ -3642,21 +3662,21 @@ const LogReviewer = (props) => {
3642
3662
  React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
3643
3663
  actionErrorFilterState.type = undefined;
3644
3664
  dispatch({
3645
- type: ActionType$3.UpdateActionErrorFilterState,
3665
+ type: ActionType$4.UpdateActionErrorFilterState,
3646
3666
  actionErrorFilterState,
3647
3667
  });
3648
3668
  }, ariaLabel: "show logs of all types", selected: actionErrorFilterState.type === undefined }),
3649
3669
  React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
3650
3670
  actionErrorFilterState.type = LogType$1.Action;
3651
3671
  dispatch({
3652
- type: ActionType$3.UpdateActionErrorFilterState,
3672
+ type: ActionType$4.UpdateActionErrorFilterState,
3653
3673
  actionErrorFilterState,
3654
3674
  });
3655
3675
  }, ariaLabel: "only show action logs", selected: actionErrorFilterState.type === LogType$1.Action }),
3656
3676
  React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
3657
3677
  actionErrorFilterState.type = LogType$1.Error;
3658
3678
  dispatch({
3659
- type: ActionType$3.UpdateActionErrorFilterState,
3679
+ type: ActionType$4.UpdateActionErrorFilterState,
3660
3680
  actionErrorFilterState,
3661
3681
  });
3662
3682
  }, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
@@ -3668,7 +3688,7 @@ const LogReviewer = (props) => {
3668
3688
  return (React__default["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) => {
3669
3689
  actionErrorFilterState.action[action] = checked;
3670
3690
  dispatch({
3671
- type: ActionType$3.UpdateActionErrorFilterState,
3691
+ type: ActionType$4.UpdateActionErrorFilterState,
3672
3692
  actionErrorFilterState,
3673
3693
  });
3674
3694
  } }));
@@ -3679,7 +3699,7 @@ const LogReviewer = (props) => {
3679
3699
  return (React__default["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) => {
3680
3700
  actionErrorFilterState.target[target] = checked;
3681
3701
  dispatch({
3682
- type: ActionType$3.UpdateActionErrorFilterState,
3702
+ type: ActionType$4.UpdateActionErrorFilterState,
3683
3703
  actionErrorFilterState,
3684
3704
  });
3685
3705
  } }));
@@ -3691,7 +3711,7 @@ const LogReviewer = (props) => {
3691
3711
  React__default["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) => {
3692
3712
  actionErrorFilterState.errorMessage = e.target.value;
3693
3713
  dispatch({
3694
- type: ActionType$3.UpdateActionErrorFilterState,
3714
+ type: ActionType$4.UpdateActionErrorFilterState,
3695
3715
  actionErrorFilterState,
3696
3716
  });
3697
3717
  } })),
@@ -3702,7 +3722,7 @@ const LogReviewer = (props) => {
3702
3722
  .trim()
3703
3723
  .toUpperCase());
3704
3724
  dispatch({
3705
- type: ActionType$3.UpdateActionErrorFilterState,
3725
+ type: ActionType$4.UpdateActionErrorFilterState,
3706
3726
  actionErrorFilterState,
3707
3727
  });
3708
3728
  } }))))));
@@ -3716,7 +3736,7 @@ const LogReviewer = (props) => {
3716
3736
  React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user first name", value: advancedFilterState.userFirstName, placeholder: "e.g. Divardo", onChange: (e) => {
3717
3737
  advancedFilterState.userFirstName = e.target.value;
3718
3738
  dispatch({
3719
- type: ActionType$3.UpdateAdvancedFilterState,
3739
+ type: ActionType$4.UpdateAdvancedFilterState,
3720
3740
  advancedFilterState,
3721
3741
  });
3722
3742
  } })),
@@ -3725,7 +3745,7 @@ const LogReviewer = (props) => {
3725
3745
  React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for user last name", value: advancedFilterState.userLastName, placeholder: "e.g. Calicci", onChange: (e) => {
3726
3746
  advancedFilterState.userLastName = e.target.value;
3727
3747
  dispatch({
3728
- type: ActionType$3.UpdateAdvancedFilterState,
3748
+ type: ActionType$4.UpdateAdvancedFilterState,
3729
3749
  advancedFilterState,
3730
3750
  });
3731
3751
  } })),
@@ -3735,7 +3755,7 @@ const LogReviewer = (props) => {
3735
3755
  advancedFilterState.userEmail = ((e.target.value)
3736
3756
  .trim());
3737
3757
  dispatch({
3738
- type: ActionType$3.UpdateAdvancedFilterState,
3758
+ type: ActionType$4.UpdateAdvancedFilterState,
3739
3759
  advancedFilterState,
3740
3760
  });
3741
3761
  } })),
@@ -3749,7 +3769,7 @@ const LogReviewer = (props) => {
3749
3769
  .trim());
3750
3770
  }
3751
3771
  dispatch({
3752
- type: ActionType$3.UpdateAdvancedFilterState,
3772
+ type: ActionType$4.UpdateAdvancedFilterState,
3753
3773
  advancedFilterState,
3754
3774
  });
3755
3775
  } })),
@@ -3757,21 +3777,21 @@ const LogReviewer = (props) => {
3757
3777
  React__default["default"].createElement(CheckboxButton, { text: "Students", onChanged: (checked) => {
3758
3778
  advancedFilterState.includeLearners = checked;
3759
3779
  dispatch({
3760
- type: ActionType$3.UpdateAdvancedFilterState,
3780
+ type: ActionType$4.UpdateAdvancedFilterState,
3761
3781
  advancedFilterState,
3762
3782
  });
3763
3783
  }, checked: advancedFilterState.includeLearners, ariaLabel: "show logs from students" }),
3764
3784
  React__default["default"].createElement(CheckboxButton, { text: "Teaching Team Members", onChanged: (checked) => {
3765
3785
  advancedFilterState.includeTTMs = checked;
3766
3786
  dispatch({
3767
- type: ActionType$3.UpdateAdvancedFilterState,
3787
+ type: ActionType$4.UpdateAdvancedFilterState,
3768
3788
  advancedFilterState,
3769
3789
  });
3770
3790
  }, checked: advancedFilterState.includeTTMs, ariaLabel: "show logs from teaching team members" }),
3771
3791
  React__default["default"].createElement(CheckboxButton, { text: "Admins", onChanged: (checked) => {
3772
3792
  advancedFilterState.includeAdmins = checked;
3773
3793
  dispatch({
3774
- type: ActionType$3.UpdateAdvancedFilterState,
3794
+ type: ActionType$4.UpdateAdvancedFilterState,
3775
3795
  advancedFilterState,
3776
3796
  });
3777
3797
  }, checked: advancedFilterState.includeAdmins, ariaLabel: "show logs from admins" }))),
@@ -3781,7 +3801,7 @@ const LogReviewer = (props) => {
3781
3801
  React__default["default"].createElement("input", { type: "text", className: "form-control", "aria-label": "query for course name", value: advancedFilterState.courseName, placeholder: "e.g. GLC 200", onChange: (e) => {
3782
3802
  advancedFilterState.courseName = e.target.value;
3783
3803
  dispatch({
3784
- type: ActionType$3.UpdateAdvancedFilterState,
3804
+ type: ActionType$4.UpdateAdvancedFilterState,
3785
3805
  advancedFilterState,
3786
3806
  });
3787
3807
  } })),
@@ -3795,7 +3815,7 @@ const LogReviewer = (props) => {
3795
3815
  .trim());
3796
3816
  }
3797
3817
  dispatch({
3798
- type: ActionType$3.UpdateAdvancedFilterState,
3818
+ type: ActionType$4.UpdateAdvancedFilterState,
3799
3819
  advancedFilterState,
3800
3820
  });
3801
3821
  } }))),
@@ -3804,21 +3824,21 @@ const LogReviewer = (props) => {
3804
3824
  React__default["default"].createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
3805
3825
  advancedFilterState.isMobile = undefined;
3806
3826
  dispatch({
3807
- type: ActionType$3.UpdateAdvancedFilterState,
3827
+ type: ActionType$4.UpdateAdvancedFilterState,
3808
3828
  advancedFilterState,
3809
3829
  });
3810
3830
  } }),
3811
3831
  React__default["default"].createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
3812
3832
  advancedFilterState.isMobile = true;
3813
3833
  dispatch({
3814
- type: ActionType$3.UpdateAdvancedFilterState,
3834
+ type: ActionType$4.UpdateAdvancedFilterState,
3815
3835
  advancedFilterState,
3816
3836
  });
3817
3837
  } }),
3818
3838
  React__default["default"].createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
3819
3839
  advancedFilterState.isMobile = false;
3820
3840
  dispatch({
3821
- type: ActionType$3.UpdateAdvancedFilterState,
3841
+ type: ActionType$4.UpdateAdvancedFilterState,
3822
3842
  advancedFilterState,
3823
3843
  });
3824
3844
  }, noMarginOnRight: true }))),
@@ -3827,21 +3847,21 @@ const LogReviewer = (props) => {
3827
3847
  React__default["default"].createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
3828
3848
  advancedFilterState.source = undefined;
3829
3849
  dispatch({
3830
- type: ActionType$3.UpdateAdvancedFilterState,
3850
+ type: ActionType$4.UpdateAdvancedFilterState,
3831
3851
  advancedFilterState,
3832
3852
  });
3833
3853
  } }),
3834
3854
  React__default["default"].createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
3835
3855
  advancedFilterState.source = LogSource$1.Client;
3836
3856
  dispatch({
3837
- type: ActionType$3.UpdateAdvancedFilterState,
3857
+ type: ActionType$4.UpdateAdvancedFilterState,
3838
3858
  advancedFilterState,
3839
3859
  });
3840
3860
  } }),
3841
3861
  React__default["default"].createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
3842
3862
  advancedFilterState.source = LogSource$1.Server;
3843
3863
  dispatch({
3844
- type: ActionType$3.UpdateAdvancedFilterState,
3864
+ type: ActionType$4.UpdateAdvancedFilterState,
3845
3865
  advancedFilterState,
3846
3866
  });
3847
3867
  }, noMarginOnRight: true })),
@@ -3852,7 +3872,7 @@ const LogReviewer = (props) => {
3852
3872
  advancedFilterState.courseName = ((e.target.value)
3853
3873
  .trim());
3854
3874
  dispatch({
3855
- type: ActionType$3.UpdateAdvancedFilterState,
3875
+ type: ActionType$4.UpdateAdvancedFilterState,
3856
3876
  advancedFilterState,
3857
3877
  });
3858
3878
  } })),
@@ -3862,7 +3882,7 @@ const LogReviewer = (props) => {
3862
3882
  advancedFilterState.courseName = ((e.target.value)
3863
3883
  .trim());
3864
3884
  dispatch({
3865
- type: ActionType$3.UpdateAdvancedFilterState,
3885
+ type: ActionType$4.UpdateAdvancedFilterState,
3866
3886
  advancedFilterState,
3867
3887
  });
3868
3888
  } })))))));
@@ -4141,7 +4161,7 @@ const LogReviewer = (props) => {
4141
4161
  }
4142
4162
  /* ---------- Wrap in Modal --------- */
4143
4163
  return (React__default["default"].createElement("div", { className: "LogReviewer-outer-container" },
4144
- React__default["default"].createElement("style", null, style$1),
4164
+ React__default["default"].createElement("style", null, style$2),
4145
4165
  React__default["default"].createElement("div", { className: "LogReviewer-inner-container" },
4146
4166
  React__default["default"].createElement("div", { className: "LogReviewer-header" },
4147
4167
  React__default["default"].createElement("div", { className: "LogReviewer-header-title" },
@@ -39467,11 +39487,11 @@ var CreatableSelect$1 = CreatableSelect;
39467
39487
  */
39468
39488
  /* ------------- Actions ------------ */
39469
39489
  // Types of actions
39470
- var ActionType$2;
39490
+ var ActionType$3;
39471
39491
  (function (ActionType) {
39472
39492
  // Update the input value
39473
39493
  ActionType["SetInputValue"] = "SetInputValue";
39474
- })(ActionType$2 || (ActionType$2 = {}));
39494
+ })(ActionType$3 || (ActionType$3 = {}));
39475
39495
  /**
39476
39496
  * Reducer that executes actions
39477
39497
  * @author Yuen Ler Chow
@@ -39479,9 +39499,9 @@ var ActionType$2;
39479
39499
  * @param action action to execute
39480
39500
  * @returns updated state
39481
39501
  */
39482
- const reducer$2 = (state, action) => {
39502
+ const reducer$3 = (state, action) => {
39483
39503
  switch (action.type) {
39484
- case ActionType$2.SetInputValue: {
39504
+ case ActionType$3.SetInputValue: {
39485
39505
  return Object.assign(Object.assign({}, state), { inputValue: action.value });
39486
39506
  }
39487
39507
  default: {
@@ -39501,7 +39521,7 @@ const CreatableMultiselect = (props) => {
39501
39521
  inputValue: '',
39502
39522
  };
39503
39523
  // Initialize state
39504
- const [state, dispatch] = React.useReducer(reducer$2, initialState);
39524
+ const [state, dispatch] = React.useReducer(reducer$3, initialState);
39505
39525
  // Destructure common state
39506
39526
  const { inputValue } = state;
39507
39527
  /*------------------------------------------------------------------------*/
@@ -39578,7 +39598,7 @@ const CreatableMultiselect = (props) => {
39578
39598
  }
39579
39599
  // Reset text field to empty because the values have been added
39580
39600
  dispatch({
39581
- type: ActionType$2.SetInputValue,
39601
+ type: ActionType$3.SetInputValue,
39582
39602
  value: '',
39583
39603
  });
39584
39604
  };
@@ -39617,7 +39637,7 @@ const CreatableMultiselect = (props) => {
39617
39637
  else {
39618
39638
  // simply update the input value to the new input value
39619
39639
  dispatch({
39620
- type: ActionType$2.SetInputValue,
39640
+ type: ActionType$3.SetInputValue,
39621
39641
  value: newValue,
39622
39642
  });
39623
39643
  }
@@ -39662,20 +39682,20 @@ const CreatableMultiselect = (props) => {
39662
39682
  /*------------------------------------------------------------------------*/
39663
39683
  /* -------------------------------- Style ------------------------------- */
39664
39684
  /*------------------------------------------------------------------------*/
39665
- const style = `
39685
+ const style$1 = `
39666
39686
  .AddOrEditDBEntry-input-label {
39667
39687
  min-width: 7rem;
39668
39688
  }
39669
39689
  `;
39670
39690
  /* ------------- Actions ------------ */
39671
39691
  // Types of actions
39672
- var ActionType$1;
39692
+ var ActionType$2;
39673
39693
  (function (ActionType) {
39674
39694
  // Update the DBEntry
39675
39695
  ActionType["UpdateDBEntry"] = "UpdateDBEntry";
39676
39696
  // Start the save spinner
39677
39697
  ActionType["StartSave"] = "StartSave";
39678
- })(ActionType$1 || (ActionType$1 = {}));
39698
+ })(ActionType$2 || (ActionType$2 = {}));
39679
39699
  /**
39680
39700
  * Reducer that executes actions
39681
39701
  * @author Yuen Ler Chow
@@ -39683,12 +39703,12 @@ var ActionType$1;
39683
39703
  * @param action action to execute
39684
39704
  * @returns updated state
39685
39705
  */
39686
- const reducer$1 = (state, action) => {
39706
+ const reducer$2 = (state, action) => {
39687
39707
  switch (action.type) {
39688
- case ActionType$1.UpdateDBEntry: {
39708
+ case ActionType$2.UpdateDBEntry: {
39689
39709
  return Object.assign(Object.assign({}, state), { entry: action.dbEntry });
39690
39710
  }
39691
- case ActionType$1.StartSave: {
39711
+ case ActionType$2.StartSave: {
39692
39712
  return Object.assign(Object.assign({}, state), { saving: true });
39693
39713
  }
39694
39714
  default: {
@@ -39713,7 +39733,7 @@ const AddOrEditDBEntry = (props) => {
39713
39733
  saving: false,
39714
39734
  };
39715
39735
  // Initialize state
39716
- const [state, dispatch] = React.useReducer(reducer$1, initialState);
39736
+ const [state, dispatch] = React.useReducer(reducer$2, initialState);
39717
39737
  // Destructure common state
39718
39738
  const { entry, saving, } = state;
39719
39739
  /*------------------------------------------------------------------------*/
@@ -39725,7 +39745,7 @@ const AddOrEditDBEntry = (props) => {
39725
39745
  */
39726
39746
  const save = () => __awaiter(void 0, void 0, void 0, function* () {
39727
39747
  // Start the save loading indicator
39728
- dispatch({ type: ActionType$1.StartSave });
39748
+ dispatch({ type: ActionType$2.StartSave });
39729
39749
  // add all default values to the entry
39730
39750
  entryFields.forEach((field) => {
39731
39751
  if (field.defaultValue && !entry[field.objectKey]) {
@@ -39908,7 +39928,7 @@ const AddOrEditDBEntry = (props) => {
39908
39928
  return (React__default["default"].createElement(RadioButton, { key: choice.value, text: choice.title, selected: entry[field.objectKey] === choice.value, onSelected: () => {
39909
39929
  entry[field.objectKey] = choice.value;
39910
39930
  dispatch({
39911
- type: ActionType$1.UpdateDBEntry,
39931
+ type: ActionType$2.UpdateDBEntry,
39912
39932
  dbEntry: entry,
39913
39933
  });
39914
39934
  }, ariaLabel: choice.title }));
@@ -39920,7 +39940,7 @@ const AddOrEditDBEntry = (props) => {
39920
39940
  React__default["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) => {
39921
39941
  entry[field.objectKey] = (e.target.value);
39922
39942
  dispatch({
39923
- type: ActionType$1.UpdateDBEntry,
39943
+ type: ActionType$2.UpdateDBEntry,
39924
39944
  dbEntry: entry,
39925
39945
  });
39926
39946
  } }))));
@@ -39933,7 +39953,7 @@ const AddOrEditDBEntry = (props) => {
39933
39953
  entry[field.objectKey] = (e.target.value
39934
39954
  .replace(/[^0-9]/g, ''));
39935
39955
  dispatch({
39936
- type: ActionType$1.UpdateDBEntry,
39956
+ type: ActionType$2.UpdateDBEntry,
39937
39957
  dbEntry: entry,
39938
39958
  });
39939
39959
  } }))));
@@ -39963,7 +39983,7 @@ const AddOrEditDBEntry = (props) => {
39963
39983
  }
39964
39984
  // Save
39965
39985
  dispatch({
39966
- type: ActionType$1.UpdateDBEntry,
39986
+ type: ActionType$2.UpdateDBEntry,
39967
39987
  dbEntry: entry,
39968
39988
  });
39969
39989
  }, ariaLabel: choice.title }));
@@ -39978,7 +39998,7 @@ const AddOrEditDBEntry = (props) => {
39978
39998
  // Update entry and save
39979
39999
  entry[field.objectKey] = values;
39980
40000
  dispatch({
39981
- type: ActionType$1.UpdateDBEntry,
40001
+ type: ActionType$2.UpdateDBEntry,
39982
40002
  dbEntry: entry,
39983
40003
  });
39984
40004
  } })))));
@@ -39991,7 +40011,7 @@ const AddOrEditDBEntry = (props) => {
39991
40011
  React__default["default"].createElement(CreatableMultiselect, { disabled: disabled, type: DBEntryFieldType$1.NumberArray, values: entry[field.objectKey] || [], onChange: (values) => {
39992
40012
  entry[field.objectKey] = values;
39993
40013
  dispatch({
39994
- type: ActionType$1.UpdateDBEntry,
40014
+ type: ActionType$2.UpdateDBEntry,
39995
40015
  dbEntry: entry,
39996
40016
  });
39997
40017
  } })))));
@@ -40040,7 +40060,7 @@ const AddOrEditDBEntry = (props) => {
40040
40060
  /* --------------- Main UI -------------- */
40041
40061
  /*----------------------------------------*/
40042
40062
  return (React__default["default"].createElement("div", { className: "alert alert-light text-black" },
40043
- React__default["default"].createElement("style", null, style),
40063
+ React__default["default"].createElement("style", null, style$1),
40044
40064
  body));
40045
40065
  };
40046
40066
 
@@ -40065,7 +40085,7 @@ const generateEndpointPath = (collectionName, adminsOnly) => {
40065
40085
  */
40066
40086
  /* ------------- Actions ------------ */
40067
40087
  // Types of actions
40068
- var ActionType;
40088
+ var ActionType$1;
40069
40089
  (function (ActionType) {
40070
40090
  // Show adder
40071
40091
  ActionType["ShowAdder"] = "ShowAdder";
@@ -40079,7 +40099,7 @@ var ActionType;
40079
40099
  ActionType["StartDelete"] = "StartDelete";
40080
40100
  // Finish deletion process
40081
40101
  ActionType["FinishDelete"] = "FinishDelete";
40082
- })(ActionType || (ActionType = {}));
40102
+ })(ActionType$1 || (ActionType$1 = {}));
40083
40103
  /**
40084
40104
  * Reducer that executes actions
40085
40105
  * @author Yuen Ler Chow
@@ -40087,18 +40107,18 @@ var ActionType;
40087
40107
  * @param action action to execute
40088
40108
  * @returns updated state
40089
40109
  */
40090
- const reducer = (state, action) => {
40110
+ const reducer$1 = (state, action) => {
40091
40111
  switch (action.type) {
40092
- case ActionType.FinishLoading: {
40112
+ case ActionType$1.FinishLoading: {
40093
40113
  return Object.assign(Object.assign({}, state), { loading: false, dbEntries: action.dbEntries });
40094
40114
  }
40095
- case ActionType.ShowAdder: {
40115
+ case ActionType$1.ShowAdder: {
40096
40116
  return Object.assign(Object.assign({}, state), { adding: true, dbEntryToEdit: undefined });
40097
40117
  }
40098
- case ActionType.ShowEditor: {
40118
+ case ActionType$1.ShowEditor: {
40099
40119
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: action.dbEntry });
40100
40120
  }
40101
- case ActionType.FinishAdd: {
40121
+ case ActionType$1.FinishAdd: {
40102
40122
  // Handle cancel
40103
40123
  const finishedEntry = action.dbEntry;
40104
40124
  if (!finishedEntry) {
@@ -40122,10 +40142,10 @@ const reducer = (state, action) => {
40122
40142
  // Update the state
40123
40143
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: undefined, dbEntries: updatedDbEntries });
40124
40144
  }
40125
- case ActionType.StartDelete: {
40145
+ case ActionType$1.StartDelete: {
40126
40146
  return Object.assign(Object.assign({}, state), { loading: true });
40127
40147
  }
40128
- case ActionType.FinishDelete: {
40148
+ case ActionType$1.FinishDelete: {
40129
40149
  return Object.assign(Object.assign({}, state), { loading: false,
40130
40150
  // Remove the deleted entry from the list
40131
40151
  dbEntries: state.dbEntries.filter((entry) => {
@@ -40151,7 +40171,7 @@ const DBEntryManagerPanel = (props) => {
40151
40171
  loading: true,
40152
40172
  };
40153
40173
  // Initialize state
40154
- const [state, dispatch] = React.useReducer(reducer, initialState);
40174
+ const [state, dispatch] = React.useReducer(reducer$1, initialState);
40155
40175
  // Destructure common state
40156
40176
  const { adding, dbEntryToEdit, dbEntries, loading, } = state;
40157
40177
  /*------------------------------------------------------------------------*/
@@ -40177,7 +40197,7 @@ const DBEntryManagerPanel = (props) => {
40177
40197
  try {
40178
40198
  // Start loader
40179
40199
  dispatch({
40180
- type: ActionType.StartDelete,
40200
+ type: ActionType$1.StartDelete,
40181
40201
  });
40182
40202
  // Perform deletion
40183
40203
  yield visitServerEndpoint({
@@ -40186,7 +40206,7 @@ const DBEntryManagerPanel = (props) => {
40186
40206
  });
40187
40207
  // Finish loader
40188
40208
  dispatch({
40189
- type: ActionType.FinishDelete,
40209
+ type: ActionType$1.FinishDelete,
40190
40210
  dbEntry: entry,
40191
40211
  idPropName,
40192
40212
  });
@@ -40215,7 +40235,7 @@ const DBEntryManagerPanel = (props) => {
40215
40235
  });
40216
40236
  // Save loaded data
40217
40237
  dispatch({
40218
- type: ActionType.FinishLoading,
40238
+ type: ActionType$1.FinishLoading,
40219
40239
  dbEntries: data,
40220
40240
  });
40221
40241
  }
@@ -40258,7 +40278,7 @@ const DBEntryManagerPanel = (props) => {
40258
40278
  React__default["default"].createElement("span", { className: "d-none d-md-inline ms-1" }, "Remove")),
40259
40279
  !disableEdit && (React__default["default"].createElement("button", { type: "button", id: `DBEntryManagerPanel-edit-with-id-${entry[idPropName]}`, className: "btn btn-primary", "aria-label": `edit db entry: ${entry[titlePropName]}`, onClick: () => {
40260
40280
  dispatch({
40261
- type: ActionType.ShowEditor,
40281
+ type: ActionType$1.ShowEditor,
40262
40282
  dbEntry: entry,
40263
40283
  });
40264
40284
  } },
@@ -40268,7 +40288,7 @@ const DBEntryManagerPanel = (props) => {
40268
40288
  React__default["default"].createElement("div", { className: "d-grid" },
40269
40289
  React__default["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: () => {
40270
40290
  dispatch({
40271
- type: ActionType.ShowAdder,
40291
+ type: ActionType$1.ShowAdder,
40272
40292
  });
40273
40293
  } },
40274
40294
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faPlus, className: "me-2" }),
@@ -40280,7 +40300,7 @@ const DBEntryManagerPanel = (props) => {
40280
40300
  if (!loading && (adding || dbEntryToEdit)) {
40281
40301
  body = (React__default["default"].createElement(AddOrEditDBEntry, { saveEndpointPath: endpoint, validateEntry: validateEntry, modifyEntry: modifyEntry, entryFields: entryFields, dbEntryToEdit: dbEntryToEdit, idPropName: idPropName, entries: dbEntries, itemName: itemName, onFinished: (entry) => {
40282
40302
  dispatch({
40283
- type: ActionType.FinishAdd,
40303
+ type: ActionType$1.FinishAdd,
40284
40304
  dbEntry: entry,
40285
40305
  idPropName,
40286
40306
  });
@@ -40292,6 +40312,403 @@ const DBEntryManagerPanel = (props) => {
40292
40312
  return (React__default["default"].createElement("div", null, body));
40293
40313
  };
40294
40314
 
40315
+ /**
40316
+ * Simple tooltip component
40317
+ * @author Gabe Abrams
40318
+ */
40319
+ /*------------------------------------------------------------------------*/
40320
+ /* ------------------------------ Constants ----------------------------- */
40321
+ /*------------------------------------------------------------------------*/
40322
+ // Tooltip widths
40323
+ const TOOLTIP_WIDTH_THIN_REM = 5;
40324
+ const TOOLTIP_WIDTH_NORMAL_REM = 7;
40325
+ const TOOLTIP_WIDTH_WIDE_REM = 10;
40326
+ // Tooltip border radius
40327
+ const TOOLTIP_BORDER_RADIUS_REM = 0.3;
40328
+ /*------------------------------------------------------------------------*/
40329
+ /* -------------------------------- Style ------------------------------- */
40330
+ /*------------------------------------------------------------------------*/
40331
+ const style = `
40332
+ /* Container for contents and tooltip */
40333
+ .Tooltip-outer-container {
40334
+ display: inline-block;
40335
+ position: relative;
40336
+ }
40337
+
40338
+ /* Container for just tooltip */
40339
+ .Tooltip-tooltip-container {
40340
+ /* Position in middle but take no space */
40341
+ /* (so layout of page is unaffected) */
40342
+ position: absolute;
40343
+ display: inline-block;
40344
+ top: 0;
40345
+ left: 50%;
40346
+ height: 0;
40347
+ width: 0;
40348
+ overflow: visible;
40349
+ }
40350
+
40351
+ /* Tooltip */
40352
+ .Tooltip-tooltip {
40353
+ /* Position above item */
40354
+ display: inline-block;
40355
+ position: absolute;
40356
+ top: -2.3rem;
40357
+ height: 1.8rem;
40358
+ z-index: 1;
40359
+
40360
+ /* Use standard black font */
40361
+ font-size: 1rem;
40362
+ color: black;
40363
+
40364
+ /* Non-interactive */
40365
+ pointer-events: none;
40366
+ }
40367
+
40368
+ /* Tooltip box (the rectangle surrounding the text) */
40369
+ .Tooltip-box,
40370
+ .Tooltip-box-shadow,
40371
+ .Tooltip-box-highlight {
40372
+ /* Fill all space with rectangle */
40373
+ position: absolute;
40374
+ left: 0;
40375
+ top: 0;
40376
+ display: inline-block;
40377
+ width: 100%;
40378
+ height: 100%;
40379
+
40380
+ /* Rounded border */
40381
+ border: 0.15rem solid black;
40382
+ border-radius: ${TOOLTIP_BORDER_RADIUS_REM}rem;
40383
+ }
40384
+
40385
+ /* Tooltip highlight (the bright background to the text) */
40386
+ .Tooltip-box-highlight {
40387
+ /* Bootstrap warning variant background */
40388
+ background-color: rgb(255, 193, 7);
40389
+ border-radius: ${TOOLTIP_BORDER_RADIUS_REM}rem;
40390
+
40391
+ /* Place on top */
40392
+ z-index: -1;
40393
+ }
40394
+
40395
+ /* Tooltip box (the black rectangle) */
40396
+ .Tooltip-box {
40397
+ /* Plain black background */
40398
+ background-color: black;
40399
+
40400
+ /* Place in middle */
40401
+ z-index: -2;
40402
+ }
40403
+
40404
+ /* Tooltip box shadow (the white shadow beneath the box) */
40405
+ .Tooltip-box-shadow {
40406
+ /* White shadow */
40407
+ box-shadow: 0 0 0.3rem white;
40408
+
40409
+ /* Place beneath */
40410
+ z-index: -3;
40411
+ }
40412
+
40413
+ /* Tooltip contents (the text and icon) */
40414
+ .Tooltip-contents {
40415
+ /* Center text, don't allow overflow */
40416
+ white-space: nowrap;
40417
+ overflow: hidden;
40418
+ text-align: center;
40419
+ text-overflow: ellipsis;
40420
+ display: flex;
40421
+ align-items: center;
40422
+ justify-content: center;
40423
+
40424
+ /* Space within parent */
40425
+ z-index: 1;
40426
+ padding-left: 0.2rem;
40427
+ padding-right: 0.2rem;
40428
+ height: 100%;
40429
+ }
40430
+
40431
+ /* Tooltip text */
40432
+ .Tooltip-text {
40433
+ /* Center text, add ellipsis */
40434
+ overflow: hidden;
40435
+ text-align: center;
40436
+ text-overflow: ellipsis;
40437
+ }
40438
+
40439
+ /* Classes to switch between tooltip visible/hidden */
40440
+ .Tooltip-tooltip-visible-true {
40441
+ opacity: 1;
40442
+ }
40443
+ .Tooltip-tooltip-visible-false {
40444
+ opacity: 0;
40445
+ }
40446
+
40447
+ /* Classes to switch between tooltip sizes */
40448
+ .Tooltip-size-thin {
40449
+ width: ${TOOLTIP_WIDTH_THIN_REM}rem;
40450
+ left: calc(50% - ${TOOLTIP_WIDTH_THIN_REM / 2}rem);
40451
+ }
40452
+ .Tooltip-size-normal {
40453
+ width: ${TOOLTIP_WIDTH_NORMAL_REM}rem;
40454
+ left: calc(50% - ${TOOLTIP_WIDTH_NORMAL_REM / 2}rem);
40455
+ }
40456
+ .Tooltip-size-wide {
40457
+ width: ${TOOLTIP_WIDTH_WIDE_REM}rem;
40458
+ left: calc(50% - ${TOOLTIP_WIDTH_WIDE_REM / 2}rem);
40459
+ }
40460
+
40461
+ /* Arrow (beneath tooltip) */
40462
+ .Tooltip-arrow,
40463
+ .Tooltip-arrow-shadow {
40464
+ /* Position beneath tooltip */
40465
+ position: absolute;
40466
+ top: -1.5rem;
40467
+ font-size: 1.5rem;
40468
+ left: calc(50% - 0.5rem);
40469
+ width: 0;
40470
+ display: inline-block;
40471
+
40472
+ /* Non-interactive */
40473
+ pointer-events: none;
40474
+ }
40475
+
40476
+ /* Arrow itself */
40477
+ .Tooltip-arrow {
40478
+ color: black;
40479
+ z-index: 4;
40480
+ }
40481
+
40482
+ /* Arrow shadow */
40483
+ .Tooltip-arrow-shadow {
40484
+ z-index: -1;
40485
+
40486
+ /* Blur a white version of the caret as a shadow */
40487
+ color: white;
40488
+ filter: blur(0.2rem);
40489
+ }
40490
+
40491
+ /* Classes to switch between arrow visible/hidden */
40492
+ .Tooltip-arrow-visible-true {
40493
+ opacity: 1;
40494
+ }
40495
+ .Tooltip-arrow-visible-false {
40496
+ opacity: 0;
40497
+ }
40498
+ `;
40499
+ /* ------------- Actions ------------ */
40500
+ // Types of actions
40501
+ var ActionType;
40502
+ (function (ActionType) {
40503
+ // Make the tooltip visible
40504
+ ActionType["Show"] = "Show";
40505
+ // Make the tooltip invisible
40506
+ ActionType["Hide"] = "Hide";
40507
+ // Set nudge pixels
40508
+ ActionType["SetNudgePx"] = "SetNudgePx";
40509
+ // Set whether bottom left corner should be square
40510
+ ActionType["SetSquareBottomLeft"] = "SetSquareBottomLeft";
40511
+ // Set whether bottom right corner should be square
40512
+ ActionType["SetSquareBottomRight"] = "SetSquareBottomRight";
40513
+ })(ActionType || (ActionType = {}));
40514
+ /**
40515
+ * Reducer that executes actions
40516
+ * @author Gabe Abrams
40517
+ * @param state current state
40518
+ * @param action action to execute
40519
+ */
40520
+ const reducer = (state, action) => {
40521
+ switch (action.type) {
40522
+ case ActionType.Show: {
40523
+ return Object.assign(Object.assign({}, state), { isVisible: true });
40524
+ }
40525
+ case ActionType.Hide: {
40526
+ return Object.assign(Object.assign({}, state), { isVisible: false, nudgePx: 0 });
40527
+ }
40528
+ case ActionType.SetNudgePx: {
40529
+ return Object.assign(Object.assign({}, state), { nudgePx: action.nudgePx });
40530
+ }
40531
+ case ActionType.SetSquareBottomLeft: {
40532
+ return Object.assign(Object.assign({}, state), { squareBottomLeft: action.squareBottomLeft });
40533
+ }
40534
+ case ActionType.SetSquareBottomRight: {
40535
+ return Object.assign(Object.assign({}, state), { squareBottomRight: action.squareBottomRight });
40536
+ }
40537
+ default: {
40538
+ return state;
40539
+ }
40540
+ }
40541
+ };
40542
+ /*------------------------------------------------------------------------*/
40543
+ /* ------------------------------ Component ----------------------------- */
40544
+ /*------------------------------------------------------------------------*/
40545
+ const Tooltip = (props) => {
40546
+ /*------------------------------------------------------------------------*/
40547
+ /* -------------------------------- Setup ------------------------------- */
40548
+ /*------------------------------------------------------------------------*/
40549
+ /* -------------- Props ------------- */
40550
+ // Destructure all props
40551
+ const { icon, text, children, wide, thin, } = props;
40552
+ /* -------------- State ------------- */
40553
+ // Initial state
40554
+ const initialState = {
40555
+ isVisible: false,
40556
+ nudgePx: 0,
40557
+ };
40558
+ // Initialize state
40559
+ const [state, dispatch] = React.useReducer(reducer, initialState);
40560
+ // Destructure common state
40561
+ const { isVisible, nudgePx, squareBottomLeft, squareBottomRight, } = state;
40562
+ /* -------------- Refs -------------- */
40563
+ // Initialize refs
40564
+ const tooltipContainer = React.useRef(null);
40565
+ const arrowElement = React.useRef(null);
40566
+ /*------------------------------------------------------------------------*/
40567
+ /* ------------------------- Lifecycle Functions ------------------------ */
40568
+ /*------------------------------------------------------------------------*/
40569
+ /**
40570
+ * Update (also called on mount)
40571
+ * @author Gabe Abrams
40572
+ */
40573
+ React.useEffect(() => {
40574
+ // Update tooltip container position
40575
+ if (tooltipContainer.current && isVisible) {
40576
+ // Get the tooltip container location
40577
+ const tooltipContainerRect = (tooltipContainer
40578
+ .current
40579
+ .getBoundingClientRect());
40580
+ // Get the window width
40581
+ const windowWidth = window.innerWidth;
40582
+ // Calculate new nudge value
40583
+ let newNudgePx;
40584
+ if (tooltipContainerRect.left < 0) {
40585
+ // Tooltip is off the left side of the screen
40586
+ newNudgePx = -1 * tooltipContainerRect.left;
40587
+ }
40588
+ else if (tooltipContainerRect.right > windowWidth) {
40589
+ // Tooltip is off the right side of the screen
40590
+ newNudgePx = -1 * (tooltipContainerRect.right - windowWidth);
40591
+ }
40592
+ else {
40593
+ // Tooltip is in the middle of the screen
40594
+ newNudgePx = 0;
40595
+ }
40596
+ // Update state
40597
+ dispatch({
40598
+ type: ActionType.SetNudgePx,
40599
+ nudgePx: newNudgePx,
40600
+ });
40601
+ }
40602
+ // Update border rounding
40603
+ if (arrowElement.current && isVisible) {
40604
+ // Get the arrow location
40605
+ const arrowRect = (arrowElement
40606
+ .current
40607
+ .getBoundingClientRect());
40608
+ // REM in pixels given font size
40609
+ const remInPixels = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10);
40610
+ // Set bottom left corner rounding
40611
+ dispatch({
40612
+ type: ActionType.SetSquareBottomLeft,
40613
+ squareBottomLeft: (arrowRect.left < (TOOLTIP_BORDER_RADIUS_REM * remInPixels)),
40614
+ });
40615
+ // Set bottom right corner rounding
40616
+ dispatch({
40617
+ type: ActionType.SetSquareBottomRight,
40618
+ squareBottomRight: (arrowRect.right
40619
+ > window.innerWidth - (TOOLTIP_BORDER_RADIUS_REM * remInPixels)),
40620
+ });
40621
+ }
40622
+ }, [isVisible]);
40623
+ /*------------------------------------------------------------------------*/
40624
+ /* ------------------------------- Render ------------------------------- */
40625
+ /*------------------------------------------------------------------------*/
40626
+ /*----------------------------------------*/
40627
+ /* --------------- Main UI -------------- */
40628
+ /*----------------------------------------*/
40629
+ // Determine size
40630
+ let size = 'normal';
40631
+ if (wide) {
40632
+ size = 'wide';
40633
+ }
40634
+ else if (thin) {
40635
+ size = 'thin';
40636
+ }
40637
+ // Render
40638
+ return (React__default["default"].createElement("div", { className: "Tooltip-outer-container", "aria-label": text, onMouseEnter: () => {
40639
+ dispatch({
40640
+ type: ActionType.Show,
40641
+ });
40642
+ }, onMouseLeave: () => {
40643
+ dispatch({
40644
+ type: ActionType.Hide,
40645
+ });
40646
+ }, onFocus: () => {
40647
+ dispatch({
40648
+ type: ActionType.Show,
40649
+ });
40650
+ }, onBlur: () => {
40651
+ dispatch({
40652
+ type: ActionType.Hide,
40653
+ });
40654
+ } },
40655
+ React__default["default"].createElement("style", null, style),
40656
+ children,
40657
+ React__default["default"].createElement("div", { className: `Tooltip-arrow Tooltip-arrow-visible-${isVisible ? 'true' : 'false'}`, ref: arrowElement },
40658
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCaretDown })),
40659
+ React__default["default"].createElement("div", { className: `Tooltip-arrow-shadow Tooltip-arrow-visible-${isVisible ? 'true' : 'false'}` },
40660
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCaretDown })),
40661
+ React__default["default"].createElement("div", { className: "Tooltip-tooltip-container" },
40662
+ React__default["default"].createElement("div", { className: `Tooltip-tooltip Tooltip-tooltip-visible-${isVisible ? 'true' : 'false'} Tooltip-size-${size}`, role: "tooltip", ref: tooltipContainer, style: {
40663
+ transform: `translateX(${nudgePx}px)`,
40664
+ } },
40665
+ React__default["default"].createElement("div", { className: "Tooltip-box-highlight" }),
40666
+ React__default["default"].createElement("div", { className: "Tooltip-box", style: {
40667
+ borderBottomLeftRadius: squareBottomLeft ? 0 : undefined,
40668
+ borderBottomRightRadius: squareBottomRight ? 0 : undefined,
40669
+ } }),
40670
+ React__default["default"].createElement("div", { className: "Tooltip-box-shadow", style: {
40671
+ borderBottomLeftRadius: squareBottomLeft ? 0 : undefined,
40672
+ borderBottomRightRadius: squareBottomRight ? 0 : undefined,
40673
+ } }),
40674
+ React__default["default"].createElement("div", { className: "Tooltip-contents" },
40675
+ icon && (React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: icon, className: "me-1" })),
40676
+ React__default["default"].createElement("span", { className: "Tooltip-text" }, text))))));
40677
+ };
40678
+
40679
+ /**
40680
+ * A toggle switch that toggles on or off
40681
+ * @author Alessandra De Lucas
40682
+ * @author Gabe Abrams
40683
+ */
40684
+ /*------------------------------------------------------------------------*/
40685
+ /* ------------------------------ Component ----------------------------- */
40686
+ /*------------------------------------------------------------------------*/
40687
+ const ToggleSwitch = (props) => {
40688
+ /*------------------------------------------------------------------------*/
40689
+ /* -------------------------------- Setup ------------------------------- */
40690
+ /*------------------------------------------------------------------------*/
40691
+ /* -------------- Props ------------- */
40692
+ // Destructure all props
40693
+ const { isOn, onToggle, id, description, backgroundVariantWhenOn = Variant$1.Info, } = props;
40694
+ /*------------------------------------------------------------------------*/
40695
+ /* ------------------------------- Render ------------------------------- */
40696
+ /*------------------------------------------------------------------------*/
40697
+ /*----------------------------------------*/
40698
+ /* --------------- Main UI -------------- */
40699
+ /*----------------------------------------*/
40700
+ const backgroundVariant = (isOn
40701
+ ? backgroundVariantWhenOn
40702
+ : 'secondary');
40703
+ return (React__default["default"].createElement("button", { id: id, "aria-label": `If on, ${description}. Currently ${isOn ? 'on' : 'off'}. Click to turn ${isOn ? 'off' : 'on'}.`, className: `alert alert-${backgroundVariant} bg-${backgroundVariant} mb-0 rounded-pill d-inline-block pt-0 pb-0 px-3`, onClick: () => {
40704
+ onToggle(!isOn);
40705
+ }, type: "button" },
40706
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "text-light", style: {
40707
+ transform: `translateX(${isOn ? '' : '-'}0.7rem)`,
40708
+ transition: '0.3s transform ease-in-out',
40709
+ } })));
40710
+ };
40711
+
40295
40712
  /**
40296
40713
  * One minute in ms
40297
40714
  * @author Gabe Abrams
@@ -42206,9 +42623,12 @@ exports.RadioButton = RadioButton;
42206
42623
  exports.ReactKitErrorCode = ReactKitErrorCode$1;
42207
42624
  exports.SimpleDateChooser = SimpleDateChooser;
42208
42625
  exports.TabBox = TabBox;
42626
+ exports.ToggleSwitch = ToggleSwitch;
42627
+ exports.Tooltip = Tooltip;
42209
42628
  exports.Variant = Variant$1;
42210
42629
  exports.abbreviate = abbreviate;
42211
42630
  exports.addDBEditorEndpoints = addDBEditorEndpoints;
42631
+ exports.addFatalErrorHandler = addFatalErrorHandler;
42212
42632
  exports.alert = alert$1;
42213
42633
  exports.avg = avg;
42214
42634
  exports.canReviewLogs = canReviewLogs;