@teselagen/ui 0.9.5 → 0.9.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.
Files changed (63) hide show
  1. package/DataTable/EditabelCell.d.ts +7 -0
  2. package/DataTable/ReactTable.d.ts +78 -0
  3. package/DataTable/defaultProps.d.ts +43 -0
  4. package/DataTable/index.d.ts +3 -3
  5. package/DataTable/utils/computePresets.d.ts +1 -0
  6. package/DataTable/utils/types/Entity.d.ts +9 -0
  7. package/DataTable/utils/types/Field.d.ts +4 -0
  8. package/DataTable/utils/types/OrderBy.d.ts +11 -0
  9. package/DataTable/utils/types/Schema.d.ts +4 -0
  10. package/DataTable/utils/useDeepEqualMemo.d.ts +1 -0
  11. package/DataTable/utils/useHotKeysWrapper.d.ts +29 -0
  12. package/DataTable/utils/useTableParams.d.ts +49 -0
  13. package/README.md +6 -2
  14. package/index.cjs.js +22410 -22287
  15. package/index.es.js +22462 -22339
  16. package/package.json +1 -2
  17. package/src/AdvancedOptions.spec.js +8 -23
  18. package/src/DataTable/Columns.jsx +945 -0
  19. package/src/DataTable/EditabelCell.js +44 -0
  20. package/src/DataTable/EditabelCell.jsx +44 -0
  21. package/src/DataTable/PagingTool.js +2 -2
  22. package/src/DataTable/ReactTable.js +738 -0
  23. package/src/DataTable/RenderCell.jsx +191 -0
  24. package/src/DataTable/defaultProps.js +45 -0
  25. package/src/DataTable/index.js +217 -1203
  26. package/src/DataTable/utils/computePresets.js +42 -0
  27. package/src/DataTable/utils/convertSchema.ts +79 -0
  28. package/src/DataTable/utils/formatPasteData.ts +34 -0
  29. package/src/DataTable/utils/getAllRows.ts +11 -0
  30. package/src/DataTable/utils/getCellCopyText.ts +7 -0
  31. package/src/DataTable/utils/getCellInfo.ts +46 -0
  32. package/src/DataTable/utils/getFieldPathToField.ts +10 -0
  33. package/src/DataTable/utils/getIdOrCodeOrIndex.ts +14 -0
  34. package/src/DataTable/utils/getLastSelectedEntity.ts +15 -0
  35. package/src/DataTable/utils/getNewEntToSelect.ts +32 -0
  36. package/src/DataTable/utils/initializeHasuraWhereAndFilter.ts +35 -0
  37. package/src/DataTable/utils/isBottomRightCornerOfRectangle.ts +27 -0
  38. package/src/DataTable/utils/isEntityClean.ts +15 -0
  39. package/src/DataTable/utils/primarySelectedValue.ts +1 -0
  40. package/src/DataTable/utils/removeCleanRows.ts +26 -0
  41. package/src/DataTable/utils/selection.ts +11 -0
  42. package/src/DataTable/utils/types/Entity.ts +13 -0
  43. package/src/DataTable/utils/types/Field.ts +4 -0
  44. package/src/DataTable/utils/types/OrderBy.ts +15 -0
  45. package/src/DataTable/utils/types/Schema.ts +5 -0
  46. package/src/DataTable/utils/useDeepEqualMemo.js +10 -0
  47. package/src/DataTable/utils/useHotKeysWrapper.js +395 -0
  48. package/src/DataTable/utils/useTableEntities.ts +60 -0
  49. package/src/DataTable/utils/useTableParams.js +361 -0
  50. package/src/DataTable/utils/utils.ts +39 -0
  51. package/src/DataTable/utils/withTableParams.js +1 -1
  52. package/src/Timeline/TimelineEvent.tsx +36 -0
  53. package/src/Timeline/index.tsx +21 -0
  54. package/src/utils/browserUtils.ts +3 -0
  55. package/src/utils/determineBlackOrWhiteTextColor.ts +11 -0
  56. package/src/utils/getTextFromEl.ts +45 -0
  57. package/src/utils/handlerHelpers.ts +32 -0
  58. package/src/utils/hooks/index.ts +1 -0
  59. package/src/utils/hooks/useDeepEqualMemo.ts +10 -0
  60. package/src/utils/hooks/useStableReference.ts +9 -0
  61. package/src/utils/hotkeyUtils.tsx +155 -0
  62. package/src/utils/isBeingCalledExcessively.ts +37 -0
  63. package/style.css +10537 -0
