@teselagen/ui 0.9.8 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CollapsibleCard/index.d.ts +2 -1
  2. package/DataTable/Columns.d.ts +4 -1
  3. package/DataTable/DisplayOptions.d.ts +2 -1
  4. package/DataTable/index.d.ts +3 -3
  5. package/DividerWithText/index.d.ts +16 -0
  6. package/index.cjs.js +21122 -21084
  7. package/index.d.ts +1 -0
  8. package/index.es.js +21125 -21087
  9. package/package.json +2 -1
  10. package/src/CollapsibleCard/index.js +8 -1
  11. package/src/DataTable/Columns.js +69 -1
  12. package/src/DataTable/DisplayOptions.js +35 -6
  13. package/src/DataTable/PagingTool.js +2 -2
  14. package/src/DataTable/RenderCell.js +8 -4
  15. package/src/DataTable/index.js +1253 -229
  16. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.js +2 -2
  17. package/src/DataTable/utils/tableQueryParamsToHasuraClauses.test.js +21 -0
  18. package/src/DataTable/utils/useTableEntities.js +3 -2
  19. package/src/DataTable/utils/withTableParams.js +34 -13
  20. package/src/DividerWithText/index.js +30 -0
  21. package/src/DividerWithText/style.css +37 -0
  22. package/src/InfoHelper/style.css +1 -0
  23. package/src/UploadCsvWizard.js +7 -5
  24. package/src/index.js +1 -0
  25. package/src/utils/hooks/useDeepEqualMemo.js +2 -2
  26. package/src/utils/isEqualIgnoreFunctions.js +23 -0
  27. package/src/utils/pureNoFunc.js +4 -20
  28. package/ui.css +38 -0
  29. package/utils/isEqualIgnoreFunctions.d.ts +1 -0
  30. package/DataTable/EditabelCell.d.ts +0 -7
  31. package/DataTable/ReactTable.d.ts +0 -78
  32. package/DataTable/defaultProps.d.ts +0 -43
  33. package/DataTable/utils/computePresets.d.ts +0 -1
  34. package/DataTable/utils/types/Entity.d.ts +0 -9
  35. package/DataTable/utils/types/Field.d.ts +0 -4
  36. package/DataTable/utils/types/OrderBy.d.ts +0 -11
  37. package/DataTable/utils/types/Schema.d.ts +0 -4
  38. package/DataTable/utils/useDeepEqualMemo.d.ts +0 -1
  39. package/DataTable/utils/useHotKeysWrapper.d.ts +0 -29
  40. package/DataTable/utils/useTableParams.d.ts +0 -49
  41. package/src/DataTable/Columns.jsx +0 -945
  42. package/src/DataTable/EditabelCell.js +0 -44
  43. package/src/DataTable/EditabelCell.jsx +0 -44
  44. package/src/DataTable/ReactTable.js +0 -738
  45. package/src/DataTable/RenderCell.jsx +0 -191
  46. package/src/DataTable/defaultProps.js +0 -45
  47. package/src/DataTable/utils/computePresets.js +0 -42
  48. package/src/DataTable/utils/convertSchema.ts +0 -79
  49. package/src/DataTable/utils/formatPasteData.ts +0 -34
  50. package/src/DataTable/utils/getAllRows.ts +0 -11
  51. package/src/DataTable/utils/getCellCopyText.ts +0 -7
  52. package/src/DataTable/utils/getCellInfo.ts +0 -46
  53. package/src/DataTable/utils/getFieldPathToField.ts +0 -10
  54. package/src/DataTable/utils/getIdOrCodeOrIndex.ts +0 -14
  55. package/src/DataTable/utils/getLastSelectedEntity.ts +0 -15
  56. package/src/DataTable/utils/getNewEntToSelect.ts +0 -32
  57. package/src/DataTable/utils/initializeHasuraWhereAndFilter.ts +0 -35
  58. package/src/DataTable/utils/isBottomRightCornerOfRectangle.ts +0 -27
  59. package/src/DataTable/utils/isEntityClean.ts +0 -15
  60. package/src/DataTable/utils/primarySelectedValue.ts +0 -1
  61. package/src/DataTable/utils/removeCleanRows.ts +0 -26
  62. package/src/DataTable/utils/selection.ts +0 -11
  63. package/src/DataTable/utils/types/Entity.ts +0 -13
  64. package/src/DataTable/utils/types/Field.ts +0 -4
  65. package/src/DataTable/utils/types/OrderBy.ts +0 -15
  66. package/src/DataTable/utils/types/Schema.ts +0 -5
  67. package/src/DataTable/utils/useDeepEqualMemo.js +0 -10
  68. package/src/DataTable/utils/useHotKeysWrapper.js +0 -395
  69. package/src/DataTable/utils/useTableEntities.ts +0 -60
  70. package/src/DataTable/utils/useTableParams.js +0 -361
  71. package/src/DataTable/utils/utils.ts +0 -39
  72. package/src/Timeline/TimelineEvent.tsx +0 -36
  73. package/src/Timeline/index.tsx +0 -21
  74. package/src/utils/browserUtils.ts +0 -3
  75. package/src/utils/determineBlackOrWhiteTextColor.ts +0 -11
  76. package/src/utils/getTextFromEl.ts +0 -45
  77. package/src/utils/handlerHelpers.ts +0 -32
  78. package/src/utils/hooks/index.ts +0 -1
  79. package/src/utils/hooks/useDeepEqualMemo.ts +0 -10
  80. package/src/utils/hooks/useStableReference.ts +0 -9
  81. package/src/utils/hotkeyUtils.tsx +0 -155
  82. package/src/utils/isBeingCalledExcessively.ts +0 -37
  83. package/style.css +0 -10537
