dce-reactkit 3.5.1-beta.1 → 3.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/.eslintrc.js +0 -2
  2. package/dist/cjs/index.js +320 -27
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/client/initClient.d.ts +1 -1
  5. package/dist/cjs/types/components/AppWrapper.d.ts +6 -6
  6. package/dist/cjs/types/components/ButtonInputGroup.d.ts +1 -1
  7. package/dist/cjs/types/components/CSVDownloadButton.d.ts +1 -1
  8. package/dist/cjs/types/components/CheckboxButton.d.ts +1 -1
  9. package/dist/cjs/types/components/CopiableBox.d.ts +1 -1
  10. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +7 -1
  11. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +5 -4
  12. package/dist/cjs/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +1 -1
  13. package/dist/cjs/types/components/DBEntryManagerPanel/index.d.ts +13 -2
  14. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +1 -1
  15. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +1 -1
  16. package/dist/cjs/types/components/Drawer.d.ts +1 -1
  17. package/dist/cjs/types/components/ErrorBox.d.ts +1 -1
  18. package/dist/cjs/types/components/IntelliTable.d.ts +1 -1
  19. package/dist/cjs/types/components/ItemPicker/NestableItemList.d.ts +1 -1
  20. package/dist/cjs/types/components/ItemPicker/index.d.ts +1 -1
  21. package/dist/cjs/types/components/ItemPicker/types/PickableItem.d.ts +1 -1
  22. package/dist/cjs/types/components/LogReviewer.d.ts +1 -1
  23. package/dist/cjs/types/components/Modal.d.ts +1 -1
  24. package/dist/cjs/types/components/PopFailureMark.d.ts +1 -1
  25. package/dist/cjs/types/components/PopPendingMark.d.ts +1 -1
  26. package/dist/cjs/types/components/PopSuccessMark.d.ts +1 -1
  27. package/dist/cjs/types/components/RadioButton.d.ts +1 -1
  28. package/dist/cjs/types/components/SimpleDateChooser.d.ts +1 -1
  29. package/dist/cjs/types/components/TabBox.d.ts +1 -1
  30. package/dist/cjs/types/helpers/abbreviate.test.d.ts +5 -0
  31. package/dist/cjs/types/helpers/addDBEditorEndpoints.d.ts +4 -3
  32. package/dist/cjs/types/helpers/avg.test.d.ts +5 -0
  33. package/dist/cjs/types/helpers/canReviewLogs.d.ts +5 -0
  34. package/dist/cjs/types/helpers/canReviewLogs.test.d.ts +5 -0
  35. package/dist/cjs/types/helpers/ceilToNumDecimals.test.d.ts +5 -0
  36. package/dist/cjs/types/helpers/compareArraysByProp.d.ts +3 -2
  37. package/dist/cjs/types/helpers/compareArraysByProp.test.d.ts +5 -0
  38. package/dist/cjs/types/helpers/extractProp.test.d.ts +5 -0
  39. package/dist/cjs/types/helpers/floorToNumDecimals.test.d.ts +5 -0
  40. package/dist/cjs/types/helpers/forceNumIntoBounds.test.d.ts +5 -0
  41. package/dist/cjs/types/helpers/genCSV.test.d.ts +5 -0
  42. package/dist/cjs/types/helpers/genCommaList.d.ts +12 -0
  43. package/dist/cjs/types/helpers/genCommaList.test.d.ts +1 -0
  44. package/dist/cjs/types/helpers/genRouteHandler.d.ts +7 -7
  45. package/dist/cjs/types/helpers/getHumanReadableDate.d.ts +1 -1
  46. package/dist/cjs/types/helpers/getHumanReadableDate.test.d.ts +5 -0
  47. package/dist/cjs/types/helpers/getLocalTimeInfo.d.ts +1 -1
  48. package/dist/cjs/types/helpers/getLocalTimeInfo.test.d.ts +6 -0
  49. package/dist/cjs/types/helpers/getMonthName.test.d.ts +5 -0
  50. package/dist/cjs/types/helpers/getOrdinal.test.d.ts +5 -0
  51. package/dist/cjs/types/helpers/getPartOfDay.test.d.ts +5 -0
  52. package/dist/cjs/types/helpers/getTimeInfoInET.d.ts +1 -1
  53. package/dist/cjs/types/helpers/getTimeInfoInET.test.d.ts +5 -0
  54. package/dist/cjs/types/helpers/parallelLimit.d.ts +1 -1
  55. package/dist/cjs/types/helpers/validators/shared/constants/ERROR_MESSAGES.d.ts +10 -0
  56. package/dist/cjs/types/helpers/validators/shared/helpers/validateRegex.d.ts +19 -0
  57. package/dist/cjs/types/helpers/validators/shared/types/ValidationResult.d.ts +12 -0
  58. package/dist/cjs/types/helpers/validators/validateEmail.d.ts +11 -0
  59. package/dist/cjs/types/helpers/validators/validateEmail.test.d.ts +1 -0
  60. package/dist/cjs/types/helpers/validators/validatePhoneNumber.d.ts +11 -0
  61. package/dist/cjs/types/helpers/validators/validatePhoneNumber.test.d.ts +1 -0
  62. package/dist/cjs/types/helpers/validators/validateString.d.ts +22 -0
  63. package/dist/cjs/types/helpers/validators/validateString.test.d.ts +1 -0
  64. package/dist/cjs/types/index.d.ts +5 -1
  65. package/dist/cjs/types/server/initServer.d.ts +1 -1
  66. package/dist/cjs/types/types/IntelliTableColumn.d.ts +1 -1
  67. package/dist/cjs/types/types/Log/LogMainInfo.d.ts +1 -1
  68. package/dist/cjs/types/types/Log/LogSourceSpecificInfo.d.ts +1 -1
  69. package/dist/cjs/types/types/Log/LogTypeSpecificInfo.d.ts +1 -1
  70. package/dist/cjs/types/types/Log/index.d.ts +1 -1
  71. package/dist/cjs/types/types/LogFunction.d.ts +1 -1
  72. package/dist/cjs/types/types/LogMetadataContextMap.d.ts +1 -1
  73. package/dist/cjs/types/types/LogMetadataTagMap.d.ts +1 -1
  74. package/dist/cjs/types/types/LogMetadataTargetMap.d.ts +1 -1
  75. package/dist/cjs/types/types/LogMetadataType.d.ts +1 -1
  76. package/dist/esm/index.js +317 -28
  77. package/dist/esm/index.js.map +1 -1
  78. package/dist/esm/types/client/initClient.d.ts +1 -1
  79. package/dist/esm/types/components/AppWrapper.d.ts +6 -6
  80. package/dist/esm/types/components/ButtonInputGroup.d.ts +1 -1
  81. package/dist/esm/types/components/CSVDownloadButton.d.ts +1 -1
  82. package/dist/esm/types/components/CheckboxButton.d.ts +1 -1
  83. package/dist/esm/types/components/CopiableBox.d.ts +1 -1
  84. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +7 -1
  85. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +5 -4
  86. package/dist/esm/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +1 -1
  87. package/dist/esm/types/components/DBEntryManagerPanel/index.d.ts +13 -2
  88. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +1 -1
  89. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +1 -1
  90. package/dist/esm/types/components/Drawer.d.ts +1 -1
  91. package/dist/esm/types/components/ErrorBox.d.ts +1 -1
  92. package/dist/esm/types/components/IntelliTable.d.ts +1 -1
  93. package/dist/esm/types/components/ItemPicker/NestableItemList.d.ts +1 -1
  94. package/dist/esm/types/components/ItemPicker/index.d.ts +1 -1
  95. package/dist/esm/types/components/ItemPicker/types/PickableItem.d.ts +1 -1
  96. package/dist/esm/types/components/LogReviewer.d.ts +1 -1
  97. package/dist/esm/types/components/Modal.d.ts +1 -1
  98. package/dist/esm/types/components/PopFailureMark.d.ts +1 -1
  99. package/dist/esm/types/components/PopPendingMark.d.ts +1 -1
  100. package/dist/esm/types/components/PopSuccessMark.d.ts +1 -1
  101. package/dist/esm/types/components/RadioButton.d.ts +1 -1
  102. package/dist/esm/types/components/SimpleDateChooser.d.ts +1 -1
  103. package/dist/esm/types/components/TabBox.d.ts +1 -1
  104. package/dist/esm/types/helpers/abbreviate.test.d.ts +5 -0
  105. package/dist/esm/types/helpers/addDBEditorEndpoints.d.ts +4 -3
  106. package/dist/esm/types/helpers/avg.test.d.ts +5 -0
  107. package/dist/esm/types/helpers/canReviewLogs.d.ts +5 -0
  108. package/dist/esm/types/helpers/canReviewLogs.test.d.ts +5 -0
  109. package/dist/esm/types/helpers/ceilToNumDecimals.test.d.ts +5 -0
  110. package/dist/esm/types/helpers/compareArraysByProp.d.ts +3 -2
  111. package/dist/esm/types/helpers/compareArraysByProp.test.d.ts +5 -0
  112. package/dist/esm/types/helpers/extractProp.test.d.ts +5 -0
  113. package/dist/esm/types/helpers/floorToNumDecimals.test.d.ts +5 -0
  114. package/dist/esm/types/helpers/forceNumIntoBounds.test.d.ts +5 -0
  115. package/dist/esm/types/helpers/genCSV.test.d.ts +5 -0
  116. package/dist/esm/types/helpers/genCommaList.d.ts +12 -0
  117. package/dist/esm/types/helpers/genCommaList.test.d.ts +1 -0
  118. package/dist/esm/types/helpers/genRouteHandler.d.ts +7 -7
  119. package/dist/esm/types/helpers/getHumanReadableDate.d.ts +1 -1
  120. package/dist/esm/types/helpers/getHumanReadableDate.test.d.ts +5 -0
  121. package/dist/esm/types/helpers/getLocalTimeInfo.d.ts +1 -1
  122. package/dist/esm/types/helpers/getLocalTimeInfo.test.d.ts +6 -0
  123. package/dist/esm/types/helpers/getMonthName.test.d.ts +5 -0
  124. package/dist/esm/types/helpers/getOrdinal.test.d.ts +5 -0
  125. package/dist/esm/types/helpers/getPartOfDay.test.d.ts +5 -0
  126. package/dist/esm/types/helpers/getTimeInfoInET.d.ts +1 -1
  127. package/dist/esm/types/helpers/getTimeInfoInET.test.d.ts +5 -0
  128. package/dist/esm/types/helpers/parallelLimit.d.ts +1 -1
  129. package/dist/esm/types/helpers/validators/shared/constants/ERROR_MESSAGES.d.ts +10 -0
  130. package/dist/esm/types/helpers/validators/shared/helpers/validateRegex.d.ts +19 -0
  131. package/dist/esm/types/helpers/validators/shared/types/ValidationResult.d.ts +12 -0
  132. package/dist/esm/types/helpers/validators/validateEmail.d.ts +11 -0
  133. package/dist/esm/types/helpers/validators/validateEmail.test.d.ts +1 -0
  134. package/dist/esm/types/helpers/validators/validatePhoneNumber.d.ts +11 -0
  135. package/dist/esm/types/helpers/validators/validatePhoneNumber.test.d.ts +1 -0
  136. package/dist/esm/types/helpers/validators/validateString.d.ts +22 -0
  137. package/dist/esm/types/helpers/validators/validateString.test.d.ts +1 -0
  138. package/dist/esm/types/index.d.ts +5 -1
  139. package/dist/esm/types/server/initServer.d.ts +1 -1
  140. package/dist/esm/types/types/IntelliTableColumn.d.ts +1 -1
  141. package/dist/esm/types/types/Log/LogMainInfo.d.ts +1 -1
  142. package/dist/esm/types/types/Log/LogSourceSpecificInfo.d.ts +1 -1
  143. package/dist/esm/types/types/Log/LogTypeSpecificInfo.d.ts +1 -1
  144. package/dist/esm/types/types/Log/index.d.ts +1 -1
  145. package/dist/esm/types/types/LogFunction.d.ts +1 -1
  146. package/dist/esm/types/types/LogMetadataContextMap.d.ts +1 -1
  147. package/dist/esm/types/types/LogMetadataTagMap.d.ts +1 -1
  148. package/dist/esm/types/types/LogMetadataTargetMap.d.ts +1 -1
  149. package/dist/esm/types/types/LogMetadataType.d.ts +1 -1
  150. package/dist/index.d.ts +134 -56
  151. package/package.json +14 -13
  152. package/src/components/ItemPicker/index.test.tsx +10 -10
  153. package/src/helpers/abbreviate.test.ts +26 -0
  154. package/src/helpers/avg.test.ts +24 -0
  155. package/src/helpers/canReviewLogs.test.ts +67 -0
  156. package/src/helpers/canReviewLogs.ts +20 -0
  157. package/src/helpers/ceilToNumDecimals.test.ts +39 -0
  158. package/src/helpers/compareArraysByProp.test.ts +147 -0
  159. package/src/helpers/compareArraysByProp.ts +41 -22
  160. package/src/helpers/extractProp.test.ts +34 -0
  161. package/src/helpers/floorToNumDecimals.test.ts +39 -0
  162. package/src/helpers/forceNumIntoBounds.test.ts +34 -0
  163. package/src/helpers/genCSV.test.ts +61 -0
  164. package/src/helpers/genCSV.ts +5 -2
  165. package/src/helpers/genCommaList.test.ts +57 -0
  166. package/src/helpers/genCommaList.ts +21 -0
  167. package/src/helpers/getHumanReadableDate.test.ts +29 -0
  168. package/src/helpers/getLocalTimeInfo.test.ts +48 -0
  169. package/src/helpers/getMonthName.test.ts +79 -0
  170. package/src/helpers/getOrdinal.test.ts +84 -0
  171. package/src/helpers/{getOrdinal.tsx → getOrdinal.ts} +1 -0
  172. package/src/helpers/getPartOfDay.test.ts +56 -0
  173. package/src/helpers/getTimeInfoInET.test.ts +72 -0
  174. package/src/helpers/validators/shared/constants/ERROR_MESSAGES.ts +18 -0
  175. package/src/helpers/validators/shared/helpers/validateRegex.ts +47 -0
  176. package/src/helpers/validators/shared/types/ValidationResult.ts +20 -0
  177. package/src/helpers/validators/validateEmail.test.ts +110 -0
  178. package/src/helpers/validators/validateEmail.ts +47 -0
  179. package/src/helpers/validators/validatePhoneNumber.test.ts +94 -0
  180. package/src/helpers/validators/validatePhoneNumber.ts +49 -0
  181. package/src/helpers/validators/validateString.test.ts +173 -0
  182. package/src/helpers/validators/validateString.ts +171 -0
  183. package/src/index.ts +8 -0
  184. package/tsconfig.json +6 -2
  185. /package/src/helpers/{abbreviate.tsx → abbreviate.ts} +0 -0
  186. /package/src/helpers/{avg.tsx → avg.ts} +0 -0
  187. /package/src/helpers/{ceilToNumDecimals.tsx → ceilToNumDecimals.ts} +0 -0
  188. /package/src/helpers/{floorToNumDecimals.tsx → floorToNumDecimals.ts} +0 -0
  189. /package/src/helpers/{forceNumIntoBounds.tsx → forceNumIntoBounds.ts} +0 -0
  190. /package/src/helpers/{getLocalTimeInfo.tsx → getLocalTimeInfo.ts} +0 -0
  191. /package/src/helpers/{getTimeInfoInET.tsx → getTimeInfoInET.ts} +0 -0
