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