@@ -1,945 +0,0 @@
1
- import React, { isValidElement, useCallback } from "react";
2
- import classNames from "classnames";
3
- import { Button, Classes, Checkbox, Icon } from "@blueprintjs/core";
4
- import {
5
- set,
6
- toString,
7
- camelCase,
8
- startCase,
9
- noop,
10
- cloneDeep,
11
- get,
12
- padStart
13
- } from "lodash-es";
14
- import dayjs from "dayjs";
15
- import localizedFormat from "dayjs/plugin/localizedFormat";
16
- import ReactMarkdown from "react-markdown";
17
- import remarkGfm from "remark-gfm";
18
- import joinUrl from "url-join";
19
- import InfoHelper from "../InfoHelper";
20
- import {
21
- getEntityIdToEntity,
22
- getFieldPathToIndex,
23
- getFieldPathToField,
24
- getIdOrCodeOrIndex,
25
- getNumberStrAtEnd,
26
- getSelectedRowsFromEntities,
27
- PRIMARY_SELECTED_VAL,
28
- stripNumberAtEnd
29
- } from "./utils";
30
- import FilterAndSortMenu from "./FilterAndSortMenu";
31
- import { ColumnFilterMenu } from "./ColumnFilterMenu";
32
- import getTextFromEl from "../utils/getTextFromEl";
33
- import rowClick, { finalizeSelection } from "./utils/rowClick";
34
- import { editCellHelper } from "./editCellHelper";
35
- import { getCellVal } from "./getCellVal";
36
- import { getCCDisplayName } from "./utils/queryParams";
37
- import { useDispatch } from "react-redux";
38
- import { change as _change } from "redux-form";
39
- import { RenderCell } from "./RenderCell";
40
-
41
- dayjs.extend(localizedFormat);
42
-
43
- const RenderColumnHeader = ({
44
- addFilters,
45
- column,
46
- compact,
47
- currentParams,
48
- entities,
49
- extraCompact,
50
- filters,
51
- isCellEditable,
52
- isLocalCall,
53
- order,
54
- removeSingleFilter,
55
- setNewParams,
56
- setOrder,
57
- updateEntitiesHelper,
58
- withFilter,
59
- withSort
60
- }) => {
61
- const {
62
- displayName,
63
- description,
64
- isUnique,
65
- sortDisabled,
66
- filterDisabled,
67
- columnFilterDisabled,
68
- renderTitleInner,
69
- filterIsActive = noop,
70
- noTitle,
71
- isNotEditable,
72
- type,
73
- path
74
- } = column;
75
- const columnDataType = column.type;
76
- const isActionColumn = columnDataType === "action";
77
- const disableSorting =
78
- sortDisabled ||
79
- isActionColumn ||
80
- (!isLocalCall && typeof path === "string" && path.includes(".")) ||
81
- columnDataType === "color";
82
- const disableFiltering =
83
- filterDisabled ||
84
- columnDataType === "color" ||
85
- isActionColumn ||
86
- columnFilterDisabled;
87
- const ccDisplayName = getCCDisplayName(column);
88
- let columnTitle = displayName || startCase(camelCase(path));
89
- if (isActionColumn) columnTitle = "";
90
-
91
- const currentFilter =
92
- filters &&
93
- !!filters.length &&
94
- filters.filter(({ filterOn }) => {
95
- return filterOn === ccDisplayName;
96
- })[0];
97
- const filterActiveForColumn =
98
- !!currentFilter || filterIsActive(currentParams);
99
- let ordering;
100
- if (order && order.length) {
101
- order.forEach(order => {
102
- const orderField = order.replace("-", "");
103
- if (orderField === ccDisplayName) {
104
- if (orderField === order) {
105
- ordering = "asc";
106
- } else {
107
- ordering = "desc";
108
- }
109
- }
110
- });
111
- }
112
-
113
- const sortDown = ordering && ordering === "asc";
114
- const sortUp = ordering && !sortDown;
115
- const FilterMenu = column.FilterMenu || FilterAndSortMenu;
116
-
117
- let maybeCheckbox;
118
- if (isCellEditable && !isNotEditable && type === "boolean") {
119
- let isIndeterminate = false;
120
- let isChecked = !!entities.length;
121
- let hasFalse;
122
- let hasTrue;
123
- entities.some(e => {
124
- if (!get(e, path)) {
125
- isChecked = false;
126
- hasFalse = true;
127
- } else {
128
- hasTrue = true;
129
- }
130
- if (hasFalse && hasTrue) {
131
- isIndeterminate = true;
132
- return true;
133
- }
134
- return false;
135
- });
136
- maybeCheckbox = (
137
- <Checkbox
138
- style={{ marginBottom: 0, marginLeft: 3 }}
139
- onChange={() => {
140
- updateEntitiesHelper(entities, ents => {
141
- ents.forEach(e => {
142
- delete e._isClean;
143
- set(e, path, isIndeterminate ? true : !isChecked);
144
- });
145
- });
146
- }}
147
- indeterminate={isIndeterminate}
148
- checked={isChecked}
149
- />
150
- );
151
- }
152
-
153
- const columnTitleTextified = getTextFromEl(columnTitle);
154
-
155
- return (
156
- <div
157
- {...(description && {
158
- "data-tip": `<div>
159
- <strong>${columnTitle}:</strong> <br>
160
- ${description} ${isUnique ? "<br>Must be unique" : ""}</div>`
161
- })}
162
- data-test={columnTitleTextified}
163
- data-path={path}
164
- data-copy-text={columnTitleTextified}
165
- data-copy-json={JSON.stringify({
166
- __strVal: columnTitleTextified,
167
- __isHeaderCell: true
168
- })}
169
- className={classNames("tg-react-table-column-header", {
170
- "sort-active": sortUp || sortDown
171
- })}
172
- >
173
- {columnTitleTextified && !noTitle && (
174
- <>
175
- {maybeCheckbox}
176
- <span
177
- title={columnTitleTextified}
178
- className={classNames({
179
- "tg-react-table-name": true,
180
- "no-data-tip": !!description
181
- })}
182
- style={{
183
- ...(description && { fontStyle: "italic" }),
184
- display: "inline-block"
185
- }}
186
- >
187
- {renderTitleInner ? renderTitleInner : columnTitle}{" "}
188
- </span>
189
- </>
190
- )}
191
- <div
192
- style={{ display: "flex", marginLeft: "auto", alignItems: "center" }}
193
- >
194
- {withSort && !disableSorting && (
195
- <div className="tg-sort-arrow-container">
196
- <Icon
197
- data-tip="Sort Z-A (Hold shift to sort multiple columns)"
198
- icon="chevron-up"
199
- className={classNames({
200
- active: sortUp
201
- })}
202
- color={sortUp ? "#106ba3" : undefined}
203
- iconSize={extraCompact ? 10 : 12}
204
- onClick={e => {
205
- setOrder("-" + ccDisplayName, sortUp, e.shiftKey);
206
- }}
207
- />
208
- <Icon
209
- data-tip="Sort A-Z (Hold shift to sort multiple columns)"
210
- icon="chevron-down"
211
- className={classNames({
212
- active: sortDown
213
- })}
214
- color={sortDown ? "#106ba3" : undefined}
215
- iconSize={extraCompact ? 10 : 12}
216
- onClick={e => {
217
- setOrder(ccDisplayName, sortDown, e.shiftKey);
218
- }}
219
- />
220
- </div>
221
- )}
222
- {withFilter && !disableFiltering && (
223
- <ColumnFilterMenu
224
- FilterMenu={FilterMenu}
225
- filterActiveForColumn={filterActiveForColumn}
226
- addFilters={addFilters}
227
- removeSingleFilter={removeSingleFilter}
228
- currentFilter={currentFilter}
229
- filterOn={ccDisplayName}
230
- dataType={columnDataType}
231
- schemaForField={column}
232
- currentParams={currentParams}
233
- setNewParams={setNewParams}
234
- compact={compact}
235
- extraCompact={extraCompact}
236
- />
237
- )}
238
- </div>
239
- </div>
240
- );
241
- };
242
-
243
- const renderCheckboxHeader = ({
244
- change,
245
- entities,
246
- isEntityDisabled,
247
- isSingleSelect,
248
- noDeselectAll,
249
- noSelect,
250
- noUserSelect = false,
251
- onDeselect,
252
- onMultiRowSelect,
253
- onRowSelect,
254
- onSingleRowSelect,
255
- reduxFormSelectedEntityIdMap
256
- }) => {
257
- const checkedRows = getSelectedRowsFromEntities(
258
- entities,
259
- reduxFormSelectedEntityIdMap
260
- );
261
- const checkboxProps = {
262
- checked: false,
263
- indeterminate: false
264
- };
265
- const notDisabledEntityCount = entities.reduce((acc, e) => {
266
- return isEntityDisabled(e) ? acc : acc + 1;
267
- }, 0);
268
- if (checkedRows.length === notDisabledEntityCount) {
269
- //tnr: maybe this will need to change if we want enable select all across pages
270
- checkboxProps.checked = notDisabledEntityCount !== 0;
271
- } else {
272
- if (checkedRows.length) {
273
- checkboxProps.indeterminate = true;
274
- }
275
- }
276
-
277
- return !isSingleSelect ? (
278
- <Checkbox
279
- name="checkBoxHeader"
280
- disabled={noSelect || noUserSelect}
281
- onChange={() => {
282
- const newIdMap = cloneDeep(reduxFormSelectedEntityIdMap) || {};
283
- entities.forEach((entity, i) => {
284
- if (isEntityDisabled(entity)) return;
285
- const entityId = getIdOrCodeOrIndex(entity, i);
286
- if (checkboxProps.checked) {
287
- delete newIdMap[entityId];
288
- } else {
289
- newIdMap[entityId] = { entity };
290
- }
291
- });
292
-
293
- finalizeSelection({
294
- idMap: newIdMap,
295
- entities,
296
- props: {
297
- onDeselect,
298
- onSingleRowSelect,
299
- onMultiRowSelect,
300
- noDeselectAll,
301
- onRowSelect,
302
- noSelect,
303
- change
304
- }
305
- });
306
- }}
307
- {...checkboxProps}
308
- />
309
- ) : null;
310
- };
311
-
312
- export const useColumns = ({
313
- addFilters,
314
- cellRenderer,
315
- columns,
316
- currentParams,
317
- compact,
318
- editingCell,
319
- editingCellSelectAll,
320
- entities,
321
- expandedEntityIdMap,
322
- extraCompact,
323
- filters,
324
- formName,
325
- getCellHoverText,
326
- isCellEditable,
327
- isEntityDisabled,
328
- isLocalCall,
329
- isSimple,
330
- isSingleSelect,
331
- isSelectionARectangle,
332
- noDeselectAll,
333
- noSelect,
334
- noUserSelect,
335
- onDeselect,
336
- onMultiRowSelect,
337
- onRowClick,
338
- onRowSelect,
339
- onSingleRowSelect,
340
- order,
341
- primarySelectedCellId,
342
- reduxFormCellValidation,
343
- reduxFormSelectedEntityIdMap,
344
- refocusTable,
345
- removeSingleFilter = noop,
346
- schema,
347
- selectedCells,
348
- setExpandedEntityIdMap,
349
- setNewParams,
350
- setOrder = noop,
351
- setSelectedCells,
352
- shouldShowSubComponent,
353
- startCellEdit,
354
- SubComponent,
355
- tableRef,
356
- updateEntitiesHelper,
357
- updateValidation,
358
- withCheckboxes,
359
- withExpandAndCollapseAllButton,
360
- withFilter: _withFilter,
361
- withSort = true
362
- }) => {
363
- const dispatch = useDispatch();
364
- const change = useCallback(
365
- (...args) => dispatch(_change(formName, ...args)),
366
- [dispatch, formName]
367
- );
368
- const withFilter = _withFilter === undefined ? !isSimple : _withFilter;
369
-
370
- const onDragEnd = useCallback(
371
- cellsToSelect => {
372
- const [primaryRowId, primaryCellPath] = primarySelectedCellId.split(":");
373
- const pathToField = getFieldPathToField(schema);
374
- const { selectedPaths, selectionGrid } = isSelectionARectangle();
375
- let allSelectedPaths = selectedPaths;
376
- if (!allSelectedPaths) {
377
- allSelectedPaths = [primaryCellPath];
378
- }
379
-
380
- updateEntitiesHelper(entities, entities => {
381
- let newSelectedCells;
382
- if (selectedPaths) {
383
- newSelectedCells = {
384
- ...selectedCells
385
- };
386
- } else {
387
- newSelectedCells = {
388
- [primarySelectedCellId]: PRIMARY_SELECTED_VAL
389
- };
390
- }
391
-
392
- const newCellValidate = {
393
- ...reduxFormCellValidation
394
- };
395
- const entityMap = getEntityIdToEntity(entities);
396
- const { e: selectedEnt } = entityMap[primaryRowId];
397
- const firstCellToSelectRowIndex =
398
- entityMap[cellsToSelect[0]?.split(":")[0]]?.i;
399
- const pathToIndex = getFieldPathToIndex(schema);
400
-
401
- allSelectedPaths.forEach(selectedPath => {
402
- const column = pathToField[selectedPath];
403
-
404
- const selectedCellVal = getCellVal(selectedEnt, selectedPath, column);
405
- const cellIndexOfSelectedPath = pathToIndex[selectedPath];
406
- let incrementStart;
407
- let incrementPrefix;
408
- let incrementPad = 0;
409
- if (column.type === "string" || column.type === "number") {
410
- const cellNumStr = getNumberStrAtEnd(selectedCellVal);
411
- const cellNum = Number(cellNumStr);
412
- const entityAbovePrimaryCell =
413
- entities[entityMap[primaryRowId].i - 1];
414
- if (cellNumStr !== null && !isNaN(cellNum)) {
415
- if (
416
- entityAbovePrimaryCell &&
417
- (!selectionGrid || selectionGrid.length <= 1)
418
- ) {
419
- const cellAboveVal = get(
420
- entityAbovePrimaryCell,
421
- selectedPath,
422
- ""
423
- );
424
- const cellAboveNumStr = getNumberStrAtEnd(cellAboveVal);
425
- const cellAboveNum = Number(cellAboveNumStr);
426
- if (!isNaN(cellAboveNum)) {
427
- const isIncremental = cellNum - cellAboveNum === 1;
428
- if (isIncremental) {
429
- const cellTextNoNum = stripNumberAtEnd(selectedCellVal);
430
- const sameText =
431
- stripNumberAtEnd(cellAboveVal) === cellTextNoNum;
432
- if (sameText) {
433
- incrementStart = cellNum + 1;
434
- incrementPrefix = cellTextNoNum || "";
435
- if (cellNumStr && cellNumStr.startsWith("0")) {
436
- incrementPad = cellNumStr.length;
437
- }
438
- }
439
- }
440
- }
441
- }
442
- if (incrementStart === undefined) {
443
- const draggingDown =
444
- firstCellToSelectRowIndex > selectionGrid?.[0][0].rowIndex;
445
- if (selectedPaths && draggingDown) {
446
- let checkIncrement;
447
- let prefix;
448
- let maybePad;
449
- // determine if all the cells in this column of the selectionGrid are incrementing
450
- const allAreIncrementing = selectionGrid.every(row => {
451
- // see if cell is selected
452
- const cellInfo = row[cellIndexOfSelectedPath];
453
- if (!cellInfo) return false;
454
- const { cellId } = cellInfo;
455
- const [rowId] = cellId.split(":");
456
- const cellVal = getCellVal(
457
- entityMap[rowId].e,
458
- selectedPath,
459
- pathToField[selectedPath]
460
- );
461
- const cellNumStr = getNumberStrAtEnd(cellVal);
462
- const cellNum = Number(cellNumStr);
463
- const cellTextNoNum = stripNumberAtEnd(cellVal);
464
- if (cellNumStr?.startsWith("0")) {
465
- maybePad = cellNumStr.length;
466
- }
467
- if (cellTextNoNum && !prefix) {
468
- prefix = cellTextNoNum;
469
- }
470
- if (cellTextNoNum && prefix !== cellTextNoNum) {
471
- return false;
472
- }
473
- if (!isNaN(cellNum)) {
474
- if (!checkIncrement) {
475
- checkIncrement = cellNum;
476
- return true;
477
- } else {
478
- return ++checkIncrement === cellNum;
479
- }
480
- } else {
481
- return false;
482
- }
483
- });
484
-
485
- if (allAreIncrementing) {
486
- incrementStart = checkIncrement + 1;
487
- incrementPrefix = prefix || "";
488
- incrementPad = maybePad;
489
- }
490
- }
491
- }
492
- }
493
- }
494
-
495
- let firstSelectedCellRowIndex;
496
- if (selectionGrid) {
497
- selectionGrid[0].some(cell => {
498
- if (cell) {
499
- firstSelectedCellRowIndex = cell.rowIndex;
500
- return true;
501
- }
502
- return false;
503
- });
504
- }
505
-
506
- cellsToSelect.forEach(cellId => {
507
- const [rowId, cellPath] = cellId.split(":");
508
- if (cellPath !== selectedPath) return;
509
- newSelectedCells[cellId] = true;
510
- const { e: entityToUpdate, i: rowIndex } = entityMap[rowId] || {};
511
- if (entityToUpdate) {
512
- delete entityToUpdate._isClean;
513
- let newVal;
514
- if (incrementStart !== undefined) {
515
- const num = incrementStart++;
516
- newVal = incrementPrefix + padStart(num, incrementPad, "0");
517
- } else {
518
- if (selectionGrid && selectionGrid.length > 1) {
519
- // if there are multiple cells selected then we want to copy them repeating
520
- // ex: if we have 1,2,3 selected and we drag for 5 more rows we want it to
521
- // be 1,2,3,1,2 for the new row cells in this column
522
- const draggingDown = rowIndex > firstSelectedCellRowIndex;
523
- const cellIndex = pathToIndex[cellPath];
524
- let cellIdToCopy;
525
- if (draggingDown) {
526
- const { cellId } = selectionGrid[
527
- (rowIndex - firstSelectedCellRowIndex) %
528
- selectionGrid.length
529
- ].find(g => g && g.cellIndex === cellIndex);
530
- cellIdToCopy = cellId;
531
- } else {
532
- const lastIndexInGrid =
533
- selectionGrid[selectionGrid.length - 1][0].rowIndex;
534
- const { cellId } = selectionGrid[
535
- (rowIndex + lastIndexInGrid + 1) % selectionGrid.length
536
- ].find(g => g.cellIndex === cellIndex);
537
- cellIdToCopy = cellId;
538
- }
539
-
540
- const [rowIdToCopy, cellPathToCopy] = cellIdToCopy.split(":");
541
- newVal = getCellVal(
542
- entityMap[rowIdToCopy].e,
543
- cellPathToCopy,
544
- pathToField[cellPathToCopy]
545
- );
546
- } else {
547
- newVal = selectedCellVal;
548
- }
549
- }
550
- const { error } = editCellHelper({
551
- entity: entityToUpdate,
552
- path: cellPath,
553
- schema,
554
- newVal
555
- });
556
- newCellValidate[cellId] = error;
557
- }
558
- });
559
- });
560
-
561
- // select the new cells
562
- updateValidation(entities, newCellValidate);
563
- setSelectedCells(newSelectedCells);
564
- });
565
- },
566
- [
567
- entities,
568
- isSelectionARectangle,
569
- primarySelectedCellId,
570
- reduxFormCellValidation,
571
- schema,
572
- selectedCells,
573
- setSelectedCells,
574
- updateEntitiesHelper,
575
- updateValidation
576
- ]
577
- );
578
-
579
- const getCopyTextForCell = useCallback(
580
- (val, row = {}, column = {}) => {
581
- // TODOCOPY we need a way to potentially omit certain columns from being added as a \t element (talk to taoh about this)
582
- let text = typeof val !== "string" ? row.value : val;
583
-
584
- // We should try to take out the props from here, it produces
585
- // unnecessary rerenders
586
- const record = row.original;
587
- if (column.getClipboardData) {
588
- text = column.getClipboardData(row.value, record, row);
589
- } else if (column.getValueToFilterOn) {
590
- text = column.getValueToFilterOn(record);
591
- } else if (column.render) {
592
- text = column.render(row.value, record, row, {
593
- currentParams,
594
- setNewParams
595
- });
596
- } else if (cellRenderer && cellRenderer[column.path]) {
597
- text = cellRenderer[column.path](row.value, row.original, row, {
598
- currentParams,
599
- setNewParams
600
- });
601
- } else if (text) {
602
- text = isValidElement(text) ? text : String(text);
603
- }
604
- const getTextFromElementOrLink = text => {
605
- if (isValidElement(text)) {
606
- if (text.props?.to) {
607
- // this will convert Link elements to url strings
608
- return joinUrl(
609
- window.location.origin,
610
- window.frontEndConfig?.clientBasePath || "",
611
- text.props.to
612
- );
613
- } else {
614
- return getTextFromEl(text);
615
- }
616
- } else {
617
- return text;
618
- }
619
- };
620
- text = getTextFromElementOrLink(text);
621
-
622
- if (Array.isArray(text)) {
623
- let arrText = text.map(getTextFromElementOrLink).join(", ");
624
- // because we sometimes insert commas after links when mapping over an array of elements we will have double ,'s
625
- arrText = arrText.replace(/, ,/g, ",");
626
- text = arrText;
627
- }
628
-
629
- const stringText = toString(text);
630
- if (stringText === "[object Object]") return "";
631
- return stringText;
632
- },
633
- [cellRenderer, currentParams, setNewParams]
634
- );
635
-
636
- const renderCheckboxCell = useCallback(
637
- row => {
638
- const rowIndex = row.index;
639
- const checkedRows = getSelectedRowsFromEntities(
640
- entities,
641
- reduxFormSelectedEntityIdMap
642
- );
643
-
644
- const isSelected = checkedRows.some(rowNum => {
645
- return rowNum === rowIndex;
646
- });
647
- if (rowIndex >= entities.length) {
648
- return <div />;
649
- }
650
- const entity = entities[rowIndex];
651
- return (
652
- <Checkbox
653
- name={`${getIdOrCodeOrIndex(entity, rowIndex)}-checkbox`}
654
- disabled={noSelect || noUserSelect || isEntityDisabled(entity)}
655
- onClick={e => {
656
- rowClick(e, row, entities, {
657
- reduxFormSelectedEntityIdMap,
658
- isSingleSelect,
659
- noSelect,
660
- onRowClick,
661
- isEntityDisabled,
662
- withCheckboxes,
663
- onDeselect,
664
- onSingleRowSelect,
665
- onMultiRowSelect,
666
- noDeselectAll,
667
- onRowSelect,
668
- change
669
- });
670
- }}
671
- checked={isSelected}
672
- />
673
- );
674
- },
675
- [
676
- change,
677
- entities,
678
- isEntityDisabled,
679
- isSingleSelect,
680
- noDeselectAll,
681
- noSelect,
682
- noUserSelect,
683
- onDeselect,
684
- onMultiRowSelect,
685
- onRowClick,
686
- onRowSelect,
687
- onSingleRowSelect,
688
- reduxFormSelectedEntityIdMap,
689
- withCheckboxes
690
- ]
691
- );
692
-
693
- const finishCellEdit = useCallback(
694
- (cellId, newVal, doNotStopEditing) => {
695
- const [rowId, path] = cellId.split(":");
696
- !doNotStopEditing && change("reduxFormEditingCell", null);
697
- updateEntitiesHelper(entities, entities => {
698
- const entity = entities.find((e, i) => {
699
- return getIdOrCodeOrIndex(e, i) === rowId;
700
- });
701
- delete entity._isClean;
702
- const { error } = editCellHelper({
703
- entity,
704
- path,
705
- schema,
706
- newVal
707
- });
708
-
709
- updateValidation(entities, {
710
- ...reduxFormCellValidation,
711
- [cellId]: error
712
- });
713
- });
714
- !doNotStopEditing && refocusTable();
715
- },
716
- [
717
- change,
718
- entities,
719
- reduxFormCellValidation,
720
- refocusTable,
721
- schema,
722
- updateEntitiesHelper,
723
- updateValidation
724
- ]
725
- );
726
-
727
- const cancelCellEdit = useCallback(() => {
728
- change("reduxFormEditingCell", null);
729
- refocusTable();
730
- }, [change, refocusTable]);
731
-
732
- if (!columns.length) {
733
- return columns;
734
- }
735
-
736
- const columnsToRender = [];
737
- if (SubComponent) {
738
- columnsToRender.push({
739
- ...(withExpandAndCollapseAllButton && {
740
- Header: () => {
741
- const showCollapseAll =
742
- Object.values(expandedEntityIdMap).filter(i => i).length ===
743
- entities.length;
744
- return (
745
- <InfoHelper
746
- content={showCollapseAll ? "Collapse All" : "Expand All"}
747
- isButton
748
- minimal
749
- small
750
- style={{ padding: 2 }}
751
- popoverProps={{
752
- modifiers: {
753
- preventOverflow: { enabled: false },
754
- hide: { enabled: false }
755
- }
756
- }}
757
- onClick={() => {
758
- showCollapseAll
759
- ? setExpandedEntityIdMap({})
760
- : setExpandedEntityIdMap(prev => {
761
- const newMap = { ...prev };
762
- entities.forEach(e => {
763
- newMap[getIdOrCodeOrIndex(e)] = true;
764
- });
765
- return newMap;
766
- });
767
- }}
768
- className={classNames("tg-expander-all")}
769
- icon={showCollapseAll ? "chevron-down" : "chevron-right"}
770
- />
771
- );
772
- }
773
- }),
774
- expander: true,
775
- Expander: ({ isExpanded, original: record }) => {
776
- let shouldShow = true;
777
- if (shouldShowSubComponent) {
778
- shouldShow = shouldShowSubComponent(record);
779
- }
780
- if (!shouldShow) return null;
781
- return (
782
- <Button
783
- className={classNames(
784
- "tg-expander",
785
- Classes.MINIMAL,
786
- Classes.SMALL
787
- )}
788
- icon={isExpanded ? "chevron-down" : "chevron-right"}
789
- />
790
- );
791
- }
792
- });
793
- }
794
-
795
- if (withCheckboxes) {
796
- columnsToRender.push({
797
- Header: renderCheckboxHeader({
798
- change,
799
- entities,
800
- isEntityDisabled,
801
- isSingleSelect,
802
- noDeselectAll,
803
- noSelect,
804
- noUserSelect,
805
- onDeselect,
806
- onMultiRowSelect,
807
- onRowSelect,
808
- onSingleRowSelect,
809
- reduxFormSelectedEntityIdMap
810
- }),
811
- Cell: renderCheckboxCell,
812
- width: 35,
813
- resizable: false,
814
- getHeaderProps: () => {
815
- return {
816
- className: "tg-react-table-checkbox-header-container",
817
- immovable: "true"
818
- };
819
- },
820
- getProps: () => {
821
- return {
822
- className: "tg-react-table-checkbox-cell-container"
823
- };
824
- }
825
- });
826
- }
827
-
828
- const tableColumns = columns.map(column => {
829
- const tableColumn = {
830
- ...column,
831
- Header: RenderColumnHeader({
832
- column,
833
- isLocalCall,
834
- filters,
835
- currentParams,
836
- order,
837
- setOrder,
838
- withSort,
839
- extraCompact,
840
- withFilter,
841
- addFilters,
842
- removeSingleFilter,
843
- setNewParams,
844
- compact,
845
- isCellEditable,
846
- entities,
847
- updateEntitiesHelper
848
- }),
849
- accessor: column.path,
850
- getHeaderProps: () => ({
851
- // needs to be a string because it is getting passed
852
- // to the dom
853
- immovable: column.immovable ? "true" : "false",
854
- columnindex: column.columnIndex
855
- })
856
- };
857
- const noEllipsis = column.noEllipsis;
858
- if (column.width) {
859
- tableColumn.width = column.width;
860
- }
861
- if (cellRenderer && cellRenderer[column.path]) {
862
- tableColumn.Cell = row => {
863
- const val = cellRenderer[column.path](row.value, row.original, row, {
864
- currentParams,
865
- setNewParams
866
- });
867
- return val;
868
- };
869
- } else if (column.render) {
870
- tableColumn.Cell = row => {
871
- const val = column.render(row.value, row.original, row, {
872
- currentParams,
873
- setNewParams
874
- });
875
- return val;
876
- };
877
- } else if (column.type === "timestamp") {
878
- tableColumn.Cell = ({ value }) => {
879
- return value ? dayjs(value).format("lll") : "";
880
- };
881
- } else if (column.type === "color") {
882
- tableColumn.Cell = ({ value }) => {
883
- return value ? (
884
- <div
885
- style={{
886
- height: 20,
887
- width: 40,
888
- background: value,
889
- border: "1px solid #182026",
890
- borderRadius: 5
891
- }}
892
- />
893
- ) : (
894
- ""
895
- );
896
- };
897
- } else if (column.type === "boolean") {
898
- if (isCellEditable) {
899
- tableColumn.Cell = ({ value }) => (value ? "True" : "False");
900
- } else {
901
- tableColumn.Cell = ({ value }) => (
902
- <Icon
903
- className={classNames({
904
- [Classes.TEXT_MUTED]: !value
905
- })}
906
- icon={value ? "tick" : "cross"}
907
- />
908
- );
909
- }
910
- } else if (column.type === "markdown") {
911
- tableColumn.Cell = ({ value }) => (
912
- <ReactMarkdown remarkPlugins={[remarkGfm]}>{value}</ReactMarkdown>
913
- );
914
- } else {
915
- tableColumn.Cell = ({ value }) => value;
916
- }
917
- const oldFunc = tableColumn.Cell;
918
-
919
- tableColumn.Cell = (...args) => (
920
- <RenderCell
921
- oldFunc={oldFunc}
922
- formName={formName}
923
- getCopyTextForCell={getCopyTextForCell}
924
- column={column}
925
- isCellEditable={isCellEditable}
926
- isEntityDisabled={isEntityDisabled}
927
- finishCellEdit={finishCellEdit}
928
- noEllipsis={noEllipsis}
929
- editingCell={editingCell}
930
- cancelCellEdit={cancelCellEdit}
931
- editingCellSelectAll={editingCellSelectAll}
932
- getCellHoverText={getCellHoverText}
933
- selectedCells={selectedCells}
934
- isSelectionARectangle={isSelectionARectangle}
935
- startCellEdit={startCellEdit}
936
- tableRef={tableRef}
937
- onDragEnd={onDragEnd}
938
- args={args}
939
- />
940
- );
941
- return tableColumn;
942
- });
943
-
944
- return columnsToRender.concat(tableColumns);
945
- };