dce-reactkit 3.5.4 → 3.5.6

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$a = `
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$a),
471
471
  React__default.createElement("div", { className: `Modal-backdrop ${backdropAnimationClass}`, style: {
472
472
  zIndex: 5000000003,
473
473
  }, onClick: () => __awaiter(void 0, void 0, void 0, function* () {
@@ -752,10 +752,10 @@ const logClientEvent = (opts) => __awaiter(void 0, void 0, void 0, function* ()
752
752
  * @author Gabe Abrams
753
753
  */
754
754
  /*------------------------------------------------------------------------*/
755
- /* Static Helpers */
755
+ /* --------------------------- Static Helpers --------------------------- */
756
756
  /*------------------------------------------------------------------------*/
757
757
  /*----------------------------------------*/
758
- /* Alert */
758
+ /* ---------------- Alert --------------- */
759
759
  /*----------------------------------------*/
760
760
  // Stored copies of setters
761
761
  let setAlertInfo;
@@ -769,6 +769,7 @@ let onAlertClosed;
769
769
  const alert$1 = (title, text) => __awaiter(void 0, void 0, void 0, function* () {
770
770
  // Fallback if alert not available
771
771
  if (!setAlertInfo) {
772
+ // eslint-disable-next-line no-alert
772
773
  window.alert(`${title}\n\n${text}`);
773
774
  return undefined;
774
775
  }
@@ -786,7 +787,7 @@ const alert$1 = (title, text) => __awaiter(void 0, void 0, void 0, function* ()
786
787
  });
787
788
  });
788
789
  /*----------------------------------------*/
789
- /* Confirm */
790
+ /* --------------- Confirm -------------- */
790
791
  /*----------------------------------------*/
791
792
  // Stored copies of setters
792
793
  let setConfirmInfo;
@@ -809,6 +810,7 @@ let onConfirmClosed;
809
810
  const confirm = (title, text, opts) => __awaiter(void 0, void 0, void 0, function* () {
810
811
  // Fallback if confirm is not available
811
812
  if (!setConfirmInfo) {
813
+ // eslint-disable-next-line no-alert
812
814
  return window.confirm(`${title}\n\n${text}`);
813
815
  }
814
816
  // Return promise that resolves with result of confirmation
@@ -826,12 +828,14 @@ const confirm = (title, text, opts) => __awaiter(void 0, void 0, void 0, functio
826
828
  });
827
829
  });
828
830
  /*----------------------------------------*/
829
- /* Fatal Error */
831
+ /* ------------- Fatal Error ------------ */
830
832
  /*----------------------------------------*/
831
833
  // Stored copies of setters
832
834
  let setFatalErrorMessage;
833
835
  let setFatalErrorCode;
834
836
  let setFatalErrorTitle;
837
+ // Fatal error listeners
838
+ const fatalErrorHandlers = [];
835
839
  /**
836
840
  * Show a fatal error message
837
841
  * @author Gabe Abrams
@@ -847,6 +851,15 @@ const showFatalError = (error, errorTitle = 'An Error Occurred') => {
847
851
  const code = (typeof error === 'string'
848
852
  ? ReactKitErrorCode$1.NoCode
849
853
  : String((_b = error.code) !== null && _b !== void 0 ? _b : ReactKitErrorCode$1.NoCode));
854
+ // Call all fatal error listeners
855
+ try {
856
+ fatalErrorHandlers.forEach((handler) => {
857
+ handler();
858
+ });
859
+ }
860
+ catch (err) {
861
+ // Ignore listener errors
862
+ }
850
863
  // Add log
851
864
  logClientEvent({
852
865
  context: LogBuiltInMetadata.Context.ClientFatalError,
@@ -870,12 +883,19 @@ const showFatalError = (error, errorTitle = 'An Error Occurred') => {
870
883
  setFatalErrorTitle(errorTitle);
871
884
  return undefined;
872
885
  };
886
+ /**
887
+ * Add a handler for when a fatal error occurs
888
+ * @author Gabe Abrams
889
+ */
890
+ const addFatalErrorHandler = (handler) => {
891
+ fatalErrorHandlers.push(handler);
892
+ };
873
893
  /*------------------------------------------------------------------------*/
874
- /* Component */
894
+ /* ------------------------------ Component ----------------------------- */
875
895
  /*------------------------------------------------------------------------*/
876
896
  const AppWrapper = (props) => {
877
897
  /*------------------------------------------------------------------------*/
878
- /* Setup */
898
+ /* -------------------------------- Setup ------------------------------- */
879
899
  /*------------------------------------------------------------------------*/
880
900
  /* -------------- Props ------------- */
881
901
  const { children, dark, } = props;
@@ -896,10 +916,10 @@ const AppWrapper = (props) => {
896
916
  // Session expired
897
917
  const [sessionHasExpired, setSessionHasExpiredInner,] = useState(false);
898
918
  /*------------------------------------------------------------------------*/
899
- /* Render */
919
+ /* ------------------------------- Render ------------------------------- */
900
920
  /*------------------------------------------------------------------------*/
901
921
  /*----------------------------------------*/
902
- /* Modal */
922
+ /* ---------------- Modal --------------- */
903
923
  /*----------------------------------------*/
904
924
  // Modal that may be defined
905
925
  let modal;
@@ -923,7 +943,7 @@ const AppWrapper = (props) => {
923
943
  }, dontAllowBackdropExit: true }, confirmInfo.text));
924
944
  }
925
945
  /*----------------------------------------*/
926
- /* Views */
946
+ /* ---------------- Views --------------- */
927
947
  /*----------------------------------------*/
928
948
  // Body that will be filled with the current view
929
949
  let body;
@@ -949,7 +969,7 @@ const AppWrapper = (props) => {
949
969
  }
950
970
  /* --------------- App -------------- */
951
971
  if (!body) {
952
- body = (React__default.createElement(React__default.Fragment, null, children));
972
+ body = children;
953
973
  }
954
974
  /*----------------------------------------*/
955
975
  /* Main UI */
@@ -966,7 +986,7 @@ const AppWrapper = (props) => {
966
986
  /*------------------------------------------------------------------------*/
967
987
  /* Style */
968
988
  /*------------------------------------------------------------------------*/
969
- const style$8 = `
989
+ const style$9 = `
970
990
  /* Container fades in */
971
991
  .LoadingSpinner-container {
972
992
  animation-name: LoadingSpinner-container-fade-in;
@@ -1044,7 +1064,7 @@ const LoadingSpinner = () => {
1044
1064
  /*------------------------------------------------------------------------*/
1045
1065
  // Add all four blips to a container
1046
1066
  return (React__default.createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
1047
- React__default.createElement("style", null, style$8),
1067
+ React__default.createElement("style", null, style$9),
1048
1068
  React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-1 me-1" }),
1049
1069
  React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-2 me-1" }),
1050
1070
  React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "LoadingSpinner-blip-3 me-1" }),
@@ -1058,7 +1078,7 @@ const LoadingSpinner = () => {
1058
1078
  /*------------------------------------------------------------------------*/
1059
1079
  /* Style */
1060
1080
  /*------------------------------------------------------------------------*/
1061
- const style$7 = `
1081
+ const style$8 = `
1062
1082
  /* Tab Box */
1063
1083
  .TabBox-box {
1064
1084
  /* Light Border */
@@ -1138,7 +1158,7 @@ const TabBox = (props) => {
1138
1158
  /*----------------------------------------*/
1139
1159
  // Full UI
1140
1160
  return (React__default.createElement("div", { className: `TabBox-container ${noBottomMargin ? '' : 'mb-2'}` },
1141
- React__default.createElement("style", null, style$7),
1161
+ React__default.createElement("style", null, style$8),
1142
1162
  React__default.createElement("div", { className: "TabBox-title-container" },
1143
1163
  React__default.createElement("div", { className: "TabBox-title" }, title)),
1144
1164
  React__default.createElement("div", { className: `TabBox-box ps-2 pt-2 pe-2 ${noBottomPadding ? '' : 'pb-2'}` },
@@ -1460,7 +1480,7 @@ const SimpleDateChooser = (props) => {
1460
1480
  /*------------------------------------------------------------------------*/
1461
1481
  /* Style */
1462
1482
  /*------------------------------------------------------------------------*/
1463
- const style$6 = `
1483
+ const style$7 = `
1464
1484
  .Drawer-container {
1465
1485
  margin-left: 1rem;
1466
1486
  margin-right: 1rem;
@@ -1494,7 +1514,7 @@ const Drawer = (props) => {
1494
1514
  return (React__default.createElement("div", { className: "Drawer-container", style: {
1495
1515
  backgroundColor: (customBackgroundColor !== null && customBackgroundColor !== void 0 ? customBackgroundColor : undefined),
1496
1516
  } },
1497
- React__default.createElement("style", null, style$6),
1517
+ React__default.createElement("style", null, style$7),
1498
1518
  children));
1499
1519
  };
1500
1520
 
@@ -1505,7 +1525,7 @@ const Drawer = (props) => {
1505
1525
  /*------------------------------------------------------------------------*/
1506
1526
  /* Style */
1507
1527
  /*------------------------------------------------------------------------*/
1508
- const style$5 = `
1528
+ const style$6 = `
1509
1529
  .PopSuccessMark-outer-container {
1510
1530
  position: relative;
1511
1531
  display: inline-block;
@@ -1610,7 +1630,7 @@ const PopSuccessMark = (props) => {
1610
1630
  width: `${sizeRem}rem`,
1611
1631
  height: `${sizeRem}rem`,
1612
1632
  }, "aria-label": "checkmark indicating success" },
1613
- React__default.createElement("style", null, style$5),
1633
+ React__default.createElement("style", null, style$6),
1614
1634
  React__default.createElement("div", { className: `PopSuccessMark-check-stroke-1 bg-${checkVariant}`, style: {
1615
1635
  borderRadius: `${sizeRem / 5}rem`,
1616
1636
  } }),
@@ -1626,7 +1646,7 @@ const PopSuccessMark = (props) => {
1626
1646
  /*------------------------------------------------------------------------*/
1627
1647
  /* Style */
1628
1648
  /*------------------------------------------------------------------------*/
1629
- const style$4 = `
1649
+ const style$5 = `
1630
1650
  .PopFailureMark-outer-container {
1631
1651
  position: relative;
1632
1652
  display: inline-block;
@@ -1730,7 +1750,7 @@ const PopFailureMark = (props) => {
1730
1750
  width: `${sizeRem}rem`,
1731
1751
  height: `${sizeRem}rem`,
1732
1752
  }, "aria-label": "mark indicating failure" },
1733
- React__default.createElement("style", null, style$4),
1753
+ React__default.createElement("style", null, style$5),
1734
1754
  React__default.createElement("div", { className: `PopFailureMark-x-stroke-1 bg-${xVariant}`, style: {
1735
1755
  borderRadius: `${sizeRem / 5}rem`,
1736
1756
  } }),
@@ -1746,7 +1766,7 @@ const PopFailureMark = (props) => {
1746
1766
  /*------------------------------------------------------------------------*/
1747
1767
  /* Style */
1748
1768
  /*------------------------------------------------------------------------*/
1749
- const style$3 = `
1769
+ const style$4 = `
1750
1770
  .PopPendingMark-outer-container {
1751
1771
  position: relative;
1752
1772
  display: inline-block;
@@ -1819,7 +1839,7 @@ const PopPendingMark = (props) => {
1819
1839
  width: `${sizeRem}rem`,
1820
1840
  height: `${sizeRem}rem`,
1821
1841
  }, "aria-label": "mark indicating that the item is pending" },
1822
- React__default.createElement("style", null, style$3),
1842
+ React__default.createElement("style", null, style$4),
1823
1843
  React__default.createElement("div", null,
1824
1844
  React__default.createElement(FontAwesomeIcon, { icon: faHourglass, className: `PopPendingMark-hourglass text-${hourglassVariant}`, style: {
1825
1845
  fontSize: `${sizeRem * 0.6}rem`,
@@ -1832,27 +1852,27 @@ const PopPendingMark = (props) => {
1832
1852
  */
1833
1853
  /* ------------- Actions ------------ */
1834
1854
  // Types of actions
1835
- var ActionType$7;
1855
+ var ActionType$8;
1836
1856
  (function (ActionType) {
1837
1857
  // Indicate that the text was recently copied
1838
1858
  ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
1839
1859
  // Clear the status
1840
1860
  ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
1841
- })(ActionType$7 || (ActionType$7 = {}));
1861
+ })(ActionType$8 || (ActionType$8 = {}));
1842
1862
  /**
1843
1863
  * Reducer that executes actions
1844
1864
  * @author Gabe Abrams
1845
1865
  * @param state current state
1846
1866
  * @param action action to execute
1847
1867
  */
1848
- const reducer$7 = (state, action) => {
1868
+ const reducer$8 = (state, action) => {
1849
1869
  switch (action.type) {
1850
- case ActionType$7.IndicateRecentlyCopied: {
1870
+ case ActionType$8.IndicateRecentlyCopied: {
1851
1871
  return {
1852
1872
  recentlyCopied: true,
1853
1873
  };
1854
1874
  }
1855
- case ActionType$7.ClearRecentlyCopiedStatus: {
1875
+ case ActionType$8.ClearRecentlyCopiedStatus: {
1856
1876
  return {
1857
1877
  recentlyCopied: false,
1858
1878
  };
@@ -1878,7 +1898,7 @@ const CopiableBox = (props) => {
1878
1898
  recentlyCopied: false,
1879
1899
  };
1880
1900
  // Initialize state
1881
- const [state, dispatch] = useReducer(reducer$7, initialState);
1901
+ const [state, dispatch] = useReducer(reducer$8, initialState);
1882
1902
  // Destructure common state
1883
1903
  const { recentlyCopied, } = state;
1884
1904
  /*------------------------------------------------------------------------*/
@@ -1898,13 +1918,13 @@ const CopiableBox = (props) => {
1898
1918
  }
1899
1919
  // Show copied notice
1900
1920
  dispatch({
1901
- type: ActionType$7.IndicateRecentlyCopied,
1921
+ type: ActionType$8.IndicateRecentlyCopied,
1902
1922
  });
1903
1923
  // Wait a moment
1904
1924
  yield waitMs(4000);
1905
1925
  // Hide copied notice
1906
1926
  dispatch({
1907
- type: ActionType$7.ClearRecentlyCopiedStatus,
1927
+ type: ActionType$8.ClearRecentlyCopiedStatus,
1908
1928
  });
1909
1929
  });
1910
1930
  /*------------------------------------------------------------------------*/
@@ -1960,20 +1980,20 @@ const CopiableBox = (props) => {
1960
1980
  */
1961
1981
  /* ------------- Actions ------------ */
1962
1982
  // Types of actions
1963
- var ActionType$6;
1983
+ var ActionType$7;
1964
1984
  (function (ActionType) {
1965
1985
  // Toggle whether a child are being shown
1966
1986
  ActionType["ToggleChild"] = "toggle-child";
1967
- })(ActionType$6 || (ActionType$6 = {}));
1987
+ })(ActionType$7 || (ActionType$7 = {}));
1968
1988
  /**
1969
1989
  * Reducer that executes actions
1970
1990
  * @author Gabe Abrams
1971
1991
  * @param state current state
1972
1992
  * @param action action to execute
1973
1993
  */
1974
- const reducer$6 = (state, action) => {
1994
+ const reducer$7 = (state, action) => {
1975
1995
  switch (action.type) {
1976
- case ActionType$6.ToggleChild: {
1996
+ case ActionType$7.ToggleChild: {
1977
1997
  return Object.assign(Object.assign({}, state), { childExpanded: Object.assign(Object.assign({}, state.childExpanded), { [String(action.id)]: !state.childExpanded[String(action.id)] }) });
1978
1998
  }
1979
1999
  default: {
@@ -2002,7 +2022,7 @@ const NestableItemList = (props) => {
2002
2022
  childExpanded: initChildExpanded,
2003
2023
  };
2004
2024
  // Initialize state
2005
- const [state, dispatch] = useReducer(reducer$6, initialState);
2025
+ const [state, dispatch] = useReducer(reducer$7, initialState);
2006
2026
  // Destructure common state
2007
2027
  const { childExpanded, } = state;
2008
2028
  /*------------------------------------------------------------------------*/
@@ -2092,7 +2112,7 @@ const NestableItemList = (props) => {
2092
2112
  backgroundColor: 'transparent',
2093
2113
  }, type: "button", onClick: () => {
2094
2114
  dispatch({
2095
- type: ActionType$6.ToggleChild,
2115
+ type: ActionType$7.ToggleChild,
2096
2116
  id: item.id,
2097
2117
  });
2098
2118
  }, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}` },