package/dist/esm/index.js CHANGED
@@ -1275,6 +1275,7 @@ const getMonthName = (month) => {
1275
1275
  return ((_a = monthNames[month - 1]) !== null && _a !== void 0 ? _a : monthNames[0]);
1276
1276
  };
1277
1277
 
1278
+ // Constants
1278
1279
  const ORDINALS = ['th', 'st', 'nd', 'rd'];
1279
1280
  /**
1280
1281
  * Get a number's ordinal
@@ -2270,12 +2271,13 @@ const roundToNumDecimals = (num, numDecimals) => {
2270
2271
  * @returns escaped cell text
2271
2272
  */
2272
2273
  const escapeCellText = (text) => {
2273
- if (!String(text).includes(',')) {
2274
+ if (!String(text).includes(',')
2275
+ && !String(text).includes('"')) {
2274
2276
  // No need to escape
2275
2277
  return String(text);
2276
2278
  }
2277
2279
  // Perform escape
2278
- return `"${String(text).replace(/"/g, '""')}`;
2280
+ return `"${String(text).replace(/"/g, '""')}"`;
2279
2281
  };
2280
2282
  /**
2281
2283
  * Generate a CSV file
@@ -39431,7 +39433,12 @@ var CreatableSelect = /*#__PURE__*/forwardRef(function (props, ref) {
39431
39433
  });
39432
39434
  var CreatableSelect$1 = CreatableSelect;
39433
39435
 
39434
- // Import React
39436
+ /**
39437
+ * Multiselect component that allows the user to type in values and add them to
39438
+ * the multiselect component
39439
+ * @author Yuen Ler Chow
39440
+ * @author Gabe Abrams
39441
+ */
39435
39442
  /* ------------- Actions ------------ */
39436
39443
  // Types of actions
39437
39444
  var ActionType$2;
@@ -39444,6 +39451,7 @@ var ActionType$2;
39444
39451
  * @author Yuen Ler Chow
39445
39452
  * @param state current state
39446
39453
  * @param action action to execute
39454
+ * @returns updated state
39447
39455
  */
39448
39456
  const reducer$2 = (state, action) => {
39449
39457
  switch (action.type) {
@@ -39477,14 +39485,18 @@ const CreatableMultiselect = (props) => {
39477
39485
  * Creates an option for the multiselect component
39478
39486
  * @author Yuen Ler Chow
39479
39487
  * @param label label of the option
39488
+ * @returns the new option
39480
39489
  */
39481
39490
  const createOption = (label) => {
39482
39491
  // set the value to the label without special characters and spaces, and lowercase
39483
39492
  return {
39484
39493
  label,
39485
39494
  value: (label
39495
+ // Make lowercase
39486
39496
  .toLowerCase()
39497
+ // Replace special characters with nothing
39487
39498
  .replace(/\W/g, '')
39499
+ // Replace spaces with dashes
39488
39500
  .replace(' ', '-')),
39489
39501
  };
39490
39502
  };
@@ -39514,6 +39526,7 @@ const CreatableMultiselect = (props) => {
39514
39526
  return value === numberVal;
39515
39527
  });
39516
39528
  }));
