@teselagen/ui 0.4.14 → 0.4.15
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/AdvancedOptions.d.ts +1 -1
- package/AssignDefaultsModeContext.d.ts +1 -1
- package/AsyncValidateFieldSpinner/index.d.ts +1 -1
- package/BlueprintError/index.d.ts +1 -1
- package/BounceLoader/index.d.ts +1 -1
- package/CollapsibleCard/index.d.ts +1 -1
- package/DNALoader/index.d.ts +1 -1
- package/DataTable/CellDragHandle.d.ts +1 -1
- package/DataTable/ColumnFilterMenu.d.ts +14 -0
- package/DataTable/DisabledLoadingComponent.d.ts +1 -1
- package/DataTable/DisplayOptions.d.ts +2 -2
- package/DataTable/DropdownCell.d.ts +8 -0
- package/DataTable/EditabelCell.d.ts +10 -0
- package/DataTable/FilterAndSortMenu.d.ts +2 -2
- package/DataTable/SearchBar.d.ts +1 -1
- package/DataTable/SortableColumns.d.ts +2 -2
- package/DataTable/TableFormTrackerContext.d.ts +1 -1
- package/DataTable/defaultProps.d.ts +1 -1
- package/DataTable/index.d.ts +0 -5
- package/DataTable/utils/computePresets.d.ts +1 -1
- package/DataTable/utils/formatPasteData.d.ts +5 -0
- package/DataTable/utils/getAllRows.d.ts +1 -0
- package/DataTable/utils/getCellCopyText.d.ts +1 -0
- package/DataTable/utils/getCellInfo.d.ts +17 -0
- package/DataTable/utils/getFieldPathToField.d.ts +1 -0
- package/DataTable/utils/getIdOrCodeOrIndex.d.ts +1 -2
- package/DataTable/utils/getLastSelectedEntity.d.ts +1 -0
- package/DataTable/utils/getNewEntToSelect.d.ts +6 -0
- package/DataTable/utils/getRowCopyText.d.ts +3 -0
- package/DataTable/utils/handleCopyColumn.d.ts +1 -0
- package/DataTable/utils/handleCopyHelper.d.ts +1 -0
- package/DataTable/utils/handleCopyRows.d.ts +5 -0
- package/DataTable/utils/index.d.ts +21 -0
- package/DataTable/utils/isBottomRightCornerOfRectangle.d.ts +8 -0
- package/DataTable/utils/isEntityClean.d.ts +1 -0
- package/DataTable/utils/removeCleanRows.d.ts +4 -0
- package/DataTable/utils/rowClick.d.ts +10 -2
- package/DataTable/utils/utils.d.ts +5 -0
- package/DataTable/viewColumn.d.ts +2 -2
- package/DialogFooter/index.d.ts +1 -1
- package/DropdownButton.d.ts +1 -1
- package/FillWindow.d.ts +1 -1
- package/FormComponents/LoadingDots.d.ts +1 -1
- package/FormComponents/Uploader.d.ts +29 -1
- package/FormComponents/index.d.ts +34 -34
- package/FormComponents/itemUpload.d.ts +1 -1
- package/HotkeysDialog/index.d.ts +1 -1
- package/InfoHelper/index.d.ts +1 -1
- package/IntentText/index.d.ts +1 -1
- package/MatchHeaders.d.ts +1 -1
- package/MenuBar/index.d.ts +4 -4
- package/PromptUnsavedChanges/index.d.ts +1 -1
- package/README.md +18 -0
- package/ResizableDraggableDialog/index.d.ts +2 -2
- package/ScrollToTop/index.d.ts +1 -1
- package/SimpleStepViz.d.ts +1 -1
- package/Tag.d.ts +1 -1
- package/TagSelect/index.d.ts +1 -1
- package/TgSelect/index.d.ts +2 -2
- package/TgSuggest/index.d.ts +3 -3
- package/Timeline/TimelineEvent.d.ts +1 -1
- package/Timeline/index.d.ts +2 -2
- package/UploadCsvWizard.d.ts +1 -1
- package/customIcons.d.ts +19 -19
- package/enhancers/withField.d.ts +1 -1
- package/enhancers/withFields.d.ts +1 -1
- package/enhancers/withLocalStorage.d.ts +1 -1
- package/index.cjs.js +14026 -12765
- package/index.d.ts +60 -60
- package/index.es.js +13844 -12583
- package/package.json +7 -4
- package/showConfirmationDialog/index.d.ts +2 -2
- package/src/DataTable/CellDragHandle.js +6 -7
- package/src/DataTable/ColumnFilterMenu.js +60 -0
- package/src/DataTable/DropdownCell.js +61 -0
- package/src/DataTable/EditabelCell.js +55 -0
- package/src/DataTable/PagingTool.js +1 -1
- package/src/DataTable/SortableColumns.js +53 -18
- package/src/DataTable/dataTableEnhancer.js +1 -1
- package/src/DataTable/index.js +385 -759
- package/src/DataTable/utils/formatPasteData.js +16 -0
- package/src/DataTable/utils/getAllRows.js +11 -0
- package/src/DataTable/utils/getCellCopyText.js +7 -0
- package/src/DataTable/utils/getCellInfo.js +36 -0
- package/src/DataTable/utils/getFieldPathToField.js +7 -0
- package/src/DataTable/utils/getIdOrCodeOrIndex.js +1 -1
- package/src/DataTable/utils/getLastSelectedEntity.js +11 -0
- package/src/DataTable/utils/getNewEntToSelect.js +25 -0
- package/src/DataTable/utils/getRowCopyText.js +28 -0
- package/src/DataTable/utils/handleCopyColumn.js +21 -0
- package/src/DataTable/utils/handleCopyHelper.js +15 -0
- package/src/DataTable/utils/handleCopyRows.js +23 -0
- package/src/DataTable/utils/index.js +51 -0
- package/src/DataTable/utils/isBottomRightCornerOfRectangle.js +20 -0
- package/src/DataTable/utils/isEntityClean.js +15 -0
- package/src/DataTable/utils/removeCleanRows.js +22 -0
- package/src/DataTable/utils/rowClick.js +7 -4
- package/src/DataTable/utils/selection.js +1 -1
- package/src/DataTable/utils/utils.js +37 -0
- package/src/DataTable/validateTableWideErrors.js +1 -1
- package/src/FillWindow.js +2 -3
- package/src/FormComponents/Uploader.js +400 -400
- package/src/FormComponents/tryToMatchSchemas.js +0 -6
- package/src/UploadCsvWizard.js +312 -371
- package/src/index.js +3 -3
- package/src/showDialogOnDocBody.js +5 -9
- package/src/useDialog.js +7 -4
- package/src/utils/renderOnDoc.js +8 -5
- package/style.css +7 -7
- package/useDialog.d.ts +2 -2
- package/utils/adHoc.d.ts +1 -1
- package/utils/commandControls.d.ts +5 -5
- package/utils/hotkeyUtils.d.ts +1 -1
- package/utils/menuUtils.d.ts +7 -7
- package/utils/renderOnDoc.d.ts +1 -1
- package/utils/tagUtils.d.ts +1 -1
- package/utils/tgFormValues.d.ts +1 -1
- package/utils/withStore.d.ts +1 -1
- package/wrapDialog.d.ts +1 -1
package/src/DataTable/index.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import React, { useState } from "react";
|
|
3
|
-
import ReactDOM from "react-dom";
|
|
4
|
-
import { arrayMove } from "react-sortable-hoc";
|
|
5
|
-
import copy from "copy-to-clipboard";
|
|
6
|
-
import download from "downloadjs";
|
|
1
|
+
import React, { createRef } from "react";
|
|
7
2
|
import {
|
|
8
3
|
invert,
|
|
9
4
|
toNumber,
|
|
10
5
|
isEmpty,
|
|
11
6
|
min,
|
|
12
7
|
max,
|
|
13
|
-
flatMap,
|
|
14
8
|
set,
|
|
15
9
|
map,
|
|
16
10
|
toString,
|
|
@@ -32,7 +26,6 @@ import {
|
|
|
32
26
|
every
|
|
33
27
|
} from "lodash-es";
|
|
34
28
|
import joinUrl from "url-join";
|
|
35
|
-
|
|
36
29
|
import {
|
|
37
30
|
Button,
|
|
38
31
|
Menu,
|
|
@@ -41,16 +34,16 @@ import {
|
|
|
41
34
|
ContextMenu,
|
|
42
35
|
Checkbox,
|
|
43
36
|
Icon,
|
|
44
|
-
Popover,
|
|
45
37
|
Intent,
|
|
46
38
|
Callout,
|
|
47
39
|
Tooltip
|
|
48
40
|
} from "@blueprintjs/core";
|
|
41
|
+
import { arrayMove, useSortable } from "@dnd-kit/sortable";
|
|
42
|
+
import { CSS } from "@dnd-kit/utilities";
|
|
49
43
|
import classNames from "classnames";
|
|
50
44
|
import scrollIntoView from "dom-scroll-into-view";
|
|
51
|
-
import { SortableElement } from "react-sortable-hoc";
|
|
52
45
|
import ReactTable from "@teselagen/react-table";
|
|
53
|
-
import { withProps,
|
|
46
|
+
import { withProps, compose } from "recompose";
|
|
54
47
|
import dayjs from "dayjs";
|
|
55
48
|
import localizedFormat from "dayjs/plugin/localizedFormat";
|
|
56
49
|
import ReactMarkdown from "react-markdown";
|
|
@@ -58,30 +51,50 @@ import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
|
|
|
58
51
|
import papaparse from "papaparse";
|
|
59
52
|
import remarkGfm from "remark-gfm";
|
|
60
53
|
|
|
61
|
-
import
|
|
62
|
-
|
|
54
|
+
import {
|
|
55
|
+
computePresets,
|
|
56
|
+
defaultParsePaste,
|
|
57
|
+
formatPasteData,
|
|
58
|
+
getAllRows,
|
|
59
|
+
getCellCopyText,
|
|
60
|
+
getCellInfo,
|
|
61
|
+
getEntityIdToEntity,
|
|
62
|
+
getFieldPathToIndex,
|
|
63
|
+
getFieldPathToField,
|
|
64
|
+
getIdOrCodeOrIndex,
|
|
65
|
+
getLastSelectedEntity,
|
|
66
|
+
getNewEntToSelect,
|
|
67
|
+
getNumberStrAtEnd,
|
|
68
|
+
getRecordsFromIdMap,
|
|
69
|
+
getRowCopyText,
|
|
70
|
+
getSelectedRowsFromEntities,
|
|
71
|
+
handleCopyColumn,
|
|
72
|
+
handleCopyHelper,
|
|
73
|
+
handleCopyRows,
|
|
74
|
+
isBottomRightCornerOfRectangle,
|
|
75
|
+
isEntityClean,
|
|
76
|
+
removeCleanRows,
|
|
77
|
+
stripNumberAtEnd
|
|
78
|
+
} from "./utils";
|
|
63
79
|
import InfoHelper from "../InfoHelper";
|
|
80
|
+
import { withHotkeys } from "../utils/hotkeyUtils";
|
|
64
81
|
import getTextFromEl from "../utils/getTextFromEl";
|
|
65
|
-
import { getSelectedRowsFromEntities } from "./utils/selection";
|
|
66
82
|
import rowClick, {
|
|
67
83
|
changeSelectedEntities,
|
|
68
84
|
finalizeSelection
|
|
69
85
|
} from "./utils/rowClick";
|
|
70
86
|
import PagingTool from "./PagingTool";
|
|
71
87
|
import FilterAndSortMenu from "./FilterAndSortMenu";
|
|
72
|
-
import getIdOrCodeOrIndex from "./utils/getIdOrCodeOrIndex";
|
|
73
88
|
import SearchBar from "./SearchBar";
|
|
74
89
|
import DisplayOptions from "./DisplayOptions";
|
|
75
90
|
import DisabledLoadingComponent from "./DisabledLoadingComponent";
|
|
76
91
|
import SortableColumns from "./SortableColumns";
|
|
77
|
-
import computePresets from "./utils/computePresets";
|
|
78
92
|
import dataTableEnhancer from "./dataTableEnhancer";
|
|
79
93
|
import defaultProps from "./defaultProps";
|
|
80
94
|
|
|
81
95
|
import "../toastr";
|
|
82
96
|
import "@teselagen/react-table/react-table.css";
|
|
83
97
|
import "./style.css";
|
|
84
|
-
import { getRecordsFromIdMap } from "./utils/withSelectedEntities";
|
|
85
98
|
import { CellDragHandle } from "./CellDragHandle";
|
|
86
99
|
import { nanoid } from "nanoid";
|
|
87
100
|
import { SwitchField } from "../FormComponents";
|
|
@@ -90,15 +103,27 @@ import { editCellHelper } from "./editCellHelper";
|
|
|
90
103
|
import { getCellVal } from "./getCellVal";
|
|
91
104
|
import { getVals } from "./getVals";
|
|
92
105
|
import { throwFormError } from "../throwFormError";
|
|
106
|
+
import { DropdownCell } from "./DropdownCell";
|
|
107
|
+
import { EditableCell } from "./EditabelCell";
|
|
108
|
+
import { ColumnFilterMenu } from "./ColumnFilterMenu";
|
|
93
109
|
enablePatches();
|
|
94
110
|
|
|
95
111
|
const PRIMARY_SELECTED_VAL = "main_cell";
|
|
96
112
|
|
|
97
113
|
dayjs.extend(localizedFormat);
|
|
98
114
|
const IS_LINUX = window.navigator.platform.toLowerCase().search("linux") > -1;
|
|
115
|
+
|
|
116
|
+
const itemSizeEstimators = {
|
|
117
|
+
compact: () => 25.34,
|
|
118
|
+
normal: () => 33.34,
|
|
119
|
+
comfortable: () => 41.34
|
|
120
|
+
};
|
|
121
|
+
|
|
99
122
|
class DataTable extends React.Component {
|
|
100
123
|
constructor(props) {
|
|
101
124
|
super(props);
|
|
125
|
+
|
|
126
|
+
this.tableRef = createRef();
|
|
102
127
|
if (this.props.helperProp) {
|
|
103
128
|
this.props.helperProp.updateValidationHelper =
|
|
104
129
|
this.updateValidationHelper;
|
|
@@ -179,25 +204,52 @@ class DataTable extends React.Component {
|
|
|
179
204
|
}
|
|
180
205
|
});
|
|
181
206
|
}
|
|
207
|
+
|
|
182
208
|
state = {
|
|
183
209
|
columns: [],
|
|
184
|
-
fullscreen: false
|
|
210
|
+
fullscreen: false,
|
|
211
|
+
// This state prevents the first letter from not being written,
|
|
212
|
+
// when the user starts typing in a cell. It is quite hacky, we should
|
|
213
|
+
// refactor this in the future.
|
|
214
|
+
editableCellInitialValue: ""
|
|
185
215
|
};
|
|
186
|
-
|
|
187
216
|
static defaultProps = defaultProps;
|
|
188
217
|
|
|
189
|
-
|
|
190
|
-
this.
|
|
191
|
-
|
|
192
|
-
|
|
218
|
+
getPrimarySelectedCellId = () => {
|
|
219
|
+
const { reduxFormSelectedCells = {} } = this.props;
|
|
220
|
+
for (const k of Object.keys(reduxFormSelectedCells)) {
|
|
221
|
+
if (reduxFormSelectedCells[k] === PRIMARY_SELECTED_VAL) {
|
|
222
|
+
return k;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
startCellEdit = (cellId, { shouldSelectAll } = {}) => {
|
|
228
|
+
const {
|
|
229
|
+
change,
|
|
230
|
+
reduxFormSelectedCells = {},
|
|
231
|
+
reduxFormEditingCell
|
|
232
|
+
} = computePresets(this.props);
|
|
233
|
+
const newSelectedCells = { ...reduxFormSelectedCells };
|
|
234
|
+
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
235
|
+
//check if the cell is already selected and editing and if so, don't change it
|
|
236
|
+
if (reduxFormEditingCell === cellId) return;
|
|
237
|
+
change("reduxFormSelectedCells", newSelectedCells);
|
|
238
|
+
change("reduxFormEditingCell", cellId);
|
|
239
|
+
if (shouldSelectAll) {
|
|
240
|
+
//we should select the text
|
|
241
|
+
change("reduxFormEditingCellSelectAll", true);
|
|
242
|
+
}
|
|
193
243
|
};
|
|
244
|
+
|
|
194
245
|
handleEnterStartCellEdit = e => {
|
|
195
246
|
e.stopPropagation();
|
|
196
247
|
this.startCellEdit(this.getPrimarySelectedCellId());
|
|
197
248
|
};
|
|
249
|
+
|
|
198
250
|
flashTableBorder = () => {
|
|
199
251
|
try {
|
|
200
|
-
const table =
|
|
252
|
+
const table = this.tableRef.current.tableRef;
|
|
201
253
|
table.classList.add("tgBorderBlue");
|
|
202
254
|
setTimeout(() => {
|
|
203
255
|
table.classList.remove("tgBorderBlue");
|
|
@@ -206,6 +258,59 @@ class DataTable extends React.Component {
|
|
|
206
258
|
console.error(`err when flashing table border:`, e);
|
|
207
259
|
}
|
|
208
260
|
};
|
|
261
|
+
|
|
262
|
+
formatAndValidateEntities = (
|
|
263
|
+
entities,
|
|
264
|
+
{ useDefaultValues, indexToStartAt } = {}
|
|
265
|
+
) => {
|
|
266
|
+
const { schema } = this.props;
|
|
267
|
+
const editableFields = schema.fields.filter(f => !f.isNotEditable);
|
|
268
|
+
const validationErrors = {};
|
|
269
|
+
|
|
270
|
+
const newEnts = immer(entities, entities => {
|
|
271
|
+
entities.forEach((e, index) => {
|
|
272
|
+
editableFields.forEach(columnSchema => {
|
|
273
|
+
if (useDefaultValues) {
|
|
274
|
+
if (e[columnSchema.path] === undefined) {
|
|
275
|
+
if (isFunction(columnSchema.defaultValue)) {
|
|
276
|
+
e[columnSchema.path] = columnSchema.defaultValue(
|
|
277
|
+
index + indexToStartAt,
|
|
278
|
+
e
|
|
279
|
+
);
|
|
280
|
+
} else e[columnSchema.path] = columnSchema.defaultValue;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
//mutative
|
|
284
|
+
const { error } = editCellHelper({
|
|
285
|
+
entity: e,
|
|
286
|
+
columnSchema,
|
|
287
|
+
newVal: e[columnSchema.path]
|
|
288
|
+
});
|
|
289
|
+
if (error) {
|
|
290
|
+
const rowId = getIdOrCodeOrIndex(e, index);
|
|
291
|
+
validationErrors[`${rowId}:${columnSchema.path}`] = error;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
return {
|
|
297
|
+
newEnts,
|
|
298
|
+
validationErrors
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
updateValidation = (entities, newCellValidate) => {
|
|
303
|
+
const { change, schema } = computePresets(this.props);
|
|
304
|
+
const tableWideErr = validateTableWideErrors({
|
|
305
|
+
entities,
|
|
306
|
+
schema,
|
|
307
|
+
newCellValidate,
|
|
308
|
+
props: this.props
|
|
309
|
+
});
|
|
310
|
+
change("reduxFormCellValidation", tableWideErr);
|
|
311
|
+
this.forceUpdate();
|
|
312
|
+
};
|
|
313
|
+
|
|
209
314
|
handleUndo = () => {
|
|
210
315
|
const {
|
|
211
316
|
change,
|
|
@@ -231,6 +336,7 @@ class DataTable extends React.Component {
|
|
|
231
336
|
});
|
|
232
337
|
}
|
|
233
338
|
};
|
|
339
|
+
|
|
234
340
|
handleRedo = () => {
|
|
235
341
|
const {
|
|
236
342
|
change,
|
|
@@ -255,6 +361,7 @@ class DataTable extends React.Component {
|
|
|
255
361
|
});
|
|
256
362
|
}
|
|
257
363
|
};
|
|
364
|
+
|
|
258
365
|
updateFromProps = (oldProps, newProps) => {
|
|
259
366
|
const {
|
|
260
367
|
selectedIds,
|
|
@@ -266,7 +373,6 @@ class DataTable extends React.Component {
|
|
|
266
373
|
reduxFormExpandedEntityIdMap,
|
|
267
374
|
change
|
|
268
375
|
} = newProps;
|
|
269
|
-
const table = ReactDOM.findDOMNode(this.table);
|
|
270
376
|
|
|
271
377
|
const idMap = reduxFormSelectedEntityIdMap;
|
|
272
378
|
|
|
@@ -332,7 +438,8 @@ class DataTable extends React.Component {
|
|
|
332
438
|
// if not changing selectedIds then we just want to make sure selected entities
|
|
333
439
|
// stored in redux are in proper format
|
|
334
440
|
// if selected ids have changed then it will handle redux selection
|
|
335
|
-
const tableScrollElement =
|
|
441
|
+
const tableScrollElement =
|
|
442
|
+
this.tableRef.current.tableRef.getElementsByClassName("rt-table")[0];
|
|
336
443
|
const {
|
|
337
444
|
entities: oldEntities = [],
|
|
338
445
|
reduxFormSelectedEntityIdMap: oldIdMap
|
|
@@ -381,8 +488,9 @@ class DataTable extends React.Component {
|
|
|
381
488
|
const entityIndexToScrollTo = entities.findIndex(
|
|
382
489
|
e => e.id === idToScrollTo || e.code === idToScrollTo
|
|
383
490
|
);
|
|
384
|
-
if (entityIndexToScrollTo === -1 || !
|
|
385
|
-
const tableBody =
|
|
491
|
+
if (entityIndexToScrollTo === -1 || !this.tableRef.current) return;
|
|
492
|
+
const tableBody =
|
|
493
|
+
this.tableRef.current.tableRef.querySelector(".rt-tbody");
|
|
386
494
|
if (!tableBody) return;
|
|
387
495
|
const rowEl =
|
|
388
496
|
tableBody.getElementsByClassName("rt-tr-group")[entityIndexToScrollTo];
|
|
@@ -397,45 +505,7 @@ class DataTable extends React.Component {
|
|
|
397
505
|
}, 0);
|
|
398
506
|
}
|
|
399
507
|
};
|
|
400
|
-
formatAndValidateEntities = (
|
|
401
|
-
entities,
|
|
402
|
-
{ useDefaultValues, indexToStartAt } = {}
|
|
403
|
-
) => {
|
|
404
|
-
const { schema } = this.props;
|
|
405
|
-
const editableFields = schema.fields.filter(f => !f.isNotEditable);
|
|
406
|
-
const validationErrors = {};
|
|
407
508
|
|
|
408
|
-
const newEnts = immer(entities, entities => {
|
|
409
|
-
entities.forEach((e, index) => {
|
|
410
|
-
editableFields.forEach(columnSchema => {
|
|
411
|
-
if (useDefaultValues) {
|
|
412
|
-
if (e[columnSchema.path] === undefined) {
|
|
413
|
-
if (isFunction(columnSchema.defaultValue)) {
|
|
414
|
-
e[columnSchema.path] = columnSchema.defaultValue(
|
|
415
|
-
index + indexToStartAt,
|
|
416
|
-
e
|
|
417
|
-
);
|
|
418
|
-
} else e[columnSchema.path] = columnSchema.defaultValue;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
//mutative
|
|
422
|
-
const { error } = editCellHelper({
|
|
423
|
-
entity: e,
|
|
424
|
-
columnSchema,
|
|
425
|
-
newVal: e[columnSchema.path]
|
|
426
|
-
});
|
|
427
|
-
if (error) {
|
|
428
|
-
const rowId = getIdOrCodeOrIndex(e, index);
|
|
429
|
-
validationErrors[`${rowId}:${columnSchema.path}`] = error;
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
});
|
|
434
|
-
return {
|
|
435
|
-
newEnts,
|
|
436
|
-
validationErrors
|
|
437
|
-
};
|
|
438
|
-
};
|
|
439
509
|
formatAndValidateTableInitial = () => {
|
|
440
510
|
const {
|
|
441
511
|
_origEntities,
|
|
@@ -462,151 +532,25 @@ class DataTable extends React.Component {
|
|
|
462
532
|
});
|
|
463
533
|
};
|
|
464
534
|
|
|
465
|
-
|
|
466
|
-
const {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
// let theads = table.getElementsByClassName("rt-thead");
|
|
482
|
-
// let tbody = table.getElementsByClassName("rt-tbody")[0];
|
|
483
|
-
|
|
484
|
-
// tbody.addEventListener("scroll", () => {
|
|
485
|
-
// for (let i = 0; i < theads.length; i++) {
|
|
486
|
-
// theads.item(i).scrollLeft = tbody.scrollLeft;
|
|
487
|
-
// }
|
|
488
|
-
// });
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
componentDidUpdate(oldProps) {
|
|
492
|
-
// const tableBody = table.querySelector(".rt-tbody");
|
|
493
|
-
// const headerNode = table.querySelector(".rt-thead.-header");
|
|
494
|
-
// if (headerNode) headerNode.style.overflowY = "inherit";
|
|
495
|
-
// if (tableBody && tableBody.scrollHeight > tableBody.clientHeight) {
|
|
496
|
-
// if (headerNode) {
|
|
497
|
-
// headerNode.style.overflowY = "scroll";
|
|
498
|
-
// headerNode.style.overflowX = "hidden";
|
|
499
|
-
// }
|
|
500
|
-
// }
|
|
501
|
-
|
|
502
|
-
this.updateFromProps(computePresets(oldProps), computePresets(this.props));
|
|
503
|
-
|
|
504
|
-
// comment in to test what is causing re-render
|
|
505
|
-
// Object.entries(this.props).forEach(
|
|
506
|
-
// ([key, val]) =>
|
|
507
|
-
// oldProps[key] !== val && console.info(`Prop '${key}' changed`)
|
|
508
|
-
// );
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
componentWillUnmount() {
|
|
512
|
-
document.removeEventListener("paste", this.handlePaste);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
handleRowMove = (type, shiftHeld) => e => {
|
|
516
|
-
e.preventDefault();
|
|
517
|
-
e.stopPropagation();
|
|
518
|
-
const props = computePresets(this.props);
|
|
519
|
-
const {
|
|
520
|
-
noSelect,
|
|
521
|
-
entities,
|
|
522
|
-
reduxFormSelectedEntityIdMap: idMap,
|
|
523
|
-
isEntityDisabled,
|
|
524
|
-
isSingleSelect
|
|
525
|
-
} = props;
|
|
526
|
-
let newIdMap = {};
|
|
527
|
-
const lastSelectedEnt = getLastSelectedEntity(idMap);
|
|
528
|
-
|
|
529
|
-
if (noSelect) return;
|
|
530
|
-
if (lastSelectedEnt) {
|
|
531
|
-
let lastSelectedIndex = entities.findIndex(
|
|
532
|
-
ent => ent === lastSelectedEnt
|
|
533
|
-
);
|
|
534
|
-
if (lastSelectedIndex === -1) {
|
|
535
|
-
if (lastSelectedEnt.id !== undefined) {
|
|
536
|
-
lastSelectedIndex = entities.findIndex(
|
|
537
|
-
ent => ent.id === lastSelectedEnt.id
|
|
538
|
-
);
|
|
539
|
-
} else if (lastSelectedEnt.code !== undefined) {
|
|
540
|
-
lastSelectedIndex = entities.findIndex(
|
|
541
|
-
ent => ent.code === lastSelectedEnt.code
|
|
542
|
-
);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
if (lastSelectedIndex === -1) {
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
const newEntToSelect = getNewEntToSelect({
|
|
549
|
-
type,
|
|
550
|
-
lastSelectedIndex,
|
|
551
|
-
entities,
|
|
552
|
-
isEntityDisabled
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
if (!newEntToSelect) return;
|
|
556
|
-
if (shiftHeld && !isSingleSelect) {
|
|
557
|
-
if (idMap[newEntToSelect.id || newEntToSelect.code]) {
|
|
558
|
-
//the entity being moved to has already been selected
|
|
559
|
-
newIdMap = omit(idMap, [lastSelectedEnt.id || lastSelectedEnt.code]);
|
|
560
|
-
newIdMap[newEntToSelect.id || newEntToSelect.code].time =
|
|
561
|
-
Date.now() + 1;
|
|
562
|
-
} else {
|
|
563
|
-
//the entity being moved to has NOT been selected yet
|
|
564
|
-
newIdMap = {
|
|
565
|
-
...idMap,
|
|
566
|
-
[newEntToSelect.id || newEntToSelect.code]: {
|
|
567
|
-
entity: newEntToSelect,
|
|
568
|
-
time: Date.now()
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
} else {
|
|
573
|
-
//no shiftHeld
|
|
574
|
-
newIdMap[newEntToSelect.id || newEntToSelect.code] = {
|
|
575
|
-
entity: newEntToSelect,
|
|
576
|
-
time: Date.now()
|
|
577
|
-
};
|
|
535
|
+
updateEntitiesHelper = (ents, fn) => {
|
|
536
|
+
const { change, reduxFormEntitiesUndoRedoStack = { currentVersion: 0 } } =
|
|
537
|
+
this.props;
|
|
538
|
+
const [nextState, patches, inversePatches] = produceWithPatches(ents, fn);
|
|
539
|
+
if (!inversePatches.length) return;
|
|
540
|
+
const thatNewNew = [...nextState];
|
|
541
|
+
thatNewNew.isDirty = true;
|
|
542
|
+
change("reduxFormEntities", thatNewNew);
|
|
543
|
+
change("reduxFormEntitiesUndoRedoStack", {
|
|
544
|
+
...omitBy(reduxFormEntitiesUndoRedoStack, (v, k) => {
|
|
545
|
+
return toNumber(k) > reduxFormEntitiesUndoRedoStack.currentVersion + 1;
|
|
546
|
+
}),
|
|
547
|
+
currentVersion: reduxFormEntitiesUndoRedoStack.currentVersion + 1,
|
|
548
|
+
[reduxFormEntitiesUndoRedoStack.currentVersion + 1]: {
|
|
549
|
+
inversePatches,
|
|
550
|
+
patches
|
|
578
551
|
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
finalizeSelection({
|
|
582
|
-
idMap: newIdMap,
|
|
583
|
-
entities,
|
|
584
|
-
props
|
|
585
552
|
});
|
|
586
553
|
};
|
|
587
|
-
handleCopyHotkey = e => {
|
|
588
|
-
const { isCellEditable, reduxFormSelectedEntityIdMap } = computePresets(
|
|
589
|
-
this.props
|
|
590
|
-
);
|
|
591
|
-
|
|
592
|
-
if (isCellEditable) {
|
|
593
|
-
this.handleCopySelectedCells(e);
|
|
594
|
-
} else {
|
|
595
|
-
this.handleCopySelectedRows(
|
|
596
|
-
getRecordsFromIdMap(reduxFormSelectedEntityIdMap),
|
|
597
|
-
e
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
getPrimarySelectedCellId = () => {
|
|
603
|
-
const { reduxFormSelectedCells = {} } = this.props;
|
|
604
|
-
for (const k of Object.keys(reduxFormSelectedCells)) {
|
|
605
|
-
if (reduxFormSelectedCells[k] === PRIMARY_SELECTED_VAL) {
|
|
606
|
-
return k;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
554
|
|
|
611
555
|
handlePaste = e => {
|
|
612
556
|
const {
|
|
@@ -757,11 +701,150 @@ class DataTable extends React.Component {
|
|
|
757
701
|
change("reduxFormSelectedCells", newSelectedCells);
|
|
758
702
|
}
|
|
759
703
|
}
|
|
760
|
-
} catch (error) {
|
|
761
|
-
console.error(`error:`, error);
|
|
704
|
+
} catch (error) {
|
|
705
|
+
console.error(`error:`, error);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
componentDidMount() {
|
|
711
|
+
const {
|
|
712
|
+
isCellEditable,
|
|
713
|
+
entities = [],
|
|
714
|
+
isLoading,
|
|
715
|
+
showForcedHiddenColumns,
|
|
716
|
+
setShowForcedHidden
|
|
717
|
+
} = this.props;
|
|
718
|
+
isCellEditable && this.formatAndValidateTableInitial();
|
|
719
|
+
this.updateFromProps({}, computePresets(this.props));
|
|
720
|
+
document.addEventListener("paste", this.handlePaste);
|
|
721
|
+
|
|
722
|
+
if (!entities.length && !isLoading && !showForcedHiddenColumns) {
|
|
723
|
+
setShowForcedHidden(true);
|
|
724
|
+
}
|
|
725
|
+
// const table = this.tableRef.current.tableRef;
|
|
726
|
+
// let theads = table.getElementsByClassName("rt-thead");
|
|
727
|
+
// let tbody = table.getElementsByClassName("rt-tbody")[0];
|
|
728
|
+
|
|
729
|
+
// tbody.addEventListener("scroll", () => {
|
|
730
|
+
// for (let i = 0; i < theads.length; i++) {
|
|
731
|
+
// theads.item(i).scrollLeft = tbody.scrollLeft;
|
|
732
|
+
// }
|
|
733
|
+
// });
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
componentDidUpdate(oldProps) {
|
|
737
|
+
// const tableBody = table.querySelector(".rt-tbody");
|
|
738
|
+
// const headerNode = table.querySelector(".rt-thead.-header");
|
|
739
|
+
// if (headerNode) headerNode.style.overflowY = "inherit";
|
|
740
|
+
// if (tableBody && tableBody.scrollHeight > tableBody.clientHeight) {
|
|
741
|
+
// if (headerNode) {
|
|
742
|
+
// headerNode.style.overflowY = "scroll";
|
|
743
|
+
// headerNode.style.overflowX = "hidden";
|
|
744
|
+
// }
|
|
745
|
+
// }
|
|
746
|
+
|
|
747
|
+
this.updateFromProps(computePresets(oldProps), computePresets(this.props));
|
|
748
|
+
|
|
749
|
+
// comment in to test what is causing re-render
|
|
750
|
+
// Object.entries(this.props).forEach(
|
|
751
|
+
// ([key, val]) =>
|
|
752
|
+
// oldProps[key] !== val && console.info(`Prop '${key}' changed`)
|
|
753
|
+
// );
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
componentWillUnmount() {
|
|
757
|
+
document.removeEventListener("paste", this.handlePaste);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
handleRowMove = (type, shiftHeld) => e => {
|
|
761
|
+
e.preventDefault();
|
|
762
|
+
e.stopPropagation();
|
|
763
|
+
const props = computePresets(this.props);
|
|
764
|
+
const {
|
|
765
|
+
noSelect,
|
|
766
|
+
entities,
|
|
767
|
+
reduxFormSelectedEntityIdMap: idMap,
|
|
768
|
+
isEntityDisabled,
|
|
769
|
+
isSingleSelect
|
|
770
|
+
} = props;
|
|
771
|
+
let newIdMap = {};
|
|
772
|
+
const lastSelectedEnt = getLastSelectedEntity(idMap);
|
|
773
|
+
|
|
774
|
+
if (noSelect) return;
|
|
775
|
+
if (lastSelectedEnt) {
|
|
776
|
+
let lastSelectedIndex = entities.findIndex(
|
|
777
|
+
ent => ent === lastSelectedEnt
|
|
778
|
+
);
|
|
779
|
+
if (lastSelectedIndex === -1) {
|
|
780
|
+
if (lastSelectedEnt.id !== undefined) {
|
|
781
|
+
lastSelectedIndex = entities.findIndex(
|
|
782
|
+
ent => ent.id === lastSelectedEnt.id
|
|
783
|
+
);
|
|
784
|
+
} else if (lastSelectedEnt.code !== undefined) {
|
|
785
|
+
lastSelectedIndex = entities.findIndex(
|
|
786
|
+
ent => ent.code === lastSelectedEnt.code
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
if (lastSelectedIndex === -1) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const newEntToSelect = getNewEntToSelect({
|
|
794
|
+
type,
|
|
795
|
+
lastSelectedIndex,
|
|
796
|
+
entities,
|
|
797
|
+
isEntityDisabled
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
if (!newEntToSelect) return;
|
|
801
|
+
if (shiftHeld && !isSingleSelect) {
|
|
802
|
+
if (idMap[newEntToSelect.id || newEntToSelect.code]) {
|
|
803
|
+
//the entity being moved to has already been selected
|
|
804
|
+
newIdMap = omit(idMap, [lastSelectedEnt.id || lastSelectedEnt.code]);
|
|
805
|
+
newIdMap[newEntToSelect.id || newEntToSelect.code].time =
|
|
806
|
+
Date.now() + 1;
|
|
807
|
+
} else {
|
|
808
|
+
//the entity being moved to has NOT been selected yet
|
|
809
|
+
newIdMap = {
|
|
810
|
+
...idMap,
|
|
811
|
+
[newEntToSelect.id || newEntToSelect.code]: {
|
|
812
|
+
entity: newEntToSelect,
|
|
813
|
+
time: Date.now()
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
} else {
|
|
818
|
+
//no shiftHeld
|
|
819
|
+
newIdMap[newEntToSelect.id || newEntToSelect.code] = {
|
|
820
|
+
entity: newEntToSelect,
|
|
821
|
+
time: Date.now()
|
|
822
|
+
};
|
|
762
823
|
}
|
|
763
824
|
}
|
|
825
|
+
|
|
826
|
+
finalizeSelection({
|
|
827
|
+
idMap: newIdMap,
|
|
828
|
+
entities,
|
|
829
|
+
props
|
|
830
|
+
});
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
handleCopyHotkey = e => {
|
|
834
|
+
const { isCellEditable, reduxFormSelectedEntityIdMap } = computePresets(
|
|
835
|
+
this.props
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
if (isCellEditable) {
|
|
839
|
+
this.handleCopySelectedCells(e);
|
|
840
|
+
} else {
|
|
841
|
+
this.handleCopySelectedRows(
|
|
842
|
+
getRecordsFromIdMap(reduxFormSelectedEntityIdMap),
|
|
843
|
+
e
|
|
844
|
+
);
|
|
845
|
+
}
|
|
764
846
|
};
|
|
847
|
+
|
|
765
848
|
handleSelectAllRows = e => {
|
|
766
849
|
const {
|
|
767
850
|
change,
|
|
@@ -800,22 +883,12 @@ class DataTable extends React.Component {
|
|
|
800
883
|
});
|
|
801
884
|
}
|
|
802
885
|
};
|
|
886
|
+
|
|
803
887
|
updateValidationHelper = () => {
|
|
804
888
|
const { entities, reduxFormCellValidation } = computePresets(this.props);
|
|
805
889
|
this.updateValidation(entities, reduxFormCellValidation);
|
|
806
890
|
};
|
|
807
891
|
|
|
808
|
-
updateValidation = (entities, newCellValidate) => {
|
|
809
|
-
const { change, schema } = computePresets(this.props);
|
|
810
|
-
const tableWideErr = validateTableWideErrors({
|
|
811
|
-
entities,
|
|
812
|
-
schema,
|
|
813
|
-
newCellValidate,
|
|
814
|
-
props: this.props
|
|
815
|
-
});
|
|
816
|
-
change("reduxFormCellValidation", tableWideErr);
|
|
817
|
-
this.forceUpdate();
|
|
818
|
-
};
|
|
819
892
|
handleDeleteCell = () => {
|
|
820
893
|
const {
|
|
821
894
|
reduxFormSelectedCells,
|
|
@@ -856,119 +929,11 @@ class DataTable extends React.Component {
|
|
|
856
929
|
this.handleCopyHotkey(e);
|
|
857
930
|
};
|
|
858
931
|
|
|
859
|
-
getCellCopyText = cellWrapper => {
|
|
860
|
-
const text = cellWrapper && cellWrapper.getAttribute("data-copy-text");
|
|
861
|
-
const jsonText = cellWrapper && cellWrapper.getAttribute("data-copy-json");
|
|
862
|
-
|
|
863
|
-
const textContent = text || cellWrapper.textContent || "";
|
|
864
|
-
return [textContent, jsonText];
|
|
865
|
-
};
|
|
866
|
-
|
|
867
|
-
handleCopyColumn = (e, cellWrapper, selectedRecords) => {
|
|
868
|
-
const specificColumn = cellWrapper.getAttribute("data-test");
|
|
869
|
-
let rowElsToCopy = getAllRows(e);
|
|
870
|
-
if (!rowElsToCopy) return;
|
|
871
|
-
if (selectedRecords) {
|
|
872
|
-
const ids = selectedRecords.map(e => getIdOrCodeOrIndex(e)?.toString());
|
|
873
|
-
rowElsToCopy = Array.from(rowElsToCopy).filter(rowEl => {
|
|
874
|
-
const id = rowEl.closest(".rt-tr-group")?.getAttribute("data-test-id");
|
|
875
|
-
return id !== undefined && ids.includes(id);
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
if (!rowElsToCopy) return;
|
|
879
|
-
this.handleCopyRows(rowElsToCopy, {
|
|
880
|
-
specificColumn,
|
|
881
|
-
onFinishMsg: "Column Copied"
|
|
882
|
-
});
|
|
883
|
-
};
|
|
884
|
-
handleCopyRows = (
|
|
885
|
-
rowElsToCopy,
|
|
886
|
-
{ specificColumn, onFinishMsg, isDownload } = {}
|
|
887
|
-
) => {
|
|
888
|
-
let textToCopy = [];
|
|
889
|
-
const jsonToCopy = [];
|
|
890
|
-
forEach(rowElsToCopy, rowEl => {
|
|
891
|
-
const [t, j] = this.getRowCopyText(rowEl, { specificColumn });
|
|
892
|
-
textToCopy.push(t);
|
|
893
|
-
jsonToCopy.push(j);
|
|
894
|
-
});
|
|
895
|
-
textToCopy = textToCopy.filter(text => text).join("\n");
|
|
896
|
-
if (!textToCopy) return window.toastr.warning("No text to copy");
|
|
897
|
-
if (isDownload) {
|
|
898
|
-
download(textToCopy.replaceAll("\t", ","), "tableData.csv", "text/csv");
|
|
899
|
-
} else {
|
|
900
|
-
this.handleCopyHelper(
|
|
901
|
-
textToCopy,
|
|
902
|
-
jsonToCopy,
|
|
903
|
-
onFinishMsg || "Row Copied"
|
|
904
|
-
);
|
|
905
|
-
}
|
|
906
|
-
};
|
|
907
|
-
updateEntitiesHelper = (ents, fn) => {
|
|
908
|
-
const { change, reduxFormEntitiesUndoRedoStack = { currentVersion: 0 } } =
|
|
909
|
-
this.props;
|
|
910
|
-
const [nextState, patches, inversePatches] = produceWithPatches(ents, fn);
|
|
911
|
-
if (!inversePatches.length) return;
|
|
912
|
-
const thatNewNew = [...nextState];
|
|
913
|
-
thatNewNew.isDirty = true;
|
|
914
|
-
change("reduxFormEntities", thatNewNew);
|
|
915
|
-
change("reduxFormEntitiesUndoRedoStack", {
|
|
916
|
-
...omitBy(reduxFormEntitiesUndoRedoStack, (v, k) => {
|
|
917
|
-
return toNumber(k) > reduxFormEntitiesUndoRedoStack.currentVersion + 1;
|
|
918
|
-
}),
|
|
919
|
-
currentVersion: reduxFormEntitiesUndoRedoStack.currentVersion + 1,
|
|
920
|
-
[reduxFormEntitiesUndoRedoStack.currentVersion + 1]: {
|
|
921
|
-
inversePatches,
|
|
922
|
-
patches
|
|
923
|
-
}
|
|
924
|
-
});
|
|
925
|
-
};
|
|
926
|
-
|
|
927
|
-
getRowCopyText = (rowEl, { specificColumn } = {}) => {
|
|
928
|
-
//takes in a row element
|
|
929
|
-
if (!rowEl) return [];
|
|
930
|
-
const textContent = [];
|
|
931
|
-
const jsonText = [];
|
|
932
|
-
|
|
933
|
-
forEach(rowEl.children, cellEl => {
|
|
934
|
-
const cellChild = cellEl.querySelector(`[data-copy-text]`);
|
|
935
|
-
if (!cellChild) {
|
|
936
|
-
if (specificColumn) return []; //strip it
|
|
937
|
-
return; //just leave it blank
|
|
938
|
-
}
|
|
939
|
-
if (
|
|
940
|
-
specificColumn &&
|
|
941
|
-
cellChild.getAttribute("data-test") !== specificColumn
|
|
942
|
-
) {
|
|
943
|
-
return [];
|
|
944
|
-
}
|
|
945
|
-
const [t, j] = this.getCellCopyText(cellChild);
|
|
946
|
-
textContent.push(t);
|
|
947
|
-
jsonText.push(j);
|
|
948
|
-
});
|
|
949
|
-
|
|
950
|
-
return [flatMap(textContent).join("\t"), jsonText];
|
|
951
|
-
};
|
|
952
|
-
|
|
953
|
-
handleCopyHelper = (stringToCopy, jsonToCopy, message) => {
|
|
954
|
-
!window.Cypress &&
|
|
955
|
-
copy(stringToCopy, {
|
|
956
|
-
onCopy: clipboardData => {
|
|
957
|
-
clipboardData.setData("application/json", JSON.stringify(jsonToCopy));
|
|
958
|
-
},
|
|
959
|
-
// keep this so that pasting into spreadsheets works.
|
|
960
|
-
format: "text/plain"
|
|
961
|
-
});
|
|
962
|
-
if (message) {
|
|
963
|
-
window.toastr.success(message);
|
|
964
|
-
}
|
|
965
|
-
};
|
|
966
|
-
|
|
967
932
|
handleCopyTable = (e, opts) => {
|
|
968
933
|
try {
|
|
969
934
|
const allRowEls = getAllRows(e);
|
|
970
935
|
if (!allRowEls) return;
|
|
971
|
-
|
|
936
|
+
handleCopyRows(allRowEls, {
|
|
972
937
|
...opts,
|
|
973
938
|
onFinishMsg: "Table Copied"
|
|
974
939
|
});
|
|
@@ -977,6 +942,7 @@ class DataTable extends React.Component {
|
|
|
977
942
|
window.toastr.error("Error copying rows.");
|
|
978
943
|
}
|
|
979
944
|
};
|
|
945
|
+
|
|
980
946
|
handleCopySelectedCells = e => {
|
|
981
947
|
const {
|
|
982
948
|
entities = [],
|
|
@@ -1022,7 +988,7 @@ class DataTable extends React.Component {
|
|
|
1022
988
|
} else {
|
|
1023
989
|
const jsonRow = [];
|
|
1024
990
|
// ignore header
|
|
1025
|
-
let [rowCopyText, json] =
|
|
991
|
+
let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
|
|
1026
992
|
rowCopyText = rowCopyText.split("\t");
|
|
1027
993
|
times(row.length, i => {
|
|
1028
994
|
const cell = row[i];
|
|
@@ -1037,7 +1003,7 @@ class DataTable extends React.Component {
|
|
|
1037
1003
|
});
|
|
1038
1004
|
if (!fullCellText) return window.toastr.warning("No text to copy");
|
|
1039
1005
|
|
|
1040
|
-
|
|
1006
|
+
handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
|
|
1041
1007
|
};
|
|
1042
1008
|
|
|
1043
1009
|
handleCopySelectedRows = (selectedRecords, e) => {
|
|
@@ -1060,7 +1026,7 @@ class DataTable extends React.Component {
|
|
|
1060
1026
|
if (!allRowEls) return;
|
|
1061
1027
|
const rowEls = rowNumbersToCopy.map(i => allRowEls[i]);
|
|
1062
1028
|
|
|
1063
|
-
|
|
1029
|
+
handleCopyRows(rowEls, {
|
|
1064
1030
|
onFinishMsg: "Selected rows copied"
|
|
1065
1031
|
});
|
|
1066
1032
|
} catch (error) {
|
|
@@ -1117,25 +1083,42 @@ class DataTable extends React.Component {
|
|
|
1117
1083
|
/>
|
|
1118
1084
|
);
|
|
1119
1085
|
};
|
|
1086
|
+
|
|
1120
1087
|
getThComponent = compose(
|
|
1121
1088
|
withProps(props => {
|
|
1122
1089
|
const { columnindex } = props;
|
|
1123
1090
|
return {
|
|
1124
|
-
index: columnindex
|
|
1091
|
+
index: columnindex ?? -1
|
|
1125
1092
|
};
|
|
1126
|
-
})
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1093
|
+
})
|
|
1094
|
+
)(({ toggleSort, immovable, className, children, style, ...rest }) => {
|
|
1095
|
+
const { attributes, listeners, setNodeRef, transform, transition } =
|
|
1096
|
+
useSortable({
|
|
1097
|
+
id: `${rest.index}`,
|
|
1098
|
+
disabled: immovable === "true"
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
const sortStyles = {
|
|
1102
|
+
transform: CSS.Transform.toString(transform),
|
|
1103
|
+
transition
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
return (
|
|
1107
|
+
<div
|
|
1108
|
+
style={{ ...sortStyles, ...style }}
|
|
1109
|
+
ref={setNodeRef}
|
|
1110
|
+
{...attributes}
|
|
1111
|
+
{...listeners}
|
|
1112
|
+
className={classNames("rt-th", className)}
|
|
1113
|
+
onClick={e => toggleSort && toggleSort(e)}
|
|
1114
|
+
role="columnheader"
|
|
1115
|
+
tabIndex="-1" // Resolves eslint issues without implementing keyboard navigation incorrectly
|
|
1116
|
+
{...rest}
|
|
1117
|
+
>
|
|
1118
|
+
{children}
|
|
1119
|
+
</div>
|
|
1120
|
+
);
|
|
1121
|
+
});
|
|
1139
1122
|
|
|
1140
1123
|
addEntitiesToSelection = entities => {
|
|
1141
1124
|
const propPresets = computePresets(this.props);
|
|
@@ -1319,7 +1302,11 @@ class DataTable extends React.Component {
|
|
|
1319
1302
|
icon="fullscreen"
|
|
1320
1303
|
active={fullscreen}
|
|
1321
1304
|
minimal
|
|
1322
|
-
onClick={
|
|
1305
|
+
onClick={() => {
|
|
1306
|
+
this.setState({
|
|
1307
|
+
fullscreen: !this.state.fullscreen
|
|
1308
|
+
});
|
|
1309
|
+
}}
|
|
1323
1310
|
/>
|
|
1324
1311
|
);
|
|
1325
1312
|
|
|
@@ -1474,24 +1461,17 @@ class DataTable extends React.Component {
|
|
|
1474
1461
|
{...(isCellEditable && {
|
|
1475
1462
|
tabIndex: -1,
|
|
1476
1463
|
onKeyDown: e => {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
// if (isArrowKey && e.target?.tagName !== "INPUT") {
|
|
1480
|
-
const isTabKey = e.keyCode === 9;
|
|
1481
|
-
// const isEnter = e.keyCode === 13;
|
|
1482
|
-
// console.log(`onKeydown datatable inner`);
|
|
1483
|
-
// console.log(`isEnter:`, isEnter)
|
|
1484
|
-
const isArrowKey = e.keyCode >= 37 && e.keyCode <= 40;
|
|
1485
|
-
// console.log(`e.target?.tagName:`,e.target?.tagName)
|
|
1464
|
+
const isTabKey = e.key === "Tab";
|
|
1465
|
+
const isArrowKey = e.key.startsWith("Arrow");
|
|
1486
1466
|
if (
|
|
1487
1467
|
(isArrowKey && e.target?.tagName !== "INPUT") ||
|
|
1488
1468
|
isTabKey
|
|
1489
1469
|
// || (isEnter && e.target?.tagName === "INPUT")
|
|
1490
1470
|
) {
|
|
1491
1471
|
const { schema, entities } = computePresets(this.props);
|
|
1492
|
-
const left = e.
|
|
1493
|
-
const up = e.
|
|
1494
|
-
const down = e.
|
|
1472
|
+
const left = e.key === "ArrowLeft";
|
|
1473
|
+
const up = e.key === "ArrowUp";
|
|
1474
|
+
const down = e.key === "ArrowDown" || e.key === "Enter";
|
|
1495
1475
|
let cellIdToUse = this.getPrimarySelectedCellId();
|
|
1496
1476
|
const pathToIndex = getFieldPathToIndex(schema);
|
|
1497
1477
|
const entityMap = getEntityIdToEntity(entities);
|
|
@@ -1584,13 +1564,23 @@ class DataTable extends React.Component {
|
|
|
1584
1564
|
const entity = entityIdToEntity[rowId].e;
|
|
1585
1565
|
if (!entity) return;
|
|
1586
1566
|
const rowDisabled = isEntityDisabled(entity);
|
|
1587
|
-
const isNum = e.
|
|
1588
|
-
const isLetter = e.
|
|
1589
|
-
if (!isNum && !isLetter)
|
|
1567
|
+
const isNum = e.code?.startsWith("Digit");
|
|
1568
|
+
const isLetter = e.code?.startsWith("Key");
|
|
1569
|
+
if (!isNum && !isLetter) {
|
|
1570
|
+
this.setState(prev => ({
|
|
1571
|
+
...prev,
|
|
1572
|
+
editableCellInitialValue: ""
|
|
1573
|
+
}));
|
|
1574
|
+
return;
|
|
1575
|
+
} else {
|
|
1576
|
+
this.setState(prev => ({
|
|
1577
|
+
...prev,
|
|
1578
|
+
editableCellInitialValue: e.key
|
|
1579
|
+
}));
|
|
1580
|
+
}
|
|
1590
1581
|
if (rowDisabled) return;
|
|
1591
1582
|
this.startCellEdit(cellId, { shouldSelectAll: true });
|
|
1592
1583
|
e.stopPropagation();
|
|
1593
|
-
// e.preventDefault();
|
|
1594
1584
|
}
|
|
1595
1585
|
})}
|
|
1596
1586
|
>
|
|
@@ -1730,10 +1720,7 @@ class DataTable extends React.Component {
|
|
|
1730
1720
|
)}
|
|
1731
1721
|
<ReactTable
|
|
1732
1722
|
data={filteredEnts}
|
|
1733
|
-
ref={
|
|
1734
|
-
if (n) this.table = n;
|
|
1735
|
-
}}
|
|
1736
|
-
// additionalBodyEl={}
|
|
1723
|
+
ref={this.tableRef}
|
|
1737
1724
|
className={classNames({
|
|
1738
1725
|
isCellEditable,
|
|
1739
1726
|
"tg-table-loading": isLoading,
|
|
@@ -1820,7 +1807,7 @@ class DataTable extends React.Component {
|
|
|
1820
1807
|
data-tip="Download Table as CSV"
|
|
1821
1808
|
minimal
|
|
1822
1809
|
icon="download"
|
|
1823
|
-
|
|
1810
|
+
/>
|
|
1824
1811
|
</div>
|
|
1825
1812
|
)}
|
|
1826
1813
|
{!noFooter && (
|
|
@@ -1965,24 +1952,6 @@ class DataTable extends React.Component {
|
|
|
1965
1952
|
};
|
|
1966
1953
|
};
|
|
1967
1954
|
|
|
1968
|
-
startCellEdit = (cellId, { shouldSelectAll } = {}) => {
|
|
1969
|
-
const {
|
|
1970
|
-
change,
|
|
1971
|
-
reduxFormSelectedCells = {},
|
|
1972
|
-
reduxFormEditingCell
|
|
1973
|
-
} = computePresets(this.props);
|
|
1974
|
-
const newSelectedCells = { ...reduxFormSelectedCells };
|
|
1975
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1976
|
-
//check if the cell is already selected and editing and if so, don't change it
|
|
1977
|
-
if (reduxFormEditingCell === cellId) return;
|
|
1978
|
-
change("reduxFormSelectedCells", newSelectedCells);
|
|
1979
|
-
change("reduxFormEditingCell", cellId);
|
|
1980
|
-
if (shouldSelectAll) {
|
|
1981
|
-
//we should select the text
|
|
1982
|
-
change("reduxFormEditingCellSelectAll", true);
|
|
1983
|
-
}
|
|
1984
|
-
};
|
|
1985
|
-
|
|
1986
1955
|
getTableCellProps = (state, rowInfo, column) => {
|
|
1987
1956
|
const {
|
|
1988
1957
|
entities,
|
|
@@ -2178,6 +2147,7 @@ class DataTable extends React.Component {
|
|
|
2178
2147
|
|
|
2179
2148
|
change("reduxFormSelectedCells", newSelectedCells);
|
|
2180
2149
|
};
|
|
2150
|
+
|
|
2181
2151
|
renderCheckboxHeader = () => {
|
|
2182
2152
|
const {
|
|
2183
2153
|
reduxFormSelectedEntityIdMap,
|
|
@@ -2300,9 +2270,10 @@ class DataTable extends React.Component {
|
|
|
2300
2270
|
change("reduxFormEditingCell", null);
|
|
2301
2271
|
this.refocusTable();
|
|
2302
2272
|
};
|
|
2273
|
+
|
|
2303
2274
|
refocusTable = () => {
|
|
2304
2275
|
setTimeout(() => {
|
|
2305
|
-
const table =
|
|
2276
|
+
const table = this.tableRef.current?.tableRef?.closest(
|
|
2306
2277
|
".data-table-container>div"
|
|
2307
2278
|
);
|
|
2308
2279
|
table?.focus();
|
|
@@ -2579,7 +2550,6 @@ class DataTable extends React.Component {
|
|
|
2579
2550
|
<Checkbox
|
|
2580
2551
|
disabled={isEntityDisabled(row.original)}
|
|
2581
2552
|
className="tg-cell-edit-boolean-checkbox"
|
|
2582
|
-
// {...dataTest}
|
|
2583
2553
|
checked={oldVal === "True"}
|
|
2584
2554
|
onChange={e => {
|
|
2585
2555
|
const checked = e.target.checked;
|
|
@@ -2589,9 +2559,6 @@ class DataTable extends React.Component {
|
|
|
2589
2559
|
);
|
|
2590
2560
|
noEllipsis = true;
|
|
2591
2561
|
} else {
|
|
2592
|
-
// if (column.type === "genericSelect") {
|
|
2593
|
-
// val =
|
|
2594
|
-
// }
|
|
2595
2562
|
if (reduxFormEditingCell === cellId) {
|
|
2596
2563
|
if (column.type === "genericSelect") {
|
|
2597
2564
|
const GenericSelectComp = column.GenericSelectComp;
|
|
@@ -2622,7 +2589,7 @@ class DataTable extends React.Component {
|
|
|
2622
2589
|
}}
|
|
2623
2590
|
dataTest={dataTest}
|
|
2624
2591
|
cancelEdit={this.cancelCellEdit}
|
|
2625
|
-
|
|
2592
|
+
/>
|
|
2626
2593
|
);
|
|
2627
2594
|
} else {
|
|
2628
2595
|
return (
|
|
@@ -2634,11 +2601,18 @@ class DataTable extends React.Component {
|
|
|
2634
2601
|
shouldSelectAll={reduxFormEditingCellSelectAll}
|
|
2635
2602
|
cancelEdit={this.cancelCellEdit}
|
|
2636
2603
|
isNumeric={column.type === "number"}
|
|
2637
|
-
initialValue={
|
|
2604
|
+
initialValue={
|
|
2605
|
+
this.state.editableCellInitialValue.length
|
|
2606
|
+
? this.state.editableCellInitialValue
|
|
2607
|
+
: text
|
|
2608
|
+
}
|
|
2609
|
+
isEditableCellInitialValue={
|
|
2610
|
+
!!this.state.editableCellInitialValue.length
|
|
2611
|
+
}
|
|
2638
2612
|
finishEdit={newVal => {
|
|
2639
2613
|
this.finishCellEdit(cellId, newVal);
|
|
2640
2614
|
}}
|
|
2641
|
-
|
|
2615
|
+
/>
|
|
2642
2616
|
);
|
|
2643
2617
|
}
|
|
2644
2618
|
}
|
|
@@ -2710,7 +2684,7 @@ class DataTable extends React.Component {
|
|
|
2710
2684
|
|
|
2711
2685
|
{isSelectedCell &&
|
|
2712
2686
|
(isRect
|
|
2713
|
-
?
|
|
2687
|
+
? isBottomRightCornerOfRectangle({
|
|
2714
2688
|
cellId,
|
|
2715
2689
|
selectionGrid,
|
|
2716
2690
|
lastRowIndex,
|
|
@@ -2721,11 +2695,11 @@ class DataTable extends React.Component {
|
|
|
2721
2695
|
: isSelectedCell === PRIMARY_SELECTED_VAL) && (
|
|
2722
2696
|
<CellDragHandle
|
|
2723
2697
|
key={cellId}
|
|
2724
|
-
thisTable={this.
|
|
2698
|
+
thisTable={this.tableRef.current.tableRef}
|
|
2725
2699
|
cellId={cellId}
|
|
2726
2700
|
isSelectionARectangle={this.isSelectionARectangle}
|
|
2727
2701
|
onDragEnd={this.onDragEnd}
|
|
2728
|
-
|
|
2702
|
+
/>
|
|
2729
2703
|
)}
|
|
2730
2704
|
</>
|
|
2731
2705
|
);
|
|
@@ -2735,26 +2709,6 @@ class DataTable extends React.Component {
|
|
|
2735
2709
|
});
|
|
2736
2710
|
return columnsToRender;
|
|
2737
2711
|
};
|
|
2738
|
-
isBottomRightCornerOfRectangle = ({
|
|
2739
|
-
cellId,
|
|
2740
|
-
selectionGrid,
|
|
2741
|
-
lastRowIndex,
|
|
2742
|
-
lastCellIndex,
|
|
2743
|
-
entityMap,
|
|
2744
|
-
pathToIndex
|
|
2745
|
-
}) => {
|
|
2746
|
-
selectionGrid.forEach(row => {
|
|
2747
|
-
// remove undefineds from start of row
|
|
2748
|
-
while (row[0] === undefined && row.length) row.shift();
|
|
2749
|
-
});
|
|
2750
|
-
const [rowId, cellPath] = cellId.split(":");
|
|
2751
|
-
const ent = entityMap[rowId];
|
|
2752
|
-
if (!ent) return;
|
|
2753
|
-
const { i } = ent;
|
|
2754
|
-
const cellIndex = pathToIndex[cellPath];
|
|
2755
|
-
const isBottomRight = i === lastRowIndex && cellIndex === lastCellIndex;
|
|
2756
|
-
return isBottomRight;
|
|
2757
|
-
};
|
|
2758
2712
|
|
|
2759
2713
|
onDragEnd = cellsToSelect => {
|
|
2760
2714
|
const {
|
|
@@ -2959,6 +2913,7 @@ class DataTable extends React.Component {
|
|
|
2959
2913
|
change("reduxFormSelectedCells", newReduxFormSelectedCells);
|
|
2960
2914
|
});
|
|
2961
2915
|
};
|
|
2916
|
+
|
|
2962
2917
|
getCopyTextForCell = (val, row = {}, column = {}) => {
|
|
2963
2918
|
const { cellRenderer } = computePresets(this.props);
|
|
2964
2919
|
// TODOCOPY we need a way to potentially omit certain columns from being added as a \t element (talk to taoh about this)
|
|
@@ -3044,6 +2999,7 @@ class DataTable extends React.Component {
|
|
|
3044
2999
|
});
|
|
3045
3000
|
});
|
|
3046
3001
|
};
|
|
3002
|
+
|
|
3047
3003
|
getEditableTableInfoAndThrowFormError = () => {
|
|
3048
3004
|
const { schema, reduxFormEntities, reduxFormCellValidation } =
|
|
3049
3005
|
computePresets(this.props);
|
|
@@ -3153,12 +3109,12 @@ class DataTable extends React.Component {
|
|
|
3153
3109
|
//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
|
|
3154
3110
|
//do we need to be able to copy hidden cells? It seems like it should just copy what's on the page..?
|
|
3155
3111
|
const specificColumn = cellWrapper.getAttribute("data-test");
|
|
3156
|
-
|
|
3112
|
+
handleCopyRows([cellWrapper.closest(".rt-tr")], {
|
|
3157
3113
|
specificColumn,
|
|
3158
3114
|
onFinishMsg: "Cell copied"
|
|
3159
3115
|
});
|
|
3160
|
-
const [text, jsonText] =
|
|
3161
|
-
|
|
3116
|
+
const [text, jsonText] = getCellCopyText(cellWrapper);
|
|
3117
|
+
handleCopyHelper(text, jsonText);
|
|
3162
3118
|
}}
|
|
3163
3119
|
text="Cell"
|
|
3164
3120
|
/>
|
|
@@ -3168,7 +3124,7 @@ class DataTable extends React.Component {
|
|
|
3168
3124
|
<MenuItem
|
|
3169
3125
|
key="copyColumn"
|
|
3170
3126
|
onClick={() => {
|
|
3171
|
-
|
|
3127
|
+
handleCopyColumn(e, cellWrapper);
|
|
3172
3128
|
}}
|
|
3173
3129
|
text="Column"
|
|
3174
3130
|
/>
|
|
@@ -3178,7 +3134,7 @@ class DataTable extends React.Component {
|
|
|
3178
3134
|
<MenuItem
|
|
3179
3135
|
key="copyColumnSelected"
|
|
3180
3136
|
onClick={() => {
|
|
3181
|
-
|
|
3137
|
+
handleCopyColumn(e, cellWrapper, selectedRecords);
|
|
3182
3138
|
}}
|
|
3183
3139
|
text="Column (Selected)"
|
|
3184
3140
|
/>
|
|
@@ -3196,7 +3152,7 @@ class DataTable extends React.Component {
|
|
|
3196
3152
|
<MenuItem
|
|
3197
3153
|
key="copySelectedRows"
|
|
3198
3154
|
onClick={() => {
|
|
3199
|
-
|
|
3155
|
+
handleCopyRows([row]);
|
|
3200
3156
|
// loop through each cell in the row
|
|
3201
3157
|
}}
|
|
3202
3158
|
text="Row"
|
|
@@ -3247,7 +3203,7 @@ class DataTable extends React.Component {
|
|
|
3247
3203
|
onClick={() => {
|
|
3248
3204
|
this.insertRows({ above: true });
|
|
3249
3205
|
}}
|
|
3250
|
-
|
|
3206
|
+
/>
|
|
3251
3207
|
<MenuItem
|
|
3252
3208
|
icon="add-row-top"
|
|
3253
3209
|
text="Add Row Below"
|
|
@@ -3255,7 +3211,7 @@ class DataTable extends React.Component {
|
|
|
3255
3211
|
onClick={() => {
|
|
3256
3212
|
this.insertRows({});
|
|
3257
3213
|
}}
|
|
3258
|
-
|
|
3214
|
+
/>
|
|
3259
3215
|
<MenuItem
|
|
3260
3216
|
icon="remove"
|
|
3261
3217
|
text={`Remove Row${selectedRowIds.length > 1 ? "s" : ""}`}
|
|
@@ -3445,7 +3401,7 @@ class DataTable extends React.Component {
|
|
|
3445
3401
|
}}
|
|
3446
3402
|
indeterminate={isIndeterminate}
|
|
3447
3403
|
checked={isChecked}
|
|
3448
|
-
|
|
3404
|
+
/>
|
|
3449
3405
|
);
|
|
3450
3406
|
}
|
|
3451
3407
|
|
|
@@ -3470,7 +3426,7 @@ class DataTable extends React.Component {
|
|
|
3470
3426
|
})}
|
|
3471
3427
|
>
|
|
3472
3428
|
{columnTitleTextified && !noTitle && (
|
|
3473
|
-
|
|
3429
|
+
<>
|
|
3474
3430
|
{maybeCheckbox}
|
|
3475
3431
|
<span
|
|
3476
3432
|
title={columnTitleTextified}
|
|
@@ -3485,7 +3441,7 @@ class DataTable extends React.Component {
|
|
|
3485
3441
|
>
|
|
3486
3442
|
{renderTitleInner ? renderTitleInner : columnTitle}{" "}
|
|
3487
3443
|
</span>
|
|
3488
|
-
|
|
3444
|
+
</>
|
|
3489
3445
|
)}
|
|
3490
3446
|
<div
|
|
3491
3447
|
style={{ display: "flex", marginLeft: "auto", alignItems: "center" }}
|
|
@@ -3507,333 +3463,3 @@ const WrappedDT = dataTableEnhancer(DataTable);
|
|
|
3507
3463
|
export default WrappedDT;
|
|
3508
3464
|
const ConnectedPagingTool = dataTableEnhancer(PagingTool);
|
|
3509
3465
|
export { ConnectedPagingTool };
|
|
3510
|
-
|
|
3511
|
-
const itemSizeEstimators = {
|
|
3512
|
-
compact: () => 25.34,
|
|
3513
|
-
normal: () => 33.34,
|
|
3514
|
-
comfortable: () => 41.34
|
|
3515
|
-
};
|
|
3516
|
-
|
|
3517
|
-
function getCellInfo({
|
|
3518
|
-
columnIndex,
|
|
3519
|
-
columnPath,
|
|
3520
|
-
rowId,
|
|
3521
|
-
schema,
|
|
3522
|
-
entities,
|
|
3523
|
-
rowIndex,
|
|
3524
|
-
isEntityDisabled,
|
|
3525
|
-
entity
|
|
3526
|
-
}) {
|
|
3527
|
-
const leftpath = schema.fields[columnIndex - 1]?.path;
|
|
3528
|
-
const rightpath = schema.fields[columnIndex + 1]?.path;
|
|
3529
|
-
const cellIdToLeft = leftpath && `${rowId}:${leftpath}`;
|
|
3530
|
-
const cellIdToRight = rightpath && `${rowId}:${rightpath}`;
|
|
3531
|
-
const rowAboveId =
|
|
3532
|
-
entities[rowIndex - 1] &&
|
|
3533
|
-
getIdOrCodeOrIndex(entities[rowIndex - 1], rowIndex - 1);
|
|
3534
|
-
const rowBelowId =
|
|
3535
|
-
entities[rowIndex + 1] &&
|
|
3536
|
-
getIdOrCodeOrIndex(entities[rowIndex + 1], rowIndex + 1);
|
|
3537
|
-
const cellIdAbove = rowAboveId && `${rowAboveId}:${columnPath}`;
|
|
3538
|
-
const cellIdBelow = rowBelowId && `${rowBelowId}:${columnPath}`;
|
|
3539
|
-
|
|
3540
|
-
const cellId = `${rowId}:${columnPath}`;
|
|
3541
|
-
const rowDisabled = isEntityDisabled(entity);
|
|
3542
|
-
return {
|
|
3543
|
-
cellId,
|
|
3544
|
-
cellIdAbove,
|
|
3545
|
-
cellIdToRight,
|
|
3546
|
-
cellIdBelow,
|
|
3547
|
-
cellIdToLeft,
|
|
3548
|
-
rowDisabled
|
|
3549
|
-
};
|
|
3550
|
-
}
|
|
3551
|
-
|
|
3552
|
-
function ColumnFilterMenu({
|
|
3553
|
-
FilterMenu,
|
|
3554
|
-
filterActiveForColumn,
|
|
3555
|
-
compact,
|
|
3556
|
-
extraCompact,
|
|
3557
|
-
...rest
|
|
3558
|
-
}) {
|
|
3559
|
-
const [columnFilterMenuOpen, setColumnFilterMenuOpen] = useState(false);
|
|
3560
|
-
return (
|
|
3561
|
-
<Popover
|
|
3562
|
-
position="bottom"
|
|
3563
|
-
onClose={() => {
|
|
3564
|
-
setColumnFilterMenuOpen(false);
|
|
3565
|
-
}}
|
|
3566
|
-
isOpen={columnFilterMenuOpen}
|
|
3567
|
-
modifiers={{
|
|
3568
|
-
preventOverflow: { enabled: true },
|
|
3569
|
-
hide: { enabled: false },
|
|
3570
|
-
flip: { enabled: false }
|
|
3571
|
-
}}
|
|
3572
|
-
>
|
|
3573
|
-
<Icon
|
|
3574
|
-
style={{ marginLeft: 5 }}
|
|
3575
|
-
icon="filter"
|
|
3576
|
-
iconSize={extraCompact ? 14 : undefined}
|
|
3577
|
-
onClick={() => {
|
|
3578
|
-
setColumnFilterMenuOpen(!columnFilterMenuOpen);
|
|
3579
|
-
}}
|
|
3580
|
-
className={classNames("tg-filter-menu-button", {
|
|
3581
|
-
"tg-active-filter": !!filterActiveForColumn
|
|
3582
|
-
})}
|
|
3583
|
-
/>
|
|
3584
|
-
<FilterMenu
|
|
3585
|
-
togglePopover={() => {
|
|
3586
|
-
setColumnFilterMenuOpen(false);
|
|
3587
|
-
}}
|
|
3588
|
-
{...rest}
|
|
3589
|
-
/>
|
|
3590
|
-
</Popover>
|
|
3591
|
-
);
|
|
3592
|
-
}
|
|
3593
|
-
|
|
3594
|
-
function getLastSelectedEntity(idMap) {
|
|
3595
|
-
let lastSelectedEnt;
|
|
3596
|
-
let latestTime;
|
|
3597
|
-
forEach(idMap, ({ time, entity }) => {
|
|
3598
|
-
if (!latestTime || time > latestTime) {
|
|
3599
|
-
lastSelectedEnt = entity;
|
|
3600
|
-
latestTime = time;
|
|
3601
|
-
}
|
|
3602
|
-
});
|
|
3603
|
-
return lastSelectedEnt;
|
|
3604
|
-
}
|
|
3605
|
-
|
|
3606
|
-
function getNewEntToSelect({
|
|
3607
|
-
type,
|
|
3608
|
-
lastSelectedIndex,
|
|
3609
|
-
entities,
|
|
3610
|
-
isEntityDisabled
|
|
3611
|
-
}) {
|
|
3612
|
-
let newIndexToSelect;
|
|
3613
|
-
if (type === "up") {
|
|
3614
|
-
newIndexToSelect = lastSelectedIndex - 1;
|
|
3615
|
-
} else {
|
|
3616
|
-
newIndexToSelect = lastSelectedIndex + 1;
|
|
3617
|
-
}
|
|
3618
|
-
const newEntToSelect = entities[newIndexToSelect];
|
|
3619
|
-
if (!newEntToSelect) return;
|
|
3620
|
-
if (isEntityDisabled && isEntityDisabled(newEntToSelect)) {
|
|
3621
|
-
return getNewEntToSelect({
|
|
3622
|
-
type,
|
|
3623
|
-
lastSelectedIndex: newIndexToSelect,
|
|
3624
|
-
entities,
|
|
3625
|
-
isEntityDisabled
|
|
3626
|
-
});
|
|
3627
|
-
} else {
|
|
3628
|
-
return newEntToSelect;
|
|
3629
|
-
}
|
|
3630
|
-
}
|
|
3631
|
-
|
|
3632
|
-
function getAllRows(e) {
|
|
3633
|
-
const el = e.target.querySelector(".data-table-container")
|
|
3634
|
-
? e.target.querySelector(".data-table-container")
|
|
3635
|
-
: e.target.closest(".data-table-container");
|
|
3636
|
-
|
|
3637
|
-
const allRowEls = el.querySelectorAll(".rt-tr");
|
|
3638
|
-
if (!allRowEls || !allRowEls.length) {
|
|
3639
|
-
return;
|
|
3640
|
-
}
|
|
3641
|
-
return allRowEls;
|
|
3642
|
-
}
|
|
3643
|
-
|
|
3644
|
-
function EditableCell({
|
|
3645
|
-
shouldSelectAll,
|
|
3646
|
-
stopSelectAll,
|
|
3647
|
-
initialValue,
|
|
3648
|
-
finishEdit,
|
|
3649
|
-
cancelEdit,
|
|
3650
|
-
isNumeric,
|
|
3651
|
-
dataTest
|
|
3652
|
-
}) {
|
|
3653
|
-
const [v, setV] = useState(initialValue);
|
|
3654
|
-
return (
|
|
3655
|
-
<input
|
|
3656
|
-
style={{
|
|
3657
|
-
border: 0,
|
|
3658
|
-
width: "95%",
|
|
3659
|
-
fontSize: 12,
|
|
3660
|
-
background: "none"
|
|
3661
|
-
}}
|
|
3662
|
-
ref={r => {
|
|
3663
|
-
if (shouldSelectAll && r) {
|
|
3664
|
-
r?.select();
|
|
3665
|
-
stopSelectAll();
|
|
3666
|
-
}
|
|
3667
|
-
}}
|
|
3668
|
-
{...dataTest}
|
|
3669
|
-
type={isNumeric ? "number" : undefined}
|
|
3670
|
-
value={v}
|
|
3671
|
-
autoFocus
|
|
3672
|
-
onKeyDown={e => {
|
|
3673
|
-
if (e.key === "Enter") {
|
|
3674
|
-
finishEdit(v);
|
|
3675
|
-
e.stopPropagation();
|
|
3676
|
-
} else if (e.key === "Escape") {
|
|
3677
|
-
e.stopPropagation();
|
|
3678
|
-
cancelEdit();
|
|
3679
|
-
}
|
|
3680
|
-
}}
|
|
3681
|
-
onBlur={() => {
|
|
3682
|
-
finishEdit(v);
|
|
3683
|
-
}}
|
|
3684
|
-
onChange={e => {
|
|
3685
|
-
setV(e.target.value);
|
|
3686
|
-
}}
|
|
3687
|
-
></input>
|
|
3688
|
-
);
|
|
3689
|
-
}
|
|
3690
|
-
|
|
3691
|
-
function DropdownCell({
|
|
3692
|
-
options,
|
|
3693
|
-
isMulti,
|
|
3694
|
-
initialValue,
|
|
3695
|
-
finishEdit,
|
|
3696
|
-
cancelEdit,
|
|
3697
|
-
dataTest
|
|
3698
|
-
}) {
|
|
3699
|
-
const [v, setV] = useState(
|
|
3700
|
-
isMulti
|
|
3701
|
-
? initialValue.split(",").map(v => ({ value: v, label: v }))
|
|
3702
|
-
: initialValue
|
|
3703
|
-
);
|
|
3704
|
-
return (
|
|
3705
|
-
<div
|
|
3706
|
-
className={classNames("tg-dropdown-cell-edit-container", {
|
|
3707
|
-
"tg-dropdown-cell-edit-container-multi": isMulti
|
|
3708
|
-
})}
|
|
3709
|
-
>
|
|
3710
|
-
<TgSelect
|
|
3711
|
-
small
|
|
3712
|
-
multi={isMulti}
|
|
3713
|
-
autoOpen
|
|
3714
|
-
value={v}
|
|
3715
|
-
onChange={val => {
|
|
3716
|
-
if (isMulti) {
|
|
3717
|
-
setV(val);
|
|
3718
|
-
return;
|
|
3719
|
-
}
|
|
3720
|
-
finishEdit(val ? val.value : null);
|
|
3721
|
-
}}
|
|
3722
|
-
{...dataTest}
|
|
3723
|
-
popoverProps={{
|
|
3724
|
-
onClose: e => {
|
|
3725
|
-
if (isMulti) {
|
|
3726
|
-
if (e && e.key === "Escape") {
|
|
3727
|
-
cancelEdit();
|
|
3728
|
-
} else {
|
|
3729
|
-
finishEdit(
|
|
3730
|
-
v && v.map
|
|
3731
|
-
? v
|
|
3732
|
-
.map(v => v.value)
|
|
3733
|
-
.filter(v => v)
|
|
3734
|
-
.join(",")
|
|
3735
|
-
: v
|
|
3736
|
-
);
|
|
3737
|
-
}
|
|
3738
|
-
} else {
|
|
3739
|
-
cancelEdit();
|
|
3740
|
-
}
|
|
3741
|
-
}
|
|
3742
|
-
}}
|
|
3743
|
-
options={options.map(value => ({ label: value, value }))}
|
|
3744
|
-
></TgSelect>
|
|
3745
|
-
</div>
|
|
3746
|
-
);
|
|
3747
|
-
}
|
|
3748
|
-
|
|
3749
|
-
function getFieldPathToIndex(schema) {
|
|
3750
|
-
const fieldToIndex = {};
|
|
3751
|
-
schema.fields.forEach((f, i) => {
|
|
3752
|
-
fieldToIndex[f.path] = i;
|
|
3753
|
-
});
|
|
3754
|
-
return fieldToIndex;
|
|
3755
|
-
}
|
|
3756
|
-
|
|
3757
|
-
function getFieldPathToField(schema) {
|
|
3758
|
-
const fieldPathToField = {};
|
|
3759
|
-
schema.fields.forEach(f => {
|
|
3760
|
-
fieldPathToField[f.path] = f;
|
|
3761
|
-
});
|
|
3762
|
-
return fieldPathToField;
|
|
3763
|
-
}
|
|
3764
|
-
|
|
3765
|
-
const defaultParsePaste = str => {
|
|
3766
|
-
return str.split(/\r\n|\n|\r/).map(row => row.split("\t"));
|
|
3767
|
-
};
|
|
3768
|
-
|
|
3769
|
-
function getEntityIdToEntity(entities) {
|
|
3770
|
-
const entityIdToEntity = {};
|
|
3771
|
-
entities.forEach((e, i) => {
|
|
3772
|
-
entityIdToEntity[getIdOrCodeOrIndex(e, i)] = { e, i };
|
|
3773
|
-
});
|
|
3774
|
-
return entityIdToEntity;
|
|
3775
|
-
}
|
|
3776
|
-
|
|
3777
|
-
function endsWithNumber(str) {
|
|
3778
|
-
return /[0-9]+$/.test(str);
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
function getNumberStrAtEnd(str) {
|
|
3782
|
-
if (endsWithNumber(str)) {
|
|
3783
|
-
return str.match(/[0-9]+$/)[0];
|
|
3784
|
-
}
|
|
3785
|
-
|
|
3786
|
-
return null;
|
|
3787
|
-
}
|
|
3788
|
-
|
|
3789
|
-
function stripNumberAtEnd(str) {
|
|
3790
|
-
return str?.replace?.(getNumberStrAtEnd(str), "");
|
|
3791
|
-
}
|
|
3792
|
-
|
|
3793
|
-
export function isEntityClean(e) {
|
|
3794
|
-
let isClean = true;
|
|
3795
|
-
some(e, (val, key) => {
|
|
3796
|
-
if (key === "id") return;
|
|
3797
|
-
if (key === "_isClean") return;
|
|
3798
|
-
if (val) {
|
|
3799
|
-
isClean = false;
|
|
3800
|
-
return true;
|
|
3801
|
-
}
|
|
3802
|
-
});
|
|
3803
|
-
return isClean;
|
|
3804
|
-
}
|
|
3805
|
-
|
|
3806
|
-
const formatPasteData = ({ schema, newVal, path }) => {
|
|
3807
|
-
const pathToField = getFieldPathToField(schema);
|
|
3808
|
-
const column = pathToField[path];
|
|
3809
|
-
if (column.type === "genericSelect") {
|
|
3810
|
-
if (newVal?.__genSelCol === path) {
|
|
3811
|
-
newVal = newVal.__strVal;
|
|
3812
|
-
} else {
|
|
3813
|
-
newVal = undefined;
|
|
3814
|
-
}
|
|
3815
|
-
} else {
|
|
3816
|
-
newVal = Object.hasOwn(newVal, "__strVal") ? newVal.__strVal : newVal;
|
|
3817
|
-
}
|
|
3818
|
-
return newVal;
|
|
3819
|
-
};
|
|
3820
|
-
|
|
3821
|
-
export function removeCleanRows(reduxFormEntities, reduxFormCellValidation) {
|
|
3822
|
-
const toFilterOut = {};
|
|
3823
|
-
const entsToUse = (reduxFormEntities || []).filter(e => {
|
|
3824
|
-
if (!(e._isClean || isEntityClean(e))) return true;
|
|
3825
|
-
else {
|
|
3826
|
-
toFilterOut[getIdOrCodeOrIndex(e)] = true;
|
|
3827
|
-
return false;
|
|
3828
|
-
}
|
|
3829
|
-
});
|
|
3830
|
-
|
|
3831
|
-
const validationToUse = {};
|
|
3832
|
-
forEach(reduxFormCellValidation, (v, k) => {
|
|
3833
|
-
const [rowId] = k.split(":");
|
|
3834
|
-
if (!toFilterOut[rowId]) {
|
|
3835
|
-
validationToUse[k] = v;
|
|
3836
|
-
}
|
|
3837
|
-
});
|
|
3838
|
-
return { entsToUse, validationToUse };
|
|
3839
|
-
}
|