@@ -2368,7 +2388,7 @@ var SortType;
2368
2388
  })(SortType || (SortType = {}));
2369
2389
  /* ------------- Actions ------------ */
2370
2390
  // Types of actions
2371
- var ActionType$5;
2391
+ var ActionType$6;
2372
2392
  (function (ActionType) {
2373
2393
  // Toggle sort column param
2374
2394
  ActionType["ToggleSortColumn"] = "toggle-sort-column";
@@ -2380,16 +2400,16 @@ var ActionType$5;
2380
2400
  ActionType["ShowAllColumns"] = "show-all-columns";
2381
2401
  // Hide all columns
2382
2402
  ActionType["HideAllColumns"] = "hide-all-columns";
2383
- })(ActionType$5 || (ActionType$5 = {}));
2403
+ })(ActionType$6 || (ActionType$6 = {}));
2384
2404
  /**
2385
2405
  * Reducer that executes actions
2386
2406
  * @author Gabe Abrams
2387
2407
  * @param state current state
2388
2408
  * @param action action to execute
2389
2409
  */
2390
- const reducer$5 = (state, action) => {
2410
+ const reducer$6 = (state, action) => {
2391
2411
  switch (action.type) {
2392
- case ActionType$5.ToggleSortColumn: {
2412
+ case ActionType$6.ToggleSortColumn: {
2393
2413
  if (action.param !== state.sortColumnParam) {
2394
2414
  // Different column param
2395
2415
  return Object.assign(Object.assign({}, state), { sortColumnParam: action.param, sortType: SortType.Ascending });
@@ -2401,22 +2421,22 @@ const reducer$5 = (state, action) => {
2401
2421
  // Stop sorting by column
2402
2422
  return Object.assign(Object.assign({}, state), { sortColumnParam: undefined, sortType: SortType.Ascending });
2403
2423
  }
2404
- case ActionType$5.UpdateColumnVisibility: {
2424
+ case ActionType$6.UpdateColumnVisibility: {
2405
2425
  const { columnVisibilityMap } = state;
2406
2426
  columnVisibilityMap[action.param] = action.visible;
2407
2427
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2408
2428
  }
2409
- case ActionType$5.ToggleColVisCusModalVisibility: {
2429
+ case ActionType$6.ToggleColVisCusModalVisibility: {
2410
2430
  return Object.assign(Object.assign({}, state), { columnVisibilityCustomizationModalVisible: !state.columnVisibilityCustomizationModalVisible });
2411
2431
  }
2412
- case ActionType$5.ShowAllColumns: {
2432
+ case ActionType$6.ShowAllColumns: {
2413
2433
  const { columnVisibilityMap } = state;
2414
2434
  Object.keys(columnVisibilityMap).forEach((param) => {
2415
2435
  columnVisibilityMap[param] = true;
2416
2436
  });
2417
2437
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2418
2438
  }
2419
- case ActionType$5.HideAllColumns: {
2439
+ case ActionType$6.HideAllColumns: {
2420
2440
  const { columnVisibilityMap } = state;
2421
2441
  Object.keys(columnVisibilityMap).forEach((param) => {
2422
2442
  columnVisibilityMap[param] = false;
@@ -2463,7 +2483,7 @@ const IntelliTable = (props) => {
2463
2483
  columnVisibilityCustomizationModalVisible: false,
2464
2484
  };
2465
2485
  // Initialize state
2466
- const [state, dispatch] = useReducer(reducer$5, initialState);
2486
+ const [state, dispatch] = useReducer(reducer$6, initialState);
2467
2487
  // Destructure common state
2468
2488
  const { sortColumnParam, sortType, columnVisibilityMap, columnVisibilityCustomizationModalVisible, } = state;
2469
2489
  /*------------------------------------------------------------------------*/
@@ -2486,13 +2506,13 @@ const IntelliTable = (props) => {
2486
2506
  return alert$1('Choose at least one column', 'To continue, you have to choose at least one column to show');
2487
2507
  }
2488
2508
  dispatch({
2489
- type: ActionType$5.ToggleColVisCusModalVisibility,
2509
+ type: ActionType$6.ToggleColVisCusModalVisibility,
2490
2510
  });
2491
2511
  }, okayVariant: Variant$1.Light },
2492
2512
  columns.map((column) => {
2493
2513
  return (React__default.createElement(CheckboxButton, { key: column.param, id: `IntelliTable-${id}-toggle-visibility-${column.param}`, className: "mb-2", text: column.title, onChanged: (checked) => {
2494
2514
  dispatch({
2495
- type: ActionType$5.UpdateColumnVisibility,
2515
+ type: ActionType$6.UpdateColumnVisibility,
2496
2516
  param: column.param,
2497
2517
  visible: checked,
2498
2518
  });
@@ -2501,12 +2521,12 @@ const IntelliTable = (props) => {
2501
2521
  React__default.createElement("div", { className: "mt-3" }, "Or you can:"),
2502
2522
  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: () => {
2503
2523
  dispatch({
2504
- type: ActionType$5.ShowAllColumns,
2524
+ type: ActionType$6.ShowAllColumns,
2505
2525
  });
2506
2526
  } }, "Select All"),
2507
2527
  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: () => {
2508
2528
  dispatch({
2509
- type: ActionType$5.HideAllColumns,
2529
+ type: ActionType$6.HideAllColumns,
2510
2530
  });
2511
2531
  } }, "Deselect All")));
2512
2532
  }
@@ -2557,7 +2577,7 @@ const IntelliTable = (props) => {
2557
2577
  React__default.createElement("div", null,
2558
2578
  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: () => {
2559
2579
  dispatch({
2560
- type: ActionType$5.ToggleSortColumn,
2580
+ type: ActionType$6.ToggleSortColumn,
2561
2581
  param: column.param,
2562
2582
  });
2563
2583
  } },
@@ -2746,7 +2766,7 @@ const IntelliTable = (props) => {
2746
2766
  React__default.createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: filename, csv: csv }),
2747
2767
  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: () => {
2748
2768
  dispatch({
2749
- type: ActionType$5.ToggleColVisCusModalVisibility,
2769
+ type: ActionType$6.ToggleColVisCusModalVisibility,
2750
2770
  });
2751
2771
  } },
2752
2772
  "Show/Hide Cols",
@@ -2778,7 +2798,7 @@ var FilterDrawer;
2778
2798
  /*------------------------------------------------------------------------*/
2779
2799
  /* Style */
2780
2800
  /*------------------------------------------------------------------------*/
2781
- const style$2 = `
2801
+ const style$3 = `
2782
2802
  .LogReviewer-outer-container {
2783
2803
  /* Full Screen */
2784
2804
  display: inline-block;
@@ -3112,7 +3132,7 @@ const genHumanReadableName = (machineReadableName) => {
3112
3132
  };
3113
3133
  /* ------------- Actions ------------ */
3114
3134
  // Types of actions
3115
- var ActionType$4;
3135
+ var ActionType$5;
3116
3136
  (function (ActionType) {
3117
3137
  // Show the loading bar
3118
3138
  ActionType["StartLoading"] = "start-loading";
@@ -3134,45 +3154,45 @@ var ActionType$4;
3134
3154
  ActionType["UpdateActionErrorFilterState"] = "update-action-error-filter-state";
3135
3155
  // Update the advanced filter state
3136
3156
  ActionType["UpdateAdvancedFilterState"] = "update-advanced-filter-state";
3137
- })(ActionType$4 || (ActionType$4 = {}));
3157
+ })(ActionType$5 || (ActionType$5 = {}));
3138
3158
  /**
3139
3159
  * Reducer that executes actions
3140
3160
  * @author Gabe Abrams
3141
3161
  * @param state current state
3142
3162
  * @param action action to execute
3143
3163
  */
3144
- const reducer$4 = (state, action) => {
3164
+ const reducer$5 = (state, action) => {
3145
3165
  switch (action.type) {
3146
- case ActionType$4.StartLoading: {
3166
+ case ActionType$5.StartLoading: {
3147
3167
  return Object.assign(Object.assign({}, state), { loading: true });
3148
3168
  }
3149
- case ActionType$4.FinishLoading: {
3169
+ case ActionType$5.FinishLoading: {
3150
3170
  return Object.assign(Object.assign({}, state), { loading: false, logMap: action.logMap });
3151
3171
  }
3152
- case ActionType$4.ToggleFilterDrawer: {
3172
+ case ActionType$5.ToggleFilterDrawer: {
3153
3173
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: (state.expandedFilterDrawer === action.filterDrawer
3154
3174
  ? undefined // hide
3155
3175
  : action.filterDrawer) });
3156
3176
  }
3157
- case ActionType$4.HideFilterDrawer: {
3177
+ case ActionType$5.HideFilterDrawer: {
3158
3178
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: undefined });
3159
3179
  }
3160
- case ActionType$4.ResetFilters: {
3180
+ case ActionType$5.ResetFilters: {
3161
3181
  return Object.assign(Object.assign({}, state), { dateFilterState: action.initDateFilterState, contextFilterState: action.initContextFilterState, tagFilterState: action.initTagFilterState, actionErrorFilterState: action.initActionErrorFilterState, advancedFilterState: action.initAdvancedFilterState });
3162
3182
  }
3163
- case ActionType$4.UpdateDateFilterState: {
3183
+ case ActionType$5.UpdateDateFilterState: {
3164
3184
  return Object.assign(Object.assign({}, state), { dateFilterState: action.dateFilterState });
3165
3185
  }
3166
- case ActionType$4.UpdateContextFilterState: {
3186
+ case ActionType$5.UpdateContextFilterState: {
3167
3187
  return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
3168
3188
  }
3169
- case ActionType$4.UpdateTagFilterState: {
3189
+ case ActionType$5.UpdateTagFilterState: {
3170
3190
  return Object.assign(Object.assign({}, state), { tagFilterState: action.tagFilterState });
3171
3191
  }
3172
- case ActionType$4.UpdateActionErrorFilterState: {
3192
+ case ActionType$5.UpdateActionErrorFilterState: {
3173
3193
  return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
3174
3194
  }
3175
- case ActionType$4.UpdateAdvancedFilterState: {
3195
+ case ActionType$5.UpdateAdvancedFilterState: {
3176
3196
  return Object.assign(Object.assign({}, state), { advancedFilterState: action.advancedFilterState });
3177
3197
  }
3178
3198
  default: {
@@ -3301,7 +3321,7 @@ const LogReviewer = (props) => {
3301
3321
  advancedFilterState: initAdvancedFilterState,
3302
3322
  };
3303
3323
  // Initialize state
3304
- const [state, dispatch] = useReducer(reducer$4, initialState);
3324
+ const [state, dispatch] = useReducer(reducer$5, initialState);
3305
3325
  // Destructure common state
3306
3326
  const { loading, logMap, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, } = state;
3307
3327
  /*------------------------------------------------------------------------*/
@@ -3352,7 +3372,7 @@ const LogReviewer = (props) => {
3352
3372
  const handleDateRangeUpdated = (newDateFilterState) => __awaiter(void 0, void 0, void 0, function* () {
3353
3373
  // Update state
3354
3374
  dispatch({
3355
- type: ActionType$4.UpdateDateFilterState,
3375
+ type: ActionType$5.UpdateDateFilterState,
3356
3376
  dateFilterState: newDateFilterState,
3357
3377
  });
3358
3378
  // Check which year/month combos we need to load
@@ -3363,7 +3383,7 @@ const LogReviewer = (props) => {
3363
3383
  }
3364
3384
  // Start loading
3365
3385
  dispatch({
3366
- type: ActionType$4.StartLoading,
3386
+ type: ActionType$5.StartLoading,
3367
3387
  });
3368
3388
  // Load required months
3369
3389
  try {
@@ -3387,7 +3407,7 @@ const LogReviewer = (props) => {
3387
3407
  }
3388
3408
  // Finish loading
3389
3409
  dispatch({
3390
- type: ActionType$4.FinishLoading,
3410
+ type: ActionType$5.FinishLoading,
3391
3411
  logMap,
3392
3412
  });
3393
3413
  });
@@ -3426,7 +3446,7 @@ const LogReviewer = (props) => {
3426
3446
  React__default.createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
3427
3447
  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: () => {
3428
3448
  dispatch({
3429
- type: ActionType$4.ToggleFilterDrawer,
3449
+ type: ActionType$5.ToggleFilterDrawer,
3430
3450
  filterDrawer: FilterDrawer.Date,
3431
3451
  });
3432
3452
  } },
@@ -3434,7 +3454,7 @@ const LogReviewer = (props) => {
3434
3454
  "Date"),
3435
3455
  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: () => {
3436
3456
  dispatch({
3437
- type: ActionType$4.ToggleFilterDrawer,
3457
+ type: ActionType$5.ToggleFilterDrawer,
3438
3458
  filterDrawer: FilterDrawer.Context,
3439
3459
  });
3440
3460
  } },
@@ -3442,7 +3462,7 @@ const LogReviewer = (props) => {
3442
3462
  "Context"),
3443
3463
  (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: () => {
3444
3464
  dispatch({
3445
- type: ActionType$4.ToggleFilterDrawer,
3465
+ type: ActionType$5.ToggleFilterDrawer,
3446
3466
  filterDrawer: FilterDrawer.Tag,
3447
3467
  });
3448
3468
  } },
@@ -3450,7 +3470,7 @@ const LogReviewer = (props) => {
3450
3470
  "Tag")),
3451
3471
  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: () => {
3452
3472
  dispatch({
3453
- type: ActionType$4.ToggleFilterDrawer,
3473
+ type: ActionType$5.ToggleFilterDrawer,
3454
3474
  filterDrawer: FilterDrawer.Action,
3455
3475
  });
3456
3476
  } },
@@ -3458,7 +3478,7 @@ const LogReviewer = (props) => {
3458
3478
  "Action"),
3459
3479
  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: () => {
3460
3480
  dispatch({
3461
- type: ActionType$4.ToggleFilterDrawer,
3481
+ type: ActionType$5.ToggleFilterDrawer,
3462
3482
  filterDrawer: FilterDrawer.Advanced,
3463
3483
  });
3464
3484
  } },
@@ -3466,7 +3486,7 @@ const LogReviewer = (props) => {
3466
3486
  "Advanced"),
3467
3487
  React__default.createElement("button", { type: "button", id: "LogReviewer-reset-filters-button", className: "btn btn-light", "aria-label": "reset filters", onClick: () => {
3468
3488
  dispatch({
3469
- type: ActionType$4.ResetFilters,
3489
+ type: ActionType$5.ResetFilters,
3470
3490
  initActionErrorFilterState,
3471
3491
  initAdvancedFilterState,
3472
3492
  initContextFilterState,
@@ -3588,7 +3608,7 @@ const LogReviewer = (props) => {
3588
3608
  }
3589
3609
  });
3590
3610
  dispatch({
3591
- type: ActionType$4.UpdateContextFilterState,
3611
+ type: ActionType$5.UpdateContextFilterState,
3592
3612
  contextFilterState,
3593
3613
  });
3594
3614
  } }));
@@ -3603,7 +3623,7 @@ const LogReviewer = (props) => {
3603
3623
  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) => {
3604
3624
  tagFilterState[tag] = checked;
3605
3625
  dispatch({
3606
- type: ActionType$4.UpdateTagFilterState,
3626
+ type: ActionType$5.UpdateTagFilterState,
3607
3627
  tagFilterState,
3608
3628
  });
3609
3629
  } }));
@@ -3616,21 +3636,21 @@ const LogReviewer = (props) => {
3616
3636
  React__default.createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
3617
3637
  actionErrorFilterState.type = undefined;
3618
3638
  dispatch({
3619
- type: ActionType$4.UpdateActionErrorFilterState,
3639
+ type: ActionType$5.UpdateActionErrorFilterState,
3620
3640
  actionErrorFilterState,
3621
3641
  });
3622
3642
  }, ariaLabel: "show logs of all types", selected: actionErrorFilterState.type === undefined }),
3623
3643
  React__default.createElement(RadioButton, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
3624
3644
  actionErrorFilterState.type = LogType$1.Action;
3625
3645
  dispatch({
3626
- type: ActionType$4.UpdateActionErrorFilterState,
3646
+ type: ActionType$5.UpdateActionErrorFilterState,
3627
3647
  actionErrorFilterState,
3628
3648
  });
3629
3649
  }, ariaLabel: "only show action logs", selected: actionErrorFilterState.type === LogType$1.Action }),
3630
3650
  React__default.createElement(RadioButton, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
3631
3651
  actionErrorFilterState.type = LogType$1.Error;
3632
3652
  dispatch({
3633
- type: ActionType$4.UpdateActionErrorFilterState,
3653
+ type: ActionType$5.UpdateActionErrorFilterState,
3634
3654
  actionErrorFilterState,
3635
3655
  });
3636
3656
  }, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
@@ -3642,7 +3662,7 @@ const LogReviewer = (props) => {
3642
3662
  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) => {
3643
3663
  actionErrorFilterState.action[action] = checked;
3644
3664
  dispatch({
3645
- type: ActionType$4.UpdateActionErrorFilterState,
3665
+ type: ActionType$5.UpdateActionErrorFilterState,
3646
3666
  actionErrorFilterState,
3647
3667
  });
3648
3668
  } }));
@@ -3653,7 +3673,7 @@ const LogReviewer = (props) => {
3653
3673
  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) => {
3654
3674
  actionErrorFilterState.target[target] = checked;
3655
3675
  dispatch({
3656
- type: ActionType$4.UpdateActionErrorFilterState,
3676
+ type: ActionType$5.UpdateActionErrorFilterState,
3657
3677
  actionErrorFilterState,
3658
3678
  });
3659
3679
  } }));
@@ -3665,7 +3685,7 @@ const LogReviewer = (props) => {
3665
3685
  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) => {
3666
3686
  actionErrorFilterState.errorMessage = e.target.value;
3667
3687
  dispatch({
3668
- type: ActionType$4.UpdateActionErrorFilterState,
3688
+ type: ActionType$5.UpdateActionErrorFilterState,
3669
3689
  actionErrorFilterState,
3670
3690
  });
3671
3691
  } })),