@@ -17,7 +17,6 @@ import {
17
17
  noop,
18
18
  cloneDeep,
19
19
  keyBy,
20
- omit,
21
20
  forEach,
22
21
  lowerCase,
23
22
  get,
@@ -30,57 +29,33 @@ import {
30
29
  some,
31
30
  identity
32
31
  } from "lodash-es";
33
- import {
34
- Button,
35
- Menu,
36
- MenuItem,
37
- ContextMenu,
38
- Icon,
39
- Intent,
40
- Callout,
41
- Tooltip,
42
- useHotkeys
43
- } from "@blueprintjs/core";
32
+ import { Button, Icon, Intent, Callout, Tooltip } from "@blueprintjs/core";
44
33
  import { arrayMove } from "@dnd-kit/sortable";
45
34
  import classNames from "classnames";
46
35
  import scrollIntoView from "dom-scroll-into-view";
47
- import ReactTable, { VIRTUALIZE_CUTOFF_LENGTH } from "@teselagen/react-table";
48
- import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
36
+ import { VIRTUALIZE_CUTOFF_LENGTH } from "@teselagen/react-table";
37
+ import immer, { produceWithPatches, enablePatches } from "immer";
49
38
  import papaparse from "papaparse";
50
39
  import { useDispatch, useSelector } from "react-redux";
51
- import { ThComponent } from "./ThComponent";
52
40
  import {
53
41
  defaultParsePaste,
54
42
  formatPasteData,
55
43
  getAllRows,
56
- getCellCopyText,
57
44
  getCellInfo,
58
45
  getEntityIdToEntity,
59
46
  getFieldPathToIndex,
60
47
  getIdOrCodeOrIndex,
61
- getLastSelectedEntity,
62
- getNewEntToSelect,
63
48
  getRecordsFromIdMap,
64
- getRowCopyText,
65
- handleCopyColumn,
66
- handleCopyHelper,
67
49
  handleCopyRows,
68
50
  handleCopyTable,
69
- isEntityClean,
70
51
  PRIMARY_SELECTED_VAL,
71
52
  removeCleanRows
72
53
  } from "./utils";
73
54
  import { useDeepEqualMemo } from "../utils/hooks";
74
- import rowClick, {
75
- changeSelectedEntities,
76
- finalizeSelection
77
- } from "./utils/rowClick";
55
+ import { changeSelectedEntities, finalizeSelection } from "./utils/rowClick";
78
56
  import PagingTool from "./PagingTool";
79
57
  import SearchBar from "./SearchBar";
80
58
  import DisplayOptions from "./DisplayOptions";
81
- import DisabledLoadingComponent from "./DisabledLoadingComponent";
82
- import SortableColumns from "./SortableColumns";
83
- import dataTableEnhancer from "./dataTableEnhancer";
84
59
  import "../toastr";
85
60
  import "@teselagen/react-table/react-table.css";
86
61
  import "./style.css";
@@ -98,21 +73,16 @@ import {
98
73
  getCurrentParamsFromUrl,
99
74
  setCurrentParamsOnUrl
100
75
  } from "./utils/queryParams";
101
- import { useColumns } from "./Columns";
102
- import { formValueSelector, change as _change } from "redux-form";
76
+ import { formValueSelector, change as _change, reduxForm } from "redux-form";
103
77
  import { throwFormError } from "../throwFormError";
104
78
  import { isObservableArray, toJS } from "mobx";
105
79
  import { isBeingCalledExcessively } from "../utils/isBeingCalledExcessively";
106
80
  import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
81
+ import { useHotKeysWrapper } from "./utils/useHotKeysWrapper";
82
+ import { withRouter } from "react-router-dom";
83
+ import { ReactTable } from "./ReactTable";
107
84
 
108
85
  enablePatches();
109
- const IS_LINUX = window.navigator.platform.toLowerCase().search("linux") > -1;
110
-
111
- const itemSizeEstimators = {
112
- compact: () => 25.34,
113
- normal: () => 33.34,
114
- comfortable: () => 41.34
115
- };
116
86
 
117
87
  const DataTable = ({
118
88
  controlled_pageSize,
@@ -406,7 +376,7 @@ const DataTable = ({
406
376
  expandAllByDefault,
407
377
  extraClasses = "",
408
378
  extraCompact: _extraCompact,
409
- filters = [],
379
+ filters,
410
380
  fragment,
411
381
  getCellHoverText,
412
382
  getRowClassName,
@@ -490,7 +460,6 @@ const DataTable = ({
490
460
  );
491
461
 
492
462
  const entities = useDeepEqualMemo(_entities);
493
-
494
463
  const entitiesAcrossPages = useDeepEqualMemo(_entitiesAcrossPages);
495
464
 
496
465
  // This is because we need to maintain the reduxFormSelectedEntityIdMap and
@@ -796,11 +765,6 @@ const DataTable = ({
796
765
  extraCompact = tableConfig.density === "extraCompact";
797
766
  }
798
767
 
799
- const resized = useMemo(
800
- () => tableConfig.resized || [],
801
- [tableConfig?.resized]
802
- );
803
-
804
768
  const pageSize = controlled_pageSize || _pageSize;
805
769
 
806
770
  const [expandedEntityIdMap, setExpandedEntityIdMap] = useState(() => {
@@ -885,189 +849,85 @@ const DataTable = ({
885
849
  [schema.fields]
886
850
  );
887
851
 
888
- const updateValidationHelper = useCallback(() => {
889
- updateValidation(entities, reduxFormCellValidation);
890
- }, [entities, reduxFormCellValidation, updateValidation]);
852
+ useEffect(() => {
853
+ // This is bad practice, we shouldn't be assigning value to an
854
+ // external variable
855
+ if (helperProp) {
856
+ helperProp.updateValidationHelper = () => {
857
+ updateValidation(entities, reduxFormCellValidation);
858
+ };
891
859
 
892
- const addEditableTableEntities = useCallback(
893
- incomingEnts => {
894
- updateEntitiesHelper(entities, entities => {
895
- const newEntities = incomingEnts.map(e => ({
896
- ...e,
897
- id: e.id || nanoid(),
898
- _isClean: false
899
- }));
860
+ helperProp.addEditableTableEntities = incomingEnts => {
861
+ updateEntitiesHelper(entities, entities => {
862
+ const newEntities = incomingEnts.map(e => ({
863
+ ...e,
864
+ id: e.id || nanoid(),
865
+ _isClean: false
866
+ }));
900
867
 
901
- const { newEnts, validationErrors } = formatAndValidateEntities(
902
- newEntities,
903
- {
904
- useDefaultValues: true,
905
- indexToStartAt: entities.length
868
+ const { newEnts, validationErrors } = formatAndValidateEntities(
869
+ newEntities,
870
+ {
871
+ useDefaultValues: true,
872
+ indexToStartAt: entities.length
873
+ }
874
+ );
875
+ if (every(entities, "_isClean")) {
876
+ forEach(newEnts, (e, i) => {
877
+ entities[i] = e;
878
+ });
879
+ } else {
880
+ entities.splice(entities.length, 0, ...newEnts);
906
881
  }
907
- );
908
- if (every(entities, "_isClean")) {
909
- forEach(newEnts, (e, i) => {
910
- entities[i] = e;
911
- });
912
- } else {
913
- entities.splice(entities.length, 0, ...newEnts);
914
- }
915
882
 
916
- updateValidation(entities, {
917
- ...reduxFormCellValidation,
918
- ...validationErrors
883
+ updateValidation(entities, {
884
+ ...reduxFormCellValidation,
885
+ ...validationErrors
886
+ });
919
887
  });
920
- });
921
- },
922
- [
923
- entities,
924
- formatAndValidateEntities,
925
- reduxFormCellValidation,
926
- updateEntitiesHelper,
927
- updateValidation
928
- ]
929
- );
930
-
931
- const getEditableTableInfoAndThrowFormError = useCallback(() => {
932
- const { entsToUse, validationToUse } = removeCleanRows(
933
- reduxFormEntities,
934
- reduxFormCellValidation
935
- );
936
- const validationWTableErrs = validateTableWideErrors({
937
- entities: entsToUse,
938
- schema,
939
- newCellValidate: validationToUse
940
- });
941
-
942
- if (!entsToUse?.length) {
943
- throwFormError(
944
- "Please add at least one row to the table before submitting."
945
- );
946
- }
947
- const invalid =
948
- isEmpty(validationWTableErrs) || !some(validationWTableErrs, v => v)
949
- ? undefined
950
- : validationWTableErrs;
888
+ };
951
889
 
952
- if (invalid) {
953
- throwFormError("Please fix the errors in the table before submitting.");
954
- }
890
+ helperProp.getEditableTableInfoAndThrowFormError = () => {
891
+ const { entsToUse, validationToUse } = removeCleanRows(
892
+ reduxFormEntities,
893
+ reduxFormCellValidation
894
+ );
895
+ const validationWTableErrs = validateTableWideErrors({
896
+ entities: entsToUse,
897
+ schema,
898
+ newCellValidate: validationToUse
899
+ });
955
900
 
956
- return entsToUse;
957
- }, [reduxFormCellValidation, reduxFormEntities, schema]);
901
+ if (!entsToUse?.length) {
902
+ throwFormError(
903
+ "Please add at least one row to the table before submitting."
904
+ );
905
+ }
906
+ const invalid =
907
+ isEmpty(validationWTableErrs) || !some(validationWTableErrs, v => v)
908
+ ? undefined
909
+ : validationWTableErrs;
910
+
911
+ if (invalid) {
912
+ throwFormError(
913
+ "Please fix the errors in the table before submitting."
914
+ );
915
+ }
958
916
 
959
- useEffect(() => {
960
- // This is bad practice, we shouldn't be assigning value to an
961
- // external variable
962
- if (helperProp) {
963
- helperProp.updateValidationHelper = updateValidationHelper;
964
- helperProp.addEditableTableEntities = addEditableTableEntities;
965
- helperProp.getEditableTableInfoAndThrowFormError =
966
- getEditableTableInfoAndThrowFormError;
917
+ return entsToUse;
918
+ };
967
919
  }
968
920
  }, [
969
- addEditableTableEntities,
970
- getEditableTableInfoAndThrowFormError,
921
+ entities,
922
+ formatAndValidateEntities,
971
923
  helperProp,
972
- updateValidationHelper
924
+ reduxFormCellValidation,
925
+ reduxFormEntities,
926
+ schema,
927
+ updateEntitiesHelper,
928
+ updateValidation
973
929
  ]);
974
930
 
975
- const handleRowMove = useCallback(
976
- (type, shiftHeld) => e => {
977
- e.preventDefault();
978
- e.stopPropagation();
979
- let newIdMap = {};
980
- const lastSelectedEnt = getLastSelectedEntity(
981
- reduxFormSelectedEntityIdMap
982
- );
983
-
984
- if (noSelect) return;
985
- if (lastSelectedEnt) {
986
- let lastSelectedIndex = entities.findIndex(
987
- ent => ent === lastSelectedEnt
988
- );
989
- if (lastSelectedIndex === -1) {
990
- if (lastSelectedEnt.id !== undefined) {
991
- lastSelectedIndex = entities.findIndex(
992
- ent => ent.id === lastSelectedEnt.id
993
- );
994
- } else if (lastSelectedEnt.code !== undefined) {
995
- lastSelectedIndex = entities.findIndex(
996
- ent => ent.code === lastSelectedEnt.code
997
- );
998
- }
999
- }
1000
- if (lastSelectedIndex === -1) {
1001
- return;
1002
- }
1003
- const newEntToSelect = getNewEntToSelect({
1004
- type,
1005
- lastSelectedIndex,
1006
- entities,
1007
- isEntityDisabled
1008
- });
1009
-
1010
- if (!newEntToSelect) return;
1011
- if (shiftHeld && !isSingleSelect) {
1012
- if (
1013
- reduxFormSelectedEntityIdMap[
1014
- newEntToSelect.id || newEntToSelect.code
1015
- ]
1016
- ) {
1017
- //the entity being moved to has already been selected
1018
- newIdMap = omit(reduxFormSelectedEntityIdMap, [
1019
- lastSelectedEnt.id || lastSelectedEnt.code
1020
- ]);
1021
- newIdMap[newEntToSelect.id || newEntToSelect.code].time =
1022
- Date.now() + 1;
1023
- } else {
1024
- //the entity being moved to has NOT been selected yet
1025
- newIdMap = {
1026
- ...reduxFormSelectedEntityIdMap,
1027
- [newEntToSelect.id || newEntToSelect.code]: {
1028
- entity: newEntToSelect,
1029
- time: Date.now()
1030
- }
1031
- };
1032
- }
1033
- } else {
1034
- //no shiftHeld
1035
- newIdMap[newEntToSelect.id || newEntToSelect.code] = {
1036
- entity: newEntToSelect,
1037
- time: Date.now()
1038
- };
1039
- }
1040
- }
1041
-
1042
- finalizeSelection({
1043
- idMap: newIdMap,
1044
- entities,
1045
- props: {
1046
- onDeselect,
1047
- onSingleRowSelect,
1048
- onMultiRowSelect,
1049
- noDeselectAll,
1050
- onRowSelect,
1051
- noSelect,
1052
- change
1053
- }
1054
- });
1055
- },
1056
- [
1057
- change,
1058
- entities,
1059
- isEntityDisabled,
1060
- isSingleSelect,
1061
- noDeselectAll,
1062
- noSelect,
1063
- onDeselect,
1064
- onMultiRowSelect,
1065
- onRowSelect,
1066
- onSingleRowSelect,
1067
- reduxFormSelectedEntityIdMap
1068
- ]
1069
- );
1070
-
1071
931
  const primarySelectedCellId = useMemo(() => {
1072
932
  for (const k of Object.keys(selectedCells)) {
1073
933
  if (selectedCells[k] === PRIMARY_SELECTED_VAL) {
@@ -1103,50 +963,6 @@ const DataTable = ({
1103
963
  [change]
1104
964
  );
1105
965
 
1106
- const handleEnterStartCellEdit = useCallback(
1107
- e => {
1108
- e.stopPropagation();
1109
- startCellEdit(primarySelectedCellId);
1110
- },
1111
- [primarySelectedCellId, startCellEdit]
1112
- );
1113
-
1114
- const handleDeleteCell = useCallback(() => {
1115
- const newCellValidate = {
1116
- ...reduxFormCellValidation
1117
- };
1118
- if (isEmpty(selectedCells)) return;
1119
- const rowIds = [];
1120
- updateEntitiesHelper(entities, entities => {
1121
- const entityIdToEntity = getEntityIdToEntity(entities);
1122
- Object.keys(selectedCells).forEach(cellId => {
1123
- const [rowId, path] = cellId.split(":");
1124
- rowIds.push(rowId);
1125
- const entity = entityIdToEntity[rowId].e;
1126
- delete entity._isClean;
1127
- const { error } = editCellHelper({
1128
- entity,
1129
- path,
1130
- schema,
1131
- newVal: ""
1132
- });
1133
- if (error) {
1134
- newCellValidate[cellId] = error;
1135
- } else {
1136
- delete newCellValidate[cellId];
1137
- }
1138
- });
1139
- updateValidation(entities, newCellValidate);
1140
- });
1141
- }, [
1142
- entities,
1143
- reduxFormCellValidation,
1144
- schema,
1145
- selectedCells,
1146
- updateEntitiesHelper,
1147
- updateValidation
1148
- ]);
1149
-
1150
966
  const waitUntilAllRowsAreRendered = useCallback(() => {
1151
967
  return new Promise(resolve => {
1152
968
  const interval = setInterval(() => {
@@ -1161,74 +977,6 @@ const DataTable = ({
1161
977
  // eslint-disable-next-line react-hooks/exhaustive-deps
1162
978
  }, []);
1163
979
 
1164
- const handleCopySelectedCells = useCallback(async () => {
1165
- // if the current selection is consecutive cells then copy with
1166
- // tabs between. if not then just select primary selected cell
1167
- if (isEmpty(selectedCells)) return;
1168
-
1169
- // Temporarily disable virtualization for large tables
1170
- if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
1171
- setNoVirtual(true);
1172
- await waitUntilAllRowsAreRendered();
1173
- }
1174
-
1175
- const pathToIndex = getFieldPathToIndex(schema);
1176
- const entityIdToEntity = getEntityIdToEntity(entities);
1177
- const selectionGrid = [];
1178
- let firstRowIndex;
1179
- let firstCellIndex;
1180
- Object.keys(selectedCells).forEach(key => {
1181
- const [rowId, path] = key.split(":");
1182
- const eInfo = entityIdToEntity[rowId];
1183
- if (eInfo) {
1184
- if (firstRowIndex === undefined || eInfo.i < firstRowIndex) {
1185
- firstRowIndex = eInfo.i;
1186
- }
1187
- if (!selectionGrid[eInfo.i]) {
1188
- selectionGrid[eInfo.i] = [];
1189
- }
1190
- const cellIndex = pathToIndex[path];
1191
- if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
1192
- firstCellIndex = cellIndex;
1193
- }
1194
- selectionGrid[eInfo.i][cellIndex] = true;
1195
- }
1196
- });
1197
- if (firstRowIndex === undefined) return;
1198
- const allRows = getAllRows(tableRef);
1199
- let fullCellText = "";
1200
- const fullJson = [];
1201
- times(selectionGrid.length, i => {
1202
- const row = selectionGrid[i];
1203
- if (fullCellText) {
1204
- fullCellText += "\n";
1205
- }
1206
- if (!row) {
1207
- return;
1208
- } else {
1209
- const jsonRow = [];
1210
- // ignore header
1211
- let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
1212
- rowCopyText = rowCopyText.split("\t");
1213
- times(row.length, i => {
1214
- const cell = row[i];
1215
- if (cell) {
1216
- fullCellText += rowCopyText[i];
1217
- jsonRow.push(json[i]);
1218
- }
1219
- if (i !== row.length - 1 && i >= firstCellIndex) fullCellText += "\t";
1220
- });
1221
- fullJson.push(jsonRow);
1222
- }
1223
- });
1224
- if (!fullCellText) return window.toastr.warning("No text to copy");
1225
-
1226
- handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
1227
-
1228
- // Re-enable virtualization if it was disabled
1229
- setNoVirtual(false);
1230
- }, [entities, selectedCells, schema, waitUntilAllRowsAreRendered]);
1231
-
1232
980
  const handleCopySelectedRows = useCallback(
1233
981
  async selectedRecords => {
1234
982
  if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
@@ -1271,237 +1019,36 @@ const DataTable = ({
1271
1019
  [entities, waitUntilAllRowsAreRendered]
1272
1020
  );
1273
1021
 
1274
- const handleCopyHotkey = useCallback(
1275
- e => {
1276
- if (isCellEditable) {
1277
- handleCopySelectedCells(e);
1278
- } else {
1279
- handleCopySelectedRows(
1280
- getRecordsFromIdMap(reduxFormSelectedEntityIdMap),
1281
- e
1282
- );
1283
- }
1284
- },
1285
- [
1286
- handleCopySelectedCells,
1287
- handleCopySelectedRows,
1288
- isCellEditable,
1289
- reduxFormSelectedEntityIdMap
1290
- ]
1291
- );
1292
-
1293
- const handleCut = useCallback(
1294
- e => {
1295
- handleDeleteCell();
1296
- handleCopyHotkey(e);
1297
- },
1298
- [handleCopyHotkey, handleDeleteCell]
1299
- );
1300
-
1301
- const flashTableBorder = () => {
1302
- try {
1303
- const table = tableRef.current.tableRef;
1304
- table.classList.add("tgBorderBlue");
1305
- setTimeout(() => {
1306
- table.classList.remove("tgBorderBlue");
1307
- }, 300);
1308
- } catch (e) {
1309
- console.error(`err when flashing table border:`, e);
1310
- }
1311
- };
1312
-
1313
- const handleUndo = useCallback(() => {
1314
- if (entitiesUndoRedoStack.currentVersion > 0) {
1315
- flashTableBorder();
1316
- const nextState = applyPatches(
1317
- entities,
1318
- entitiesUndoRedoStack[entitiesUndoRedoStack.currentVersion]
1319
- .inversePatches
1320
- );
1321
- const { newEnts, validationErrors } =
1322
- formatAndValidateEntities(nextState);
1323
- setEntitiesUndoRedoStack(prev => ({
1324
- ...prev,
1325
- currentVersion: prev.currentVersion - 1
1326
- }));
1327
- updateValidation(newEnts, validationErrors);
1328
- change("reduxFormEntities", newEnts);
1329
- }
1330
- }, [
1022
+ const { handleKeyDown, handleKeyUp } = useHotKeysWrapper({
1331
1023
  change,
1332
1024
  entities,
1333
- formatAndValidateEntities,
1334
1025
  entitiesUndoRedoStack,
1335
- updateValidation
1336
- ]);
1337
-
1338
- const handleRedo = useCallback(() => {
1339
- const nextV = entitiesUndoRedoStack.currentVersion + 1;
1340
- if (entitiesUndoRedoStack[nextV]) {
1341
- flashTableBorder();
1342
- const nextState = applyPatches(
1343
- entities,
1344
- entitiesUndoRedoStack[nextV].patches
1345
- );
1346
- const { newEnts, validationErrors } =
1347
- formatAndValidateEntities(nextState);
1348
- change("reduxFormEntities", newEnts);
1349
- updateValidation(newEnts, validationErrors);
1350
- setEntitiesUndoRedoStack(prev => ({
1351
- ...prev,
1352
- currentVersion: nextV
1353
- }));
1354
- }
1355
- }, [
1356
- change,
1357
- entities,
1358
1026
  formatAndValidateEntities,
1359
- entitiesUndoRedoStack,
1360
- updateValidation
1361
- ]);
1362
-
1363
- const handleSelectAllRows = useCallback(
1364
- e => {
1365
- if (isSingleSelect) return;
1366
- e.preventDefault();
1367
-
1368
- if (isCellEditable) {
1369
- const schemaPaths = schema.fields.map(f => f.path);
1370
- const newSelectedCells = {};
1371
- entities.forEach((entity, i) => {
1372
- if (isEntityDisabled(entity)) return;
1373
- const entityId = getIdOrCodeOrIndex(entity, i);
1374
- schemaPaths.forEach(p => {
1375
- newSelectedCells[`${entityId}:${p}`] = true;
1376
- });
1377
- });
1378
- setSelectedCells(newSelectedCells);
1379
- } else {
1380
- const newIdMap = {};
1381
-
1382
- entities.forEach((entity, i) => {
1383
- if (isEntityDisabled(entity)) return;
1384
- const entityId = getIdOrCodeOrIndex(entity, i);
1385
- newIdMap[entityId] = { entity };
1386
- });
1387
- finalizeSelection({
1388
- idMap: newIdMap,
1389
- entities,
1390
- props: {
1391
- onDeselect,
1392
- onSingleRowSelect,
1393
- onMultiRowSelect,
1394
- noDeselectAll,
1395
- onRowSelect,
1396
- noSelect,
1397
- change
1398
- }
1399
- });
1400
- }
1401
- },
1402
- [
1403
- change,
1404
- entities,
1405
- isCellEditable,
1406
- isEntityDisabled,
1407
- isSingleSelect,
1408
- noDeselectAll,
1409
- noSelect,
1410
- onDeselect,
1411
- onMultiRowSelect,
1412
- onRowSelect,
1413
- onSingleRowSelect,
1414
- schema.fields
1415
- ]
1416
- );
1417
-
1418
- const hotKeys = useMemo(
1419
- () => [
1420
- {
1421
- global: false,
1422
- combo: "up",
1423
- label: "Move Up a Row",
1424
- onKeyDown: handleRowMove("up")
1425
- },
1426
- {
1427
- global: false,
1428
- combo: "down",
1429
- label: "Move Down a Row",
1430
- onKeyDown: handleRowMove("down")
1431
- },
1432
- {
1433
- global: false,
1434
- combo: "up+shift",
1435
- label: "Move Up a Row",
1436
- onKeyDown: handleRowMove("up", true)
1437
- },
1438
- ...(isCellEditable
1439
- ? [
1440
- {
1441
- global: false,
1442
- combo: "enter",
1443
- label: "Enter -> Start Cell Edit",
1444
- onKeyDown: handleEnterStartCellEdit
1445
- },
1446
- {
1447
- global: false,
1448
- combo: "mod+x",
1449
- label: "Cut",
1450
- onKeyDown: handleCut
1451
- },
1452
- {
1453
- global: false,
1454
- combo: IS_LINUX ? "alt+z" : "mod+z",
1455
- label: "Undo",
1456
- onKeyDown: handleUndo
1457
- },
1458
- {
1459
- global: false,
1460
- combo: IS_LINUX ? "alt+shift+z" : "mod+shift+z",
1461
- label: "Redo",
1462
- onKeyDown: handleRedo
1463
- },
1464
- {
1465
- global: false,
1466
- combo: "backspace",
1467
- label: "Delete Cell",
1468
- onKeyDown: handleDeleteCell
1469
- }
1470
- ]
1471
- : []),
1472
- {
1473
- global: false,
1474
- combo: "down+shift",
1475
- label: "Move Down a Row",
1476
- onKeyDown: handleRowMove("down", true)
1477
- },
1478
- {
1479
- global: false,
1480
- combo: "mod + c",
1481
- label: "Copy rows",
1482
- onKeyDown: handleCopyHotkey
1483
- },
1484
- {
1485
- global: false,
1486
- combo: "mod + a",
1487
- label: "Select rows",
1488
- onKeyDown: handleSelectAllRows
1489
- }
1490
- ],
1491
- [
1492
- handleCopyHotkey,
1493
- handleCut,
1494
- handleDeleteCell,
1495
- handleEnterStartCellEdit,
1496
- handleRedo,
1497
- handleRowMove,
1498
- handleSelectAllRows,
1499
- handleUndo,
1500
- isCellEditable
1501
- ]
1502
- );
1027
+ handleCopySelectedRows,
1028
+ isCellEditable,
1029
+ isEntityDisabled,
1030
+ isSingleSelect,
1031
+ noDeselectAll,
1032
+ noSelect,
1033
+ onDeselect,
1034
+ onMultiRowSelect,
1035
+ onRowSelect,
1036
+ onSingleRowSelect,
1037
+ primarySelectedCellId,
1038
+ reduxFormCellValidation,
1039
+ reduxFormSelectedEntityIdMap,
1040
+ schema,
1041
+ selectedCells,
1042
+ setEntitiesUndoRedoStack,
1043
+ setNoVirtual,
1044
+ setSelectedCells,
1045
+ startCellEdit,
1046
+ tableRef,
1047
+ updateEntitiesHelper,
1048
+ updateValidation,
1049
+ waitUntilAllRowsAreRendered
1050
+ });
1503
1051
 
1504
- const { handleKeyDown, handleKeyUp } = useHotkeys(hotKeys);
1505
1052
  const [columns, setColumns] = useState([]);
1506
1053
  const [fullscreen, setFullscreen] = useState(false);
1507
1054
  const [selectingAll, setSelectingAll] = useState(false);
@@ -1805,42 +1352,6 @@ const DataTable = ({
1805
1352
  }
1806
1353
  }, [entities, selectedIds, selectAllByDefault, setSelectedIds]);
1807
1354
 
1808
- const TheadComponent = useCallback(
1809
- ({ className, style, children }) => {
1810
- const moveColumn = ({ oldIndex, newIndex }) => {
1811
- let oldStateColumnIndex, newStateColumnIndex;
1812
- columns.forEach((column, i) => {
1813
- if (oldIndex === column.columnIndex) oldStateColumnIndex = i;
1814
- if (newIndex === column.columnIndex) newStateColumnIndex = i;
1815
- });
1816
- // because it is all handled in state we need
1817
- // to perform the move and update the columnIndices
1818
- // because they are used for the sortable columns
1819
- const newColumns = arrayMove(
1820
- columns,
1821
- oldStateColumnIndex,
1822
- newStateColumnIndex
1823
- ).map((column, i) => {
1824
- return {
1825
- ...column,
1826
- columnIndex: i
1827
- };
1828
- });
1829
- setColumns(newColumns);
1830
- };
1831
- return (
1832
- <SortableColumns
1833
- className={className}
1834
- style={style}
1835
- moveColumn={moveColumnPersist || moveColumn}
1836
- >
1837
- {children}
1838
- </SortableColumns>
1839
- );
1840
- },
1841
- [columns, moveColumnPersist]
1842
- );
1843
-
1844
1355
  const addEntitiesToSelection = entities => {
1845
1356
  const idMap = reduxFormSelectedEntityIdMap || {};
1846
1357
  const newIdMap = cloneDeep(idMap) || {};
@@ -2077,426 +1588,6 @@ const DataTable = ({
2077
1588
  ]
2078
1589
  );
2079
1590
 
2080
- const showContextMenu = useCallback(
2081
- (e, { idMap, selectedCells } = {}) => {
2082
- let selectedRecords;
2083
- if (isCellEditable) {
2084
- const rowIds = {};
2085
- Object.keys(selectedCells).forEach(cellKey => {
2086
- const [rowId] = cellKey.split(":");
2087
- rowIds[rowId] = true;
2088
- });
2089
- selectedRecords = entities.filter(
2090
- ent => rowIds[getIdOrCodeOrIndex(ent)]
2091
- );
2092
- } else {
2093
- selectedRecords = getRecordsFromIdMap(idMap);
2094
- }
2095
-
2096
- const itemsToRender = contextMenu({
2097
- selectedRecords,
2098
- history
2099
- });
2100
- if (!itemsToRender && !isCopyable) return null;
2101
- const copyMenuItems = [];
2102
-
2103
- e.persist();
2104
- if (isCopyable) {
2105
- //compute the cellWrapper here so we don't lose access to it
2106
- const cellWrapper =
2107
- e.target.querySelector(".tg-cell-wrapper") ||
2108
- e.target.closest(".tg-cell-wrapper");
2109
- if (cellWrapper) {
2110
- copyMenuItems.push(
2111
- <MenuItem
2112
- key="copyCell"
2113
- onClick={() => {
2114
- //TODOCOPY: we need to make sure that the cell copy is being used by the row copy.. right now we have 2 different things going on
2115
- //do we need to be able to copy hidden cells? It seems like it should just copy what's on the page..?
2116
- const specificColumn = cellWrapper.getAttribute("data-test");
2117
- handleCopyRows([cellWrapper.closest(".rt-tr")], {
2118
- specificColumn,
2119
- onFinishMsg: "Cell copied"
2120
- });
2121
- const [text, jsonText] = getCellCopyText(cellWrapper);
2122
- handleCopyHelper(text, jsonText);
2123
- }}
2124
- text="Cell"
2125
- />
2126
- );
2127
-
2128
- copyMenuItems.push(
2129
- <MenuItem
2130
- key="copyColumn"
2131
- onClick={() => {
2132
- handleCopyColumn(tableRef, cellWrapper);
2133
- }}
2134
- text="Column"
2135
- />
2136
- );
2137
- if (selectedRecords.length > 1) {
2138
- copyMenuItems.push(
2139
- <MenuItem
2140
- key="copyColumnSelected"
2141
- onClick={() => {
2142
- handleCopyColumn(tableRef, cellWrapper, selectedRecords);
2143
- }}
2144
- text="Column (Selected)"
2145
- />
2146
- );
2147
- }
2148
- }
2149
- if (selectedRecords.length === 0 || selectedRecords.length === 1) {
2150
- //compute the row here so we don't lose access to it
2151
- const cell =
2152
- e.target.querySelector(".tg-cell-wrapper") ||
2153
- e.target.closest(".tg-cell-wrapper") ||
2154
- e.target.closest(".rt-td");
2155
- const row = cell.closest(".rt-tr");
2156
- copyMenuItems.push(
2157
- <MenuItem
2158
- key="copySelectedRows"
2159
- onClick={() => {
2160
- handleCopyRows([row]);
2161
- // loop through each cell in the row
2162
- }}
2163
- text="Row"
2164
- />
2165
- );
2166
- } else if (selectedRecords.length > 1) {
2167
- copyMenuItems.push(
2168
- <MenuItem
2169
- key="copySelectedRows"
2170
- onClick={() => {
2171
- handleCopySelectedRows(selectedRecords, e);
2172
- // loop through each cell in the row
2173
- }}
2174
- text="Rows"
2175
- />
2176
- );
2177
- }
2178
- copyMenuItems.push(
2179
- <MenuItem
2180
- key="copyFullTableRows"
2181
- onClick={() => {
2182
- handleCopyTable(tableRef);
2183
- // loop through each cell in the row
2184
- }}
2185
- text="Table"
2186
- />
2187
- );
2188
- }
2189
- const selectedRowIds = Object.keys(selectedCells).map(cellId => {
2190
- const [rowId] = cellId.split(":");
2191
- return rowId;
2192
- });
2193
-
2194
- const menu = (
2195
- <Menu>
2196
- {itemsToRender}
2197
- {copyMenuItems.length && (
2198
- <MenuItem icon="clipboard" key="copyOpts" text="Copy">
2199
- {copyMenuItems}
2200
- </MenuItem>
2201
- )}
2202
- {isCellEditable && (
2203
- <>
2204
- <MenuItem
2205
- icon="add-row-top"
2206
- text="Add Row Above"
2207
- key="addRowAbove"
2208
- onClick={() => {
2209
- insertRows({ above: true });
2210
- }}
2211
- />
2212
- <MenuItem
2213
- icon="add-row-top"
2214
- text="Add Row Below"
2215
- key="addRowBelow"
2216
- onClick={() => {
2217
- insertRows({});
2218
- }}
2219
- />
2220
- <MenuItem
2221
- icon="remove"
2222
- text={`Remove Row${selectedRowIds.length > 1 ? "s" : ""}`}
2223
- key="removeRow"
2224
- onClick={() => {
2225
- const selectedRowIds = Object.keys(selectedCells).map(
2226
- cellId => {
2227
- const [rowId] = cellId.split(":");
2228
- return rowId;
2229
- }
2230
- );
2231
- updateEntitiesHelper(entities, entities => {
2232
- const ents = entities.filter(
2233
- (e, i) =>
2234
- !selectedRowIds.includes(getIdOrCodeOrIndex(e, i))
2235
- );
2236
- updateValidation(
2237
- ents,
2238
- omitBy(reduxFormCellValidation, (v, cellId) =>
2239
- selectedRowIds.includes(cellId.split(":")[0])
2240
- )
2241
- );
2242
- return ents;
2243
- });
2244
- refocusTable();
2245
- }}
2246
- />
2247
- </>
2248
- )}
2249
- </Menu>
2250
- );
2251
- ContextMenu.show(menu, { left: e.clientX, top: e.clientY });
2252
- },
2253
- [
2254
- contextMenu,
2255
- entities,
2256
- handleCopySelectedRows,
2257
- history,
2258
- insertRows,
2259
- isCellEditable,
2260
- isCopyable,
2261
- reduxFormCellValidation,
2262
- refocusTable,
2263
- updateEntitiesHelper,
2264
- updateValidation
2265
- ]
2266
- );
2267
-
2268
- const getTableRowProps = useCallback(
2269
- (state, rowInfo) => {
2270
- if (!rowInfo) {
2271
- return {
2272
- className: "no-row-data"
2273
- };
2274
- }
2275
- const entity = rowInfo.original;
2276
- const rowId = getIdOrCodeOrIndex(entity, rowInfo.index);
2277
- const rowSelected = reduxFormSelectedEntityIdMap[rowId];
2278
- const isExpanded = expandedEntityIdMap[rowId];
2279
- const rowDisabled = isEntityDisabled(entity);
2280
- const dataId = entity.id || entity.code;
2281
- return {
2282
- onClick: e => {
2283
- if (isCellEditable) return;
2284
- // if checkboxes are activated or row expander is clicked don't select row
2285
- if (e.target.matches(".tg-expander, .tg-expander *")) {
2286
- setExpandedEntityIdMap(prev => ({ ...prev, [rowId]: !isExpanded }));
2287
- return;
2288
- } else if (
2289
- e.target.closest(".tg-react-table-checkbox-cell-container")
2290
- ) {
2291
- return;
2292
- } else if (mustClickCheckboxToSelect) {
2293
- return;
2294
- }
2295
- if (e.detail > 1) {
2296
- return; //cancel multiple quick clicks
2297
- }
2298
- rowClick(e, rowInfo, entities, {
2299
- reduxFormSelectedEntityIdMap,
2300
- isSingleSelect,
2301
- noSelect,
2302
- onRowClick,
2303
- isEntityDisabled,
2304
- withCheckboxes,
2305
- onDeselect,
2306
- onSingleRowSelect,
2307
- onMultiRowSelect,
2308
- noDeselectAll,
2309
- onRowSelect,
2310
- change
2311
- });
2312
- },
2313
- //row right click
2314
- onContextMenu: e => {
2315
- e.preventDefault();
2316
- if (rowId === undefined || rowDisabled || isCellEditable) return;
2317
- const oldIdMap = cloneDeep(reduxFormSelectedEntityIdMap) || {};
2318
- let newIdMap;
2319
- if (withCheckboxes) {
2320
- newIdMap = oldIdMap;
2321
- } else {
2322
- // if we are not using checkboxes we need to make sure
2323
- // that the id of the record gets added to the id map
2324
- newIdMap = oldIdMap[rowId] ? oldIdMap : { [rowId]: { entity } };
2325
-
2326
- // tgreen: this will refresh the selection with fresh data. The entities in redux might not be up to date
2327
- const keyedEntities = keyBy(entities, getIdOrCodeOrIndex);
2328
- forEach(newIdMap, (val, key) => {
2329
- const freshEntity = keyedEntities[key];
2330
- if (freshEntity) {
2331
- newIdMap[key] = { ...newIdMap[key], entity: freshEntity };
2332
- }
2333
- });
2334
- finalizeSelection({
2335
- idMap: newIdMap,
2336
- entities,
2337
- props: {
2338
- onDeselect,
2339
- onSingleRowSelect,
2340
- onMultiRowSelect,
2341
- noDeselectAll,
2342
- onRowSelect,
2343
- noSelect,
2344
- change
2345
- }
2346
- });
2347
- }
2348
- showContextMenu(e, { idMap: newIdMap, selectedCells });
2349
- },
2350
- className: classNames(
2351
- "with-row-data",
2352
- getRowClassName && getRowClassName(rowInfo, state),
2353
- {
2354
- disabled: rowDisabled,
2355
- selected: rowSelected && !withCheckboxes,
2356
- "rt-tr-last-row": rowInfo.index === entities.length - 1
2357
- }
2358
- ),
2359
- "data-test-id": dataId === undefined ? rowInfo.index : dataId,
2360
- "data-index": rowInfo.index,
2361
- "data-tip": typeof rowDisabled === "string" ? rowDisabled : undefined,
2362
- onDoubleClick: e => {
2363
- if (rowDisabled) return;
2364
- onDoubleClick &&
2365
- onDoubleClick(rowInfo.original, rowInfo.index, history, e);
2366
- }
2367
- };
2368
- },
2369
- [
2370
- change,
2371
- entities,
2372
- expandedEntityIdMap,
2373
- getRowClassName,
2374
- history,
2375
- isCellEditable,
2376
- isEntityDisabled,
2377
- isSingleSelect,
2378
- mustClickCheckboxToSelect,
2379
- noDeselectAll,
2380
- noSelect,
2381
- onDeselect,
2382
- onDoubleClick,
2383
- onMultiRowSelect,
2384
- onRowClick,
2385
- onRowSelect,
2386
- onSingleRowSelect,
2387
- reduxFormSelectedEntityIdMap,
2388
- selectedCells,
2389
- showContextMenu,
2390
- withCheckboxes
2391
- ]
2392
- );
2393
-
2394
- const getTableCellProps = useCallback(
2395
- (state, rowInfo, column) => {
2396
- if (!isCellEditable) return {}; //only allow cell selection to do stuff here
2397
- if (!rowInfo) return {};
2398
- if (!reduxFormCellValidation) return {};
2399
- const entity = rowInfo.original;
2400
- const rowIndex = rowInfo.index;
2401
- const rowId = getIdOrCodeOrIndex(entity, rowIndex);
2402
- const {
2403
- cellId,
2404
- cellIdAbove,
2405
- cellIdToRight,
2406
- cellIdBelow,
2407
- cellIdToLeft,
2408
- rowDisabled,
2409
- columnIndex
2410
- } = getCellInfo({
2411
- columnIndex: column.index,
2412
- columnPath: column.path,
2413
- rowId,
2414
- schema,
2415
- entities,
2416
- rowIndex,
2417
- isEntityDisabled,
2418
- entity
2419
- });
2420
-
2421
- const _isClean =
2422
- (entity._isClean && doNotValidateUntouchedRows) ||
2423
- isEntityClean(entity);
2424
-
2425
- const err = !_isClean && reduxFormCellValidation[cellId];
2426
- let selectedTopBorder,
2427
- selectedRightBorder,
2428
- selectedBottomBorder,
2429
- selectedLeftBorder;
2430
- if (selectedCells[cellId]) {
2431
- selectedTopBorder = !selectedCells[cellIdAbove];
2432
- selectedRightBorder = !selectedCells[cellIdToRight];
2433
- selectedBottomBorder = !selectedCells[cellIdBelow];
2434
- selectedLeftBorder = !selectedCells[cellIdToLeft];
2435
- }
2436
- const isPrimarySelected = selectedCells[cellId] === PRIMARY_SELECTED_VAL;
2437
- const className = classNames({
2438
- isSelectedCell: selectedCells[cellId],
2439
- isPrimarySelected,
2440
- isSecondarySelected: selectedCells[cellId] === true,
2441
- noSelectedTopBorder: !selectedTopBorder,
2442
- isCleanRow: _isClean,
2443
- noSelectedRightBorder: !selectedRightBorder,
2444
- noSelectedBottomBorder: !selectedBottomBorder,
2445
- noSelectedLeftBorder: !selectedLeftBorder,
2446
- isDropdownCell: column.type === "dropdown",
2447
- isEditingCell: reduxFormEditingCell === cellId,
2448
- hasCellError: !!err,
2449
- "no-data-tip": selectedCells[cellId]
2450
- });
2451
- return {
2452
- onDoubleClick: () => {
2453
- // cell double click
2454
- if (rowDisabled) return;
2455
- startCellEdit(cellId);
2456
- },
2457
- ...(err && {
2458
- "data-tip": err?.message || err,
2459
- "data-no-child-data-tip": true
2460
- }),
2461
- onContextMenu: e => {
2462
- const newSelectedCells = { ...selectedCells };
2463
- if (!isPrimarySelected) {
2464
- if (primarySelectedCellId) {
2465
- newSelectedCells[primarySelectedCellId] = true;
2466
- }
2467
- newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
2468
- setSelectedCells(newSelectedCells);
2469
- }
2470
- showContextMenu(e, { selectedCells: newSelectedCells });
2471
- },
2472
- onClick: event => {
2473
- handleCellClick({
2474
- event,
2475
- cellId,
2476
- rowDisabled,
2477
- rowIndex,
2478
- columnIndex
2479
- });
2480
- },
2481
- className
2482
- };
2483
- },
2484
- [
2485
- doNotValidateUntouchedRows,
2486
- entities,
2487
- handleCellClick,
2488
- isCellEditable,
2489
- isEntityDisabled,
2490
- primarySelectedCellId,
2491
- reduxFormCellValidation,
2492
- reduxFormEditingCell,
2493
- schema,
2494
- selectedCells,
2495
- showContextMenu,
2496
- startCellEdit
2497
- ]
2498
- );
2499
-
2500
1591
  if (withSelectAll && !safeQuery) {
2501
1592
  throw new Error("safeQuery is needed for selecting all table records");
2502
1593
  }
@@ -2512,7 +1603,7 @@ const DataTable = ({
2512
1603
  : "";
2513
1604
 
2514
1605
  const hasFilters =
2515
- filters.length ||
1606
+ filters?.length ||
2516
1607
  searchTerm ||
2517
1608
  schema.fields.some(
2518
1609
  field => field.filterIsActive && field.filterIsActive(currentParams)
@@ -2525,7 +1616,7 @@ const DataTable = ({
2525
1616
 
2526
1617
  const filtersOnNonDisplayedFields = useMemo(() => {
2527
1618
  const _filtersOnNonDisplayedFields = [];
2528
- if (filters && filters.length) {
1619
+ if (filters?.length) {
2529
1620
  schema.fields.forEach(field => {
2530
1621
  const ccDisplayName = getCCDisplayName(field);
2531
1622
  if (field.isHidden) {
@@ -2550,18 +1641,6 @@ const DataTable = ({
2550
1641
  );
2551
1642
  const selectedRowCount = Object.keys(idMap).filter(key => idMap[key]).length;
2552
1643
 
2553
- let rowsToShow = doNotShowEmptyRows
2554
- ? Math.min(numRows, entities.length)
2555
- : numRows;
2556
- // if there are no entities then provide enough space to show
2557
- // no rows found message
2558
- if (entities.length === 0 && rowsToShow < 3) rowsToShow = 3;
2559
- const expandedRows = entities.reduce((acc, row, index) => {
2560
- const rowId = getIdOrCodeOrIndex(row, index);
2561
- acc[index] = expandedEntityIdMap[rowId];
2562
- return acc;
2563
- }, {});
2564
-
2565
1644
  const showHeader = (withTitle || withSearch || children) && !noHeader;
2566
1645
  const toggleFullscreenButton = (
2567
1646
  <Button
@@ -2648,21 +1727,6 @@ const DataTable = ({
2648
1727
  withPaging &&
2649
1728
  (hidePageSizeWhenPossible ? entityCount > pageSize : true);
2650
1729
 
2651
- const SubComponentToUse = useMemo(() => {
2652
- if (SubComponent) {
2653
- return row => {
2654
- let shouldShow = true;
2655
- if (shouldShowSubComponent) {
2656
- shouldShow = shouldShowSubComponent(row.original);
2657
- }
2658
- if (shouldShow) {
2659
- return SubComponent(row);
2660
- }
2661
- };
2662
- }
2663
- return;
2664
- }, [SubComponent, shouldShowSubComponent]);
2665
-
2666
1730
  const nonDisplayedFilterComp = useMemo(() => {
2667
1731
  if (filtersOnNonDisplayedFields.length) {
2668
1732
  const content = filtersOnNonDisplayedFields.map(
@@ -2707,173 +1771,12 @@ const DataTable = ({
2707
1771
  return null;
2708
1772
  }, [filtersOnNonDisplayedFields]);
2709
1773
 
2710
- const filteredEnts = useMemo(() => {
2711
- if (onlyShowRowsWErrors) {
2712
- const rowToErrorMap = {};
2713
- forEach(reduxFormCellValidation, (err, cellId) => {
2714
- if (err) {
2715
- const [rowId] = cellId.split(":");
2716
- rowToErrorMap[rowId] = true;
2717
- }
2718
- });
2719
- return entities.filter(e => {
2720
- return rowToErrorMap[e.id];
2721
- });
2722
- }
2723
- return entities;
2724
- }, [entities, onlyShowRowsWErrors, reduxFormCellValidation]);
2725
-
2726
- const renderColumns = useColumns({
2727
- addFilters,
2728
- cellRenderer,
2729
- columns,
2730
- currentParams,
2731
- compact,
2732
- editingCellSelectAll,
2733
- entities,
2734
- expandedEntityIdMap,
2735
- extraCompact,
2736
- filters,
2737
- formName,
2738
- getCellHoverText,
2739
- isCellEditable,
2740
- isEntityDisabled,
2741
- isLocalCall,
2742
- isSimple,
2743
- isSingleSelect,
2744
- isSelectionARectangle,
2745
- noDeselectAll,
2746
- noSelect,
2747
- noUserSelect,
2748
- onDeselect,
2749
- onMultiRowSelect,
2750
- onRowClick,
2751
- onRowSelect,
2752
- onSingleRowSelect,
2753
- order,
2754
- primarySelectedCellId,
2755
- reduxFormCellValidation,
2756
- reduxFormSelectedEntityIdMap,
2757
- refocusTable,
2758
- removeSingleFilter,
2759
- schema,
2760
- selectedCells,
2761
- setExpandedEntityIdMap,
2762
- setNewParams,
2763
- setOrder,
2764
- setSelectedCells,
2765
- shouldShowSubComponent,
2766
- startCellEdit,
2767
- SubComponent,
2768
- tableRef,
2769
- updateEntitiesHelper,
2770
- updateValidation,
2771
- withCheckboxes,
2772
- withExpandAndCollapseAllButton,
2773
- withFilter,
2774
- withSort,
2775
- recordIdToIsVisibleMap,
2776
- setRecordIdToIsVisibleMap
2777
- });
2778
-
2779
1774
  const scrollToTop = useCallback(
2780
1775
  () =>
2781
1776
  tableRef.current?.tableRef?.children?.[0]?.children?.[0]?.scrollIntoView(),
2782
1777
  []
2783
1778
  );
2784
1779
 
2785
- const reactTable = useMemo(
2786
- () => (
2787
- <ReactTable
2788
- data={filteredEnts}
2789
- ref={tableRef}
2790
- noVirtual={noVirtual}
2791
- className={classNames({
2792
- isCellEditable,
2793
- "tg-table-loading": isLoading,
2794
- "tg-table-disabled": disabled
2795
- })}
2796
- itemSizeEstimator={
2797
- extraCompact
2798
- ? itemSizeEstimators.compact
2799
- : compact
2800
- ? itemSizeEstimators.normal
2801
- : itemSizeEstimators.comfortable
2802
- }
2803
- TfootComponent={() => {
2804
- return <button>hasdfasdf</button>;
2805
- }}
2806
- // We should try to not give all the props to the render column
2807
- columns={renderColumns}
2808
- pageSize={rowsToShow}
2809
- expanded={expandedRows}
2810
- showPagination={false}
2811
- sortable={false}
2812
- loading={isLoading || disabled}
2813
- defaultResized={resized}
2814
- onResizedChange={(newResized = []) => {
2815
- const resizedToUse = newResized.map(column => {
2816
- // have a min width of 50 so that columns don't disappear
2817
- if (column.value < 50) {
2818
- return {
2819
- ...column,
2820
- value: 50
2821
- };
2822
- } else {
2823
- return column;
2824
- }
2825
- });
2826
- resizePersist(resizedToUse);
2827
- }}
2828
- TheadComponent={TheadComponent}
2829
- ThComponent={ThComponent}
2830
- getTrGroupProps={getTableRowProps}
2831
- getTdProps={getTableCellProps}
2832
- NoDataComponent={({ children }) =>
2833
- isLoading ? null : (
2834
- <div className="rt-noData">{noRowsFoundMessage || children}</div>
2835
- )
2836
- }
2837
- LoadingComponent={({ loadingText, loading }) => (
2838
- <DisabledLoadingComponent
2839
- loading={loading}
2840
- loadingText={loadingText}
2841
- disabled={disabled}
2842
- />
2843
- )}
2844
- style={{
2845
- maxHeight,
2846
- minHeight: 150,
2847
- ...style
2848
- }}
2849
- SubComponent={SubComponentToUse}
2850
- {...ReactTableProps}
2851
- />
2852
- ),
2853
- [
2854
- ReactTableProps,
2855
- SubComponentToUse,
2856
- TheadComponent,
2857
- compact,
2858
- disabled,
2859
- expandedRows,
2860
- extraCompact,
2861
- filteredEnts,
2862
- getTableCellProps,
2863
- getTableRowProps,
2864
- isCellEditable,
2865
- isLoading,
2866
- maxHeight,
2867
- noRowsFoundMessage,
2868
- renderColumns,
2869
- resizePersist,
2870
- resized,
2871
- rowsToShow,
2872
- style,
2873
- noVirtual
2874
- ]
2875
- );
2876
-
2877
1780
  return (
2878
1781
  <div
2879
1782
  tabIndex="1"
@@ -3169,7 +2072,84 @@ const DataTable = ({
3169
2072
  />
3170
2073
  </div>
3171
2074
  )}
3172
- {reactTable}
2075
+ <ReactTable
2076
+ addFilters={addFilters}
2077
+ cellRenderer={cellRenderer}
2078
+ change={change}
2079
+ columns={columns}
2080
+ compact={compact}
2081
+ contextMenu={contextMenu}
2082
+ currentParams={currentParams}
2083
+ disabled={disabled}
2084
+ doNotShowEmptyRows={doNotShowEmptyRows}
2085
+ doNotValidateUntouchedRows={doNotValidateUntouchedRows}
2086
+ editingCellSelectAll={editingCellSelectAll}
2087
+ entities={entities}
2088
+ expandedEntityIdMap={expandedEntityIdMap}
2089
+ extraCompact={extraCompact}
2090
+ filters={filters}
2091
+ formName={formName}
2092
+ getCellHoverText={getCellHoverText}
2093
+ getRowClassName={getRowClassName}
2094
+ handleCellClick={handleCellClick}
2095
+ handleCopySelectedRows={handleCopySelectedRows}
2096
+ history={history}
2097
+ insertRows={insertRows}
2098
+ isCellEditable={isCellEditable}
2099
+ isCopyable={isCopyable}
2100
+ isEntityDisabled={isEntityDisabled}
2101
+ isLoading={isLoading}
2102
+ isLocalCall={isLocalCall}
2103
+ isSelectionARectangle={isSelectionARectangle}
2104
+ isSimple={isSimple}
2105
+ isSingleSelect={isSingleSelect}
2106
+ maxHeight={maxHeight}
2107
+ moveColumnPersist={moveColumnPersist}
2108
+ mustClickCheckboxToSelect={mustClickCheckboxToSelect}
2109
+ noDeselectAll={noDeselectAll}
2110
+ noRowsFoundMessage={noRowsFoundMessage}
2111
+ noSelect={noSelect}
2112
+ noUserSelect={noUserSelect}
2113
+ noVirtual={noVirtual}
2114
+ numRows={numRows}
2115
+ onDeselect={onDeselect}
2116
+ onDoubleClick={onDoubleClick}
2117
+ onlyShowRowsWErrors={onlyShowRowsWErrors}
2118
+ onMultiRowSelect={onMultiRowSelect}
2119
+ onRowClick={onRowClick}
2120
+ onRowSelect={onRowSelect}
2121
+ onSingleRowSelect={onSingleRowSelect}
2122
+ order={order}
2123
+ primarySelectedCellId={primarySelectedCellId}
2124
+ ReactTableProps={ReactTableProps}
2125
+ recordIdToIsVisibleMap={recordIdToIsVisibleMap}
2126
+ reduxFormCellValidation={reduxFormCellValidation}
2127
+ reduxFormEditingCell={reduxFormEditingCell}
2128
+ reduxFormSelectedEntityIdMap={reduxFormSelectedEntityIdMap}
2129
+ refocusTable={refocusTable}
2130
+ removeSingleFilter={removeSingleFilter}
2131
+ resizePersist={resizePersist}
2132
+ schema={schema}
2133
+ selectedCells={selectedCells}
2134
+ setColumns={setColumns}
2135
+ setExpandedEntityIdMap={setExpandedEntityIdMap}
2136
+ setNewParams={setNewParams}
2137
+ setOrder={setOrder}
2138
+ setRecordIdToIsVisibleMap={setRecordIdToIsVisibleMap}
2139
+ setSelectedCells={setSelectedCells}
2140
+ shouldShowSubComponent={shouldShowSubComponent}
2141
+ startCellEdit={startCellEdit}
2142
+ style={style}
2143
+ SubComponent={SubComponent}
2144
+ tableConfig={tableConfig}
2145
+ tableRef={tableRef}
2146
+ updateEntitiesHelper={updateEntitiesHelper}
2147
+ updateValidation={updateValidation}
2148
+ withCheckboxes={withCheckboxes}
2149
+ withExpandAndCollapseAllButton={withExpandAndCollapseAllButton}
2150
+ withFilter={withFilter}
2151
+ withSort={withSort}
2152
+ />
3173
2153
  {isCellEditable && (
3174
2154
  <div style={{ display: "flex" }}>
3175
2155
  <div
@@ -3267,7 +2247,41 @@ const DataTable = ({
3267
2247
  );
3268
2248
  };
3269
2249
 
3270
- const WrappedDT = dataTableEnhancer(DataTable);
3271
- export default WrappedDT;
3272
- const ConnectedPagingTool = dataTableEnhancer(PagingTool);
2250
+ const WithRouterDatatable = withRouter(DataTable);
2251
+
2252
+ const RouterDTWrapper = props => {
2253
+ if (props.noRouter) {
2254
+ return <DataTable {...props} />;
2255
+ }
2256
+ return <WithRouterDatatable {...props} />;
2257
+ };
2258
+
2259
+ const WithReduxFormDataTable = reduxForm({})(RouterDTWrapper);
2260
+
2261
+ const ReduxFormDTWrapper = props => {
2262
+ if (props.noForm) {
2263
+ return <RouterDTWrapper {...props} form={props.formName} />;
2264
+ }
2265
+ return <WithReduxFormDataTable {...props} form={props.formName} />;
2266
+ };
2267
+
2268
+ const WithRouterPagingTool = withRouter(PagingTool);
2269
+
2270
+ const RouterPTWrapper = props => {
2271
+ if (props.noRouter) {
2272
+ return <DataTable {...props} />;
2273
+ }
2274
+ return <WithRouterPagingTool {...props} />;
2275
+ };
2276
+
2277
+ const WithReduxFormPagingTool = reduxForm({})(RouterPTWrapper);
2278
+
2279
+ const ConnectedPagingTool = props => {
2280
+ if (props.noForm) {
2281
+ return <RouterPTWrapper {...props} form={props.formName} />;
2282
+ }
2283
+ return <WithReduxFormPagingTool {...props} form={props.formName} />;
2284
+ };
2285
+
2286
+ export default ReduxFormDTWrapper;
3273
2287
  export { ConnectedPagingTool };