39529
+ // Notify parent of new values
39517
39530
  onChange([...values, ...newValues]);
39518
39531
  }
39519
39532
  else {
@@ -39534,9 +39547,10 @@ const CreatableMultiselect = (props) => {
39534
39547
  return value === val;
39535
39548
  });
39536
39549
  }));
39550
+ // Notify parent of new values
39537
39551
  onChange([...values, ...newValues]);
39538
39552
  }
39539
- // resets text field to empty because the values have been added
39553
+ // Reset text field to empty because the values have been added
39540
39554
  dispatch({
39541
39555
  type: ActionType$2.SetInputValue,
39542
39556
  value: '',
@@ -39595,7 +39609,7 @@ const CreatableMultiselect = (props) => {
39595
39609
  // Update values based on type
39596
39610
  if (type === DBEntryFieldType$1.NumberArray) {
39597
39611
  const numberValues = newValues.map((val) => {
39598
- return Number(val.value);
39612
+ return Number.parseFloat(val.value);
39599
39613
  });
39600
39614
  onChange(numberValues);
39601
39615
  }
@@ -39617,6 +39631,7 @@ const CreatableMultiselect = (props) => {
39617
39631
  /**
39618
39632
  * Panel for adding a DBEntry to the database
39619
39633
  * @author Yuen Ler Chow
39634
+ * @author Gabe Abrams
39620
39635
  */
39621
39636
  /*------------------------------------------------------------------------*/
39622
39637
  /* -------------------------------- Style ------------------------------- */
@@ -39640,6 +39655,7 @@ var ActionType$1;
39640
39655
  * @author Yuen Ler Chow
39641
39656
  * @param state current state
39642
39657
  * @param action action to execute
39658
+ * @returns updated state
39643
39659
  */
39644
39660
  const reducer$1 = (state, action) => {
39645
39661
  switch (action.type) {
@@ -39690,7 +39706,10 @@ const AddOrEditDBEntry = (props) => {
39690
39706
  entry[field.objectKey] = field.defaultValue;
39691
39707
  }
39692
39708
  });
39693
- const modifiedEntry = modifyEntry ? modifyEntry(entry) : entry;
39709
+ // Modify entry if needed
39710
+ const modifiedEntry = (modifyEntry
39711
+ ? yield modifyEntry(entry)
39712
+ : entry);
39694
39713
  // add id key to entry so that when we delete the item, the key will always be "id"
39695
39714
  modifiedEntry.id = modifiedEntry[idPropName];
39696
39715
  // Send to server
@@ -39727,14 +39746,18 @@ const AddOrEditDBEntry = (props) => {
39727
39746
  for (let i = 0; i < fields.length; i += 1) {
39728
39747
  const field = fields[i];
39729
39748
  const value = entry[field.objectKey];
39730
- // Check if required field is empty. Field is automatically required if it is the idPropName
39749
+ // Check if required field is empty. Field is automatically required if
39750
+ // it is the idPropName
39731
39751
  if ((field.required || (field.objectKey === idPropName)) && !value) {
39732
39752
  validationError = `Please fill in the ${field.label} field`;
39733
39753
  return validationError;
39734
39754
  }
39735
39755
  // Check if unique field is unique
39736
39756
  if (field.objectKey === idPropName && !dbEntryToEdit) {
39737
- if (entries.find((e) => { return e[idPropName] === value; })) {
39757
+ const notUnique = entries.find((e) => {
39758
+ return e[idPropName] === value;
39759
+ });
39760
+ if (notUnique) {
39738
39761
  validationError = `An item with the ${field.label} ${value} already exists. ${field.label} must be unique.`;
39739
39762
  return validationError;
39740
39763
  }
@@ -39846,6 +39869,7 @@ const AddOrEditDBEntry = (props) => {
39846
39869
  * @author Yuen Ler Chow
39847
39870
  * @param field the entry field to render
39848
39871
  * @param disabled true if the field should be disabled
39872
+ * @returns rendered entry field
39849
39873
  */
39850
39874
  const renderEntryField = (field, disabled) => {
39851
39875
  if (field.type === DBEntryFieldType$1.String) {
@@ -39967,9 +39991,11 @@ const AddOrEditDBEntry = (props) => {
39967
39991
  }),
39968
39992
  React__default.createElement("div", { className: "text-center mt-2" },
39969
39993
  React__default.createElement("button", { type: "button", id: "AddOrEditDBEntry-save-changes-button", className: "btn btn-primary btn-lg me-1", "aria-label": "Save changes", onClick: () => __awaiter(void 0, void 0, void 0, function* () {
39994
+ // Show validation errors
39970
39995
  if (validationError && validationError.length > 0) {
39971
39996
  return alert$1('Please fix the following error', validationError);
39972
39997
  }
39998
+ // Run the included validator if it exists
39973
39999
  if (validateEntry) {
39974
40000
  try {
39975
40001
  yield validateEntry(entry);
@@ -39982,7 +40008,7 @@ const AddOrEditDBEntry = (props) => {
39982
40008
  }) },
39983
40009
  React__default.createElement(FontAwesomeIcon, { icon: faSave, className: "me-1" }),
39984
40010
  "Save"),
39985
- React__default.createElement("button", { type: "button", id: "AddOrEditDBEntry-cancel-button", className: "btn btn-secondary btn-lg me-1", "aria-label": "save changes", onClick: cancel }, "Cancel"))));
40011
+ React__default.createElement("button", { type: "button", id: "AddOrEditDBEntry-cancel-button", className: "btn btn-secondary btn-lg", "aria-label": "save changes", onClick: cancel }, "Cancel"))));
39986
40012
  }
39987
40013
  /*----------------------------------------*/
39988
40014
  /* --------------- Main UI -------------- */
@@ -40009,6 +40035,7 @@ const generateEndpointPath = (collectionName, adminsOnly) => {
40009
40035
  /**
40010
40036
  * DB Entry Manager Panel
40011
40037
  * @author Yuen Ler Chow
40038
+ * @author Gabe Abrams
40012
40039
  */
40013
40040
  /* ------------- Actions ------------ */
40014
40041
  // Types of actions
@@ -40032,6 +40059,7 @@ var ActionType;
40032
40059
  * @author Yuen Ler Chow
40033
40060
  * @param state current state
40034
40061
  * @param action action to execute
40062
+ * @returns updated state
40035
40063
  */
40036
40064
  const reducer = (state, action) => {
40037
40065
  switch (action.type) {
@@ -41661,8 +41689,14 @@ const initLogCollection = (Collection) => {
41661
41689
  });
41662
41690
  };
41663
41691
 
41692
+ /*------------------------------------------------------------------------*/
41693
+ /* -------------------------------- Cache ------------------------------- */
41694
+ /*------------------------------------------------------------------------*/
41664
41695
  // Cache user's ability
41665
41696
  let canReview = undefined;
41697
+ /*------------------------------------------------------------------------*/
41698
+ /* -------------------------------- Main -------------------------------- */
41699
+ /*------------------------------------------------------------------------*/
41666
41700
  /**
41667
41701
  * Check if the current user can review logs
41668
41702
  * @author Gabe Abrams
@@ -41702,36 +41736,49 @@ const extractProp = (arr, prop) => {
41702
41736
  });
41703
41737
  };
41704
41738
 
41705
- // Import shared helpers
41706
41739
  /**
41707
41740
  * Compare two arrays of objects by only comparing the values in a specific
41708
41741
  * property (e.g. compare user arrays by comparing their user.id values)
41709
41742
  * @author Gabe Abrams
41710
41743
  * @param a the first array
41711
41744
  * @param b the second array
41712
- * @param prop the property to compare with
41745
+ * @param prop the property to compare with, or an array of props to compare
41746
+ * with (if array, all values associated with those props must match)
41713
41747
  * @returns true if the arrays contain the same objects as determined by
41714
41748
  * the values associated with each object's prop
41715
41749
  */
41716
41750
  const compareArraysByProp = (a, b, prop) => {
41717
- // Extract values for comparison
41718
- const aVals = new Set(extractProp(a, prop));
41719
- const bVals = new Set(extractProp(b, prop));
41720
- // Compare sizes first
41721
- if (aVals.size !== bVals.size) {
41751
+ // Immediately return if size of arrays is different
41752
+ if (a.length !== b.length) {
41722
41753
  return false;
41723
41754
  }
41724
- // Same number of items. Make sure every object in aVals appears in bVals
41725
- // (if so, they should be equivalent since the sizes are the same)
41726
- // > Create map of items in bVals
41727
- const inBVals = {}; // item => true if in bVals
41728
- Array.from(bVals.values()).forEach((item) => {
41729
- inBVals[item] = true;
41730
- });
41731
- // > Loop through aVals and make sure every item is in bVals
41732
- return Array.from(aVals.values()).every((item) => {
41733
- return inBVals[item];
41734
- });
41755
+ // Get all props
41756
+ const props = (Array.isArray(prop) ? prop : [prop]);
41757
+ // Clone second array so we can work on it
41758
+ const bCloned = [...b];
41759
+ // Remove elements from b as we find them in a
41760
+ for (let i = 0; i < a.length; i++) {
41761
+ // Find matching element in b
41762
+ const matchingIndex = bCloned.findIndex((bItem) => {
41763
+ // Compare based on all props
41764
+ return props.every((propToCompareBy) => {
41765
+ var _a;
41766
+ const aVal = ((_a = a[i]) !== null && _a !== void 0 ? _a : {})[propToCompareBy];
41767
+ const bVal = (bItem !== null && bItem !== void 0 ? bItem : {})[propToCompareBy];
41768
+ return aVal === bVal;
41769
+ });
41770
+ });
41771
+ // Check if no match
41772
+ const noMatch = (matchingIndex < 0);
41773
+ // If no match, there's no corresponding element in b
41774
+ if (noMatch) {
41775
+ return false;
41776
+ }
41777
+ // Remove the matching element
41778
+ bCloned.splice(matchingIndex, 1);
41779
+ }
41780
+ // If we made it here, all elements in a have a corresponding element in b
41781
+ return true;
41735
41782
  };
41736
41783
 
41737
41784
  /**
@@ -41789,9 +41836,11 @@ const getLocalTimeInfo = (dateOrTimestamp) => {
41789
41836
  * @param opts.app express app to add routes too
41790
41837
  * @param opts.collectionName the name of the collection
41791
41838
  * @param opts.adminsOnly true if the endpoint is for admins only
41839
+ * @param opts.collection dce-mango db collection
41792
41840
  */
41793
41841
  const addDBEditorEndpoints = (opts) => {
41794
41842
  const { app, collectionName, adminsOnly, collection, } = opts;
41843
+ // Generate the endpoint path
41795
41844
  const endpointPath = generateEndpointPath(collectionName, adminsOnly);
41796
41845
  /**
41797
41846
  * List all items in the collection
@@ -41840,6 +41889,246 @@ const addDBEditorEndpoints = (opts) => {
41840
41889
  }));
41841
41890
  };
41842
41891
 
41892
+ /**
41893
+ * Given an array of strings, create a single comma-separated string that includes
41894
+ * 'and' as well as an oxford comma.
41895
+ * Ex: ['apples'] => 'apples'
41896
+ * Ex: ['apples', 'bananas'] => 'apples and bananas'
41897
+ * Ex: ['apples', 'bananas', 'grapes'] => 'apples, bananas, and grapes'
41898
+ * @author Austen Money
41899
+ * @param list an array of elements to be made into a single comma-separated string.
41900
+ * @returns a comma-separated string.
41901
+ */
41902
+ const genCommaList = (list) => {
41903
+ const { length } = list;
41904
+ return (length < 2
41905
+ ? list.join('')
41906
+ : `${list.slice(0, length - 1).join(', ')}${length < 3 ? ' and ' : ', and '}${list[length - 1]}`);
41907
+ };
41908
+
41909
+ /*------------------------------------------------------------------------*/
41910
+ /* ------------------------------ Constants ----------------------------- */
41911
+ /*------------------------------------------------------------------------*/
41912
+ const INVALID_REGEX_ERROR = 'input does not follow the requested format';
41913
+ const INVALID_EMAIL_ERROR = 'Please provide a valid email address.';
41914
+ const INVALID_PHONE_ERROR = 'Please provide a valid phone number.';
41915
+ const INVALID_STRING_ERRORS = {
41916
+ MIN_LEN: (minLen) => {
41917
+ return `input must not be under ${minLen} character(s)`;
41918
+ },
41919
+ MAX_LEN: (maxLen) => {
41920
+ return `input must not be over ${maxLen} character(s)`;
41921
+ },
41922
+ LETTERS_ONLY: 'input must only contain letters',
41923
+ NUMBERS_ONLY: 'input must only contain numbers',
41924
+ MESSAGE_INTRO: 'The following error(s) occurred: ',
41925
+ };
41926
+
41927
+ // Import constants
41928
+ /**
41929
+ * Determines whether a given input string is considered valid based on
41930
+ * the provided regex.
41931
+ * @author Austen Money
41932
+ * @param opts object containing all args
41933
+ * @param opts.input user-provided input to validate
41934
+ * @param opts.regex regular expression to check against input
41935
+ * @param [opts.regexDescription] description of what regexString is checking
41936
+ * for, used to customize error message
41937
+ * @returns the unchanged input if valid, or a customized error message if
41938
+ * invalid
41939
+ */
41940
+ const validateRegex = (opts) => {
41941
+ // customize error message in case of invalid input
41942
+ const errorMessage = `${INVALID_REGEX_ERROR}${opts.regexDescription
41943
+ ? ': '
41944
+ : ''}${opts.regexDescription}`;
41945
+ // return error message if test is invalid, or input string if valid
41946
+ return (opts.regex.test(opts.input)
41947
+ ? {
41948
+ isValid: true,
41949
+ cleanedValue: opts.input,
41950
+ }
41951
+ : {
41952
+ isValid: false,
41953
+ errorMessage,
41954
+ });
41955
+ };
41956
+
41957
+ // Import helpers
41958
+ /**
41959
+ * Determines whether a given email address is valid.
41960
+ * @author Austen Money
41961
+ * @param email email address to validate
41962
+ * @returns whether email fulfills proper formatting requirements, includes a
41963
+ * cleaned version of the address without leading or trailing
41964
+ * whitespace if valid or an error message if invalid.
41965
+ */
41966
+ const validateEmail = (email) => {
41967
+ // validation regex, sourced from HTML living standard: http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
41968
+ // eslint-disable-next-line max-len
41969
+ const emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
41970
+ // remove leading and trailing whitespace
41971
+ const cleanedValue = email.replace(/^\s+|\s+$/g, '');
41972
+ // validate email with regex, and return error if not valid
41973
+ return (validateRegex({
41974
+ input: cleanedValue,
41975
+ regex: emailRegex,
41976
+ }).isValid
41977
+ ? {
41978
+ isValid: true,
41979
+ cleanedValue,
41980
+ }
41981
+ : {
41982
+ isValid: false,
41983
+ errorMessage: INVALID_EMAIL_ERROR,
41984
+ });
41985
+ };
41986
+
41987
+ // Import helpers
41988
+ /**
41989
+ * Determines whether a given phone number is valid.
41990
+ * @author Austen Money
41991
+ * @param phoneNumber phone number to validate
41992
+ * @returns whether phone number is considered valid - if valid, also returns
41993
+ * a cleaned version of the number without any formatting. If invalid,
41994
+ * returns an error message.
41995
+ */
41996
+ const validatePhoneNumber = (phoneNumber) => {
41997
+ // regex to validate phone number
41998
+ const validationRegex = /^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$/;
41999
+ // validate phone number with regex
42000
+ const validationResponse = validateRegex({
42001
+ input: phoneNumber,
42002
+ regex: validationRegex,
42003
+ });
42004
+ // remove all non-digits from number
42005
+ const cleanedValue = phoneNumber.replace(/\D/g, '');
42006
+ // return cleaned value if valid, or error message if invalid
42007
+ return (validationResponse.isValid
42008
+ ? {
42009
+ isValid: true,
42010
+ cleanedValue,
42011
+ }
42012
+ : {
42013
+ isValid: false,
42014
+ errorMessage: INVALID_PHONE_ERROR,
42015
+ });
42016
+ };
42017
+
42018
+ // Import helpers
42019
+ /*------------------------------------------------------------------------*/
42020
+ /* ------------------------------ Constants ----------------------------- */
42021
+ /*------------------------------------------------------------------------*/
42022
+ // define minimum and maximum range for lowercase ASCII chars
42023
+ const LOWERCASE_MIN = 65;
42024
+ const LOWERCASE_MAX = 90;
42025
+ // define minimum and maximum range for uppercase ASCII chars
42026
+ const UPPERCASE_MIN = 97;
42027
+ const UPPERCASE_MAX = 122;
42028
+ // define minimum and maximum range for ASCII digits
42029
+ const DIGIT_MIN = 48;
42030
+ const DIGIT_MAX = 57;
42031
+ /*------------------------------------------------------------------------*/
42032
+ /* ---------------------------- Main Function --------------------------- */
42033
+ /*------------------------------------------------------------------------*/
42034
+ /**
42035
+ * Determines whether a given input string is considered valid based on
42036
+ * the provided requirements.
42037
+ * @author Austen Money
42038
+ * @param input input string
42039
+ * @param opts options for validation
42040
+ * @returns whether input is considered valid according to reqs - if
42041
+ * valid, returns a cleaned version of input; if invalid, returns
42042
+ * a string containing error messages describing which requirements
42043
+ * were not met.
42044
+ */
42045
+ const validateString = (input, opts) => {
42046
+ // stores all invalid input errors
42047
+ const errorMessages = [];
42048
+ // contains version of input that will be returned
42049
+ let cleanedValue = input;
42050
+ // remove whitespace if required
42051
+ if (opts.ignoreWhitespace) {
42052
+ cleanedValue = input.replace(/\s+/g, '');
42053
+ }
42054
+ // apply max char requirement
42055
+ if (opts.minLen) {
42056
+ if (cleanedValue.length < opts.minLen) {
42057
+ errorMessages.push(INVALID_STRING_ERRORS.MIN_LEN(opts.minLen));
42058
+ }
42059
+ }
42060
+ // apply max char requirement
42061
+ if (opts.maxLen) {
42062
+ if (cleanedValue.length > opts.maxLen) {
42063
+ errorMessages.push(INVALID_STRING_ERRORS.MAX_LEN(opts.maxLen));
42064
+ }
42065
+ }
42066
+ // apply alphabetical requirement
42067
+ if (opts.lettersOnly) {
42068
+ // remove diacritics
42069
+ cleanedValue = cleanedValue.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
42070
+ const containsNonLetters = (cleanedValue
42071
+ // split into characters
42072
+ .split('')
42073
+ // convert into character codes
42074
+ .map((curr) => {
42075
+ return curr.charCodeAt(0);
42076
+ })
42077
+ // check for non-letters
42078
+ .some((currCode) => {
42079
+ return (!(currCode >= LOWERCASE_MIN && currCode <= LOWERCASE_MAX)
42080
+ && !(currCode >= UPPERCASE_MIN && currCode <= UPPERCASE_MAX));
42081
+ }));
42082
+ if (containsNonLetters) {
42083
+ errorMessages.push(INVALID_STRING_ERRORS.LETTERS_ONLY);
42084
+ }
42085
+ }
42086
+ // apply numerical requirement
42087
+ if (opts.numbersOnly) {
42088
+ const containsNonNumbers = (cleanedValue
42089
+ // split into characters
42090
+ .split('')
42091
+ // convert into character codes
42092
+ .map((curr) => {
42093
+ return curr.charCodeAt(0);
42094
+ })
42095
+ // check for non-numbers
42096
+ .some((currCode) => {
42097
+ return (!(currCode >= DIGIT_MIN && currCode <= DIGIT_MAX));
42098
+ }));
42099
+ if (containsNonNumbers) {
42100
+ errorMessages.push(INVALID_STRING_ERRORS.NUMBERS_ONLY);
42101
+ }
42102
+ }
42103
+ // apply regex requirement
42104
+ if (opts.regexTest) {
42105
+ const regex = opts.regexTest;
42106
+ // validate and create customized error message if description is provided
42107
+ const result = validateRegex({
42108
+ input: cleanedValue,
42109
+ regex,
42110
+ regexDescription: opts.regexDescription,
42111
+ });
42112
+ // if string did not pass regex validation, add error message
42113
+ if (result.isValid === false) {
42114
+ errorMessages.push(result.errorMessage);
42115
+ }
42116
+ }
42117
+ // combine all error messages into one string to return
42118
+ const errorMessage = `${INVALID_STRING_ERRORS.MESSAGE_INTRO}${genCommaList(errorMessages)}.`;
42119
+ return (
42120
+ // if no error messages, string is valid; if not, it is invalid
42121
+ errorMessages.length === 0
42122
+ ? {
42123
+ isValid: true,
42124
+ cleanedValue,
42125
+ }
42126
+ : {
42127
+ isValid: false,
42128
+ errorMessage,
42129
+ });
42130
+ };
42131
+
41843
42132
  /**
41844
42133
  * Days of the week
41845
42134
  * @author Gabe Abrams
@@ -41856,5 +42145,5 @@ var DayOfWeek;
41856
42145
  })(DayOfWeek || (DayOfWeek = {}));
41857
42146
  var DayOfWeek$1 = DayOfWeek;
41858
42147
 
41859
- 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, Variant$1 as Variant, abbreviate, addDBEditorEndpoints, alert$1 as alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, initClient, initLogCollection, initServer, isMobileOrTablet, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, visitServerEndpoint, waitMs };
42148
+ 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, 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 };
41860
42149
  //# sourceMappingURL=index.js.map