@@ -3676,7 +3696,7 @@ const LogReviewer = (props) => {
3676
3696
  .trim()
3677
3697
  .toUpperCase());
3678
3698
  dispatch({
3679
- type: ActionType$4.UpdateActionErrorFilterState,
3699
+ type: ActionType$5.UpdateActionErrorFilterState,
3680
3700
  actionErrorFilterState,
3681
3701
  });
3682
3702
  } }))))));
@@ -3690,7 +3710,7 @@ const LogReviewer = (props) => {
3690
3710
  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) => {
3691
3711
  advancedFilterState.userFirstName = e.target.value;
3692
3712
  dispatch({
3693
- type: ActionType$4.UpdateAdvancedFilterState,
3713
+ type: ActionType$5.UpdateAdvancedFilterState,
3694
3714
  advancedFilterState,
3695
3715
  });
3696
3716
  } })),
@@ -3699,7 +3719,7 @@ const LogReviewer = (props) => {
3699
3719
  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) => {
3700
3720
  advancedFilterState.userLastName = e.target.value;
3701
3721
  dispatch({
3702
- type: ActionType$4.UpdateAdvancedFilterState,
3722
+ type: ActionType$5.UpdateAdvancedFilterState,
3703
3723
  advancedFilterState,
3704
3724
  });
3705
3725
  } })),
