dce-reactkit 3.5.5 → 3.5.7

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$9 = `
322
+ const style$a = `
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$9),
496
+ React__default["default"].createElement("style", null, style$a),
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* () {
@@ -1012,7 +1012,7 @@ const AppWrapper = (props) => {
1012
1012
  /*------------------------------------------------------------------------*/
1013
1013
  /* Style */
1014
1014
  /*------------------------------------------------------------------------*/
1015
- const style$8 = `
1015
+ const style$9 = `
1016
1016
  /* Container fades in */
1017
1017
  .LoadingSpinner-container {
1018
1018
  animation-name: LoadingSpinner-container-fade-in;
@@ -1090,7 +1090,7 @@ const LoadingSpinner = () => {
1090
1090
  /*------------------------------------------------------------------------*/
1091
1091
  // Add all four blips to a container
1092
1092
  return (React__default["default"].createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
1093
- React__default["default"].createElement("style", null, style$8),
1093
+ React__default["default"].createElement("style", null, style$9),
1094
1094
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-1 me-1" }),
1095
1095
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-2 me-1" }),
1096
1096
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-3 me-1" }),
@@ -1104,7 +1104,7 @@ const LoadingSpinner = () => {
1104
1104
  /*------------------------------------------------------------------------*/
1105
1105
  /* Style */
1106
1106
  /*------------------------------------------------------------------------*/
1107
- const style$7 = `
1107
+ const style$8 = `
1108
1108
  /* Tab Box */
1109
1109
  .TabBox-box {
1110
1110
  /* Light Border */
@@ -1184,7 +1184,7 @@ const TabBox = (props) => {
1184
1184
  /*----------------------------------------*/
1185
1185
  // Full UI
1186
1186
  return (React__default["default"].createElement("div", { className: `TabBox-container ${noBottomMargin ? '' : 'mb-2'}` },
1187
- React__default["default"].createElement("style", null, style$7),
1187
+ React__default["default"].createElement("style", null, style$8),
1188
1188
  React__default["default"].createElement("div", { className: "TabBox-title-container" },
1189
1189
  React__default["default"].createElement("div", { className: "TabBox-title" }, title)),
1190
1190
  React__default["default"].createElement("div", { className: `TabBox-box ps-2 pt-2 pe-2 ${noBottomPadding ? '' : 'pb-2'}` },
@@ -1506,7 +1506,7 @@ const SimpleDateChooser = (props) => {
1506
1506
  /*------------------------------------------------------------------------*/
1507
1507
  /* Style */
1508
1508
  /*------------------------------------------------------------------------*/
1509
- const style$6 = `
1509
+ const style$7 = `
1510
1510
  .Drawer-container {
1511
1511
  margin-left: 1rem;
1512
1512
  margin-right: 1rem;
@@ -1540,7 +1540,7 @@ const Drawer = (props) => {
1540
1540
  return (React__default["default"].createElement("div", { className: "Drawer-container", style: {
1541
1541
  backgroundColor: (customBackgroundColor !== null && customBackgroundColor !== void 0 ? customBackgroundColor : undefined),
1542
1542
  } },
1543
- React__default["default"].createElement("style", null, style$6),
1543
+ React__default["default"].createElement("style", null, style$7),
1544
1544
  children));
1545
1545
  };
1546
1546
 
@@ -1551,7 +1551,7 @@ const Drawer = (props) => {
1551
1551
  /*------------------------------------------------------------------------*/
1552
1552
  /* Style */
1553
1553
  /*------------------------------------------------------------------------*/
1554
- const style$5 = `
1554
+ const style$6 = `
1555
1555
  .PopSuccessMark-outer-container {
1556
1556
  position: relative;
1557
1557
  display: inline-block;
@@ -1656,7 +1656,7 @@ const PopSuccessMark = (props) => {
1656
1656
  width: `${sizeRem}rem`,
1657
1657
  height: `${sizeRem}rem`,
1658
1658
  }, "aria-label": "checkmark indicating success" },
1659
- React__default["default"].createElement("style", null, style$5),
1659
+ React__default["default"].createElement("style", null, style$6),
1660
1660
  React__default["default"].createElement("div", { className: `PopSuccessMark-check-stroke-1 bg-${checkVariant}`, style: {
1661
1661
  borderRadius: `${sizeRem / 5}rem`,
1662
1662
  } }),
@@ -1672,7 +1672,7 @@ const PopSuccessMark = (props) => {
1672
1672
  /*------------------------------------------------------------------------*/
1673
1673
  /* Style */
1674
1674
  /*------------------------------------------------------------------------*/
1675
- const style$4 = `
1675
+ const style$5 = `
1676
1676
  .PopFailureMark-outer-container {
1677
1677
  position: relative;
1678
1678
  display: inline-block;
@@ -1776,7 +1776,7 @@ const PopFailureMark = (props) => {
1776
1776
  width: `${sizeRem}rem`,
1777
1777
  height: `${sizeRem}rem`,
1778
1778
  }, "aria-label": "mark indicating failure" },
1779
- React__default["default"].createElement("style", null, style$4),
1779
+ React__default["default"].createElement("style", null, style$5),
1780
1780
  React__default["default"].createElement("div", { className: `PopFailureMark-x-stroke-1 bg-${xVariant}`, style: {
1781
1781
  borderRadius: `${sizeRem / 5}rem`,
1782
1782
  } }),
@@ -1792,7 +1792,7 @@ const PopFailureMark = (props) => {
1792
1792
  /*------------------------------------------------------------------------*/
1793
1793
  /* Style */
1794
1794
  /*------------------------------------------------------------------------*/
1795
- const style$3 = `
1795
+ const style$4 = `
1796
1796
  .PopPendingMark-outer-container {
1797
1797
  position: relative;
1798
1798
  display: inline-block;
@@ -1865,7 +1865,7 @@ const PopPendingMark = (props) => {
1865
1865
  width: `${sizeRem}rem`,
1866
1866
  height: `${sizeRem}rem`,
1867
1867
  }, "aria-label": "mark indicating that the item is pending" },
1868
- React__default["default"].createElement("style", null, style$3),
1868
+ React__default["default"].createElement("style", null, style$4),
1869
1869
  React__default["default"].createElement("div", null,
1870
1870
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faHourglass, className: `PopPendingMark-hourglass text-${hourglassVariant}`, style: {
1871
1871
  fontSize: `${sizeRem * 0.6}rem`,
@@ -1878,27 +1878,27 @@ const PopPendingMark = (props) => {
1878
1878
  */
1879
1879
  /* ------------- Actions ------------ */
1880
1880
  // Types of actions
1881
- var ActionType$7;
1881
+ var ActionType$8;
1882
1882
  (function (ActionType) {
1883
1883
  // Indicate that the text was recently copied
1884
1884
  ActionType["IndicateRecentlyCopied"] = "indicate-recently-copied";
1885
1885
  // Clear the status
1886
1886
  ActionType["ClearRecentlyCopiedStatus"] = "clear-recently-copied-status";
1887
- })(ActionType$7 || (ActionType$7 = {}));
1887
+ })(ActionType$8 || (ActionType$8 = {}));
1888
1888
  /**
1889
1889
  * Reducer that executes actions
1890
1890
  * @author Gabe Abrams
1891
1891
  * @param state current state
1892
1892
  * @param action action to execute
1893
1893
  */
1894
- const reducer$7 = (state, action) => {
1894
+ const reducer$8 = (state, action) => {
1895
1895
  switch (action.type) {
1896
- case ActionType$7.IndicateRecentlyCopied: {
1896
+ case ActionType$8.IndicateRecentlyCopied: {
1897
1897
  return {
1898
1898
  recentlyCopied: true,
1899
1899
  };
1900
1900
  }
1901
- case ActionType$7.ClearRecentlyCopiedStatus: {
1901
+ case ActionType$8.ClearRecentlyCopiedStatus: {
1902
1902
  return {
1903
1903
  recentlyCopied: false,
1904
1904
  };
@@ -1924,7 +1924,7 @@ const CopiableBox = (props) => {
1924
1924
  recentlyCopied: false,
1925
1925
  };
1926
1926
  // Initialize state
1927
- const [state, dispatch] = React.useReducer(reducer$7, initialState);
1927
+ const [state, dispatch] = React.useReducer(reducer$8, initialState);
1928
1928
  // Destructure common state
1929
1929
  const { recentlyCopied, } = state;
1930
1930
  /*------------------------------------------------------------------------*/
@@ -1944,13 +1944,13 @@ const CopiableBox = (props) => {
1944
1944
  }
1945
1945
  // Show copied notice
1946
1946
  dispatch({
1947
- type: ActionType$7.IndicateRecentlyCopied,
1947
+ type: ActionType$8.IndicateRecentlyCopied,
1948
1948
  });
1949
1949
  // Wait a moment
1950
1950
  yield waitMs(4000);
1951
1951
  // Hide copied notice
1952
1952
  dispatch({
1953
- type: ActionType$7.ClearRecentlyCopiedStatus,
1953
+ type: ActionType$8.ClearRecentlyCopiedStatus,
1954
1954
  });
1955
1955
  });
1956
1956
  /*------------------------------------------------------------------------*/
@@ -2006,20 +2006,20 @@ const CopiableBox = (props) => {
2006
2006
  */
2007
2007
  /* ------------- Actions ------------ */
2008
2008
  // Types of actions
2009
- var ActionType$6;
2009
+ var ActionType$7;
2010
2010
  (function (ActionType) {
2011
2011
  // Toggle whether a child are being shown
2012
2012
  ActionType["ToggleChild"] = "toggle-child";
2013
- })(ActionType$6 || (ActionType$6 = {}));
2013
+ })(ActionType$7 || (ActionType$7 = {}));
2014
2014
  /**
2015
2015
  * Reducer that executes actions
2016
2016
  * @author Gabe Abrams
2017
2017
  * @param state current state
2018
2018
  * @param action action to execute
2019
2019
  */
2020
- const reducer$6 = (state, action) => {
2020
+ const reducer$7 = (state, action) => {
2021
2021
  switch (action.type) {
2022
- case ActionType$6.ToggleChild: {
2022
+ case ActionType$7.ToggleChild: {
2023
2023
  return Object.assign(Object.assign({}, state), { childExpanded: Object.assign(Object.assign({}, state.childExpanded), { [String(action.id)]: !state.childExpanded[String(action.id)] }) });
2024
2024
  }
2025
2025
  default: {
@@ -2048,7 +2048,7 @@ const NestableItemList = (props) => {
2048
2048
  childExpanded: initChildExpanded,
2049
2049
  };
2050
2050
  // Initialize state
2051
- const [state, dispatch] = React.useReducer(reducer$6, initialState);
2051
+ const [state, dispatch] = React.useReducer(reducer$7, initialState);
2052
2052
  // Destructure common state
2053
2053
  const { childExpanded, } = state;
2054
2054
  /*------------------------------------------------------------------------*/
@@ -2138,7 +2138,7 @@ const NestableItemList = (props) => {
2138
2138
  backgroundColor: 'transparent',
2139
2139
  }, type: "button", onClick: () => {
2140
2140
  dispatch({
2141
- type: ActionType$6.ToggleChild,
2141
+ type: ActionType$7.ToggleChild,
2142
2142
  id: item.id,
2143
2143
  });
2144
2144
  }, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${item.name}` },
@@ -2414,7 +2414,7 @@ var SortType;
2414
2414
  })(SortType || (SortType = {}));
2415
2415
  /* ------------- Actions ------------ */
2416
2416
  // Types of actions
2417
- var ActionType$5;
2417
+ var ActionType$6;
2418
2418
  (function (ActionType) {
2419
2419
  // Toggle sort column param
2420
2420
  ActionType["ToggleSortColumn"] = "toggle-sort-column";
@@ -2426,16 +2426,16 @@ var ActionType$5;
2426
2426
  ActionType["ShowAllColumns"] = "show-all-columns";
2427
2427
  // Hide all columns
2428
2428
  ActionType["HideAllColumns"] = "hide-all-columns";
2429
- })(ActionType$5 || (ActionType$5 = {}));
2429
+ })(ActionType$6 || (ActionType$6 = {}));
2430
2430
  /**
2431
2431
  * Reducer that executes actions
2432
2432
  * @author Gabe Abrams
2433
2433
  * @param state current state
2434
2434
  * @param action action to execute
2435
2435
  */
2436
- const reducer$5 = (state, action) => {
2436
+ const reducer$6 = (state, action) => {
2437
2437
  switch (action.type) {
2438
- case ActionType$5.ToggleSortColumn: {
2438
+ case ActionType$6.ToggleSortColumn: {
2439
2439
  if (action.param !== state.sortColumnParam) {
2440
2440
  // Different column param
2441
2441
  return Object.assign(Object.assign({}, state), { sortColumnParam: action.param, sortType: SortType.Ascending });
@@ -2447,22 +2447,22 @@ const reducer$5 = (state, action) => {
2447
2447
  // Stop sorting by column
2448
2448
  return Object.assign(Object.assign({}, state), { sortColumnParam: undefined, sortType: SortType.Ascending });
2449
2449
  }
2450
- case ActionType$5.UpdateColumnVisibility: {
2450
+ case ActionType$6.UpdateColumnVisibility: {
2451
2451
  const { columnVisibilityMap } = state;
2452
2452
  columnVisibilityMap[action.param] = action.visible;
2453
2453
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2454
2454
  }
2455
- case ActionType$5.ToggleColVisCusModalVisibility: {
2455
+ case ActionType$6.ToggleColVisCusModalVisibility: {
2456
2456
  return Object.assign(Object.assign({}, state), { columnVisibilityCustomizationModalVisible: !state.columnVisibilityCustomizationModalVisible });
2457
2457
  }
2458
- case ActionType$5.ShowAllColumns: {
2458
+ case ActionType$6.ShowAllColumns: {
2459
2459
  const { columnVisibilityMap } = state;
2460
2460
  Object.keys(columnVisibilityMap).forEach((param) => {
2461
2461
  columnVisibilityMap[param] = true;
2462
2462
  });
2463
2463
  return Object.assign(Object.assign({}, state), { columnVisibilityMap });
2464
2464
  }
2465
- case ActionType$5.HideAllColumns: {
2465
+ case ActionType$6.HideAllColumns: {
2466
2466
  const { columnVisibilityMap } = state;
2467
2467
  Object.keys(columnVisibilityMap).forEach((param) => {
2468
2468
  columnVisibilityMap[param] = false;
@@ -2509,7 +2509,7 @@ const IntelliTable = (props) => {
2509
2509
  columnVisibilityCustomizationModalVisible: false,
2510
2510
  };
2511
2511
  // Initialize state
2512
- const [state, dispatch] = React.useReducer(reducer$5, initialState);
2512
+ const [state, dispatch] = React.useReducer(reducer$6, initialState);
2513
2513
  // Destructure common state
2514
2514
  const { sortColumnParam, sortType, columnVisibilityMap, columnVisibilityCustomizationModalVisible, } = state;
2515
2515
  /*------------------------------------------------------------------------*/
@@ -2532,13 +2532,13 @@ const IntelliTable = (props) => {
2532
2532
  return alert$1('Choose at least one column', 'To continue, you have to choose at least one column to show');
2533
2533
  }
2534
2534
  dispatch({
2535
- type: ActionType$5.ToggleColVisCusModalVisibility,
2535
+ type: ActionType$6.ToggleColVisCusModalVisibility,
2536
2536
  });
2537
2537
  }, okayVariant: Variant$1.Light },
2538
2538
  columns.map((column) => {
2539
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) => {
2540
2540
  dispatch({
2541
- type: ActionType$5.UpdateColumnVisibility,
2541
+ type: ActionType$6.UpdateColumnVisibility,
2542
2542
  param: column.param,
2543
2543
  visible: checked,
2544
2544
  });
@@ -2547,12 +2547,12 @@ const IntelliTable = (props) => {
2547
2547
  React__default["default"].createElement("div", { className: "mt-3" }, "Or you can:"),
2548
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: () => {
2549
2549
  dispatch({
2550
- type: ActionType$5.ShowAllColumns,
2550
+ type: ActionType$6.ShowAllColumns,
2551
2551
  });
2552
2552
  } }, "Select All"),
2553
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: () => {
2554
2554
  dispatch({
2555
- type: ActionType$5.HideAllColumns,
2555
+ type: ActionType$6.HideAllColumns,
2556
2556
  });
2557
2557
  } }, "Deselect All")));
2558
2558
  }
@@ -2603,7 +2603,7 @@ const IntelliTable = (props) => {
2603
2603
  React__default["default"].createElement("div", null,
2604
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: () => {
2605
2605
  dispatch({
2606
- type: ActionType$5.ToggleSortColumn,
2606
+ type: ActionType$6.ToggleSortColumn,
2607
2607
  param: column.param,
2608
2608
  });
2609
2609
  } },
@@ -2792,7 +2792,7 @@ const IntelliTable = (props) => {
2792
2792
  React__default["default"].createElement(CSVDownloadButton, { "aria-label": `download data as csv for ${title}`, id: `IntelliTable-${id}-download-as-csv`, filename: filename, csv: csv }),
2793
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: () => {
2794
2794
  dispatch({
2795
- type: ActionType$5.ToggleColVisCusModalVisibility,
2795
+ type: ActionType$6.ToggleColVisCusModalVisibility,
2796
2796
  });
2797
2797
  } },
2798
2798
  "Show/Hide Cols",
@@ -2824,7 +2824,7 @@ var FilterDrawer;
2824
2824
  /*------------------------------------------------------------------------*/
2825
2825
  /* Style */
2826
2826
  /*------------------------------------------------------------------------*/
2827
- const style$2 = `
2827
+ const style$3 = `
2828
2828
  .LogReviewer-outer-container {
2829
2829
  /* Full Screen */
2830
2830
  display: inline-block;
@@ -3158,7 +3158,7 @@ const genHumanReadableName = (machineReadableName) => {
3158
3158
  };
3159
3159
  /* ------------- Actions ------------ */
3160
3160
  // Types of actions
3161
- var ActionType$4;
3161
+ var ActionType$5;
3162
3162
  (function (ActionType) {
3163
3163
  // Show the loading bar
3164
3164
  ActionType["StartLoading"] = "start-loading";
@@ -3180,45 +3180,45 @@ var ActionType$4;
3180
3180
  ActionType["UpdateActionErrorFilterState"] = "update-action-error-filter-state";
3181
3181
  // Update the advanced filter state
3182
3182
  ActionType["UpdateAdvancedFilterState"] = "update-advanced-filter-state";
3183
- })(ActionType$4 || (ActionType$4 = {}));
3183
+ })(ActionType$5 || (ActionType$5 = {}));
3184
3184
  /**
3185
3185
  * Reducer that executes actions
3186
3186
  * @author Gabe Abrams
3187
3187
  * @param state current state
3188
3188
  * @param action action to execute
3189
3189
  */
3190
- const reducer$4 = (state, action) => {
3190
+ const reducer$5 = (state, action) => {
3191
3191
  switch (action.type) {
3192
- case ActionType$4.StartLoading: {
3192
+ case ActionType$5.StartLoading: {
3193
3193
  return Object.assign(Object.assign({}, state), { loading: true });
3194
3194
  }
3195
- case ActionType$4.FinishLoading: {
3195
+ case ActionType$5.FinishLoading: {
3196
3196
  return Object.assign(Object.assign({}, state), { loading: false, logMap: action.logMap });
3197
3197
  }
3198
- case ActionType$4.ToggleFilterDrawer: {
3198
+ case ActionType$5.ToggleFilterDrawer: {
3199
3199
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: (state.expandedFilterDrawer === action.filterDrawer
3200
3200
  ? undefined // hide
3201
3201
  : action.filterDrawer) });
3202
3202
  }
3203
- case ActionType$4.HideFilterDrawer: {
3203
+ case ActionType$5.HideFilterDrawer: {
3204
3204
  return Object.assign(Object.assign({}, state), { expandedFilterDrawer: undefined });
3205
3205
  }
3206
- case ActionType$4.ResetFilters: {
3206
+ case ActionType$5.ResetFilters: {
3207
3207
  return Object.assign(Object.assign({}, state), { dateFilterState: action.initDateFilterState, contextFilterState: action.initContextFilterState, tagFilterState: action.initTagFilterState, actionErrorFilterState: action.initActionErrorFilterState, advancedFilterState: action.initAdvancedFilterState });
3208
3208
  }
3209
- case ActionType$4.UpdateDateFilterState: {
3209
+ case ActionType$5.UpdateDateFilterState: {
3210
3210
  return Object.assign(Object.assign({}, state), { dateFilterState: action.dateFilterState });
3211
3211
  }
3212
- case ActionType$4.UpdateContextFilterState: {
3212
+ case ActionType$5.UpdateContextFilterState: {
3213
3213
  return Object.assign(Object.assign({}, state), { contextFilterState: action.contextFilterState });
3214
3214
  }
3215
- case ActionType$4.UpdateTagFilterState: {
3215
+ case ActionType$5.UpdateTagFilterState: {
3216
3216
  return Object.assign(Object.assign({}, state), { tagFilterState: action.tagFilterState });
3217
3217
  }
3218
- case ActionType$4.UpdateActionErrorFilterState: {
3218
+ case ActionType$5.UpdateActionErrorFilterState: {
3219
3219
  return Object.assign(Object.assign({}, state), { actionErrorFilterState: action.actionErrorFilterState });
3220
3220
  }
3221
- case ActionType$4.UpdateAdvancedFilterState: {
3221
+ case ActionType$5.UpdateAdvancedFilterState: {
3222
3222
  return Object.assign(Object.assign({}, state), { advancedFilterState: action.advancedFilterState });
3223
3223
  }
3224
3224
  default: {
@@ -3347,7 +3347,7 @@ const LogReviewer = (props) => {
3347
3347
  advancedFilterState: initAdvancedFilterState,
3348
3348
  };
3349
3349
  // Initialize state
3350
- const [state, dispatch] = React.useReducer(reducer$4, initialState);
3350
+ const [state, dispatch] = React.useReducer(reducer$5, initialState);
3351
3351
  // Destructure common state
3352
3352
  const { loading, logMap, expandedFilterDrawer, dateFilterState, contextFilterState, tagFilterState, actionErrorFilterState, advancedFilterState, } = state;
3353
3353
  /*------------------------------------------------------------------------*/
@@ -3398,7 +3398,7 @@ const LogReviewer = (props) => {
3398
3398
  const handleDateRangeUpdated = (newDateFilterState) => __awaiter(void 0, void 0, void 0, function* () {
3399
3399
  // Update state
3400
3400
  dispatch({
3401
- type: ActionType$4.UpdateDateFilterState,
3401
+ type: ActionType$5.UpdateDateFilterState,
3402
3402
  dateFilterState: newDateFilterState,
3403
3403
  });
3404
3404
  // Check which year/month combos we need to load
@@ -3409,7 +3409,7 @@ const LogReviewer = (props) => {
3409
3409
  }
3410
3410
  // Start loading
3411
3411
  dispatch({
3412
- type: ActionType$4.StartLoading,
3412
+ type: ActionType$5.StartLoading,
3413
3413
  });
3414
3414
  // Load required months
3415
3415
  try {
@@ -3433,7 +3433,7 @@ const LogReviewer = (props) => {
3433
3433
  }
3434
3434
  // Finish loading
3435
3435
  dispatch({
3436
- type: ActionType$4.FinishLoading,
3436
+ type: ActionType$5.FinishLoading,
3437
3437
  logMap,
3438
3438
  });
3439
3439
  });
@@ -3472,7 +3472,7 @@ const LogReviewer = (props) => {
3472
3472
  React__default["default"].createElement("div", { className: "LogReviewer-filter-toggle-buttons alert alert-secondary p-2 m-0" },
3473
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: () => {
3474
3474
  dispatch({
3475
- type: ActionType$4.ToggleFilterDrawer,
3475
+ type: ActionType$5.ToggleFilterDrawer,
3476
3476
  filterDrawer: FilterDrawer.Date,
3477
3477
  });
3478
3478
  } },
@@ -3480,7 +3480,7 @@ const LogReviewer = (props) => {
3480
3480
  "Date"),
3481
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: () => {
3482
3482
  dispatch({
3483
- type: ActionType$4.ToggleFilterDrawer,
3483
+ type: ActionType$5.ToggleFilterDrawer,
3484
3484
  filterDrawer: FilterDrawer.Context,
3485
3485
  });
3486
3486
  } },
@@ -3488,7 +3488,7 @@ const LogReviewer = (props) => {
3488
3488
  "Context"),
3489
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: () => {
3490
3490
  dispatch({
3491
- type: ActionType$4.ToggleFilterDrawer,
3491
+ type: ActionType$5.ToggleFilterDrawer,
3492
3492
  filterDrawer: FilterDrawer.Tag,
3493
3493
  });
3494
3494
  } },
@@ -3496,7 +3496,7 @@ const LogReviewer = (props) => {
3496
3496
  "Tag")),
3497
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: () => {
3498
3498
  dispatch({
3499
- type: ActionType$4.ToggleFilterDrawer,
3499
+ type: ActionType$5.ToggleFilterDrawer,
3500
3500
  filterDrawer: FilterDrawer.Action,
3501
3501
  });
3502
3502
  } },
@@ -3504,7 +3504,7 @@ const LogReviewer = (props) => {
3504
3504
  "Action"),
3505
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: () => {
3506
3506
  dispatch({
3507
- type: ActionType$4.ToggleFilterDrawer,
3507
+ type: ActionType$5.ToggleFilterDrawer,
3508
3508
  filterDrawer: FilterDrawer.Advanced,
3509
3509
  });
3510
3510
  } },
@@ -3512,7 +3512,7 @@ const LogReviewer = (props) => {
3512
3512
  "Advanced"),
3513
3513
  React__default["default"].createElement("button", { type: "button", id: "LogReviewer-reset-filters-button", className: "btn btn-light", "aria-label": "reset filters", onClick: () => {
3514
3514
  dispatch({
3515
- type: ActionType$4.ResetFilters,
3515
+ type: ActionType$5.ResetFilters,
3516
3516
  initActionErrorFilterState,
3517
3517
  initAdvancedFilterState,
3518
3518
  initContextFilterState,
@@ -3634,7 +3634,7 @@ const LogReviewer = (props) => {
3634
3634
  }
3635
3635
  });
3636
3636
  dispatch({
3637
- type: ActionType$4.UpdateContextFilterState,
3637
+ type: ActionType$5.UpdateContextFilterState,
3638
3638
  contextFilterState,
3639
3639
  });
3640
3640
  } }));
@@ -3649,7 +3649,7 @@ const LogReviewer = (props) => {
3649
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) => {
3650
3650
  tagFilterState[tag] = checked;
3651
3651
  dispatch({
3652
- type: ActionType$4.UpdateTagFilterState,
3652
+ type: ActionType$5.UpdateTagFilterState,
3653
3653
  tagFilterState,
3654
3654
  });
3655
3655
  } }));
@@ -3662,21 +3662,21 @@ const LogReviewer = (props) => {
3662
3662
  React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-all", text: "All Logs", onSelected: () => {
3663
3663
  actionErrorFilterState.type = undefined;
3664
3664
  dispatch({
3665
- type: ActionType$4.UpdateActionErrorFilterState,
3665
+ type: ActionType$5.UpdateActionErrorFilterState,
3666
3666
  actionErrorFilterState,
3667
3667
  });
3668
3668
  }, ariaLabel: "show logs of all types", selected: actionErrorFilterState.type === undefined }),
3669
3669
  React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-action-only", text: "Action Logs Only", onSelected: () => {
3670
3670
  actionErrorFilterState.type = LogType$1.Action;
3671
3671
  dispatch({
3672
- type: ActionType$4.UpdateActionErrorFilterState,
3672
+ type: ActionType$5.UpdateActionErrorFilterState,
3673
3673
  actionErrorFilterState,
3674
3674
  });
3675
3675
  }, ariaLabel: "only show action logs", selected: actionErrorFilterState.type === LogType$1.Action }),
3676
3676
  React__default["default"].createElement(RadioButton, { id: "LogReviewer-type-error-only", text: "Action Error Only", onSelected: () => {
3677
3677
  actionErrorFilterState.type = LogType$1.Error;
3678
3678
  dispatch({
3679
- type: ActionType$4.UpdateActionErrorFilterState,
3679
+ type: ActionType$5.UpdateActionErrorFilterState,
3680
3680
  actionErrorFilterState,
3681
3681
  });
3682
3682
  }, ariaLabel: "only show error logs", selected: actionErrorFilterState.type === LogType$1.Error, noMarginOnRight: true })),
@@ -3688,7 +3688,7 @@ const LogReviewer = (props) => {
3688
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) => {
3689
3689
  actionErrorFilterState.action[action] = checked;
3690
3690
  dispatch({
3691
- type: ActionType$4.UpdateActionErrorFilterState,
3691
+ type: ActionType$5.UpdateActionErrorFilterState,
3692
3692
  actionErrorFilterState,
3693
3693
  });
3694
3694
  } }));
@@ -3699,7 +3699,7 @@ const LogReviewer = (props) => {
3699
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) => {
3700
3700
  actionErrorFilterState.target[target] = checked;
3701
3701
  dispatch({
3702
- type: ActionType$4.UpdateActionErrorFilterState,
3702
+ type: ActionType$5.UpdateActionErrorFilterState,
3703
3703
  actionErrorFilterState,
3704
3704
  });
3705
3705
  } }));
@@ -3711,7 +3711,7 @@ const LogReviewer = (props) => {
3711
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) => {
3712
3712
  actionErrorFilterState.errorMessage = e.target.value;
3713
3713
  dispatch({
3714
- type: ActionType$4.UpdateActionErrorFilterState,
3714
+ type: ActionType$5.UpdateActionErrorFilterState,
3715
3715
  actionErrorFilterState,
3716
3716
  });
3717
3717
  } })),
@@ -3722,7 +3722,7 @@ const LogReviewer = (props) => {
3722
3722
  .trim()
3723
3723
  .toUpperCase());
3724
3724
  dispatch({
3725
- type: ActionType$4.UpdateActionErrorFilterState,
3725
+ type: ActionType$5.UpdateActionErrorFilterState,
3726
3726
  actionErrorFilterState,
3727
3727
  });
3728
3728
  } }))))));
@@ -3736,7 +3736,7 @@ const LogReviewer = (props) => {
3736
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) => {
3737
3737
  advancedFilterState.userFirstName = e.target.value;
3738
3738
  dispatch({
3739
- type: ActionType$4.UpdateAdvancedFilterState,
3739
+ type: ActionType$5.UpdateAdvancedFilterState,
3740
3740
  advancedFilterState,
3741
3741
  });
3742
3742
  } })),
@@ -3745,7 +3745,7 @@ const LogReviewer = (props) => {
3745
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) => {
3746
3746
  advancedFilterState.userLastName = e.target.value;
3747
3747
  dispatch({
3748
- type: ActionType$4.UpdateAdvancedFilterState,
3748
+ type: ActionType$5.UpdateAdvancedFilterState,
3749
3749
  advancedFilterState,
3750
3750
  });
3751
3751
  } })),
@@ -3755,7 +3755,7 @@ const LogReviewer = (props) => {
3755
3755
  advancedFilterState.userEmail = ((e.target.value)
3756
3756
  .trim());
3757
3757
  dispatch({
3758
- type: ActionType$4.UpdateAdvancedFilterState,
3758
+ type: ActionType$5.UpdateAdvancedFilterState,
3759
3759
  advancedFilterState,
3760
3760
  });
3761
3761
  } })),
@@ -3769,7 +3769,7 @@ const LogReviewer = (props) => {
3769
3769
  .trim());
3770
3770
  }
3771
3771
  dispatch({
3772
- type: ActionType$4.UpdateAdvancedFilterState,
3772
+ type: ActionType$5.UpdateAdvancedFilterState,
3773
3773
  advancedFilterState,
3774
3774
  });
3775
3775
  } })),
@@ -3777,21 +3777,21 @@ const LogReviewer = (props) => {
3777
3777
  React__default["default"].createElement(CheckboxButton, { text: "Students", onChanged: (checked) => {
3778
3778
  advancedFilterState.includeLearners = checked;
3779
3779
  dispatch({
3780
- type: ActionType$4.UpdateAdvancedFilterState,
3780
+ type: ActionType$5.UpdateAdvancedFilterState,
3781
3781
  advancedFilterState,
3782
3782
  });
3783
3783
  }, checked: advancedFilterState.includeLearners, ariaLabel: "show logs from students" }),
3784
3784
  React__default["default"].createElement(CheckboxButton, { text: "Teaching Team Members", onChanged: (checked) => {
3785
3785
  advancedFilterState.includeTTMs = checked;
3786
3786
  dispatch({
3787
- type: ActionType$4.UpdateAdvancedFilterState,
3787
+ type: ActionType$5.UpdateAdvancedFilterState,
3788
3788
  advancedFilterState,
3789
3789
  });
3790
3790
  }, checked: advancedFilterState.includeTTMs, ariaLabel: "show logs from teaching team members" }),
3791
3791
  React__default["default"].createElement(CheckboxButton, { text: "Admins", onChanged: (checked) => {
3792
3792
  advancedFilterState.includeAdmins = checked;
3793
3793
  dispatch({
3794
- type: ActionType$4.UpdateAdvancedFilterState,
3794
+ type: ActionType$5.UpdateAdvancedFilterState,
3795
3795
  advancedFilterState,
3796
3796
  });
3797
3797
  }, checked: advancedFilterState.includeAdmins, ariaLabel: "show logs from admins" }))),
@@ -3801,7 +3801,7 @@ const LogReviewer = (props) => {
3801
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) => {
3802
3802
  advancedFilterState.courseName = e.target.value;
3803
3803
  dispatch({
3804
- type: ActionType$4.UpdateAdvancedFilterState,
3804
+ type: ActionType$5.UpdateAdvancedFilterState,
3805
3805
  advancedFilterState,
3806
3806
  });
3807
3807
  } })),
@@ -3815,7 +3815,7 @@ const LogReviewer = (props) => {
3815
3815
  .trim());
3816
3816
  }
3817
3817
  dispatch({
3818
- type: ActionType$4.UpdateAdvancedFilterState,
3818
+ type: ActionType$5.UpdateAdvancedFilterState,
3819
3819
  advancedFilterState,
3820
3820
  });
3821
3821
  } }))),
@@ -3824,21 +3824,21 @@ const LogReviewer = (props) => {
3824
3824
  React__default["default"].createElement(RadioButton, { text: "All Devices", ariaLabel: "show logs from all devices", selected: advancedFilterState.isMobile === undefined, onSelected: () => {
3825
3825
  advancedFilterState.isMobile = undefined;
3826
3826
  dispatch({
3827
- type: ActionType$4.UpdateAdvancedFilterState,
3827
+ type: ActionType$5.UpdateAdvancedFilterState,
3828
3828
  advancedFilterState,
3829
3829
  });
3830
3830
  } }),
3831
3831
  React__default["default"].createElement(RadioButton, { text: "Mobile Only", ariaLabel: "show logs from mobile devices", selected: advancedFilterState.isMobile === true, onSelected: () => {
3832
3832
  advancedFilterState.isMobile = true;
3833
3833
  dispatch({
3834
- type: ActionType$4.UpdateAdvancedFilterState,
3834
+ type: ActionType$5.UpdateAdvancedFilterState,
3835
3835
  advancedFilterState,
3836
3836
  });
3837
3837
  } }),
3838
3838
  React__default["default"].createElement(RadioButton, { text: "Desktop Only", ariaLabel: "show logs from desktop devices", selected: advancedFilterState.isMobile === false, onSelected: () => {
3839
3839
  advancedFilterState.isMobile = false;
3840
3840
  dispatch({
3841
- type: ActionType$4.UpdateAdvancedFilterState,
3841
+ type: ActionType$5.UpdateAdvancedFilterState,
3842
3842
  advancedFilterState,
3843
3843
  });
3844
3844
  }, noMarginOnRight: true }))),
@@ -3847,21 +3847,21 @@ const LogReviewer = (props) => {
3847
3847
  React__default["default"].createElement(RadioButton, { text: "Both", ariaLabel: "show logs from all sources", selected: advancedFilterState.source === undefined, onSelected: () => {
3848
3848
  advancedFilterState.source = undefined;
3849
3849
  dispatch({
3850
- type: ActionType$4.UpdateAdvancedFilterState,
3850
+ type: ActionType$5.UpdateAdvancedFilterState,
3851
3851
  advancedFilterState,
3852
3852
  });
3853
3853
  } }),
3854
3854
  React__default["default"].createElement(RadioButton, { text: "Client Only", ariaLabel: "show logs from client source", selected: advancedFilterState.source === LogSource$1.Client, onSelected: () => {
3855
3855
  advancedFilterState.source = LogSource$1.Client;
3856
3856
  dispatch({
3857
- type: ActionType$4.UpdateAdvancedFilterState,
3857
+ type: ActionType$5.UpdateAdvancedFilterState,
3858
3858
  advancedFilterState,
3859
3859
  });
3860
3860
  } }),
3861
3861
  React__default["default"].createElement(RadioButton, { text: "Server Only", ariaLabel: "show logs from server source", selected: advancedFilterState.source === LogSource$1.Server, onSelected: () => {
3862
3862
  advancedFilterState.source = LogSource$1.Server;
3863
3863
  dispatch({
3864
- type: ActionType$4.UpdateAdvancedFilterState,
3864
+ type: ActionType$5.UpdateAdvancedFilterState,
3865
3865
  advancedFilterState,
3866
3866
  });
3867
3867
  }, noMarginOnRight: true })),
@@ -3872,7 +3872,7 @@ const LogReviewer = (props) => {
3872
3872
  advancedFilterState.courseName = ((e.target.value)
3873
3873
  .trim());
3874
3874
  dispatch({
3875
- type: ActionType$4.UpdateAdvancedFilterState,
3875
+ type: ActionType$5.UpdateAdvancedFilterState,
3876
3876
  advancedFilterState,
3877
3877
  });
3878
3878
  } })),
@@ -3882,7 +3882,7 @@ const LogReviewer = (props) => {
3882
3882
  advancedFilterState.courseName = ((e.target.value)
3883
3883
  .trim());
3884
3884
  dispatch({
3885
- type: ActionType$4.UpdateAdvancedFilterState,
3885
+ type: ActionType$5.UpdateAdvancedFilterState,
3886
3886
  advancedFilterState,
3887
3887
  });
3888
3888
  } })))))));
@@ -4161,7 +4161,7 @@ const LogReviewer = (props) => {
4161
4161
  }
4162
4162
  /* ---------- Wrap in Modal --------- */
4163
4163
  return (React__default["default"].createElement("div", { className: "LogReviewer-outer-container" },
4164
- React__default["default"].createElement("style", null, style$2),
4164
+ React__default["default"].createElement("style", null, style$3),
4165
4165
  React__default["default"].createElement("div", { className: "LogReviewer-inner-container" },
4166
4166
  React__default["default"].createElement("div", { className: "LogReviewer-header" },
4167
4167
  React__default["default"].createElement("div", { className: "LogReviewer-header-title" },
@@ -39487,11 +39487,11 @@ var CreatableSelect$1 = CreatableSelect;
39487
39487
  */
39488
39488
  /* ------------- Actions ------------ */
39489
39489
  // Types of actions
39490
- var ActionType$3;
39490
+ var ActionType$4;
39491
39491
  (function (ActionType) {
39492
39492
  // Update the input value
39493
39493
  ActionType["SetInputValue"] = "SetInputValue";
39494
- })(ActionType$3 || (ActionType$3 = {}));
39494
+ })(ActionType$4 || (ActionType$4 = {}));
39495
39495
  /**
39496
39496
  * Reducer that executes actions
39497
39497
  * @author Yuen Ler Chow
@@ -39499,9 +39499,9 @@ var ActionType$3;
39499
39499
  * @param action action to execute
39500
39500
  * @returns updated state
39501
39501
  */
39502
- const reducer$3 = (state, action) => {
39502
+ const reducer$4 = (state, action) => {
39503
39503
  switch (action.type) {
39504
- case ActionType$3.SetInputValue: {
39504
+ case ActionType$4.SetInputValue: {
39505
39505
  return Object.assign(Object.assign({}, state), { inputValue: action.value });
39506
39506
  }
39507
39507
  default: {
@@ -39521,7 +39521,7 @@ const CreatableMultiselect = (props) => {
39521
39521
  inputValue: '',
39522
39522
  };
39523
39523
  // Initialize state
39524
- const [state, dispatch] = React.useReducer(reducer$3, initialState);
39524
+ const [state, dispatch] = React.useReducer(reducer$4, initialState);
39525
39525
  // Destructure common state
39526
39526
  const { inputValue } = state;
39527
39527
  /*------------------------------------------------------------------------*/
@@ -39598,7 +39598,7 @@ const CreatableMultiselect = (props) => {
39598
39598
  }
39599
39599
  // Reset text field to empty because the values have been added
39600
39600
  dispatch({
39601
- type: ActionType$3.SetInputValue,
39601
+ type: ActionType$4.SetInputValue,
39602
39602
  value: '',
39603
39603
  });
39604
39604
  };
@@ -39637,7 +39637,7 @@ const CreatableMultiselect = (props) => {
39637
39637
  else {
39638
39638
  // simply update the input value to the new input value
39639
39639
  dispatch({
39640
- type: ActionType$3.SetInputValue,
39640
+ type: ActionType$4.SetInputValue,
39641
39641
  value: newValue,
39642
39642
  });
39643
39643
  }
@@ -39682,20 +39682,20 @@ const CreatableMultiselect = (props) => {
39682
39682
  /*------------------------------------------------------------------------*/
39683
39683
  /* -------------------------------- Style ------------------------------- */
39684
39684
  /*------------------------------------------------------------------------*/
39685
- const style$1 = `
39685
+ const style$2 = `
39686
39686
  .AddOrEditDBEntry-input-label {
39687
39687
  min-width: 7rem;
39688
39688
  }
39689
39689
  `;
39690
39690
  /* ------------- Actions ------------ */
39691
39691
  // Types of actions
39692
- var ActionType$2;
39692
+ var ActionType$3;
39693
39693
  (function (ActionType) {
39694
39694
  // Update the DBEntry
39695
39695
  ActionType["UpdateDBEntry"] = "UpdateDBEntry";
39696
39696
  // Start the save spinner
39697
39697
  ActionType["StartSave"] = "StartSave";
39698
- })(ActionType$2 || (ActionType$2 = {}));
39698
+ })(ActionType$3 || (ActionType$3 = {}));
39699
39699
  /**
39700
39700
  * Reducer that executes actions
39701
39701
  * @author Yuen Ler Chow
@@ -39703,12 +39703,12 @@ var ActionType$2;
39703
39703
  * @param action action to execute
39704
39704
  * @returns updated state
39705
39705
  */
39706
- const reducer$2 = (state, action) => {
39706
+ const reducer$3 = (state, action) => {
39707
39707
  switch (action.type) {
39708
- case ActionType$2.UpdateDBEntry: {
39708
+ case ActionType$3.UpdateDBEntry: {
39709
39709
  return Object.assign(Object.assign({}, state), { entry: action.dbEntry });
39710
39710
  }
39711
- case ActionType$2.StartSave: {
39711
+ case ActionType$3.StartSave: {
39712
39712
  return Object.assign(Object.assign({}, state), { saving: true });
39713
39713
  }
39714
39714
  default: {
@@ -39733,7 +39733,7 @@ const AddOrEditDBEntry = (props) => {
39733
39733
  saving: false,
39734
39734
  };
39735
39735
  // Initialize state
39736
- const [state, dispatch] = React.useReducer(reducer$2, initialState);
39736
+ const [state, dispatch] = React.useReducer(reducer$3, initialState);
39737
39737
  // Destructure common state
39738
39738
  const { entry, saving, } = state;
39739
39739
  /*------------------------------------------------------------------------*/
@@ -39745,7 +39745,7 @@ const AddOrEditDBEntry = (props) => {
39745
39745
  */
39746
39746
  const save = () => __awaiter(void 0, void 0, void 0, function* () {
39747
39747
  // Start the save loading indicator
39748
- dispatch({ type: ActionType$2.StartSave });
39748
+ dispatch({ type: ActionType$3.StartSave });
39749
39749
  // add all default values to the entry
39750
39750
  entryFields.forEach((field) => {
39751
39751
  if (field.defaultValue && !entry[field.objectKey]) {
@@ -39928,7 +39928,7 @@ const AddOrEditDBEntry = (props) => {
39928
39928
  return (React__default["default"].createElement(RadioButton, { key: choice.value, text: choice.title, selected: entry[field.objectKey] === choice.value, onSelected: () => {
39929
39929
  entry[field.objectKey] = choice.value;
39930
39930
  dispatch({
39931
- type: ActionType$2.UpdateDBEntry,
39931
+ type: ActionType$3.UpdateDBEntry,
39932
39932
  dbEntry: entry,
39933
39933
  });
39934
39934
  }, ariaLabel: choice.title }));
@@ -39940,7 +39940,7 @@ const AddOrEditDBEntry = (props) => {
39940
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) => {
39941
39941
  entry[field.objectKey] = (e.target.value);
39942
39942
  dispatch({
39943
- type: ActionType$2.UpdateDBEntry,
39943
+ type: ActionType$3.UpdateDBEntry,
39944
39944
  dbEntry: entry,
39945
39945
  });
39946
39946
  } }))));
@@ -39953,7 +39953,7 @@ const AddOrEditDBEntry = (props) => {
39953
39953
  entry[field.objectKey] = (e.target.value
39954
39954
  .replace(/[^0-9]/g, ''));
39955
39955
  dispatch({
39956
- type: ActionType$2.UpdateDBEntry,
39956
+ type: ActionType$3.UpdateDBEntry,
39957
39957
  dbEntry: entry,
39958
39958
  });
39959
39959
  } }))));
@@ -39983,7 +39983,7 @@ const AddOrEditDBEntry = (props) => {
39983
39983
  }
39984
39984
  // Save
39985
39985
  dispatch({
39986
- type: ActionType$2.UpdateDBEntry,
39986
+ type: ActionType$3.UpdateDBEntry,
39987
39987
  dbEntry: entry,
39988
39988
  });
39989
39989
  }, ariaLabel: choice.title }));
@@ -39998,7 +39998,7 @@ const AddOrEditDBEntry = (props) => {
39998
39998
  // Update entry and save
39999
39999
  entry[field.objectKey] = values;
40000
40000
  dispatch({
40001
- type: ActionType$2.UpdateDBEntry,
40001
+ type: ActionType$3.UpdateDBEntry,
40002
40002
  dbEntry: entry,
40003
40003
  });
40004
40004
  } })))));
@@ -40011,7 +40011,7 @@ const AddOrEditDBEntry = (props) => {
40011
40011
  React__default["default"].createElement(CreatableMultiselect, { disabled: disabled, type: DBEntryFieldType$1.NumberArray, values: entry[field.objectKey] || [], onChange: (values) => {
40012
40012
  entry[field.objectKey] = values;
40013
40013
  dispatch({
40014
- type: ActionType$2.UpdateDBEntry,
40014
+ type: ActionType$3.UpdateDBEntry,
40015
40015
  dbEntry: entry,
40016
40016
  });
40017
40017
  } })))));
@@ -40060,7 +40060,7 @@ const AddOrEditDBEntry = (props) => {
40060
40060
  /* --------------- Main UI -------------- */
40061
40061
  /*----------------------------------------*/
40062
40062
  return (React__default["default"].createElement("div", { className: "alert alert-light text-black" },
40063
- React__default["default"].createElement("style", null, style$1),
40063
+ React__default["default"].createElement("style", null, style$2),
40064
40064
  body));
40065
40065
  };
40066
40066
 
@@ -40085,7 +40085,7 @@ const generateEndpointPath = (collectionName, adminsOnly) => {
40085
40085
  */
40086
40086
  /* ------------- Actions ------------ */
40087
40087
  // Types of actions
40088
- var ActionType$1;
40088
+ var ActionType$2;
40089
40089
  (function (ActionType) {
40090
40090
  // Show adder
40091
40091
  ActionType["ShowAdder"] = "ShowAdder";
@@ -40099,7 +40099,7 @@ var ActionType$1;
40099
40099
  ActionType["StartDelete"] = "StartDelete";
40100
40100
  // Finish deletion process
40101
40101
  ActionType["FinishDelete"] = "FinishDelete";
40102
- })(ActionType$1 || (ActionType$1 = {}));
40102
+ })(ActionType$2 || (ActionType$2 = {}));
40103
40103
  /**
40104
40104
  * Reducer that executes actions
40105
40105
  * @author Yuen Ler Chow
@@ -40107,18 +40107,18 @@ var ActionType$1;
40107
40107
  * @param action action to execute
40108
40108
  * @returns updated state
40109
40109
  */
40110
- const reducer$1 = (state, action) => {
40110
+ const reducer$2 = (state, action) => {
40111
40111
  switch (action.type) {
40112
- case ActionType$1.FinishLoading: {
40112
+ case ActionType$2.FinishLoading: {
40113
40113
  return Object.assign(Object.assign({}, state), { loading: false, dbEntries: action.dbEntries });
40114
40114
  }
40115
- case ActionType$1.ShowAdder: {
40115
+ case ActionType$2.ShowAdder: {
40116
40116
  return Object.assign(Object.assign({}, state), { adding: true, dbEntryToEdit: undefined });
40117
40117
  }
40118
- case ActionType$1.ShowEditor: {
40118
+ case ActionType$2.ShowEditor: {
40119
40119
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: action.dbEntry });
40120
40120
  }
40121
- case ActionType$1.FinishAdd: {
40121
+ case ActionType$2.FinishAdd: {
40122
40122
  // Handle cancel
40123
40123
  const finishedEntry = action.dbEntry;
40124
40124
  if (!finishedEntry) {
@@ -40142,10 +40142,10 @@ const reducer$1 = (state, action) => {
40142
40142
  // Update the state
40143
40143
  return Object.assign(Object.assign({}, state), { adding: false, dbEntryToEdit: undefined, dbEntries: updatedDbEntries });
40144
40144
  }
40145
- case ActionType$1.StartDelete: {
40145
+ case ActionType$2.StartDelete: {
40146
40146
  return Object.assign(Object.assign({}, state), { loading: true });
40147
40147
  }
40148
- case ActionType$1.FinishDelete: {
40148
+ case ActionType$2.FinishDelete: {
40149
40149
  return Object.assign(Object.assign({}, state), { loading: false,
40150
40150
  // Remove the deleted entry from the list
40151
40151
  dbEntries: state.dbEntries.filter((entry) => {
@@ -40171,7 +40171,7 @@ const DBEntryManagerPanel = (props) => {
40171
40171
  loading: true,
40172
40172
  };
40173
40173
  // Initialize state
40174
- const [state, dispatch] = React.useReducer(reducer$1, initialState);
40174
+ const [state, dispatch] = React.useReducer(reducer$2, initialState);
40175
40175
  // Destructure common state
40176
40176
  const { adding, dbEntryToEdit, dbEntries, loading, } = state;
40177
40177
  /*------------------------------------------------------------------------*/
@@ -40197,7 +40197,7 @@ const DBEntryManagerPanel = (props) => {
40197
40197
  try {
40198
40198
  // Start loader
40199
40199
  dispatch({
40200
- type: ActionType$1.StartDelete,
40200
+ type: ActionType$2.StartDelete,
40201
40201
  });
40202
40202
  // Perform deletion
40203
40203
  yield visitServerEndpoint({
@@ -40206,7 +40206,7 @@ const DBEntryManagerPanel = (props) => {
40206
40206
  });
40207
40207
  // Finish loader
40208
40208
  dispatch({
40209
- type: ActionType$1.FinishDelete,
40209
+ type: ActionType$2.FinishDelete,
40210
40210
  dbEntry: entry,
40211
40211
  idPropName,
40212
40212
  });
@@ -40235,7 +40235,7 @@ const DBEntryManagerPanel = (props) => {
40235
40235
  });
40236
40236
  // Save loaded data
40237
40237
  dispatch({
40238
- type: ActionType$1.FinishLoading,
40238
+ type: ActionType$2.FinishLoading,
40239
40239
  dbEntries: data,
40240
40240
  });
40241
40241
  }
@@ -40278,7 +40278,7 @@ const DBEntryManagerPanel = (props) => {
40278
40278
  React__default["default"].createElement("span", { className: "d-none d-md-inline ms-1" }, "Remove")),
40279
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: () => {
40280
40280
  dispatch({
40281
- type: ActionType$1.ShowEditor,
40281
+ type: ActionType$2.ShowEditor,
40282
40282
  dbEntry: entry,
40283
40283
  });
40284
40284
  } },
@@ -40288,7 +40288,7 @@ const DBEntryManagerPanel = (props) => {
40288
40288
  React__default["default"].createElement("div", { className: "d-grid" },
40289
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: () => {
40290
40290
  dispatch({
40291
- type: ActionType$1.ShowAdder,
40291
+ type: ActionType$2.ShowAdder,
40292
40292
  });
40293
40293
  } },
40294
40294
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faPlus, className: "me-2" }),
@@ -40300,7 +40300,7 @@ const DBEntryManagerPanel = (props) => {
40300
40300
  if (!loading && (adding || dbEntryToEdit)) {
40301
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) => {
40302
40302
  dispatch({
40303
- type: ActionType$1.FinishAdd,
40303
+ type: ActionType$2.FinishAdd,
40304
40304
  dbEntry: entry,
40305
40305
  idPropName,
40306
40306
  });
@@ -40328,7 +40328,7 @@ const TOOLTIP_BORDER_RADIUS_REM = 0.3;
40328
40328
  /*------------------------------------------------------------------------*/
40329
40329
  /* -------------------------------- Style ------------------------------- */
40330
40330
  /*------------------------------------------------------------------------*/
40331
- const style = `
40331
+ const style$1 = `
40332
40332
  /* Container for contents and tooltip */
40333
40333
  .Tooltip-outer-container {
40334
40334
  display: inline-block;
@@ -40498,7 +40498,7 @@ const style = `
40498
40498
  `;
40499
40499
  /* ------------- Actions ------------ */
40500
40500
  // Types of actions
40501
- var ActionType;
40501
+ var ActionType$1;
40502
40502
  (function (ActionType) {
40503
40503
  // Make the tooltip visible
40504
40504
  ActionType["Show"] = "Show";
@@ -40510,28 +40510,28 @@ var ActionType;
40510
40510
  ActionType["SetSquareBottomLeft"] = "SetSquareBottomLeft";
40511
40511
  // Set whether bottom right corner should be square
40512
40512
  ActionType["SetSquareBottomRight"] = "SetSquareBottomRight";
40513
- })(ActionType || (ActionType = {}));
40513
+ })(ActionType$1 || (ActionType$1 = {}));
40514
40514
  /**
40515
40515
  * Reducer that executes actions
40516
40516
  * @author Gabe Abrams
40517
40517
  * @param state current state
40518
40518
  * @param action action to execute
40519
40519
  */
40520
- const reducer = (state, action) => {
40520
+ const reducer$1 = (state, action) => {
40521
40521
  switch (action.type) {
40522
- case ActionType.Show: {
40522
+ case ActionType$1.Show: {
40523
40523
  return Object.assign(Object.assign({}, state), { isVisible: true });
40524
40524
  }
40525
- case ActionType.Hide: {
40525
+ case ActionType$1.Hide: {
40526
40526
  return Object.assign(Object.assign({}, state), { isVisible: false, nudgePx: 0 });
40527
40527
  }
40528
- case ActionType.SetNudgePx: {
40528
+ case ActionType$1.SetNudgePx: {
40529
40529
  return Object.assign(Object.assign({}, state), { nudgePx: action.nudgePx });
40530
40530
  }
40531
- case ActionType.SetSquareBottomLeft: {
40531
+ case ActionType$1.SetSquareBottomLeft: {
40532
40532
  return Object.assign(Object.assign({}, state), { squareBottomLeft: action.squareBottomLeft });
40533
40533
  }
40534
- case ActionType.SetSquareBottomRight: {
40534
+ case ActionType$1.SetSquareBottomRight: {
40535
40535
  return Object.assign(Object.assign({}, state), { squareBottomRight: action.squareBottomRight });
40536
40536
  }
40537
40537
  default: {
@@ -40556,7 +40556,7 @@ const Tooltip = (props) => {
40556
40556
  nudgePx: 0,
40557
40557
  };
40558
40558
  // Initialize state
40559
- const [state, dispatch] = React.useReducer(reducer, initialState);
40559
+ const [state, dispatch] = React.useReducer(reducer$1, initialState);
40560
40560
  // Destructure common state
40561
40561
  const { isVisible, nudgePx, squareBottomLeft, squareBottomRight, } = state;
40562
40562
  /* -------------- Refs -------------- */
@@ -40595,7 +40595,7 @@ const Tooltip = (props) => {
40595
40595
  }
40596
40596
  // Update state
40597
40597
  dispatch({
40598
- type: ActionType.SetNudgePx,
40598
+ type: ActionType$1.SetNudgePx,
40599
40599
  nudgePx: newNudgePx,
40600
40600
  });
40601
40601
  }
@@ -40609,12 +40609,12 @@ const Tooltip = (props) => {
40609
40609
  const remInPixels = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10);
40610
40610
  // Set bottom left corner rounding
40611
40611
  dispatch({
40612
- type: ActionType.SetSquareBottomLeft,
40612
+ type: ActionType$1.SetSquareBottomLeft,
40613
40613
  squareBottomLeft: (arrowRect.left < (TOOLTIP_BORDER_RADIUS_REM * remInPixels)),
40614
40614
  });
40615
40615
  // Set bottom right corner rounding
40616
40616
  dispatch({
40617
- type: ActionType.SetSquareBottomRight,
40617
+ type: ActionType$1.SetSquareBottomRight,
40618
40618
  squareBottomRight: (arrowRect.right
40619
40619
  > window.innerWidth - (TOOLTIP_BORDER_RADIUS_REM * remInPixels)),
40620
40620
  });
@@ -40637,22 +40637,22 @@ const Tooltip = (props) => {
40637
40637
  // Render
40638
40638
  return (React__default["default"].createElement("div", { className: "Tooltip-outer-container", "aria-label": text, onMouseEnter: () => {
40639
40639
  dispatch({
40640
- type: ActionType.Show,
40640
+ type: ActionType$1.Show,
40641
40641
  });
40642
40642
  }, onMouseLeave: () => {
40643
40643
  dispatch({
40644
- type: ActionType.Hide,
40644
+ type: ActionType$1.Hide,
40645
40645
  });
40646
40646
  }, onFocus: () => {
40647
40647
  dispatch({
40648
- type: ActionType.Show,
40648
+ type: ActionType$1.Show,
40649
40649
  });
40650
40650
  }, onBlur: () => {
40651
40651
  dispatch({
40652
- type: ActionType.Hide,
40652
+ type: ActionType$1.Hide,
40653
40653
  });
40654
40654
  } },
40655
- React__default["default"].createElement("style", null, style),
40655
+ React__default["default"].createElement("style", null, style$1),
40656
40656
  children,
40657
40657
  React__default["default"].createElement("div", { className: `Tooltip-arrow Tooltip-arrow-visible-${isVisible ? 'true' : 'false'}`, ref: arrowElement },
40658
40658
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCaretDown })),
@@ -40709,6 +40709,306 @@ const ToggleSwitch = (props) => {
40709
40709
  } })));
40710
40710
  };
40711
40711
 
40712
+ /**
40713
+ * Convert a string to hyphenated lowercase format with no space or
40714
+ * non-alphanumeric characters
40715
+ * @author Gabe Abrams
40716
+ * @param str the string to convert
40717
+ * @returns the idified string
40718
+ */
40719
+ const idify = (str) => {
40720
+ return (str
40721
+ // Trim whitespace
40722
+ .trim()
40723
+ // Convert to lowercase
40724
+ .toLowerCase()
40725
+ // Replace non-alphanumeric characters with hyphens
40726
+ .replace(/[^a-z0-9]+/g, '-')
40727
+ // Change multiple hyphens in a row for a single hyphen
40728
+ .replace(/-+/g, '-')
40729
+ // Remove hyphens at the beginning and end of the string
40730
+ .replace(/^-+|-+$/g, ''));
40731
+ };
40732
+
40733
+ /**
40734
+ * Container that automatically scrolls when new items are added,
40735
+ * lets the user scroll up to see old items, but resumes
40736
+ * autoscroll when the user scrolls back to the bottom.
40737
+ * Note: takes up full height of parent, so parent should
40738
+ * have a determined height for the scroll to work.
40739
+ * @author Gabe Abrams
40740
+ */
40741
+ /*------------------------------------------------------------------------*/
40742
+ /* -------------------------------- Style ------------------------------- */
40743
+ /*------------------------------------------------------------------------*/
40744
+ const style = `
40745
+ .AutoscrollToBottomContainer-outer-container {
40746
+ /* Take up all space */
40747
+ height: 100%;
40748
+ position: relative;
40749
+ }
40750
+
40751
+ .AutoscrollToBottomContainer-scrollable-container {
40752
+ /* Take up max 100% height, don't take it up if not needed */
40753
+ /* (so column-reverse layout doesn't start at the bottom) */
40754
+ max-height: 100%;
40755
+ overflow-y: auto;
40756
+
40757
+ /* Allow children to position */
40758
+ position: relative;
40759
+
40760
+ /* Reverse order of children so scroll starts at bottom */
40761
+ /* (but children will have to be rendered in reverse order) */
40762
+ display: flex;
40763
+ flex-direction: column-reverse;
40764
+ }
40765
+
40766
+ .AutoscrollToBottomContainer-jump-to-bottom-container {
40767
+ /* Don't take any space in parent */
40768
+ height: 0;
40769
+ overflow: visible;
40770
+
40771
+ /* On top of items */
40772
+ z-index: 2;
40773
+
40774
+ /* Position in center bottom */
40775
+ position: absolute;
40776
+ bottom: 2rem;
40777
+
40778
+ /* Center horizontally */
40779
+ width: 100%;
40780
+ text-align: center;
40781
+ }
40782
+
40783
+ .AutoscrollToBottomContainer-item-container {
40784
+ /* Normal Height */
40785
+ position: relative;
40786
+ z-index: 1;
40787
+ }
40788
+ `;
40789
+ /*------------------------------------------------------------------------*/
40790
+ /* ------------------------------ Constants ----------------------------- */
40791
+ /*------------------------------------------------------------------------*/
40792
+ // Scrolled to bottom threshold
40793
+ // (how close you have to be to the bottom for it to count as the bottom)
40794
+ const SCROLLED_TO_BOTTOM_THRESHOLD_REMS = 2;
40795
+ /*------------------------------------------------------------------------*/
40796
+ /* -------------------------- Static Functions -------------------------- */
40797
+ /*------------------------------------------------------------------------*/
40798
+ /**
40799
+ * Get ids of items
40800
+ * @author Gabe Abrams
40801
+ * @param items the items in the container
40802
+ * @returns ids of items
40803
+ */
40804
+ const getItemIds = (items) => {
40805
+ return Array.from(items).map((child) => {
40806
+ return child.id;
40807
+ });
40808
+ };
40809
+ /* ------------- Actions ------------ */
40810
+ // Types of actions
40811
+ var ActionType;
40812
+ (function (ActionType) {
40813
+ // Identify that the user is now scrolled to the bottom
40814
+ ActionType["NowScrolledToBottom"] = "NowScrolledToBottom";
40815
+ // Identify that the user scrolled away from the bottom
40816
+ ActionType["NowScrolledAwayFromBottom"] = "NowScrolledAwayFromBottom";
40817
+ // Identify that new content appeared at the bottom but is not visible
40818
+ ActionType["NewContentAtBottom"] = "NewContentAtBottom";
40819
+ })(ActionType || (ActionType = {}));
40820
+ /**
40821
+ * Reducer that executes actions
40822
+ * @author Gabe Abrams
40823
+ * @param state current state
40824
+ * @param action action to execute
40825
+ */
40826
+ const reducer = (state, action) => {
40827
+ switch (action.type) {
40828
+ case ActionType.NowScrolledToBottom: {
40829
+ return Object.assign(Object.assign({}, state), {
40830
+ // Store the event
40831
+ wasScrolledToBottom: true,
40832
+ // Hide the "jump to bottom" button
40833
+ jumpToBottomButtonVisible: false });
40834
+ }
40835
+ case ActionType.NowScrolledAwayFromBottom: {
40836
+ return Object.assign(Object.assign({}, state), {
40837
+ // Store the event
40838
+ wasScrolledToBottom: false });
40839
+ }
40840
+ case ActionType.NewContentAtBottom: {
40841
+ return Object.assign(Object.assign({}, state), {
40842
+ // Store the event
40843
+ wasScrolledToBottom: false,
40844
+ // Show the "jump to bottom" button
40845
+ jumpToBottomButtonVisible: true });
40846
+ }
40847
+ default: {
40848
+ return state;
40849
+ }
40850
+ }
40851
+ };
40852
+ /*------------------------------------------------------------------------*/
40853
+ /* ------------------------------ Component ----------------------------- */
40854
+ /*------------------------------------------------------------------------*/
40855
+ const AutoscrollToBottomContainer = (props) => {
40856
+ /*------------------------------------------------------------------------*/
40857
+ /* -------------------------------- Setup ------------------------------- */
40858
+ /*------------------------------------------------------------------------*/
40859
+ /* -------------- Props ------------- */
40860
+ // Destructure all props
40861
+ const { itemsName, items, jumpToBottomButtonVariant = Variant$1.Danger, } = props;
40862
+ /* -------------- State ------------- */
40863
+ // Initial state
40864
+ const initialState = {
40865
+ wasScrolledToBottom: true,
40866
+ jumpToBottomButtonVisible: false,
40867
+ };
40868
+ // Initialize state
40869
+ const [state, dispatch] = React.useReducer(reducer, initialState);
40870
+ // Destructure common state
40871
+ const { wasScrolledToBottom, jumpToBottomButtonVisible, } = state;
40872
+ /* -------------- Refs -------------- */
40873
+ // Initialize refs
40874
+ const lastItemIds = React.useRef([]);
40875
+ const container = React.useRef(null);
40876
+ /*------------------------------------------------------------------------*/
40877
+ /* ------------------------- Component Functions ------------------------ */
40878
+ /*------------------------------------------------------------------------*/
40879
+ /*----------------------------------------*/
40880
+ /* --------------- Scroll --------------- */
40881
+ /*----------------------------------------*/
40882
+ /**
40883
+ * Check if the user is scrolled to the bottom
40884
+ * @author Gabe Abrams
40885
+ * @returns true if scrolled to the bottom
40886
+ */
40887
+ const isScrolledToBottom = () => {
40888
+ // Skip if no container
40889
+ if (!container.current) {
40890
+ return true;
40891
+ }
40892
+ // Get info about container
40893
+ const { scrollTop, } = container.current;
40894
+ // Distance to bottom
40895
+ const rootFontSizePx = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10);
40896
+ const distanceToBottomRems = Math.abs(scrollTop / rootFontSizePx);
40897
+ // Figure out if we're scrolled to the bottom
40898
+ return (distanceToBottomRems < SCROLLED_TO_BOTTOM_THRESHOLD_REMS);
40899
+ };
40900
+ /**
40901
+ * Scroll the user to the bottom of the container
40902
+ * @author Gabe Abrams
40903
+ */
40904
+ const scrollToBottom = () => {
40905
+ // Skip if no container
40906
+ if (!container.current) {
40907
+ return;
40908
+ }
40909
+ // Update state
40910
+ dispatch({
40911
+ type: ActionType.NowScrolledToBottom,
40912
+ });
40913
+ // Scroll to bottom
40914
+ container.current.scrollTop = 0;
40915
+ };
40916
+ /*----------------------------------------*/
40917
+ /* -------------- Handlers -------------- */
40918
+ /*----------------------------------------*/
40919
+ /**
40920
+ * Handle scroll events on the container
40921
+ * @author Gabe Abrams
40922
+ */
40923
+ const handleScroll = () => {
40924
+ // Skip if no container
40925
+ if (!container.current) {
40926
+ return;
40927
+ }
40928
+ // Check if now scrolled to bottom
40929
+ const nowScrolledToBottom = isScrolledToBottom();
40930
+ // Remember if now no longer scrolled to bottom
40931
+ if (nowScrolledToBottom) {
40932
+ dispatch({
40933
+ type: ActionType.NowScrolledToBottom,
40934
+ });
40935
+ }
40936
+ else {
40937
+ dispatch({
40938
+ type: ActionType.NowScrolledAwayFromBottom,
40939
+ });
40940
+ }
40941
+ };
40942
+ /*------------------------------------------------------------------------*/
40943
+ /* ------------------------- Lifecycle Functions ------------------------ */
40944
+ /*------------------------------------------------------------------------*/
40945
+ /**
40946
+ * Mount
40947
+ * @author Gabe Abrams
40948
+ */
40949
+ React.useEffect(() => {
40950
+ // Scroll to the bottom
40951
+ scrollToBottom();
40952
+ }, []);
40953
+ /**
40954
+ * Update (also called on mount)
40955
+ * @author Gabe Abrams
40956
+ */
40957
+ React.useEffect(() => {
40958
+ // Check if new content appeared
40959
+ const currentItemIds = getItemIds(items);
40960
+ // Check if new content appeared at bottom
40961
+ const newContentAtBottom = (currentItemIds.length > 0
40962
+ && (currentItemIds[currentItemIds.length - 1]
40963
+ !== lastItemIds.current[lastItemIds.current.length - 1]));
40964
+ // Do nothing if no new content
40965
+ if (!newContentAtBottom) {
40966
+ return;
40967
+ }
40968
+ // Check if used to be scrolled to the bottom
40969
+ if (wasScrolledToBottom) {
40970
+ // Was scrolled to the bottom! Autoscroll.
40971
+ scrollToBottom();
40972
+ }
40973
+ else {
40974
+ // Not scrolled to bottom. Show "jump to bottom" button.
40975
+ dispatch({
40976
+ type: ActionType.NewContentAtBottom,
40977
+ });
40978
+ }
40979
+ // Update last item ids
40980
+ lastItemIds.current = currentItemIds;
40981
+ }, [items]);
40982
+ /*------------------------------------------------------------------------*/
40983
+ /* ------------------------------- Render ------------------------------- */
40984
+ /*------------------------------------------------------------------------*/
40985
+ /*----------------------------------------*/
40986
+ /* --------------- Main UI -------------- */
40987
+ /*----------------------------------------*/
40988
+ // Jump to Bottom button
40989
+ let jumpToBottomButton;
40990
+ if (jumpToBottomButtonVisible) {
40991
+ jumpToBottomButton = (React__default["default"].createElement("div", { className: `AutoscrollToBottomContainer-jump-to-bottom-container AutoscrollToBottomContainer-for-${idify(itemsName !== null && itemsName !== void 0 ? itemsName : 'items')}` },
40992
+ React__default["default"].createElement("button", { type: "button", className: `AutoscrollToBottomContainer-jump-to-bottom-button AutoscrollToBottomContainer-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" },
40993
+ "New",
40994
+ ' ', itemsName !== null && itemsName !== void 0 ? itemsName : 'Content',
40995
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faChevronDown, className: "ms-1" }))));
40996
+ }
40997
+ // Main UI
40998
+ return (React__default["default"].createElement("div", { className: "AutoscrollToBottomContainer-outer-container" },
40999
+ React__default["default"].createElement("style", null, style),
41000
+ jumpToBottomButton,
41001
+ React__default["default"].createElement("div", { className: "AutoscrollToBottomContainer-scrollable-container", onScroll: () => {
41002
+ handleScroll();
41003
+ }, ref: container }, items
41004
+ // Render each item with a key
41005
+ .map((item) => {
41006
+ return (React__default["default"].createElement("div", { className: "AutoscrollToBottomContainer-item-container", key: item.id }, item.item));
41007
+ })
41008
+ // Reverse order because flex column is reverse
41009
+ .reverse())));
41010
+ };
41011
+
40712
41012
  /**
40713
41013
  * One minute in ms
40714
41014
  * @author Gabe Abrams
@@ -42589,6 +42889,7 @@ var DayOfWeek;
42589
42889
  var DayOfWeek$1 = DayOfWeek;
42590
42890
 
42591
42891
  exports.AppWrapper = AppWrapper;
42892
+ exports.AutoscrollToBottomContainer = AutoscrollToBottomContainer;
42592
42893
  exports.ButtonInputGroup = ButtonInputGroup;
42593
42894
  exports.CSVDownloadButton = CSVDownloadButton;
42594
42895
  exports.CheckboxButton = CheckboxButton;
@@ -42649,6 +42950,7 @@ exports.getPartOfDay = getPartOfDay;
42649
42950
  exports.getTimeInfoInET = getTimeInfoInET;
42650
42951
  exports.handleError = handleError;
42651
42952
  exports.handleSuccess = handleSuccess;
42953
+ exports.idify = idify;
42652
42954
  exports.initClient = initClient;
42653
42955
  exports.initLogCollection = initLogCollection;
42654
42956
  exports.initServer = initServer;