@teselagen/ui 0.5.19 → 0.5.20
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 +5 -0
- package/DataTable/utils/getIdOrCodeOrIndex.d.ts +2 -1
- package/DataTable/utils/rowClick.d.ts +2 -10
- package/FormComponents/Uploader.d.ts +1 -29
- package/index.cjs.js +6639 -6640
- package/index.d.ts +2 -2
- package/index.es.js +6636 -6637
- package/package.json +3 -1
- package/src/DataTable/CellDragHandle.js +7 -6
- package/src/DataTable/PagingTool.js +1 -1
- package/src/DataTable/index.js +779 -389
- package/src/DataTable/utils/getIdOrCodeOrIndex.js +1 -1
- package/src/DataTable/utils/rowClick.js +4 -7
- package/src/DataTable/utils/selection.js +1 -1
- package/src/DataTable/validateTableWideErrors.js +1 -1
- package/src/FillWindow.js +3 -2
- package/src/FormComponents/Uploader.js +400 -400
- package/src/FormComponents/tryToMatchSchemas.js +6 -0
- package/src/UploadCsvWizard.js +371 -312
- package/src/index.js +3 -3
- package/src/showDialogOnDocBody.js +9 -5
- package/src/useDialog.js +4 -7
- package/src/utils/renderOnDoc.js +5 -8
- package/style.css +7 -7
- package/utils/renderOnDoc.d.ts +1 -1
- package/src/ExcelCell.js +0 -38
package/src/DataTable/index.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint react/jsx-no-bind: 0 */
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import ReactDOM from "react-dom";
|
|
4
|
+
import copy from "copy-to-clipboard";
|
|
5
|
+
import download from "downloadjs";
|
|
2
6
|
import {
|
|
3
7
|
invert,
|
|
4
8
|
toNumber,
|
|
5
9
|
isEmpty,
|
|
6
10
|
min,
|
|
7
11
|
max,
|
|
12
|
+
flatMap,
|
|
8
13
|
set,
|
|
9
14
|
map,
|
|
10
15
|
toString,
|
|
@@ -26,6 +31,7 @@ import {
|
|
|
26
31
|
every
|
|
27
32
|
} from "lodash-es";
|
|
28
33
|
import joinUrl from "url-join";
|
|
34
|
+
|
|
29
35
|
import {
|
|
30
36
|
Button,
|
|
31
37
|
Menu,
|
|
@@ -34,6 +40,7 @@ import {
|
|
|
34
40
|
ContextMenu,
|
|
35
41
|
Checkbox,
|
|
36
42
|
Icon,
|
|
43
|
+
Popover,
|
|
37
44
|
Intent,
|
|
38
45
|
Callout,
|
|
39
46
|
Tooltip
|
|
@@ -51,50 +58,30 @@ import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
|
|
|
51
58
|
import papaparse from "papaparse";
|
|
52
59
|
import remarkGfm from "remark-gfm";
|
|
53
60
|
|
|
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";
|
|
79
|
-
import InfoHelper from "../InfoHelper";
|
|
61
|
+
import TgSelect from "../TgSelect";
|
|
80
62
|
import { withHotkeys } from "../utils/hotkeyUtils";
|
|
63
|
+
import InfoHelper from "../InfoHelper";
|
|
81
64
|
import getTextFromEl from "../utils/getTextFromEl";
|
|
65
|
+
import { getSelectedRowsFromEntities } from "./utils/selection";
|
|
82
66
|
import rowClick, {
|
|
83
67
|
changeSelectedEntities,
|
|
84
68
|
finalizeSelection
|
|
85
69
|
} from "./utils/rowClick";
|
|
86
70
|
import PagingTool from "./PagingTool";
|
|
87
71
|
import FilterAndSortMenu from "./FilterAndSortMenu";
|
|
72
|
+
import getIdOrCodeOrIndex from "./utils/getIdOrCodeOrIndex";
|
|
88
73
|
import SearchBar from "./SearchBar";
|
|
89
74
|
import DisplayOptions from "./DisplayOptions";
|
|
90
75
|
import DisabledLoadingComponent from "./DisabledLoadingComponent";
|
|
91
76
|
import SortableColumns from "./SortableColumns";
|
|
77
|
+
import computePresets from "./utils/computePresets";
|
|
92
78
|
import dataTableEnhancer from "./dataTableEnhancer";
|
|
93
79
|
import defaultProps from "./defaultProps";
|
|
94
80
|
|
|
95
81
|
import "../toastr";
|
|
96
82
|
import "@teselagen/react-table/react-table.css";
|
|
97
83
|
import "./style.css";
|
|
84
|
+
import { getRecordsFromIdMap } from "./utils/withSelectedEntities";
|
|
98
85
|
import { CellDragHandle } from "./CellDragHandle";
|
|
99
86
|
import { nanoid } from "nanoid";
|
|
100
87
|
import { SwitchField } from "../FormComponents";
|
|
@@ -103,27 +90,15 @@ import { editCellHelper } from "./editCellHelper";
|
|
|
103
90
|
import { getCellVal } from "./getCellVal";
|
|
104
91
|
import { getVals } from "./getVals";
|
|
105
92
|
import { throwFormError } from "../throwFormError";
|
|
106
|
-
import { DropdownCell } from "./DropdownCell";
|
|
107
|
-
import { EditableCell } from "./EditabelCell";
|
|
108
|
-
import { ColumnFilterMenu } from "./ColumnFilterMenu";
|
|
109
93
|
enablePatches();
|
|
110
94
|
|
|
111
95
|
const PRIMARY_SELECTED_VAL = "main_cell";
|
|
112
96
|
|
|
113
97
|
dayjs.extend(localizedFormat);
|
|
114
98
|
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
|
-
|
|
122
99
|
class DataTable extends React.Component {
|
|
123
100
|
constructor(props) {
|
|
124
101
|
super(props);
|
|
125
|
-
|
|
126
|
-
this.tableRef = createRef();
|
|
127
102
|
if (this.props.helperProp) {
|
|
128
103
|
this.props.helperProp.updateValidationHelper =
|
|
129
104
|
this.updateValidationHelper;
|
|
@@ -204,52 +179,25 @@ class DataTable extends React.Component {
|
|
|
204
179
|
}
|
|
205
180
|
});
|
|
206
181
|
}
|
|
207
|
-
|
|
208
182
|
state = {
|
|
209
183
|
columns: [],
|
|
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: ""
|
|
184
|
+
fullscreen: false
|
|
215
185
|
};
|
|
216
|
-
static defaultProps = defaultProps;
|
|
217
186
|
|
|
218
|
-
|
|
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
|
-
};
|
|
187
|
+
static defaultProps = defaultProps;
|
|
226
188
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
}
|
|
189
|
+
toggleFullscreen = () => {
|
|
190
|
+
this.setState({
|
|
191
|
+
fullscreen: !this.state.fullscreen
|
|
192
|
+
});
|
|
243
193
|
};
|
|
244
|
-
|
|
245
194
|
handleEnterStartCellEdit = e => {
|
|
246
195
|
e.stopPropagation();
|
|
247
196
|
this.startCellEdit(this.getPrimarySelectedCellId());
|
|
248
197
|
};
|
|
249
|
-
|
|
250
198
|
flashTableBorder = () => {
|
|
251
199
|
try {
|
|
252
|
-
const table = this.
|
|
200
|
+
const table = ReactDOM.findDOMNode(this.table);
|
|
253
201
|
table.classList.add("tgBorderBlue");
|
|
254
202
|
setTimeout(() => {
|
|
255
203
|
table.classList.remove("tgBorderBlue");
|
|
@@ -258,59 +206,6 @@ class DataTable extends React.Component {
|
|
|
258
206
|
console.error(`err when flashing table border:`, e);
|
|
259
207
|
}
|
|
260
208
|
};
|
|
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
|
-
|
|
314
209
|
handleUndo = () => {
|
|
315
210
|
const {
|
|
316
211
|
change,
|
|
@@ -336,7 +231,6 @@ class DataTable extends React.Component {
|
|
|
336
231
|
});
|
|
337
232
|
}
|
|
338
233
|
};
|
|
339
|
-
|
|
340
234
|
handleRedo = () => {
|
|
341
235
|
const {
|
|
342
236
|
change,
|
|
@@ -361,7 +255,6 @@ class DataTable extends React.Component {
|
|
|
361
255
|
});
|
|
362
256
|
}
|
|
363
257
|
};
|
|
364
|
-
|
|
365
258
|
updateFromProps = (oldProps, newProps) => {
|
|
366
259
|
const {
|
|
367
260
|
selectedIds,
|
|
@@ -373,6 +266,7 @@ class DataTable extends React.Component {
|
|
|
373
266
|
reduxFormExpandedEntityIdMap,
|
|
374
267
|
change
|
|
375
268
|
} = newProps;
|
|
269
|
+
const table = ReactDOM.findDOMNode(this.table);
|
|
376
270
|
|
|
377
271
|
const idMap = reduxFormSelectedEntityIdMap;
|
|
378
272
|
|
|
@@ -438,8 +332,7 @@ class DataTable extends React.Component {
|
|
|
438
332
|
// if not changing selectedIds then we just want to make sure selected entities
|
|
439
333
|
// stored in redux are in proper format
|
|
440
334
|
// if selected ids have changed then it will handle redux selection
|
|
441
|
-
const tableScrollElement =
|
|
442
|
-
this.tableRef.current.tableRef.getElementsByClassName("rt-table")[0];
|
|
335
|
+
const tableScrollElement = table.getElementsByClassName("rt-table")[0];
|
|
443
336
|
const {
|
|
444
337
|
entities: oldEntities = [],
|
|
445
338
|
reduxFormSelectedEntityIdMap: oldIdMap
|
|
@@ -488,9 +381,8 @@ class DataTable extends React.Component {
|
|
|
488
381
|
const entityIndexToScrollTo = entities.findIndex(
|
|
489
382
|
e => e.id === idToScrollTo || e.code === idToScrollTo
|
|
490
383
|
);
|
|
491
|
-
if (entityIndexToScrollTo === -1 || !
|
|
492
|
-
const tableBody =
|
|
493
|
-
this.tableRef.current.tableRef.querySelector(".rt-tbody");
|
|
384
|
+
if (entityIndexToScrollTo === -1 || !table) return;
|
|
385
|
+
const tableBody = table.querySelector(".rt-tbody");
|
|
494
386
|
if (!tableBody) return;
|
|
495
387
|
const rowEl =
|
|
496
388
|
tableBody.getElementsByClassName("rt-tr-group")[entityIndexToScrollTo];
|
|
@@ -505,7 +397,45 @@ class DataTable extends React.Component {
|
|
|
505
397
|
}, 0);
|
|
506
398
|
}
|
|
507
399
|
};
|
|
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 = {};
|
|
508
407
|
|
|
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
|
+
};
|
|
509
439
|
formatAndValidateTableInitial = () => {
|
|
510
440
|
const {
|
|
511
441
|
_origEntities,
|
|
@@ -532,25 +462,151 @@ class DataTable extends React.Component {
|
|
|
532
462
|
});
|
|
533
463
|
};
|
|
534
464
|
|
|
535
|
-
|
|
536
|
-
const {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
465
|
+
componentDidMount() {
|
|
466
|
+
const {
|
|
467
|
+
isCellEditable,
|
|
468
|
+
entities = [],
|
|
469
|
+
isLoading,
|
|
470
|
+
showForcedHiddenColumns,
|
|
471
|
+
setShowForcedHidden
|
|
472
|
+
} = this.props;
|
|
473
|
+
isCellEditable && this.formatAndValidateTableInitial();
|
|
474
|
+
this.updateFromProps({}, computePresets(this.props));
|
|
475
|
+
document.addEventListener("paste", this.handlePaste);
|
|
476
|
+
|
|
477
|
+
if (!entities.length && !isLoading && !showForcedHiddenColumns) {
|
|
478
|
+
setShowForcedHidden(true);
|
|
479
|
+
}
|
|
480
|
+
// const table = ReactDOM.findDOMNode(this.table);
|
|
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
|
+
};
|
|
551
578
|
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
finalizeSelection({
|
|
582
|
+
idMap: newIdMap,
|
|
583
|
+
entities,
|
|
584
|
+
props
|
|
552
585
|
});
|
|
553
586
|
};
|
|
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
|
+
};
|
|
554
610
|
|
|
555
611
|
handlePaste = e => {
|
|
556
612
|
const {
|
|
@@ -663,188 +719,49 @@ class DataTable extends React.Component {
|
|
|
663
719
|
const pathToIndex = getFieldPathToIndex(schema);
|
|
664
720
|
const indexToPath = invert(pathToIndex);
|
|
665
721
|
const startCellIndex = pathToIndex[primaryCellPath];
|
|
666
|
-
pasteData.forEach((row, i) => {
|
|
667
|
-
row.forEach((newVal, j) => {
|
|
668
|
-
if (newVal) {
|
|
669
|
-
const cellIndexToChange = startCellIndex + j;
|
|
670
|
-
const entity = entitiesToManipulate[i];
|
|
671
|
-
if (entity) {
|
|
672
|
-
delete entity._isClean;
|
|
673
|
-
const path = indexToPath[cellIndexToChange];
|
|
674
|
-
if (path) {
|
|
675
|
-
const { error } = editCellHelper({
|
|
676
|
-
entity,
|
|
677
|
-
path,
|
|
678
|
-
schema,
|
|
679
|
-
newVal: formatPasteData({
|
|
680
|
-
newVal,
|
|
681
|
-
path,
|
|
682
|
-
schema
|
|
683
|
-
})
|
|
684
|
-
});
|
|
685
|
-
const cellId = `${getIdOrCodeOrIndex(entity)}:${path}`;
|
|
686
|
-
if (!newSelectedCells[cellId]) {
|
|
687
|
-
newSelectedCells[cellId] = true;
|
|
688
|
-
}
|
|
689
|
-
if (error) {
|
|
690
|
-
newCellValidate[cellId] = error;
|
|
691
|
-
} else {
|
|
692
|
-
delete newCellValidate[cellId];
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
});
|
|
698
|
-
});
|
|
699
|
-
this.updateValidation(entities, newCellValidate);
|
|
700
|
-
});
|
|
701
|
-
change("reduxFormSelectedCells", newSelectedCells);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
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
|
-
};
|
|
722
|
+
pasteData.forEach((row, i) => {
|
|
723
|
+
row.forEach((newVal, j) => {
|
|
724
|
+
if (newVal) {
|
|
725
|
+
const cellIndexToChange = startCellIndex + j;
|
|
726
|
+
const entity = entitiesToManipulate[i];
|
|
727
|
+
if (entity) {
|
|
728
|
+
delete entity._isClean;
|
|
729
|
+
const path = indexToPath[cellIndexToChange];
|
|
730
|
+
if (path) {
|
|
731
|
+
const { error } = editCellHelper({
|
|
732
|
+
entity,
|
|
733
|
+
path,
|
|
734
|
+
schema,
|
|
735
|
+
newVal: formatPasteData({
|
|
736
|
+
newVal,
|
|
737
|
+
path,
|
|
738
|
+
schema
|
|
739
|
+
})
|
|
740
|
+
});
|
|
741
|
+
const cellId = `${getIdOrCodeOrIndex(entity)}:${path}`;
|
|
742
|
+
if (!newSelectedCells[cellId]) {
|
|
743
|
+
newSelectedCells[cellId] = true;
|
|
744
|
+
}
|
|
745
|
+
if (error) {
|
|
746
|
+
newCellValidate[cellId] = error;
|
|
747
|
+
} else {
|
|
748
|
+
delete newCellValidate[cellId];
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
this.updateValidation(entities, newCellValidate);
|
|
756
|
+
});
|
|
757
|
+
change("reduxFormSelectedCells", newSelectedCells);
|
|
758
|
+
}
|
|
816
759
|
}
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
newIdMap[newEntToSelect.id || newEntToSelect.code] = {
|
|
820
|
-
entity: newEntToSelect,
|
|
821
|
-
time: Date.now()
|
|
822
|
-
};
|
|
760
|
+
} catch (error) {
|
|
761
|
+
console.error(`error:`, error);
|
|
823
762
|
}
|
|
824
763
|
}
|
|
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
|
-
}
|
|
846
764
|
};
|
|
847
|
-
|
|
848
765
|
handleSelectAllRows = e => {
|
|
849
766
|
const {
|
|
850
767
|
change,
|
|
@@ -883,12 +800,22 @@ class DataTable extends React.Component {
|
|
|
883
800
|
});
|
|
884
801
|
}
|
|
885
802
|
};
|
|
886
|
-
|
|
887
803
|
updateValidationHelper = () => {
|
|
888
804
|
const { entities, reduxFormCellValidation } = computePresets(this.props);
|
|
889
805
|
this.updateValidation(entities, reduxFormCellValidation);
|
|
890
806
|
};
|
|
891
807
|
|
|
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
|
+
};
|
|
892
819
|
handleDeleteCell = () => {
|
|
893
820
|
const {
|
|
894
821
|
reduxFormSelectedCells,
|
|
@@ -929,11 +856,119 @@ class DataTable extends React.Component {
|
|
|
929
856
|
this.handleCopyHotkey(e);
|
|
930
857
|
};
|
|
931
858
|
|
|
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
|
+
|
|
932
967
|
handleCopyTable = (e, opts) => {
|
|
933
968
|
try {
|
|
934
969
|
const allRowEls = getAllRows(e);
|
|
935
970
|
if (!allRowEls) return;
|
|
936
|
-
handleCopyRows(allRowEls, {
|
|
971
|
+
this.handleCopyRows(allRowEls, {
|
|
937
972
|
...opts,
|
|
938
973
|
onFinishMsg: "Table Copied"
|
|
939
974
|
});
|
|
@@ -942,7 +977,6 @@ class DataTable extends React.Component {
|
|
|
942
977
|
window.toastr.error("Error copying rows.");
|
|
943
978
|
}
|
|
944
979
|
};
|
|
945
|
-
|
|
946
980
|
handleCopySelectedCells = e => {
|
|
947
981
|
const {
|
|
948
982
|
entities = [],
|
|
@@ -988,7 +1022,7 @@ class DataTable extends React.Component {
|
|
|
988
1022
|
} else {
|
|
989
1023
|
const jsonRow = [];
|
|
990
1024
|
// ignore header
|
|
991
|
-
let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
|
|
1025
|
+
let [rowCopyText, json] = this.getRowCopyText(allRows[i + 1]);
|
|
992
1026
|
rowCopyText = rowCopyText.split("\t");
|
|
993
1027
|
times(row.length, i => {
|
|
994
1028
|
const cell = row[i];
|
|
@@ -1003,7 +1037,7 @@ class DataTable extends React.Component {
|
|
|
1003
1037
|
});
|
|
1004
1038
|
if (!fullCellText) return window.toastr.warning("No text to copy");
|
|
1005
1039
|
|
|
1006
|
-
handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
|
|
1040
|
+
this.handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
|
|
1007
1041
|
};
|
|
1008
1042
|
|
|
1009
1043
|
handleCopySelectedRows = (selectedRecords, e) => {
|
|
@@ -1026,7 +1060,7 @@ class DataTable extends React.Component {
|
|
|
1026
1060
|
if (!allRowEls) return;
|
|
1027
1061
|
const rowEls = rowNumbersToCopy.map(i => allRowEls[i]);
|
|
1028
1062
|
|
|
1029
|
-
handleCopyRows(rowEls, {
|
|
1063
|
+
this.handleCopyRows(rowEls, {
|
|
1030
1064
|
onFinishMsg: "Selected rows copied"
|
|
1031
1065
|
});
|
|
1032
1066
|
} catch (error) {
|
|
@@ -1083,7 +1117,6 @@ class DataTable extends React.Component {
|
|
|
1083
1117
|
/>
|
|
1084
1118
|
);
|
|
1085
1119
|
};
|
|
1086
|
-
|
|
1087
1120
|
getThComponent = compose(
|
|
1088
1121
|
withProps(props => {
|
|
1089
1122
|
const { columnindex } = props;
|
|
@@ -1302,11 +1335,7 @@ class DataTable extends React.Component {
|
|
|
1302
1335
|
icon="fullscreen"
|
|
1303
1336
|
active={fullscreen}
|
|
1304
1337
|
minimal
|
|
1305
|
-
onClick={
|
|
1306
|
-
this.setState({
|
|
1307
|
-
fullscreen: !this.state.fullscreen
|
|
1308
|
-
});
|
|
1309
|
-
}}
|
|
1338
|
+
onClick={this.toggleFullscreen}
|
|
1310
1339
|
/>
|
|
1311
1340
|
);
|
|
1312
1341
|
|
|
@@ -1461,17 +1490,24 @@ class DataTable extends React.Component {
|
|
|
1461
1490
|
{...(isCellEditable && {
|
|
1462
1491
|
tabIndex: -1,
|
|
1463
1492
|
onKeyDown: e => {
|
|
1464
|
-
const
|
|
1465
|
-
|
|
1493
|
+
// const isArrowKey =
|
|
1494
|
+
// (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode === 9;
|
|
1495
|
+
// if (isArrowKey && e.target?.tagName !== "INPUT") {
|
|
1496
|
+
const isTabKey = e.keyCode === 9;
|
|
1497
|
+
// const isEnter = e.keyCode === 13;
|
|
1498
|
+
// console.log(`onKeydown datatable inner`);
|
|
1499
|
+
// console.log(`isEnter:`, isEnter)
|
|
1500
|
+
const isArrowKey = e.keyCode >= 37 && e.keyCode <= 40;
|
|
1501
|
+
// console.log(`e.target?.tagName:`,e.target?.tagName)
|
|
1466
1502
|
if (
|
|
1467
1503
|
(isArrowKey && e.target?.tagName !== "INPUT") ||
|
|
1468
1504
|
isTabKey
|
|
1469
1505
|
// || (isEnter && e.target?.tagName === "INPUT")
|
|
1470
1506
|
) {
|
|
1471
1507
|
const { schema, entities } = computePresets(this.props);
|
|
1472
|
-
const left = e.
|
|
1473
|
-
const up = e.
|
|
1474
|
-
const down = e.
|
|
1508
|
+
const left = e.keyCode === 37;
|
|
1509
|
+
const up = e.keyCode === 38;
|
|
1510
|
+
const down = e.keyCode === 40 || e.keyCode === 13;
|
|
1475
1511
|
let cellIdToUse = this.getPrimarySelectedCellId();
|
|
1476
1512
|
const pathToIndex = getFieldPathToIndex(schema);
|
|
1477
1513
|
const entityMap = getEntityIdToEntity(entities);
|
|
@@ -1564,23 +1600,13 @@ class DataTable extends React.Component {
|
|
|
1564
1600
|
const entity = entityIdToEntity[rowId].e;
|
|
1565
1601
|
if (!entity) return;
|
|
1566
1602
|
const rowDisabled = isEntityDisabled(entity);
|
|
1567
|
-
const isNum = e.
|
|
1568
|
-
const isLetter = e.
|
|
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
|
-
}
|
|
1603
|
+
const isNum = e.keyCode >= 48 && e.keyCode <= 57;
|
|
1604
|
+
const isLetter = e.keyCode >= 65 && e.keyCode <= 90;
|
|
1605
|
+
if (!isNum && !isLetter) return;
|
|
1581
1606
|
if (rowDisabled) return;
|
|
1582
1607
|
this.startCellEdit(cellId, { shouldSelectAll: true });
|
|
1583
1608
|
e.stopPropagation();
|
|
1609
|
+
// e.preventDefault();
|
|
1584
1610
|
}
|
|
1585
1611
|
})}
|
|
1586
1612
|
>
|
|
@@ -1720,7 +1746,10 @@ class DataTable extends React.Component {
|
|
|
1720
1746
|
)}
|
|
1721
1747
|
<ReactTable
|
|
1722
1748
|
data={filteredEnts}
|
|
1723
|
-
ref={
|
|
1749
|
+
ref={n => {
|
|
1750
|
+
if (n) this.table = n;
|
|
1751
|
+
}}
|
|
1752
|
+
// additionalBodyEl={}
|
|
1724
1753
|
className={classNames({
|
|
1725
1754
|
isCellEditable,
|
|
1726
1755
|
"tg-table-loading": isLoading,
|
|
@@ -1807,7 +1836,7 @@ class DataTable extends React.Component {
|
|
|
1807
1836
|
data-tip="Download Table as CSV"
|
|
1808
1837
|
minimal
|
|
1809
1838
|
icon="download"
|
|
1810
|
-
|
|
1839
|
+
></Button>
|
|
1811
1840
|
</div>
|
|
1812
1841
|
)}
|
|
1813
1842
|
{!noFooter && (
|
|
@@ -1952,6 +1981,24 @@ class DataTable extends React.Component {
|
|
|
1952
1981
|
};
|
|
1953
1982
|
};
|
|
1954
1983
|
|
|
1984
|
+
startCellEdit = (cellId, { shouldSelectAll } = {}) => {
|
|
1985
|
+
const {
|
|
1986
|
+
change,
|
|
1987
|
+
reduxFormSelectedCells = {},
|
|
1988
|
+
reduxFormEditingCell
|
|
1989
|
+
} = computePresets(this.props);
|
|
1990
|
+
const newSelectedCells = { ...reduxFormSelectedCells };
|
|
1991
|
+
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1992
|
+
//check if the cell is already selected and editing and if so, don't change it
|
|
1993
|
+
if (reduxFormEditingCell === cellId) return;
|
|
1994
|
+
change("reduxFormSelectedCells", newSelectedCells);
|
|
1995
|
+
change("reduxFormEditingCell", cellId);
|
|
1996
|
+
if (shouldSelectAll) {
|
|
1997
|
+
//we should select the text
|
|
1998
|
+
change("reduxFormEditingCellSelectAll", true);
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
|
|
1955
2002
|
getTableCellProps = (state, rowInfo, column) => {
|
|
1956
2003
|
const {
|
|
1957
2004
|
entities,
|
|
@@ -2147,7 +2194,6 @@ class DataTable extends React.Component {
|
|
|
2147
2194
|
|
|
2148
2195
|
change("reduxFormSelectedCells", newSelectedCells);
|
|
2149
2196
|
};
|
|
2150
|
-
|
|
2151
2197
|
renderCheckboxHeader = () => {
|
|
2152
2198
|
const {
|
|
2153
2199
|
reduxFormSelectedEntityIdMap,
|
|
@@ -2270,10 +2316,9 @@ class DataTable extends React.Component {
|
|
|
2270
2316
|
change("reduxFormEditingCell", null);
|
|
2271
2317
|
this.refocusTable();
|
|
2272
2318
|
};
|
|
2273
|
-
|
|
2274
2319
|
refocusTable = () => {
|
|
2275
2320
|
setTimeout(() => {
|
|
2276
|
-
const table = this.
|
|
2321
|
+
const table = ReactDOM.findDOMNode(this.table)?.closest(
|
|
2277
2322
|
".data-table-container>div"
|
|
2278
2323
|
);
|
|
2279
2324
|
table?.focus();
|
|
@@ -2550,6 +2595,7 @@ class DataTable extends React.Component {
|
|
|
2550
2595
|
<Checkbox
|
|
2551
2596
|
disabled={isEntityDisabled(row.original)}
|
|
2552
2597
|
className="tg-cell-edit-boolean-checkbox"
|
|
2598
|
+
// {...dataTest}
|
|
2553
2599
|
checked={oldVal === "True"}
|
|
2554
2600
|
onChange={e => {
|
|
2555
2601
|
const checked = e.target.checked;
|
|
@@ -2559,6 +2605,9 @@ class DataTable extends React.Component {
|
|
|
2559
2605
|
);
|
|
2560
2606
|
noEllipsis = true;
|
|
2561
2607
|
} else {
|
|
2608
|
+
// if (column.type === "genericSelect") {
|
|
2609
|
+
// val =
|
|
2610
|
+
// }
|
|
2562
2611
|
if (reduxFormEditingCell === cellId) {
|
|
2563
2612
|
if (column.type === "genericSelect") {
|
|
2564
2613
|
const GenericSelectComp = column.GenericSelectComp;
|
|
@@ -2589,7 +2638,7 @@ class DataTable extends React.Component {
|
|
|
2589
2638
|
}}
|
|
2590
2639
|
dataTest={dataTest}
|
|
2591
2640
|
cancelEdit={this.cancelCellEdit}
|
|
2592
|
-
|
|
2641
|
+
></DropdownCell>
|
|
2593
2642
|
);
|
|
2594
2643
|
} else {
|
|
2595
2644
|
return (
|
|
@@ -2601,18 +2650,11 @@ class DataTable extends React.Component {
|
|
|
2601
2650
|
shouldSelectAll={reduxFormEditingCellSelectAll}
|
|
2602
2651
|
cancelEdit={this.cancelCellEdit}
|
|
2603
2652
|
isNumeric={column.type === "number"}
|
|
2604
|
-
initialValue={
|
|
2605
|
-
this.state.editableCellInitialValue.length
|
|
2606
|
-
? this.state.editableCellInitialValue
|
|
2607
|
-
: text
|
|
2608
|
-
}
|
|
2609
|
-
isEditableCellInitialValue={
|
|
2610
|
-
!!this.state.editableCellInitialValue.length
|
|
2611
|
-
}
|
|
2653
|
+
initialValue={text}
|
|
2612
2654
|
finishEdit={newVal => {
|
|
2613
2655
|
this.finishCellEdit(cellId, newVal);
|
|
2614
2656
|
}}
|
|
2615
|
-
|
|
2657
|
+
></EditableCell>
|
|
2616
2658
|
);
|
|
2617
2659
|
}
|
|
2618
2660
|
}
|
|
@@ -2684,7 +2726,7 @@ class DataTable extends React.Component {
|
|
|
2684
2726
|
|
|
2685
2727
|
{isSelectedCell &&
|
|
2686
2728
|
(isRect
|
|
2687
|
-
? isBottomRightCornerOfRectangle({
|
|
2729
|
+
? this.isBottomRightCornerOfRectangle({
|
|
2688
2730
|
cellId,
|
|
2689
2731
|
selectionGrid,
|
|
2690
2732
|
lastRowIndex,
|
|
@@ -2695,11 +2737,11 @@ class DataTable extends React.Component {
|
|
|
2695
2737
|
: isSelectedCell === PRIMARY_SELECTED_VAL) && (
|
|
2696
2738
|
<CellDragHandle
|
|
2697
2739
|
key={cellId}
|
|
2698
|
-
thisTable={this.
|
|
2740
|
+
thisTable={this.table}
|
|
2699
2741
|
cellId={cellId}
|
|
2700
2742
|
isSelectionARectangle={this.isSelectionARectangle}
|
|
2701
2743
|
onDragEnd={this.onDragEnd}
|
|
2702
|
-
|
|
2744
|
+
></CellDragHandle>
|
|
2703
2745
|
)}
|
|
2704
2746
|
</>
|
|
2705
2747
|
);
|
|
@@ -2709,6 +2751,26 @@ class DataTable extends React.Component {
|
|
|
2709
2751
|
});
|
|
2710
2752
|
return columnsToRender;
|
|
2711
2753
|
};
|
|
2754
|
+
isBottomRightCornerOfRectangle = ({
|
|
2755
|
+
cellId,
|
|
2756
|
+
selectionGrid,
|
|
2757
|
+
lastRowIndex,
|
|
2758
|
+
lastCellIndex,
|
|
2759
|
+
entityMap,
|
|
2760
|
+
pathToIndex
|
|
2761
|
+
}) => {
|
|
2762
|
+
selectionGrid.forEach(row => {
|
|
2763
|
+
// remove undefineds from start of row
|
|
2764
|
+
while (row[0] === undefined && row.length) row.shift();
|
|
2765
|
+
});
|
|
2766
|
+
const [rowId, cellPath] = cellId.split(":");
|
|
2767
|
+
const ent = entityMap[rowId];
|
|
2768
|
+
if (!ent) return;
|
|
2769
|
+
const { i } = ent;
|
|
2770
|
+
const cellIndex = pathToIndex[cellPath];
|
|
2771
|
+
const isBottomRight = i === lastRowIndex && cellIndex === lastCellIndex;
|
|
2772
|
+
return isBottomRight;
|
|
2773
|
+
};
|
|
2712
2774
|
|
|
2713
2775
|
onDragEnd = cellsToSelect => {
|
|
2714
2776
|
const {
|
|
@@ -2913,7 +2975,6 @@ class DataTable extends React.Component {
|
|
|
2913
2975
|
change("reduxFormSelectedCells", newReduxFormSelectedCells);
|
|
2914
2976
|
});
|
|
2915
2977
|
};
|
|
2916
|
-
|
|
2917
2978
|
getCopyTextForCell = (val, row = {}, column = {}) => {
|
|
2918
2979
|
const { cellRenderer } = computePresets(this.props);
|
|
2919
2980
|
// TODOCOPY we need a way to potentially omit certain columns from being added as a \t element (talk to taoh about this)
|
|
@@ -2999,7 +3060,6 @@ class DataTable extends React.Component {
|
|
|
2999
3060
|
});
|
|
3000
3061
|
});
|
|
3001
3062
|
};
|
|
3002
|
-
|
|
3003
3063
|
getEditableTableInfoAndThrowFormError = () => {
|
|
3004
3064
|
const { schema, reduxFormEntities, reduxFormCellValidation } =
|
|
3005
3065
|
computePresets(this.props);
|
|
@@ -3109,12 +3169,12 @@ class DataTable extends React.Component {
|
|
|
3109
3169
|
//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
|
|
3110
3170
|
//do we need to be able to copy hidden cells? It seems like it should just copy what's on the page..?
|
|
3111
3171
|
const specificColumn = cellWrapper.getAttribute("data-test");
|
|
3112
|
-
handleCopyRows([cellWrapper.closest(".rt-tr")], {
|
|
3172
|
+
this.handleCopyRows([cellWrapper.closest(".rt-tr")], {
|
|
3113
3173
|
specificColumn,
|
|
3114
3174
|
onFinishMsg: "Cell copied"
|
|
3115
3175
|
});
|
|
3116
|
-
const [text, jsonText] = getCellCopyText(cellWrapper);
|
|
3117
|
-
handleCopyHelper(text, jsonText);
|
|
3176
|
+
const [text, jsonText] = this.getCellCopyText(cellWrapper);
|
|
3177
|
+
this.handleCopyHelper(text, jsonText);
|
|
3118
3178
|
}}
|
|
3119
3179
|
text="Cell"
|
|
3120
3180
|
/>
|
|
@@ -3124,7 +3184,7 @@ class DataTable extends React.Component {
|
|
|
3124
3184
|
<MenuItem
|
|
3125
3185
|
key="copyColumn"
|
|
3126
3186
|
onClick={() => {
|
|
3127
|
-
handleCopyColumn(e, cellWrapper);
|
|
3187
|
+
this.handleCopyColumn(e, cellWrapper);
|
|
3128
3188
|
}}
|
|
3129
3189
|
text="Column"
|
|
3130
3190
|
/>
|
|
@@ -3134,7 +3194,7 @@ class DataTable extends React.Component {
|
|
|
3134
3194
|
<MenuItem
|
|
3135
3195
|
key="copyColumnSelected"
|
|
3136
3196
|
onClick={() => {
|
|
3137
|
-
handleCopyColumn(e, cellWrapper, selectedRecords);
|
|
3197
|
+
this.handleCopyColumn(e, cellWrapper, selectedRecords);
|
|
3138
3198
|
}}
|
|
3139
3199
|
text="Column (Selected)"
|
|
3140
3200
|
/>
|
|
@@ -3152,7 +3212,7 @@ class DataTable extends React.Component {
|
|
|
3152
3212
|
<MenuItem
|
|
3153
3213
|
key="copySelectedRows"
|
|
3154
3214
|
onClick={() => {
|
|
3155
|
-
handleCopyRows([row]);
|
|
3215
|
+
this.handleCopyRows([row]);
|
|
3156
3216
|
// loop through each cell in the row
|
|
3157
3217
|
}}
|
|
3158
3218
|
text="Row"
|
|
@@ -3203,7 +3263,7 @@ class DataTable extends React.Component {
|
|
|
3203
3263
|
onClick={() => {
|
|
3204
3264
|
this.insertRows({ above: true });
|
|
3205
3265
|
}}
|
|
3206
|
-
|
|
3266
|
+
></MenuItem>
|
|
3207
3267
|
<MenuItem
|
|
3208
3268
|
icon="add-row-top"
|
|
3209
3269
|
text="Add Row Below"
|
|
@@ -3211,7 +3271,7 @@ class DataTable extends React.Component {
|
|
|
3211
3271
|
onClick={() => {
|
|
3212
3272
|
this.insertRows({});
|
|
3213
3273
|
}}
|
|
3214
|
-
|
|
3274
|
+
></MenuItem>
|
|
3215
3275
|
<MenuItem
|
|
3216
3276
|
icon="remove"
|
|
3217
3277
|
text={`Remove Row${selectedRowIds.length > 1 ? "s" : ""}`}
|
|
@@ -3401,7 +3461,7 @@ class DataTable extends React.Component {
|
|
|
3401
3461
|
}}
|
|
3402
3462
|
indeterminate={isIndeterminate}
|
|
3403
3463
|
checked={isChecked}
|
|
3404
|
-
|
|
3464
|
+
></Checkbox>
|
|
3405
3465
|
);
|
|
3406
3466
|
}
|
|
3407
3467
|
|
|
@@ -3426,7 +3486,7 @@ class DataTable extends React.Component {
|
|
|
3426
3486
|
})}
|
|
3427
3487
|
>
|
|
3428
3488
|
{columnTitleTextified && !noTitle && (
|
|
3429
|
-
|
|
3489
|
+
<React.Fragment>
|
|
3430
3490
|
{maybeCheckbox}
|
|
3431
3491
|
<span
|
|
3432
3492
|
title={columnTitleTextified}
|
|
@@ -3441,7 +3501,7 @@ class DataTable extends React.Component {
|
|
|
3441
3501
|
>
|
|
3442
3502
|
{renderTitleInner ? renderTitleInner : columnTitle}{" "}
|
|
3443
3503
|
</span>
|
|
3444
|
-
|
|
3504
|
+
</React.Fragment>
|
|
3445
3505
|
)}
|
|
3446
3506
|
<div
|
|
3447
3507
|
style={{ display: "flex", marginLeft: "auto", alignItems: "center" }}
|
|
@@ -3463,3 +3523,333 @@ const WrappedDT = dataTableEnhancer(DataTable);
|
|
|
3463
3523
|
export default WrappedDT;
|
|
3464
3524
|
const ConnectedPagingTool = dataTableEnhancer(PagingTool);
|
|
3465
3525
|
export { ConnectedPagingTool };
|
|
3526
|
+
|
|
3527
|
+
const itemSizeEstimators = {
|
|
3528
|
+
compact: () => 25.34,
|
|
3529
|
+
normal: () => 33.34,
|
|
3530
|
+
comfortable: () => 41.34
|
|
3531
|
+
};
|
|
3532
|
+
|
|
3533
|
+
function getCellInfo({
|
|
3534
|
+
columnIndex,
|
|
3535
|
+
columnPath,
|
|
3536
|
+
rowId,
|
|
3537
|
+
schema,
|
|
3538
|
+
entities,
|
|
3539
|
+
rowIndex,
|
|
3540
|
+
isEntityDisabled,
|
|
3541
|
+
entity
|
|
3542
|
+
}) {
|
|
3543
|
+
const leftpath = schema.fields[columnIndex - 1]?.path;
|
|
3544
|
+
const rightpath = schema.fields[columnIndex + 1]?.path;
|
|
3545
|
+
const cellIdToLeft = leftpath && `${rowId}:${leftpath}`;
|
|
3546
|
+
const cellIdToRight = rightpath && `${rowId}:${rightpath}`;
|
|
3547
|
+
const rowAboveId =
|
|
3548
|
+
entities[rowIndex - 1] &&
|
|
3549
|
+
getIdOrCodeOrIndex(entities[rowIndex - 1], rowIndex - 1);
|
|
3550
|
+
const rowBelowId =
|
|
3551
|
+
entities[rowIndex + 1] &&
|
|
3552
|
+
getIdOrCodeOrIndex(entities[rowIndex + 1], rowIndex + 1);
|
|
3553
|
+
const cellIdAbove = rowAboveId && `${rowAboveId}:${columnPath}`;
|
|
3554
|
+
const cellIdBelow = rowBelowId && `${rowBelowId}:${columnPath}`;
|
|
3555
|
+
|
|
3556
|
+
const cellId = `${rowId}:${columnPath}`;
|
|
3557
|
+
const rowDisabled = isEntityDisabled(entity);
|
|
3558
|
+
return {
|
|
3559
|
+
cellId,
|
|
3560
|
+
cellIdAbove,
|
|
3561
|
+
cellIdToRight,
|
|
3562
|
+
cellIdBelow,
|
|
3563
|
+
cellIdToLeft,
|
|
3564
|
+
rowDisabled
|
|
3565
|
+
};
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
function ColumnFilterMenu({
|
|
3569
|
+
FilterMenu,
|
|
3570
|
+
filterActiveForColumn,
|
|
3571
|
+
compact,
|
|
3572
|
+
extraCompact,
|
|
3573
|
+
...rest
|
|
3574
|
+
}) {
|
|
3575
|
+
const [columnFilterMenuOpen, setColumnFilterMenuOpen] = useState(false);
|
|
3576
|
+
return (
|
|
3577
|
+
<Popover
|
|
3578
|
+
position="bottom"
|
|
3579
|
+
onClose={() => {
|
|
3580
|
+
setColumnFilterMenuOpen(false);
|
|
3581
|
+
}}
|
|
3582
|
+
isOpen={columnFilterMenuOpen}
|
|
3583
|
+
modifiers={{
|
|
3584
|
+
preventOverflow: { enabled: true },
|
|
3585
|
+
hide: { enabled: false },
|
|
3586
|
+
flip: { enabled: false }
|
|
3587
|
+
}}
|
|
3588
|
+
>
|
|
3589
|
+
<Icon
|
|
3590
|
+
style={{ marginLeft: 5 }}
|
|
3591
|
+
icon="filter"
|
|
3592
|
+
iconSize={extraCompact ? 14 : undefined}
|
|
3593
|
+
onClick={() => {
|
|
3594
|
+
setColumnFilterMenuOpen(!columnFilterMenuOpen);
|
|
3595
|
+
}}
|
|
3596
|
+
className={classNames("tg-filter-menu-button", {
|
|
3597
|
+
"tg-active-filter": !!filterActiveForColumn
|
|
3598
|
+
})}
|
|
3599
|
+
/>
|
|
3600
|
+
<FilterMenu
|
|
3601
|
+
togglePopover={() => {
|
|
3602
|
+
setColumnFilterMenuOpen(false);
|
|
3603
|
+
}}
|
|
3604
|
+
{...rest}
|
|
3605
|
+
/>
|
|
3606
|
+
</Popover>
|
|
3607
|
+
);
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
function getLastSelectedEntity(idMap) {
|
|
3611
|
+
let lastSelectedEnt;
|
|
3612
|
+
let latestTime;
|
|
3613
|
+
forEach(idMap, ({ time, entity }) => {
|
|
3614
|
+
if (!latestTime || time > latestTime) {
|
|
3615
|
+
lastSelectedEnt = entity;
|
|
3616
|
+
latestTime = time;
|
|
3617
|
+
}
|
|
3618
|
+
});
|
|
3619
|
+
return lastSelectedEnt;
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
function getNewEntToSelect({
|
|
3623
|
+
type,
|
|
3624
|
+
lastSelectedIndex,
|
|
3625
|
+
entities,
|
|
3626
|
+
isEntityDisabled
|
|
3627
|
+
}) {
|
|
3628
|
+
let newIndexToSelect;
|
|
3629
|
+
if (type === "up") {
|
|
3630
|
+
newIndexToSelect = lastSelectedIndex - 1;
|
|
3631
|
+
} else {
|
|
3632
|
+
newIndexToSelect = lastSelectedIndex + 1;
|
|
3633
|
+
}
|
|
3634
|
+
const newEntToSelect = entities[newIndexToSelect];
|
|
3635
|
+
if (!newEntToSelect) return;
|
|
3636
|
+
if (isEntityDisabled && isEntityDisabled(newEntToSelect)) {
|
|
3637
|
+
return getNewEntToSelect({
|
|
3638
|
+
type,
|
|
3639
|
+
lastSelectedIndex: newIndexToSelect,
|
|
3640
|
+
entities,
|
|
3641
|
+
isEntityDisabled
|
|
3642
|
+
});
|
|
3643
|
+
} else {
|
|
3644
|
+
return newEntToSelect;
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
function getAllRows(e) {
|
|
3649
|
+
const el = e.target.querySelector(".data-table-container")
|
|
3650
|
+
? e.target.querySelector(".data-table-container")
|
|
3651
|
+
: e.target.closest(".data-table-container");
|
|
3652
|
+
|
|
3653
|
+
const allRowEls = el.querySelectorAll(".rt-tr");
|
|
3654
|
+
if (!allRowEls || !allRowEls.length) {
|
|
3655
|
+
return;
|
|
3656
|
+
}
|
|
3657
|
+
return allRowEls;
|
|
3658
|
+
}
|
|
3659
|
+
|
|
3660
|
+
function EditableCell({
|
|
3661
|
+
shouldSelectAll,
|
|
3662
|
+
stopSelectAll,
|
|
3663
|
+
initialValue,
|
|
3664
|
+
finishEdit,
|
|
3665
|
+
cancelEdit,
|
|
3666
|
+
isNumeric,
|
|
3667
|
+
dataTest
|
|
3668
|
+
}) {
|
|
3669
|
+
const [v, setV] = useState(initialValue);
|
|
3670
|
+
return (
|
|
3671
|
+
<input
|
|
3672
|
+
style={{
|
|
3673
|
+
border: 0,
|
|
3674
|
+
width: "95%",
|
|
3675
|
+
fontSize: 12,
|
|
3676
|
+
background: "none"
|
|
3677
|
+
}}
|
|
3678
|
+
ref={r => {
|
|
3679
|
+
if (shouldSelectAll && r) {
|
|
3680
|
+
r?.select();
|
|
3681
|
+
stopSelectAll();
|
|
3682
|
+
}
|
|
3683
|
+
}}
|
|
3684
|
+
{...dataTest}
|
|
3685
|
+
type={isNumeric ? "number" : undefined}
|
|
3686
|
+
value={v}
|
|
3687
|
+
autoFocus
|
|
3688
|
+
onKeyDown={e => {
|
|
3689
|
+
if (e.key === "Enter") {
|
|
3690
|
+
finishEdit(v);
|
|
3691
|
+
e.stopPropagation();
|
|
3692
|
+
} else if (e.key === "Escape") {
|
|
3693
|
+
e.stopPropagation();
|
|
3694
|
+
cancelEdit();
|
|
3695
|
+
}
|
|
3696
|
+
}}
|
|
3697
|
+
onBlur={() => {
|
|
3698
|
+
finishEdit(v);
|
|
3699
|
+
}}
|
|
3700
|
+
onChange={e => {
|
|
3701
|
+
setV(e.target.value);
|
|
3702
|
+
}}
|
|
3703
|
+
></input>
|
|
3704
|
+
);
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
function DropdownCell({
|
|
3708
|
+
options,
|
|
3709
|
+
isMulti,
|
|
3710
|
+
initialValue,
|
|
3711
|
+
finishEdit,
|
|
3712
|
+
cancelEdit,
|
|
3713
|
+
dataTest
|
|
3714
|
+
}) {
|
|
3715
|
+
const [v, setV] = useState(
|
|
3716
|
+
isMulti
|
|
3717
|
+
? initialValue.split(",").map(v => ({ value: v, label: v }))
|
|
3718
|
+
: initialValue
|
|
3719
|
+
);
|
|
3720
|
+
return (
|
|
3721
|
+
<div
|
|
3722
|
+
className={classNames("tg-dropdown-cell-edit-container", {
|
|
3723
|
+
"tg-dropdown-cell-edit-container-multi": isMulti
|
|
3724
|
+
})}
|
|
3725
|
+
>
|
|
3726
|
+
<TgSelect
|
|
3727
|
+
small
|
|
3728
|
+
multi={isMulti}
|
|
3729
|
+
autoOpen
|
|
3730
|
+
value={v}
|
|
3731
|
+
onChange={val => {
|
|
3732
|
+
if (isMulti) {
|
|
3733
|
+
setV(val);
|
|
3734
|
+
return;
|
|
3735
|
+
}
|
|
3736
|
+
finishEdit(val ? val.value : null);
|
|
3737
|
+
}}
|
|
3738
|
+
{...dataTest}
|
|
3739
|
+
popoverProps={{
|
|
3740
|
+
onClose: e => {
|
|
3741
|
+
if (isMulti) {
|
|
3742
|
+
if (e && e.key === "Escape") {
|
|
3743
|
+
cancelEdit();
|
|
3744
|
+
} else {
|
|
3745
|
+
finishEdit(
|
|
3746
|
+
v && v.map
|
|
3747
|
+
? v
|
|
3748
|
+
.map(v => v.value)
|
|
3749
|
+
.filter(v => v)
|
|
3750
|
+
.join(",")
|
|
3751
|
+
: v
|
|
3752
|
+
);
|
|
3753
|
+
}
|
|
3754
|
+
} else {
|
|
3755
|
+
cancelEdit();
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
}}
|
|
3759
|
+
options={options.map(value => ({ label: value, value }))}
|
|
3760
|
+
></TgSelect>
|
|
3761
|
+
</div>
|
|
3762
|
+
);
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
function getFieldPathToIndex(schema) {
|
|
3766
|
+
const fieldToIndex = {};
|
|
3767
|
+
schema.fields.forEach((f, i) => {
|
|
3768
|
+
fieldToIndex[f.path] = i;
|
|
3769
|
+
});
|
|
3770
|
+
return fieldToIndex;
|
|
3771
|
+
}
|
|
3772
|
+
|
|
3773
|
+
function getFieldPathToField(schema) {
|
|
3774
|
+
const fieldPathToField = {};
|
|
3775
|
+
schema.fields.forEach(f => {
|
|
3776
|
+
fieldPathToField[f.path] = f;
|
|
3777
|
+
});
|
|
3778
|
+
return fieldPathToField;
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3781
|
+
const defaultParsePaste = str => {
|
|
3782
|
+
return str.split(/\r\n|\n|\r/).map(row => row.split("\t"));
|
|
3783
|
+
};
|
|
3784
|
+
|
|
3785
|
+
function getEntityIdToEntity(entities) {
|
|
3786
|
+
const entityIdToEntity = {};
|
|
3787
|
+
entities.forEach((e, i) => {
|
|
3788
|
+
entityIdToEntity[getIdOrCodeOrIndex(e, i)] = { e, i };
|
|
3789
|
+
});
|
|
3790
|
+
return entityIdToEntity;
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
function endsWithNumber(str) {
|
|
3794
|
+
return /[0-9]+$/.test(str);
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
function getNumberStrAtEnd(str) {
|
|
3798
|
+
if (endsWithNumber(str)) {
|
|
3799
|
+
return str.match(/[0-9]+$/)[0];
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3802
|
+
return null;
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
function stripNumberAtEnd(str) {
|
|
3806
|
+
return str?.replace?.(getNumberStrAtEnd(str), "");
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
export function isEntityClean(e) {
|
|
3810
|
+
let isClean = true;
|
|
3811
|
+
some(e, (val, key) => {
|
|
3812
|
+
if (key === "id") return;
|
|
3813
|
+
if (key === "_isClean") return;
|
|
3814
|
+
if (val) {
|
|
3815
|
+
isClean = false;
|
|
3816
|
+
return true;
|
|
3817
|
+
}
|
|
3818
|
+
});
|
|
3819
|
+
return isClean;
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
const formatPasteData = ({ schema, newVal, path }) => {
|
|
3823
|
+
const pathToField = getFieldPathToField(schema);
|
|
3824
|
+
const column = pathToField[path];
|
|
3825
|
+
if (column.type === "genericSelect") {
|
|
3826
|
+
if (newVal?.__genSelCol === path) {
|
|
3827
|
+
newVal = newVal.__strVal;
|
|
3828
|
+
} else {
|
|
3829
|
+
newVal = undefined;
|
|
3830
|
+
}
|
|
3831
|
+
} else {
|
|
3832
|
+
newVal = Object.hasOwn(newVal, "__strVal") ? newVal.__strVal : newVal;
|
|
3833
|
+
}
|
|
3834
|
+
return newVal;
|
|
3835
|
+
};
|
|
3836
|
+
|
|
3837
|
+
export function removeCleanRows(reduxFormEntities, reduxFormCellValidation) {
|
|
3838
|
+
const toFilterOut = {};
|
|
3839
|
+
const entsToUse = (reduxFormEntities || []).filter(e => {
|
|
3840
|
+
if (!(e._isClean || isEntityClean(e))) return true;
|
|
3841
|
+
else {
|
|
3842
|
+
toFilterOut[getIdOrCodeOrIndex(e)] = true;
|
|
3843
|
+
return false;
|
|
3844
|
+
}
|
|
3845
|
+
});
|
|
3846
|
+
|
|
3847
|
+
const validationToUse = {};
|
|
3848
|
+
forEach(reduxFormCellValidation, (v, k) => {
|
|
3849
|
+
const [rowId] = k.split(":");
|
|
3850
|
+
if (!toFilterOut[rowId]) {
|
|
3851
|
+
validationToUse[k] = v;
|
|
3852
|
+
}
|
|
3853
|
+
});
|
|
3854
|
+
return { entsToUse, validationToUse };
|
|
3855
|
+
}
|