@@ -3709,7 +3729,7 @@ const LogReviewer = (props) => {
3709
3729
  advancedFilterState.userEmail = ((e.target.value)
3710
3730
  .trim());
3711
3731
  dispatch({
3712
- type: ActionType$4.UpdateAdvancedFilterState,
3732
+ type: ActionType$5.UpdateAdvancedFilterState,
3713
3733
  advancedFilterState,
3714
3734
  });
3715
3735
  } })),
@@ -3723,7 +3743,7 @@ const LogReviewer = (props) => {
3723
3743
  .trim());
3724
3744
  }
3725
3745
  dispatch({
3726
- type: ActionType$4.UpdateAdvancedFilterState,
3746
+ type: ActionType$5.UpdateAdvancedFilterState,
3727
3747
  advancedFilterState,
3728
3748
  });
3729
3749
  } })),
@@ -3731,21 +3751,21 @@ const LogReviewer = (props) => {
3731
3751
  React__default.createElement(CheckboxButton, { text: "Students", onChanged: (checked) => {
3732
3752
  advancedFilterState.includeLearners = checked;
3733
3753
  dispatch({
3734
- type: ActionType$4.UpdateAdvancedFilterState,
3754
+ type: ActionType$5.UpdateAdvancedFilterState,
3735
3755
  advancedFilterState,
3736
3756
  });
3737
3757
  }, checked: advancedFilterState.includeLearners, ariaLabel: "show logs from students" }),
3738
3758
  React__default.createElement(CheckboxButton, { text: "Teaching Team Members", onChanged: (checked) => {
3739
3759
  advancedFilterState.includeTTMs = checked;
3740
3760
  dispatch({
3741
- type: ActionType$4.UpdateAdvancedFilterState,
3761
+ type: ActionType$5.UpdateAdvancedFilterState,
3742
3762
  advancedFilterState,
3743
3763
  });
3744
3764
  }, checked: advancedFilterState.includeTTMs, ariaLabel: "show logs from teaching team members" }),
3745
3765
  React__default.createElement(CheckboxButton, { text: "Admins", onChanged: (checked) => {
3746
3766
  advancedFilterState.includeAdmins = checked;
3747
3767
  dispatch({
3748
- type: ActionType$4.UpdateAdvancedFilterState,
3768
+ type: ActionType$5.UpdateAdvancedFilterState,
3749
3769
  advancedFilterState,
3750
3770
  });
3751
3771
  }, checked: advancedFilterState.includeAdmins, ariaLabel: "show logs from admins" }))),
@@ -3755,7 +3775,7 @@ const LogReviewer = (props) => {
3755
3775
  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) => {
3756
3776
  advancedFilterState.courseName = e.target.value;
3757
3777
  dispatch({
3758
- type: ActionType$4.UpdateAdvancedFilterState,
3778
+ type: ActionType$5.UpdateAdvancedFilterState,
3759
3779
  advancedFilterState,
3760
3780
  });
3761
3781
  } })),
@@ -3769,7 +3789,7 @@ const LogReviewer = (props) => {
3769
3789
  .trim());
3770
3790
  }
3771
3791
  dispatch({
3772
- type: ActionType$4.UpdateAdvancedFilterState,
3792
+ type: ActionType$5.UpdateAdvancedFilterState,
3773
3793
  advancedFilterState,
3774
3794
  });
3775
3795
  } }))),
@@ -3778,21 +3798,21 @@ const LogReviewer = (props) => {
3778
3798
  React__default.createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
3779
3799
  advancedFilterState.isMobile = undefined;
3780
3800
  dispatch({
3781
- type: ActionType$4.UpdateAdvancedFilterState,
3801
+ type: ActionType$5.UpdateAdvancedFilterState,
3782
3802
  advancedFilterState,
3783
3803
  });
3784
3804
  } }),
3785
3805
  React__default.createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
3786
3806
  advancedFilterState.isMobile = true;
