@teselagen/ui 0.9.7 → 0.10.2
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/DataTable/index.d.ts +3 -3
- package/index.cjs.js +21025 -21144
- package/index.es.js +21028 -21147
- package/package.json +2 -1
- package/src/DataTable/PagingTool.js +2 -2
- package/src/DataTable/RenderCell.js +8 -4
- package/src/DataTable/index.js +1210 -224
- package/src/DataTable/utils/useTableEntities.js +3 -2
- package/src/DataTable/utils/withTableParams.js +8 -7
- package/src/UploadCsvWizard.js +7 -5
- package/src/utils/hooks/useDeepEqualMemo.js +2 -2
- package/src/utils/isEqualIgnoreFunctions.js +23 -0
- package/src/utils/pureNoFunc.js +4 -20
- package/utils/isEqualIgnoreFunctions.d.ts +1 -0
- package/DataTable/EditabelCell.d.ts +0 -7
- package/DataTable/ReactTable.d.ts +0 -78
- package/DataTable/defaultProps.d.ts +0 -43
- package/DataTable/utils/computePresets.d.ts +0 -1
- package/DataTable/utils/types/Entity.d.ts +0 -9
- package/DataTable/utils/types/Field.d.ts +0 -4
- package/DataTable/utils/types/OrderBy.d.ts +0 -11
- package/DataTable/utils/types/Schema.d.ts +0 -4
- package/DataTable/utils/useDeepEqualMemo.d.ts +0 -1
- package/DataTable/utils/useHotKeysWrapper.d.ts +0 -29
- package/DataTable/utils/useTableParams.d.ts +0 -49
- package/src/DataTable/Columns.jsx +0 -945
- package/src/DataTable/EditabelCell.js +0 -44
- package/src/DataTable/EditabelCell.jsx +0 -44
- package/src/DataTable/ReactTable.js +0 -738
- package/src/DataTable/RenderCell.jsx +0 -191
- package/src/DataTable/defaultProps.js +0 -45
- package/src/DataTable/utils/computePresets.js +0 -42
- package/src/DataTable/utils/convertSchema.ts +0 -79
- package/src/DataTable/utils/formatPasteData.ts +0 -34
- package/src/DataTable/utils/getAllRows.ts +0 -11
- package/src/DataTable/utils/getCellCopyText.ts +0 -7
- package/src/DataTable/utils/getCellInfo.ts +0 -46
- package/src/DataTable/utils/getFieldPathToField.ts +0 -10
- package/src/DataTable/utils/getIdOrCodeOrIndex.ts +0 -14
- package/src/DataTable/utils/getLastSelectedEntity.ts +0 -15
- package/src/DataTable/utils/getNewEntToSelect.ts +0 -32
- package/src/DataTable/utils/initializeHasuraWhereAndFilter.ts +0 -35
- package/src/DataTable/utils/isBottomRightCornerOfRectangle.ts +0 -27
- package/src/DataTable/utils/isEntityClean.ts +0 -15
- package/src/DataTable/utils/primarySelectedValue.ts +0 -1
- package/src/DataTable/utils/removeCleanRows.ts +0 -26
- package/src/DataTable/utils/selection.ts +0 -11
- package/src/DataTable/utils/types/Entity.ts +0 -13
- package/src/DataTable/utils/types/Field.ts +0 -4
- package/src/DataTable/utils/types/OrderBy.ts +0 -15
- package/src/DataTable/utils/types/Schema.ts +0 -5
- package/src/DataTable/utils/useDeepEqualMemo.js +0 -10
- package/src/DataTable/utils/useHotKeysWrapper.js +0 -395
- package/src/DataTable/utils/useTableEntities.ts +0 -60
- package/src/DataTable/utils/useTableParams.js +0 -361
- package/src/DataTable/utils/utils.ts +0 -39
- package/src/Timeline/TimelineEvent.tsx +0 -36
- package/src/Timeline/index.tsx +0 -21
- package/src/utils/browserUtils.ts +0 -3
- package/src/utils/determineBlackOrWhiteTextColor.ts +0 -11
- package/src/utils/getTextFromEl.ts +0 -45
- package/src/utils/handlerHelpers.ts +0 -32
- package/src/utils/hooks/index.ts +0 -1
- package/src/utils/hooks/useDeepEqualMemo.ts +0 -10
- package/src/utils/hooks/useStableReference.ts +0 -9
- package/src/utils/hotkeyUtils.tsx +0 -155
- package/src/utils/isBeingCalledExcessively.ts +0 -37
- package/style.css +0 -10537
package/src/DataTable/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
noop,
|
|
18
18
|
cloneDeep,
|
|
19
19
|
keyBy,
|
|
20
|
+
omit,
|
|
20
21
|
forEach,
|
|
21
22
|
lowerCase,
|
|
22
23
|
get,
|
|
@@ -29,33 +30,57 @@ import {
|
|
|
29
30
|
some,
|
|
30
31
|
identity
|
|
31
32
|
} from "lodash-es";
|
|
32
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
Button,
|
|
35
|
+
Menu,
|
|
36
|
+
MenuItem,
|
|
37
|
+
ContextMenu,
|
|
38
|
+
Icon,
|
|
39
|
+
Intent,
|
|
40
|
+
Callout,
|
|
41
|
+
Tooltip,
|
|
42
|
+
useHotkeys
|
|
43
|
+
} from "@blueprintjs/core";
|
|
33
44
|
import { arrayMove } from "@dnd-kit/sortable";
|
|
34
45
|
import classNames from "classnames";
|
|
35
46
|
import scrollIntoView from "dom-scroll-into-view";
|
|
36
|
-
import { VIRTUALIZE_CUTOFF_LENGTH } from "@teselagen/react-table";
|
|
37
|
-
import immer, { produceWithPatches, enablePatches } from "immer";
|
|
47
|
+
import ReactTable, { VIRTUALIZE_CUTOFF_LENGTH } from "@teselagen/react-table";
|
|
48
|
+
import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
|
|
38
49
|
import papaparse from "papaparse";
|
|
39
50
|
import { useDispatch, useSelector } from "react-redux";
|
|
51
|
+
import { ThComponent } from "./ThComponent";
|
|
40
52
|
import {
|
|
41
53
|
defaultParsePaste,
|
|
42
54
|
formatPasteData,
|
|
43
55
|
getAllRows,
|
|
56
|
+
getCellCopyText,
|
|
44
57
|
getCellInfo,
|
|
45
58
|
getEntityIdToEntity,
|
|
46
59
|
getFieldPathToIndex,
|
|
47
60
|
getIdOrCodeOrIndex,
|
|
61
|
+
getLastSelectedEntity,
|
|
62
|
+
getNewEntToSelect,
|
|
48
63
|
getRecordsFromIdMap,
|
|
64
|
+
getRowCopyText,
|
|
65
|
+
handleCopyColumn,
|
|
66
|
+
handleCopyHelper,
|
|
49
67
|
handleCopyRows,
|
|
50
68
|
handleCopyTable,
|
|
69
|
+
isEntityClean,
|
|
51
70
|
PRIMARY_SELECTED_VAL,
|
|
52
71
|
removeCleanRows
|
|
53
72
|
} from "./utils";
|
|
54
73
|
import { useDeepEqualMemo } from "../utils/hooks";
|
|
55
|
-
import
|
|
74
|
+
import rowClick, {
|
|
75
|
+
changeSelectedEntities,
|
|
76
|
+
finalizeSelection
|
|
77
|
+
} from "./utils/rowClick";
|
|
56
78
|
import PagingTool from "./PagingTool";
|
|
57
79
|
import SearchBar from "./SearchBar";
|
|
58
80
|
import DisplayOptions from "./DisplayOptions";
|
|
81
|
+
import DisabledLoadingComponent from "./DisabledLoadingComponent";
|
|
82
|
+
import SortableColumns from "./SortableColumns";
|
|
83
|
+
import dataTableEnhancer from "./dataTableEnhancer";
|
|
59
84
|
import "../toastr";
|
|
60
85
|
import "@teselagen/react-table/react-table.css";
|
|
61
86
|
import "./style.css";
|
|
@@ -73,16 +98,21 @@ import {
|
|
|
73
98
|
getCurrentParamsFromUrl,
|
|
74
99
|
setCurrentParamsOnUrl
|
|
75
100
|
} from "./utils/queryParams";
|
|
76
|
-
import {
|
|
101
|
+
import { useColumns } from "./Columns";
|
|
102
|
+
import { formValueSelector, change as _change } from "redux-form";
|
|
77
103
|
import { throwFormError } from "../throwFormError";
|
|
78
104
|
import { isObservableArray, toJS } from "mobx";
|
|
79
105
|
import { isBeingCalledExcessively } from "../utils/isBeingCalledExcessively";
|
|
80
106
|
import { getCCDisplayName } from "./utils/tableQueryParamsToHasuraClauses";
|
|
81
|
-
import { useHotKeysWrapper } from "./utils/useHotKeysWrapper";
|
|
82
|
-
import { withRouter } from "react-router-dom";
|
|
83
|
-
import { ReactTable } from "./ReactTable";
|
|
84
107
|
|
|
85
108
|
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
|
+
};
|
|
86
116
|
|
|
87
117
|
const DataTable = ({
|
|
88
118
|
controlled_pageSize,
|
|
@@ -143,15 +173,15 @@ const DataTable = ({
|
|
|
143
173
|
reduxFormEntities,
|
|
144
174
|
reduxFormQueryParams: _reduxFormQueryParams = {},
|
|
145
175
|
reduxFormSelectedEntityIdMap: _reduxFormSelectedEntityIdMap = {}
|
|
146
|
-
} = useSelector(state
|
|
147
|
-
formValueSelector(formName)(
|
|
176
|
+
} = useSelector(function dtFormParamsSelector(state) {
|
|
177
|
+
return formValueSelector(formName)(
|
|
148
178
|
state,
|
|
149
179
|
"reduxFormCellValidation",
|
|
150
180
|
"reduxFormEntities",
|
|
151
181
|
"reduxFormQueryParams",
|
|
152
182
|
"reduxFormSelectedEntityIdMap"
|
|
153
|
-
)
|
|
154
|
-
);
|
|
183
|
+
);
|
|
184
|
+
});
|
|
155
185
|
|
|
156
186
|
// We want to make sure we don't rerender everything unnecessary
|
|
157
187
|
// with redux-forms we tend to do unnecessary renders
|
|
@@ -376,7 +406,7 @@ const DataTable = ({
|
|
|
376
406
|
expandAllByDefault,
|
|
377
407
|
extraClasses = "",
|
|
378
408
|
extraCompact: _extraCompact,
|
|
379
|
-
filters,
|
|
409
|
+
filters = [],
|
|
380
410
|
fragment,
|
|
381
411
|
getCellHoverText,
|
|
382
412
|
getRowClassName,
|
|
@@ -458,8 +488,8 @@ const DataTable = ({
|
|
|
458
488
|
() => (reduxFormEntities?.length ? reduxFormEntities : _origEntities) || [],
|
|
459
489
|
[_origEntities, reduxFormEntities]
|
|
460
490
|
);
|
|
461
|
-
|
|
462
491
|
const entities = useDeepEqualMemo(_entities);
|
|
492
|
+
|
|
463
493
|
const entitiesAcrossPages = useDeepEqualMemo(_entitiesAcrossPages);
|
|
464
494
|
|
|
465
495
|
// This is because we need to maintain the reduxFormSelectedEntityIdMap and
|
|
@@ -474,12 +504,13 @@ const DataTable = ({
|
|
|
474
504
|
entities,
|
|
475
505
|
change
|
|
476
506
|
});
|
|
477
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
478
507
|
}, [
|
|
479
508
|
entitiesAcrossPages,
|
|
480
509
|
reduxFormSelectedEntityIdMap,
|
|
481
510
|
change,
|
|
482
|
-
noExcessiveCheck
|
|
511
|
+
noExcessiveCheck,
|
|
512
|
+
entities,
|
|
513
|
+
formName
|
|
483
514
|
]);
|
|
484
515
|
|
|
485
516
|
const [tableConfig, setTableConfig] = useState({ fieldOptions: [] });
|
|
@@ -765,6 +796,11 @@ const DataTable = ({
|
|
|
765
796
|
extraCompact = tableConfig.density === "extraCompact";
|
|
766
797
|
}
|
|
767
798
|
|
|
799
|
+
const resized = useMemo(
|
|
800
|
+
() => tableConfig.resized || [],
|
|
801
|
+
[tableConfig?.resized]
|
|
802
|
+
);
|
|
803
|
+
|
|
768
804
|
const pageSize = controlled_pageSize || _pageSize;
|
|
769
805
|
|
|
770
806
|
const [expandedEntityIdMap, setExpandedEntityIdMap] = useState(() => {
|
|
@@ -849,85 +885,189 @@ const DataTable = ({
|
|
|
849
885
|
[schema.fields]
|
|
850
886
|
);
|
|
851
887
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
if (helperProp) {
|
|
856
|
-
helperProp.updateValidationHelper = () => {
|
|
857
|
-
updateValidation(entities, reduxFormCellValidation);
|
|
858
|
-
};
|
|
888
|
+
const updateValidationHelper = useCallback(() => {
|
|
889
|
+
updateValidation(entities, reduxFormCellValidation);
|
|
890
|
+
}, [entities, reduxFormCellValidation, updateValidation]);
|
|
859
891
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
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
|
+
}));
|
|
867
900
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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);
|
|
901
|
+
const { newEnts, validationErrors } = formatAndValidateEntities(
|
|
902
|
+
newEntities,
|
|
903
|
+
{
|
|
904
|
+
useDefaultValues: true,
|
|
905
|
+
indexToStartAt: entities.length
|
|
881
906
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
907
|
+
);
|
|
908
|
+
if (every(entities, "_isClean")) {
|
|
909
|
+
forEach(newEnts, (e, i) => {
|
|
910
|
+
entities[i] = e;
|
|
886
911
|
});
|
|
887
|
-
}
|
|
888
|
-
|
|
912
|
+
} else {
|
|
913
|
+
entities.splice(entities.length, 0, ...newEnts);
|
|
914
|
+
}
|
|
889
915
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
reduxFormCellValidation
|
|
894
|
-
);
|
|
895
|
-
const validationWTableErrs = validateTableWideErrors({
|
|
896
|
-
entities: entsToUse,
|
|
897
|
-
schema,
|
|
898
|
-
newCellValidate: validationToUse
|
|
916
|
+
updateValidation(entities, {
|
|
917
|
+
...reduxFormCellValidation,
|
|
918
|
+
...validationErrors
|
|
899
919
|
});
|
|
920
|
+
});
|
|
921
|
+
},
|
|
922
|
+
[
|
|
923
|
+
entities,
|
|
924
|
+
formatAndValidateEntities,
|
|
925
|
+
reduxFormCellValidation,
|
|
926
|
+
updateEntitiesHelper,
|
|
927
|
+
updateValidation
|
|
928
|
+
]
|
|
929
|
+
);
|
|
900
930
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
if (invalid) {
|
|
912
|
-
throwFormError(
|
|
913
|
-
"Please fix the errors in the table before submitting."
|
|
914
|
-
);
|
|
915
|
-
}
|
|
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
|
+
});
|
|
916
941
|
|
|
917
|
-
|
|
918
|
-
|
|
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;
|
|
951
|
+
|
|
952
|
+
if (invalid) {
|
|
953
|
+
throwFormError("Please fix the errors in the table before submitting.");
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
return entsToUse;
|
|
957
|
+
}, [reduxFormCellValidation, reduxFormEntities, schema]);
|
|
958
|
+
|
|
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;
|
|
919
967
|
}
|
|
920
968
|
}, [
|
|
921
|
-
|
|
922
|
-
|
|
969
|
+
addEditableTableEntities,
|
|
970
|
+
getEditableTableInfoAndThrowFormError,
|
|
923
971
|
helperProp,
|
|
924
|
-
|
|
925
|
-
reduxFormEntities,
|
|
926
|
-
schema,
|
|
927
|
-
updateEntitiesHelper,
|
|
928
|
-
updateValidation
|
|
972
|
+
updateValidationHelper
|
|
929
973
|
]);
|
|
930
974
|
|
|
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
|
+
|
|
931
1071
|
const primarySelectedCellId = useMemo(() => {
|
|
932
1072
|
for (const k of Object.keys(selectedCells)) {
|
|
933
1073
|
if (selectedCells[k] === PRIMARY_SELECTED_VAL) {
|
|
@@ -963,6 +1103,50 @@ const DataTable = ({
|
|
|
963
1103
|
[change]
|
|
964
1104
|
);
|
|
965
1105
|
|
|
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
|
+
|
|
966
1150
|
const waitUntilAllRowsAreRendered = useCallback(() => {
|
|
967
1151
|
return new Promise(resolve => {
|
|
968
1152
|
const interval = setInterval(() => {
|
|
@@ -977,6 +1161,74 @@ const DataTable = ({
|
|
|
977
1161
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
978
1162
|
}, []);
|
|
979
1163
|
|
|
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
|
+
|
|
980
1232
|
const handleCopySelectedRows = useCallback(
|
|
981
1233
|
async selectedRecords => {
|
|
982
1234
|
if (entities.length > VIRTUALIZE_CUTOFF_LENGTH) {
|
|
@@ -1019,36 +1271,237 @@ const DataTable = ({
|
|
|
1019
1271
|
[entities, waitUntilAllRowsAreRendered]
|
|
1020
1272
|
);
|
|
1021
1273
|
|
|
1022
|
-
const
|
|
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
|
+
}, [
|
|
1023
1331
|
change,
|
|
1024
1332
|
entities,
|
|
1333
|
+
formatAndValidateEntities,
|
|
1025
1334
|
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,
|
|
1026
1358
|
formatAndValidateEntities,
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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
|
+
);
|
|
1051
1503
|
|
|
1504
|
+
const { handleKeyDown, handleKeyUp } = useHotkeys(hotKeys);
|
|
1052
1505
|
const [columns, setColumns] = useState([]);
|
|
1053
1506
|
const [fullscreen, setFullscreen] = useState(false);
|
|
1054
1507
|
const [selectingAll, setSelectingAll] = useState(false);
|
|
@@ -1352,6 +1805,42 @@ const DataTable = ({
|
|
|
1352
1805
|
}
|
|
1353
1806
|
}, [entities, selectedIds, selectAllByDefault, setSelectedIds]);
|
|
1354
1807
|
|
|
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
|
+
|
|
1355
1844
|
const addEntitiesToSelection = entities => {
|
|
1356
1845
|
const idMap = reduxFormSelectedEntityIdMap || {};
|
|
1357
1846
|
const newIdMap = cloneDeep(idMap) || {};
|
|
@@ -1588,6 +2077,426 @@ const DataTable = ({
|
|
|
1588
2077
|
]
|
|
1589
2078
|
);
|
|
1590
2079
|
|
|
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
|
+
|
|
1591
2500
|
if (withSelectAll && !safeQuery) {
|
|
1592
2501
|
throw new Error("safeQuery is needed for selecting all table records");
|
|
1593
2502
|
}
|
|
@@ -1603,7 +2512,7 @@ const DataTable = ({
|
|
|
1603
2512
|
: "";
|
|
1604
2513
|
|
|
1605
2514
|
const hasFilters =
|
|
1606
|
-
filters
|
|
2515
|
+
filters.length ||
|
|
1607
2516
|
searchTerm ||
|
|
1608
2517
|
schema.fields.some(
|
|
1609
2518
|
field => field.filterIsActive && field.filterIsActive(currentParams)
|
|
@@ -1616,7 +2525,7 @@ const DataTable = ({
|
|
|
1616
2525
|
|
|
1617
2526
|
const filtersOnNonDisplayedFields = useMemo(() => {
|
|
1618
2527
|
const _filtersOnNonDisplayedFields = [];
|
|
1619
|
-
if (filters
|
|
2528
|
+
if (filters && filters.length) {
|
|
1620
2529
|
schema.fields.forEach(field => {
|
|
1621
2530
|
const ccDisplayName = getCCDisplayName(field);
|
|
1622
2531
|
if (field.isHidden) {
|
|
@@ -1641,6 +2550,18 @@ const DataTable = ({
|
|
|
1641
2550
|
);
|
|
1642
2551
|
const selectedRowCount = Object.keys(idMap).filter(key => idMap[key]).length;
|
|
1643
2552
|
|
|
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
|
+
|
|
1644
2565
|
const showHeader = (withTitle || withSearch || children) && !noHeader;
|
|
1645
2566
|
const toggleFullscreenButton = (
|
|
1646
2567
|
<Button
|
|
@@ -1727,6 +2648,21 @@ const DataTable = ({
|
|
|
1727
2648
|
withPaging &&
|
|
1728
2649
|
(hidePageSizeWhenPossible ? entityCount > pageSize : true);
|
|
1729
2650
|
|
|
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
|
+
|
|
1730
2666
|
const nonDisplayedFilterComp = useMemo(() => {
|
|
1731
2667
|
if (filtersOnNonDisplayedFields.length) {
|
|
1732
2668
|
const content = filtersOnNonDisplayedFields.map(
|
|
@@ -1771,12 +2707,173 @@ const DataTable = ({
|
|
|
1771
2707
|
return null;
|
|
1772
2708
|
}, [filtersOnNonDisplayedFields]);
|
|
1773
2709
|
|
|
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
|
+
|
|
1774
2779
|
const scrollToTop = useCallback(
|
|
1775
2780
|
() =>
|
|
1776
2781
|
tableRef.current?.tableRef?.children?.[0]?.children?.[0]?.scrollIntoView(),
|
|
1777
2782
|
[]
|
|
1778
2783
|
);
|
|
1779
2784
|
|
|
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
|
+
|
|
1780
2877
|
return (
|
|
1781
2878
|
<div
|
|
1782
2879
|
tabIndex="1"
|
|
@@ -2072,84 +3169,7 @@ const DataTable = ({
|
|
|
2072
3169
|
/>
|
|
2073
3170
|
</div>
|
|
2074
3171
|
)}
|
|
2075
|
-
|
|
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
|
-
/>
|
|
3172
|
+
{reactTable}
|
|
2153
3173
|
{isCellEditable && (
|
|
2154
3174
|
<div style={{ display: "flex" }}>
|
|
2155
3175
|
<div
|
|
@@ -2247,41 +3267,7 @@ const DataTable = ({
|
|
|
2247
3267
|
);
|
|
2248
3268
|
};
|
|
2249
3269
|
|
|
2250
|
-
const
|
|
2251
|
-
|
|
2252
|
-
const
|
|
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;
|
|
3270
|
+
const WrappedDT = dataTableEnhancer(DataTable);
|
|
3271
|
+
export default WrappedDT;
|
|
3272
|
+
const ConnectedPagingTool = dataTableEnhancer(PagingTool);
|
|
2287
3273
|
export { ConnectedPagingTool };
|