3787
3807
  dispatch({
3788
- type: ActionType$4.UpdateAdvancedFilterState,
3808
+ type: ActionType$5.UpdateAdvancedFilterState,
3789
3809
  advancedFilterState,
3790
3810
  });
3791
3811
  } }),
3792
3812
  React__default.createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
3793
3813
  advancedFilterState.isMobile = false;
3794
3814
  dispatch({
3795
- type: ActionType$4.UpdateAdvancedFilterState,
3815
+ type: ActionType$5.UpdateAdvancedFilterState,
3796
3816
  advancedFilterState,
3797
3817
  });
3798
3818
  }, noMarginOnRight: true }))),
@@ -3801,21 +3821,21 @@ const LogReviewer = (props) => {
3801
3821
  React__default.createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
3802
3822
  advancedFilterState.source = undefined;
3803
3823
  dispatch({
3804
- type: ActionType$4.UpdateAdvancedFilterState,
3824
+ type: ActionType$5.UpdateAdvancedFilterState,
3805
3825
  advancedFilterState,
3806
3826
  });
3807
3827
  } }),
3808
3828
  React__default.createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
3809
3829
  advancedFilterState.source = LogSource$1.Client;
3810
3830
  dispatch({
3811
- type: ActionType$4.UpdateAdvancedFilterState,
3831
+ type: ActionType$5.UpdateAdvancedFilterState,
3812
3832
  advancedFilterState,
3813
3833
  });
3814
3834
  } }),
3815
3835
  React__default.createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
3816
3836
  advancedFilterState.source = LogSource$1.Server;
3817
3837
  dispatch({
3818
- type: ActionType$4.UpdateAdvancedFilterState,
3838
+ type: ActionType$5.UpdateAdvancedFilterState,
3819
3839
  advancedFilterState,
3820
3840
  });
3821
3841
  }, noMarginOnRight: true })),
@@ -3826,7 +3846,7 @@ const LogReviewer = (props) => {
3826
3846
  advancedFilterState.courseName = ((e.target.value)
3827
3847
  .trim());
3828
3848
  dispatch({
3829
- type: ActionType$4.UpdateAdvancedFilterState,
3849
+ type: ActionType$5.UpdateAdvancedFilterState,
3830
3850
  advancedFilterState,
3831
3851
  });
3832
3852
  } })),
@@ -3836,7 +3856,7 @@ const LogReviewer = (props) => {
3836
3856
  advancedFilterState.courseName = ((e.target.value)
3837
3857
  .trim());
3838
3858
  dispatch({
3839
- type: ActionType$4.UpdateAdvancedFilterState,
3859
+ type: ActionType$5.UpdateAdvancedFilterState,
3840
3860
  advancedFilterState,
3841
3861
  });
3842
3862
  } })))))));
@@ -4115,7 +4135,7 @@ const LogReviewer = (props) => {
4115
4135
  }
4116
4136
  /* ---------- Wrap in Modal --------- */
4117
4137
  return (React__default.createElement("div", { className: "LogReviewer-outer-container" },
4118
- React__default.createElement("style", null, style$2),
4138
+ React__default.createElement("style", null, style$3),
4119
4139
  React__default.createElement("div", { className: "LogReviewer-inner-container" },
4120
4140
  React__default.createElement("div", { className: "LogReviewer-header" },
4121
4141
  React__default.createElement("div", { className: "LogReviewer-header-title" },
@@ -39441,11 +39461,11 @@ var CreatableSelect$1 = CreatableSelect;
39441
39461
  */
39442
39462
  /* ------------- Actions ------------ */
39443
39463
  // Types of actions
39444
- var ActionType$3;
39464
+ var ActionType$4;
39445
39465
  (function (ActionType) {
39446
39466
  // Update the input value
39447
39467
  ActionType["SetInputValue"] = "SetInputValue";
39448
- })(ActionType$3 || (ActionType$3 = {}));
39468
+ })(ActionType$4 || (ActionType$4 = {}));
39449
39469
  /**
39450
39470
  * Reducer that executes actions
39451
39471
  * @author Yuen Ler Chow
@@ -39453,9 +39473,9 @@ var ActionType$3;
39453
39473
  * @param action action to execute
39454
39474
  * @returns updated state
39455
39475
  */
39456
- const reducer$3 = (state, action) => {
39476
+ const reducer$4 = (state, action) => {
39457
39477
  switch (action.type) {
39458
- case ActionType$3.SetInputValue: {
39478
+ case ActionType$4.SetInputValue: {
39459
39479
  return Object.assign(Object.assign({}, state), { inputValue: action.value });
39460
39480
  }
39461
39481
  default: {
@@ -39475,7 +39495,7 @@ const CreatableMultiselect = (props) => {
39475
39495
  inputValue: '',
39476
39496
  };
39477
39497
  // Initialize state
39478
- const [state, dispatch] = useReducer(reducer$3, initialState);
39498
+ const [state, dispatch] = useReducer(reducer$4, initialState);
39479
39499
  // Destructure common state
39480
39500
  const { inputValue } = state;
39481
39501
  /*------------------------------------------------------------------------*/
@@ -39552,7 +39572,7 @@ const CreatableMultiselect = (props) => {
39552
39572
  }
39553
39573
  // Reset text field to empty because the values have been added
39554
39574
  dispatch({
39555
- type: ActionType$3.SetInputValue,
39575
+ type: ActionType$4.SetInputValue,
39556
39576
  value: '',
39557
39577
  });
39558
39578
  };
@@ -39591,7 +39611,7 @@ const CreatableMultiselect = (props) => {
39591
39611
  else {
39592
39612
  // simply update the input value to the new input value
39593
39613
  dispatch({
39594
- type: ActionType$3.SetInputValue,
39614
+ type: ActionType$4.SetInputValue,
39595
39615
  value: newValue,
39596
39616
  });
39597
39617
  }
@@ -39636,20 +39656,20 @@ const CreatableMultiselect = (props) => {
39636
39656
  /*------------------------------------------------------------------------*/
39637
39657
  /* -------------------------------- Style ------------------------------- */
39638
39658
  /*------------------------------------------------------------------------*/
39639
- const style$1 = `
39659
+ const style$2 = `
39640
39660
  .AddOrEditDBEntry-input-label {
39641
39661
  min-width: 7rem;
39642
39662
  }
39643
39663
  `;
39644
39664
  /* ------------- Actions ------------ */
39645
39665
  // Types of actions
39646
- var ActionType$2;
39666
+ var ActionType$3;
39647
39667
  (function (ActionType) {
39648
39668
  // Update the DBEntry
39649
39669
  ActionType["UpdateDBEntry"] = "UpdateDBEntry";
39650
39670
  // Start the save spinner
39651
39671
  ActionType["StartSave"] = "StartSave";
39652
- })(ActionType$2 || (ActionType$2 = {}));
39672
+ })(ActionType$3 || (ActionType$3 = {}));
39653
39673
  /**
39654
39674
  * Reducer that executes actions
39655
39675
  * @author Yuen Ler Chow
@@ -39657,12 +39677,12 @@ var ActionType$2;
39657
39677
  * @param action action to execute
39658
39678
  * @returns updated state
39659
39679
  */
39660
- const reducer$2 = (state, action) => {
39680
+ const reducer$3 = (state, action) => {
39661
39681
  switch (action.type) {
39662
- case ActionType$2.UpdateDBEntry: {
39682
+ case ActionType$3.UpdateDBEntry: {
39663
39683
  return Object.assign(Object.assign({}, state), { entry: action.dbEntry });
39664
39684
  }
39665
- case ActionType$2.StartSave: {
39685
+ case ActionType$3.StartSave: {
39666
39686
  return Object.assign(Object.assign({}, state), { saving: true });
39667
39687
  }
39668
39688
  default: {
@@ -39687,7 +39707,7 @@ const AddOrEditDBEntry = (props) => {
39687
39707
  saving: false,
39688
39708
  };
39689
39709
  // Initialize state
39690
- const [state, dispatch] = useReducer(reducer$2, initialState);
39710
+ const [state, dispatch] = useReducer(reducer$3, initialState);
39691
39711
  // Destructure common state
39692
39712
  const { entry, saving, } = state;
39693
39713
  /*------------------------------------------------------------------------*/
@@ -39699,7 +39719,7 @@ const AddOrEditDBEntry = (props) => {
39699
39719
  */
39700
39720
  const save = () => __awaiter(void 0, void 0, void 0, function* () {
39701
39721
  // Start the save loading indicator
39702
- dispatch({ type: ActionType$2.StartSave });
39722
+ dispatch({ type: ActionType$3.StartSave });
39703
39723
  // add all default values to the entry
39704
39724
  entryFields.forEach((field) => {
39705
39725
  if (field.defaultValue && !entry[field.objectKey]) {
@@ -39882,7 +39902,7 @@ const AddOrEditDBEntry = (props) => {
39882
39902
  return (React__default.createElement(RadioButton, { key: choice.value, text: choice.title, selected: entry[field.objectKey] === choice.value, onSelected: () => {
39883
39903
  entry[field.objectKey] = choice.value;
39884
39904
  dispatch({
39885
- type: ActionType$2.UpdateDBEntry,
39905
+ type: ActionType$3.UpdateDBEntry,
39886
39906
  dbEntry: entry,
39887
39907
  });
39888
39908
  }, ariaLabel: choice.title }));
@@ -39894,7 +39914,7 @@ const AddOrEditDBEntry = (props) => {
39894
39914
  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) => {
39895
39915
  entry[field.objectKey] = (e.target.value);
39896
39916
  dispatch({
39897
- type: ActionType$2.UpdateDBEntry,
39917
+ type: ActionType$3.UpdateDBEntry,
39898
39918
  dbEntry: entry,
39899
39919
  });
39900
39920
  } }))));
@@ -39907,7 +39927,7 @@ const AddOrEditDBEntry = (props) => {
39907
39927
  entry[field.objectKey] = (e.target.value
39908
39928
  .replace(/[^0-9]/g, ''));
39909
39929
  dispatch({
39910
- type: ActionType$2.UpdateDBEntry,
39930
+ type: ActionType$3.UpdateDBEntry,
39911
39931
  dbEntry: entry,
39912
39932
  });
39913
39933
  } }))));
@@ -39937,7 +39957,7 @@ const AddOrEditDBEntry = (props) => {
39937
39957
  }
39938
39958
  // Save
39939
39959
  dispatch({
39940
- type: ActionType$2.UpdateDBEntry,
39960
+ type: ActionType$3.UpdateDBEntry,
39941
39961
  dbEntry: entry,
39942
39962
  });
39943
39963
  }, ariaLabel: choice.title }));
@@ -39952,7 +39972,7 @@ const AddOrEditDBEntry = (props) => {
39952
39972
  // Update entry and save
39953
39973
  entry[field.objectKey] = values;
39954
39974
  dispatch({
39955
- type: ActionType$2.UpdateDBEntry,
39975
+ type: ActionType$3.UpdateDBEntry,
39956
39976
  dbEntry: entry,
39957
39977
  });
39958
39978
  } })))));
@@ -39965,7 +39985,7 @@ const AddOrEditDBEntry = (props) => {
39965
39985
  React__default.createElement(CreatableMultiselect, { disabled: disabled, type: DBEntryFieldType$1.NumberArray, values: entry[field.objectKey] || [], onChange: (values) => {
39966
39986
  entry[field.objectKey] = values;
39967
39987
  dispatch({
39968
- type: ActionType$2.UpdateDBEntry,
39988
+ type: ActionType$3.UpdateDBEntry,
39969
39989
  dbEntry: entry,
39970
39990
  });
39971
39991
  } })))));
@@ -40014,7 +40034,7 @@ const AddOrEditDBEntry = (props) => {
40014
40034
  /* --------------- Main UI -------------- */
40015
40035
  /*----------------------------------------*/
40016
40036
  return (React__default.createElement("div", { className: "alert alert-light text-black" },
40017
- React__default.createElement("style", null, style$1),
40037
+ React__default.createElement("style", null, style$2),
40018
40038
  body));
40019
40039
  };
40020
40040
 
@@ -40039,7 +40059,7 @@ const generateEndpointPath = (collectionName, adminsOnly) => {
40039
40059
  */
40040
40060
  /* ------------- Actions ------------ */
40041
40061
  // Types of actions
40042
- var ActionType$1;
40062
+ var ActionType$2;
40043
40063
  (function (ActionType) {
40044
40064
  // Show adder
40045
40065
  ActionType["ShowAdder"] = "ShowAdder";
@@ -40053,7 +40073,7 @@ var ActionType$1;
40053
40073
  ActionType["StartDelete"] = "StartDelete";
40054
40074
  // Finish deletion process
40055
40075
  ActionType["FinishDelete"] = "FinishDelete";
40056
- })(ActionType$1 || (ActionType$1 = {}));
40076
+ })(ActionType$2 || (ActionType$2 = {}));
40057
40077
  /**
40058
40078
  * Reducer that executes actions
40059
40079
  * @author Yuen Ler Chow
@@ -40061,18 +40081,18 @@ var ActionType$1;
40061
40081
  * @param action action to execute
40062
40082
  * @returns updated state
40063
40083
  */
40064
- const reducer$1 = (state, action) => {
40084
+ const reducer$2 = (state, action) => {
40065
40085
  switch (action.type) {
40066
- case ActionType$1.FinishLoading: {
40086
+ case ActionType$2.FinishLoading: {
40067
40087
  return Object.assign(Object.assign({}, state), { loading: false, dbEntries: action.dbEntries });
40068
40088
  }
40069
- case ActionType$1.ShowAdder: {
40089
+ case ActionType$2.ShowAdder: {
40070
40090
  return Object.assign(Object.assign({}, state), { adding: true, dbEntryToEdit: undefined });
40071
40091
  }
40072
- case ActionType$1.ShowEditor: {
40092
+ case ActionType$2.ShowEditor: {
40073
40093
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: action.dbEntry });
40074
40094
  }
40075
- case ActionType$1.FinishAdd: {
40095
+ case ActionType$2.FinishAdd: {
40076
40096
  // Handle cancel
40077
40097
  const finishedEntry = action.dbEntry;
40078
40098
  if (!finishedEntry) {
@@ -40096,10 +40116,10 @@ const reducer$1 = (state, action) => {
40096
40116
  // Update the state
40097
40117
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: undefined, dbEntries: updatedDbEntries });
40098
40118
  }
40099
- case ActionType$1.StartDelete: {
40119
+ case ActionType$2.StartDelete: {
40100
40120
  return Object.assign(Object.assign({}, state), { loading: true });
40101
40121
  }
40102
- case ActionType$1.FinishDelete: {
40122
+ case ActionType$2.FinishDelete: {
40103
40123
  return Object.assign(Object.assign({}, state), { loading: false,
40104
40124
  // Remove the deleted entry from the list
40105
40125
  dbEntries: state.dbEntries.filter((entry) => {
@@ -40125,7 +40145,7 @@ const DBEntryManagerPanel = (props) => {
40125
40145
  loading: true,
40126
40146
  };
40127
40147
  // Initialize state
40128
- const [state, dispatch] = useReducer(reducer$1, initialState);
40148
+ const [state, dispatch] = useReducer(reducer$2, initialState);
40129
40149
  // Destructure common state
40130
40150
  const { adding, dbEntryToEdit, dbEntries, loading, } = state;
40131
40151
  /*------------------------------------------------------------------------*/
@@ -40151,7 +40171,7 @@ const DBEntryManagerPanel = (props) => {
40151
40171
  try {
40152
40172
  // Start loader
40153
40173
  dispatch({
40154
- type: ActionType$1.StartDelete,
40174
+ type: ActionType$2.StartDelete,
40155
40175
  });
40156
40176
  // Perform deletion
40157
40177
  yield visitServerEndpoint({
@@ -40160,7 +40180,7 @@ const DBEntryManagerPanel = (props) => {
40160
40180
  });
40161
40181
  // Finish loader
40162
40182
  dispatch({
40163
- type: ActionType$1.FinishDelete,
40183
+ type: ActionType$2.FinishDelete,
40164
40184
  dbEntry: entry,
40165
40185
  idPropName,
40166
40186
  });
@@ -40189,7 +40209,7 @@ const DBEntryManagerPanel = (props) => {
40189
40209
  });
40190
40210
  // Save loaded data
40191
40211
  dispatch({
40192
- type: ActionType$1.FinishLoading,
40212
+ type: ActionType$2.FinishLoading,
40193
40213
  dbEntries: data,
40194
40214
  });
40195
40215
  }
@@ -40232,7 +40252,7 @@ const DBEntryManagerPanel = (props) => {
40232
40252
  React__default.createElement("span", { className: "d-none d-md-inline ms-1" }, "Remove")),
40233
40253
  !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: () => {
40234
40254
  dispatch({
40235
- type: ActionType$1.ShowEditor,
40255
+ type: ActionType$2.ShowEditor,
40236
40256
  dbEntry: entry,
40237
40257
  });
40238
40258
  } },
@@ -40242,7 +40262,7 @@ const DBEntryManagerPanel = (props) => {
40242
40262
  React__default.createElement("div", { className: "d-grid" },
40243
40263
  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: () => {
40244
40264
  dispatch({
40245
- type: ActionType$1.ShowAdder,
40265
+ type: ActionType$2.ShowAdder,
40246
40266
  });
40247
40267
  } },
40248
40268
  React__default.createElement(FontAwesomeIcon, { icon: faPlus, className: "me-2" }),
@@ -40254,7 +40274,7 @@ const DBEntryManagerPanel = (props) => {
40254
40274
  if (!loading && (adding || dbEntryToEdit)) {
40255
40275
  body = (React__default.createElement(AddOrEditDBEntry, { saveEndpointPath: endpoint, validateEntry: validateEntry, modifyEntry: modifyEntry, entryFields: entryFields, dbEntryToEdit: dbEntryToEdit, idPropName: idPropName, entries: dbEntries, itemName: itemName, onFinished: (entry) => {
40256
40276
  dispatch({
40257
- type: ActionType$1.FinishAdd,
40277
+ type: ActionType$2.FinishAdd,
40258
40278
  dbEntry: entry,
40259
40279
  idPropName,
40260
40280
  });
@@ -40282,7 +40302,7 @@ const TOOLTIP_BORDER_RADIUS_REM = 0.3;
40282
40302
  /*------------------------------------------------------------------------*/
40283
40303
  /* -------------------------------- Style ------------------------------- */
40284
40304
  /*------------------------------------------------------------------------*/
40285
- const style = `
40305
+ const style$1 = `
40286
40306
  /* Container for contents and tooltip */
40287
40307
  .Tooltip-outer-container {
40288
40308
  display: inline-block;
@@ -40452,7 +40472,7 @@ const style = `
40452
40472
  `;
40453
40473
  /* ------------- Actions ------------ */
40454
40474
  // Types of actions
40455
- var ActionType;
40475
+ var ActionType$1;
40456
40476
  (function (ActionType) {
40457
40477
  // Make the tooltip visible
40458
40478
  ActionType["Show"] = "Show";
@@ -40464,28 +40484,28 @@ var ActionType;
40464
40484
  ActionType["SetSquareBottomLeft"] = "SetSquareBottomLeft";
40465
40485
  // Set whether bottom right corner should be square
40466
40486
  ActionType["SetSquareBottomRight"] = "SetSquareBottomRight";
40467
- })(ActionType || (ActionType = {}));
40487
+ })(ActionType$1 || (ActionType$1 = {}));
40468
40488
  /**
40469
40489
  * Reducer that executes actions
40470
40490
  * @author Gabe Abrams
40471
40491
  * @param state current state
40472
40492
  * @param action action to execute
40473
40493
  */
40474
- const reducer = (state, action) => {
40494
+ const reducer$1 = (state, action) => {
40475
40495
  switch (action.type) {
40476
- case ActionType.Show: {
40496
+ case ActionType$1.Show: {
40477
40497
  return Object.assign(Object.assign({}, state), { isVisible: true });
40478
40498
  }
40479
- case ActionType.Hide: {
40499
+ case ActionType$1.Hide: {
40480
40500
  return Object.assign(Object.assign({}, state), { isVisible: false, nudgePx: 0 });
40481
40501
  }
40482
- case ActionType.SetNudgePx: {
40502
+ case ActionType$1.SetNudgePx: {
40483
40503
  return Object.assign(Object.assign({}, state), { nudgePx: action.nudgePx });
40484
40504
  }
40485
- case ActionType.SetSquareBottomLeft: {
40505
+ case ActionType$1.SetSquareBottomLeft: {
40486
40506
  return Object.assign(Object.assign({}, state), { squareBottomLeft: action.squareBottomLeft });
40487
40507
  }
40488
- case ActionType.SetSquareBottomRight: {
40508
+ case ActionType$1.SetSquareBottomRight: {
40489
40509
  return Object.assign(Object.assign({}, state), { squareBottomRight: action.squareBottomRight });
40490
40510
  }
40491
40511
  default: {
@@ -40510,7 +40530,7 @@ const Tooltip = (props) => {
40510
40530
  nudgePx: 0,
40511
40531
  };
40512
40532
  // Initialize state
40513
- const [state, dispatch] = useReducer(reducer, initialState);
40533
+ const [state, dispatch] = useReducer(reducer$1, initialState);
40514
40534
  // Destructure common state
40515
40535
  const { isVisible, nudgePx, squareBottomLeft, squareBottomRight, } = state;
40516
40536
  /* -------------- Refs -------------- */
@@ -40549,7 +40569,7 @@ const Tooltip = (props) => {
40549
40569
  }
40550
40570
  // Update state
40551
40571
  dispatch({
40552
- type: ActionType.SetNudgePx,
40572
+ type: ActionType$1.SetNudgePx,
40553
40573
  nudgePx: newNudgePx,
40554
40574
  });
40555
40575
  }
@@ -40563,12 +40583,12 @@ const Tooltip = (props) => {
40563
40583
  const remInPixels = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10);
40564
40584
  // Set bottom left corner rounding
40565
40585
  dispatch({
40566
- type: ActionType.SetSquareBottomLeft,
40586
+ type: ActionType$1.SetSquareBottomLeft,
40567
40587
  squareBottomLeft: (arrowRect.left < (TOOLTIP_BORDER_RADIUS_REM * remInPixels)),
40568
40588
  });
40569
40589
  // Set bottom right corner rounding
40570
40590
  dispatch({
40571
- type: ActionType.SetSquareBottomRight,
40591
+ type: ActionType$1.SetSquareBottomRight,
40572
40592
  squareBottomRight: (arrowRect.right
40573
40593
  > window.innerWidth - (TOOLTIP_BORDER_RADIUS_REM * remInPixels)),
40574
40594
  });
@@ -40591,22 +40611,22 @@ const Tooltip = (props) => {
40591
40611
  // Render
40592
40612
  return (React__default.createElement("div", { className: "Tooltip-outer-container", "aria-label": text, onMouseEnter: () => {
40593
40613
  dispatch({
40594
- type: ActionType.Show,
40614
+ type: ActionType$1.Show,
40595
40615
  });
40596
40616
  }, onMouseLeave: () => {
40597
40617
  dispatch({
40598
- type: ActionType.Hide,
40618
+ type: ActionType$1.Hide,
40599
40619
  });
40600
40620
  }, onFocus: () => {
40601
40621
  dispatch({
40602
- type: ActionType.Show,
40622
+ type: ActionType$1.Show,
40603
40623
  });
40604
40624
  }, onBlur: () => {
40605
40625
  dispatch({
40606
- type: ActionType.Hide,
40626
+ type: ActionType$1.Hide,
40607
40627
  });
40608
40628
  } },
40609
- React__default.createElement("style", null, style),
40629
+ React__default.createElement("style", null, style$1),
40610
40630
  children,
40611
40631
  React__default.createElement("div", { className: `Tooltip-arrow Tooltip-arrow-visible-${isVisible ? 'true' : 'false'}`, ref: arrowElement },
40612
40632
  React__default.createElement(FontAwesomeIcon, { icon: faCaretDown })),
@@ -40630,6 +40650,337 @@ const Tooltip = (props) => {
40630
40650
  React__default.createElement("span", { className: "Tooltip-text" }, text))))));
40631
40651
  };
40632
40652
 
40653
+ /**
40654
+ * A toggle switch that toggles on or off
40655
+ * @author Alessandra De Lucas
40656
+ * @author Gabe Abrams
40657
+ */
40658
+ /*------------------------------------------------------------------------*/
40659
+ /* ------------------------------ Component ----------------------------- */
40660
+ /*------------------------------------------------------------------------*/
40661
+ const ToggleSwitch = (props) => {
40662
+ /*------------------------------------------------------------------------*/
40663
+ /* -------------------------------- Setup ------------------------------- */
40664
+ /*------------------------------------------------------------------------*/
40665
+ /* -------------- Props ------------- */
40666
+ // Destructure all props
40667
+ const { isOn, onToggle, id, description, backgroundVariantWhenOn = Variant$1.Info, } = props;
40668
+ /*------------------------------------------------------------------------*/
40669
+ /* ------------------------------- Render ------------------------------- */
40670
+ /*------------------------------------------------------------------------*/
40671
+ /*----------------------------------------*/
40672
+ /* --------------- Main UI -------------- */
40673
+ /*----------------------------------------*/
40674
+ const backgroundVariant = (isOn
40675
+ ? backgroundVariantWhenOn
40676
+ : 'secondary');
40677
+ return (React__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: () => {
40678
+ onToggle(!isOn);
40679
+ }, type: "button" },
40680
+ React__default.createElement(FontAwesomeIcon, { icon: faCircle, className: "text-light", style: {
40681
+ transform: `translateX(${isOn ? '' : '-'}0.7rem)`,
40682
+ transition: '0.3s transform ease-in-out',
40683
+ } })));
40684
+ };
40685
+
40686
+ /**
40687
+ * Convert a string to hyphenated lowercase format with no space or
40688
+ * non-alphanumeric characters
40689
+ * @author Gabe Abrams
40690
+ * @param str the string to convert
40691
+ * @returns the idified string
40692
+ */
40693
+ const idify = (str) => {
40694
+ return (str
40695
+ // Trim whitespace
40696
+ .trim()
40697
+ // Convert to lowercase
40698
+ .toLowerCase()
40699
+ // Replace non-alphanumeric characters with hyphens
40700
+ .replace(/[^a-z0-9]+/g, '-')
40701
+ // Change multiple hyphens in a row for a single hyphen
40702
+ .replace(/-+/g, '-')
40703
+ // Remove hyphens at the beginning and end of the string
40704
+ .replace(/^-+|-+$/g, ''));
40705
+ };
40706
+
40707
+ /**
40708
+ * Container that automatically scrolls when new items are added,
40709
+ * lets the user scroll up to see old items, but resumes
40710
+ * autoscroll when the user scrolls back to the bottom
40711
+ * @author Gabe Abrams
40712
+ */
40713
+ /*------------------------------------------------------------------------*/
40714
+ /* -------------------------------- Style ------------------------------- */
40715
+ /*------------------------------------------------------------------------*/
40716
+ const style = `
40717
+ .ScrollLockToBottom-outer-container {
40718
+ /* Take up all space */
40719
+ height: 100%;
40720
+ position: relative;
40721
+ }
40722
+
40723
+ .ScrollLockToBottom-scrollable-container {
40724
+ /* Take up max 100% height, don't take it up if not needed */
40725
+ /* (so column-reverse layout doesn't start at the bottom) */
40726
+ max-height: 100%;
40727
+ overflow-y: auto;
40728
+
40729
+ /* Allow children to position */
40730
+ position: relative;
40731
+
40732
+ /* Reverse order of children so scroll starts at bottom */
40733
+ /* (but children will have to be rendered in reverse order) */
40734
+ display: flex;
40735
+ flex-direction: column-reverse;
40736
+ }
40737
+
40738
+ .ScrollLockToBottom-jump-to-bottom-container {
40739
+ /* Don't take any space in parent */
40740
+ height: 0;
40741
+ overflow: visible;
40742
+
40743
+ /* On top of items */
40744
+ z-index: 2;
40745
+
40746
+ /* Position in center bottom */
40747
+ position: absolute;
40748
+ bottom: 2rem;
40749
+
40750
+ /* Center horizontally */
40751
+ width: 100%;
40752
+ text-align: center;
40753
+ }
40754
+
40755
+ .ScrollLockToBottom-item-container {
40756
+ /* Normal Height */
40757
+ position: relative;
40758
+ z-index: 1;
40759
+ }
40760
+ `;
40761
+ /*------------------------------------------------------------------------*/
40762
+ /* ------------------------------ Constants ----------------------------- */
40763
+ /*------------------------------------------------------------------------*/
40764
+ // Scrolled to bottom threshold
40765
+ // (how close you have to be to the bottom for it to count as the bottom)
40766
+ const SCROLLED_TO_BOTTOM_THRESHOLD_REMS = 2;
40767
+ /*------------------------------------------------------------------------*/
40768
+ /* -------------------------- Static Functions -------------------------- */
40769
+ /*------------------------------------------------------------------------*/
40770
+ /**
40771
+ * Get ids of items
40772
+ * @author Gabe Abrams
40773
+ * @param items the items in the container
40774
+ * @returns ids of items
40775
+ */
40776
+ const getItemIds = (items) => {
40777
+ return Array.from(items).map((child) => {
40778
+ return child.id;
40779
+ });
40780
+ };
40781
+ /* ------------- Actions ------------ */
40782
+ // Types of actions
40783
+ var ActionType;
40784
+ (function (ActionType) {
40785
+ // Identify that the user is now scrolled to the bottom
40786
+ ActionType["NowScrolledToBottom"] = "NowScrolledToBottom";
40787
+ // Identify that the user scrolled away from the bottom
40788
+ ActionType["NowScrolledAwayFromBottom"] = "NowScrolledAwayFromBottom";
40789
+ // Identify that new content appeared at the bottom but is not visible
40790
+ ActionType["NewContentAtBottom"] = "NewContentAtBottom";
40791
+ })(ActionType || (ActionType = {}));
40792
+ /**
40793
+ * Reducer that executes actions
40794
+ * @author Gabe Abrams
40795
+ * @param state current state
40796
+ * @param action action to execute
40797
+ */
40798
+ const reducer = (state, action) => {
40799
+ switch (action.type) {
40800
+ case ActionType.NowScrolledToBottom: {
40801
+ return Object.assign(Object.assign({}, state), {
40802
+ // Store the event
40803
+ wasScrolledToBottom: true,
40804
+ // Hide the "jump to bottom" button
40805
+ jumpToBottomButtonVisible: false });
40806
+ }
40807
+ case ActionType.NowScrolledAwayFromBottom: {
40808
+ return Object.assign(Object.assign({}, state), {
40809
+ // Store the event
40810
+ wasScrolledToBottom: false });
40811
+ }
40812
+ case ActionType.NewContentAtBottom: {
40813
+ return Object.assign(Object.assign({}, state), {
40814
+ // Store the event
40815
+ wasScrolledToBottom: false,
40816
+ // Show the "jump to bottom" button
40817
+ jumpToBottomButtonVisible: true });
40818
+ }
40819
+ default: {
40820
+ return state;
40821
+ }
40822
+ }
40823
+ };
40824
+ /*------------------------------------------------------------------------*/
40825
+ /* ------------------------------ Component ----------------------------- */
40826
+ /*------------------------------------------------------------------------*/
40827
+ const ScrollLockToBottom = (props) => {
40828
+ /*------------------------------------------------------------------------*/
40829
+ /* -------------------------------- Setup ------------------------------- */
40830
+ /*------------------------------------------------------------------------*/
40831
+ /* -------------- Props ------------- */
40832
+ // Destructure all props
40833
+ const { itemsName, items, jumpToBottomButtonVariant = Variant$1.Danger, } = props;
40834
+ /* -------------- State ------------- */
40835
+ // Initial state
40836
+ const initialState = {
40837
+ wasScrolledToBottom: true,
40838
+ jumpToBottomButtonVisible: false,
40839
+ };
40840
+ // Initialize state
40841
+ const [state, dispatch] = useReducer(reducer, initialState);
40842
+ // Destructure common state
40843
+ const { wasScrolledToBottom, jumpToBottomButtonVisible, } = state;
40844
+ /* -------------- Refs -------------- */
40845
+ // Initialize refs
40846
+ const lastItemIds = useRef([]);
40847
+ const container = useRef(null);
40848
+ /*------------------------------------------------------------------------*/
40849
+ /* ------------------------- Component Functions ------------------------ */
40850
+ /*------------------------------------------------------------------------*/
40851
+ /*----------------------------------------*/
40852
+ /* --------------- Scroll --------------- */
40853
+ /*----------------------------------------*/
40854
+ /**
40855
+ * Check if the user is scrolled to the bottom
40856
+ * @author Gabe Abrams
40857
+ * @returns true if scrolled to the bottom
40858
+ */
40859
+ const isScrolledToBottom = () => {
40860
+ // Skip if no container
40861
+ if (!container.current) {
40862
+ return true;
40863
+ }
40864
+ // Get info about container
40865
+ const { scrollTop, } = container.current;
40866
+ // Distance to bottom
40867
+ const rootFontSizePx = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10);
40868
+ const distanceToBottomRems = Math.abs(scrollTop / rootFontSizePx);
40869
+ // Figure out if we're scrolled to the bottom
40870
+ return (distanceToBottomRems < SCROLLED_TO_BOTTOM_THRESHOLD_REMS);
40871
+ };
40872
+ /**
40873
+ * Scroll the user to the bottom of the container
40874
+ * @author Gabe Abrams
40875
+ */
40876
+ const scrollToBottom = () => {
40877
+ // Skip if no container
40878
+ if (!container.current) {
40879
+ return;
40880
+ }
40881
+ // Update state
40882
+ dispatch({
40883
+ type: ActionType.NowScrolledToBottom,
40884
+ });
40885
+ // Scroll to bottom
40886
+ container.current.scrollTop = 0;
40887
+ };
40888
+ /*----------------------------------------*/
40889
+ /* -------------- Handlers -------------- */
40890
+ /*----------------------------------------*/
40891
+ /**
40892
+ * Handle scroll events on the container
40893
+ * @author Gabe Abrams
40894
+ */
40895
+ const handleScroll = () => {
40896
+ // Skip if no container
40897
+ if (!container.current) {
40898
+ return;
40899
+ }
40900
+ // Check if now scrolled to bottom
40901
+ const nowScrolledToBottom = isScrolledToBottom();
40902
+ // Remember if now no longer scrolled to bottom
40903
+ if (nowScrolledToBottom) {
40904
+ dispatch({
40905
+ type: ActionType.NowScrolledToBottom,
40906
+ });
40907
+ }
40908
+ else {
40909
+ dispatch({
40910
+ type: ActionType.NowScrolledAwayFromBottom,
40911
+ });
40912
+ }
40913
+ };
40914
+ /*------------------------------------------------------------------------*/
40915
+ /* ------------------------- Lifecycle Functions ------------------------ */
40916
+ /*------------------------------------------------------------------------*/
40917
+ /**
40918
+ * Mount
40919
+ * @author Gabe Abrams
40920
+ */
40921
+ useEffect(() => {
40922
+ // Scroll to the bottom
40923
+ scrollToBottom();
40924
+ }, []);
40925
+ /**
40926
+ * Update (also called on mount)
40927
+ * @author Gabe Abrams
40928
+ */
40929
+ useEffect(() => {
40930
+ // Check if new content appeared
40931
+ const currentItemIds = getItemIds(items);
40932
+ // Check if new content appeared at bottom
40933
+ const newContentAtBottom = (currentItemIds.length > 0
40934
+ && (currentItemIds[currentItemIds.length - 1]
40935
+ !== lastItemIds.current[lastItemIds.current.length - 1]));
40936
+ // Do nothing if no new content
40937
+ if (!newContentAtBottom) {
40938
+ return;
40939
+ }
40940
+ // Check if used to be scrolled to the bottom
40941
+ if (wasScrolledToBottom) {
40942
+ // Was scrolled to the bottom! Autoscroll.
40943
+ scrollToBottom();
40944
+ }
40945
+ else {
40946
+ // Not scrolled to bottom. Show "jump to bottom" button.
40947
+ dispatch({
40948
+ type: ActionType.NewContentAtBottom,
40949
+ });
40950
+ }
40951
+ // Update last item ids
40952
+ lastItemIds.current = currentItemIds;
40953
+ }, [items]);
40954
+ /*------------------------------------------------------------------------*/
40955
+ /* ------------------------------- Render ------------------------------- */
40956
+ /*------------------------------------------------------------------------*/
40957
+ /*----------------------------------------*/
40958
+ /* --------------- Main UI -------------- */
40959
+ /*----------------------------------------*/
40960
+ // Jump to Bottom button
40961
+ let jumpToBottomButton;
40962
+ if (jumpToBottomButtonVisible) {
40963
+ jumpToBottomButton = (React__default.createElement("div", { className: `ScrollLockToBottom-jump-to-bottom-container ScrollLockToBottom-for-${idify(itemsName !== null && itemsName !== void 0 ? itemsName : 'items')}` },
40964
+ React__default.createElement("button", { type: "button", className: `ScrollLockToBottom-jump-to-bottom-button ScrollLockToBottom-jump-to-bottom-button-for-${idify(itemsName !== null && itemsName !== void 0 ? itemsName : 'items')} btn btn-sm btn-${jumpToBottomButtonVariant} pt-0 pb-0`, onClick: scrollToBottom, "aria-label": "scroll back to bottom and show new content" },
40965
+ "New",
40966
+ ' ', itemsName !== null && itemsName !== void 0 ? itemsName : 'Content',
40967
+ React__default.createElement(FontAwesomeIcon, { icon: faChevronDown, className: "ms-1" }))));
40968
+ }
40969
+ // Main UI
40970
+ return (React__default.createElement("div", { className: "ScrollLockToBottom-outer-container bg-warning" },
40971
+ React__default.createElement("style", null, style),
40972
+ jumpToBottomButton,
40973
+ React__default.createElement("div", { className: "ScrollLockToBottom-scrollable-container", onScroll: () => {
40974
+ handleScroll();
40975
+ }, ref: container }, items
40976
+ // Render each item with a key
40977
+ .map((item) => {
40978
+ return (React__default.createElement("div", { className: "ScrollLockToBottom-item-container", key: item.id }, item.item));
40979
+ })
40980
+ // Reverse order because flex column is reverse
40981
+ .reverse())));
40982
+ };
40983
+
40633
40984
  /**
40634
40985
  * One minute in ms
40635
40986
  * @author Gabe Abrams
@@ -42509,5 +42860,5 @@ var DayOfWeek;
42509
42860
  })(DayOfWeek || (DayOfWeek = {}));
42510
42861
  var DayOfWeek$1 = DayOfWeek;
42511
42862
 
42512
- export { AppWrapper, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, DayOfWeek$1 as DayOfWeek, Drawer, DynamicWord, ErrorBox, 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$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, ParamType$1 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$1 as ReactKitErrorCode, SimpleDateChooser, TabBox, Tooltip, Variant$1 as Variant, abbreviate, addDBEditorEndpoints, alert$1 as alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, initClient, initLogCollection, initServer, isMobileOrTablet, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, validateEmail, validatePhoneNumber, validateString, visitServerEndpoint, waitMs };
42863
+ export { AppWrapper, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, DayOfWeek$1 as DayOfWeek, Drawer, DynamicWord, ErrorBox, 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$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, ParamType$1 as ParamType, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode$1 as ReactKitErrorCode, ScrollLockToBottom, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant$1 as Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert$1 as alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, idify, initClient, initLogCollection, initServer, isMobileOrTablet, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, validateEmail, validatePhoneNumber, validateString, visitServerEndpoint, waitMs };
42513
42864
  //# sourceMappingURL=index.js.map