@teselagen/ui 0.5.23-beta.23 → 0.5.23-beta.25

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.
@@ -1,4 +1,4 @@
1
- import React, { isValidElement, useCallback } from "react";
1
+ import React, { isValidElement } from "react";
2
2
  import classNames from "classnames";
3
3
  import { Button, Classes, Checkbox, Icon } from "@blueprintjs/core";
4
4
  import {
@@ -24,6 +24,7 @@ import {
24
24
  getIdOrCodeOrIndex,
25
25
  getNumberStrAtEnd,
26
26
  getSelectedRowsFromEntities,
27
+ isBottomRightCornerOfRectangle,
27
28
  PRIMARY_SELECTED_VAL,
28
29
  stripNumberAtEnd
29
30
  } from "./utils";
@@ -32,11 +33,12 @@ import { ColumnFilterMenu } from "./ColumnFilterMenu";
32
33
  import getTextFromEl from "../utils/getTextFromEl";
33
34
  import rowClick, { finalizeSelection } from "./utils/rowClick";
34
35
  import { editCellHelper } from "./editCellHelper";
36
+ import { DropdownCell } from "./DropdownCell";
37
+ import { EditableCell } from "./EditabelCell";
38
+ import { getVals } from "./getVals";
39
+ import { CellDragHandle } from "./CellDragHandle";
35
40
  import { getCellVal } from "./getCellVal";
36
41
  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
42
 
41
43
  dayjs.extend(localizedFormat);
42
44
 
@@ -309,424 +311,479 @@ const renderCheckboxHeader = ({
309
311
  ) : null;
310
312
  };
311
313
 
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,
314
+ const RenderCell = ({
315
+ oldFunc,
316
+ getCopyTextForCell,
317
+ column,
326
318
  isCellEditable,
327
319
  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,
320
+ finishCellEdit,
321
+ noEllipsis,
322
+ editingCell,
323
+ cancelCellEdit,
324
+ editableCellValue,
325
+ setEditableCellValue,
326
+ getCellHoverText,
347
327
  selectedCells,
348
- setExpandedEntityIdMap,
349
- setNewParams,
350
- setOrder = noop,
351
- setSelectedCells,
352
- shouldShowSubComponent,
328
+ isSelectionARectangle,
353
329
  startCellEdit,
354
- SubComponent,
355
330
  tableRef,
356
- updateEntitiesHelper,
357
- updateValidation,
358
- withCheckboxes,
359
- withExpandAndCollapseAllButton,
360
- withFilter: _withFilter,
361
- withSort = true
331
+ onDragEnd,
332
+ args
362
333
  }) => {
363
- const dispatch = useDispatch();
364
- const change = useCallback(
365
- (...args) => dispatch(_change(formName, ...args)),
366
- [dispatch, formName]
334
+ const [row] = args;
335
+ const rowId = getIdOrCodeOrIndex(row.original, row.index);
336
+ const cellId = `${rowId}:${row.column.path}`;
337
+ let val = oldFunc(...args);
338
+ const oldVal = val;
339
+ const text = getCopyTextForCell(val, row, column);
340
+ const isBool = column.type === "boolean";
341
+ const dataTest = {
342
+ "data-test": "tgCell_" + column.path
343
+ };
344
+ const fullValue = row.original?.[row.column.path];
345
+ if (isCellEditable && isBool) {
346
+ val = (
347
+ <Checkbox
348
+ disabled={isEntityDisabled(row.original)}
349
+ className="tg-cell-edit-boolean-checkbox"
350
+ checked={oldVal === "True"}
351
+ onChange={e => {
352
+ const checked = e.target.checked;
353
+ finishCellEdit(cellId, checked);
354
+ }}
355
+ />
356
+ );
357
+ noEllipsis = true;
358
+ } else if (editingCell === cellId) {
359
+ if (column.type === "genericSelect") {
360
+ const GenericSelectComp = column.GenericSelectComp;
361
+
362
+ return (
363
+ <GenericSelectComp
364
+ rowId={rowId}
365
+ fullValue={fullValue}
366
+ initialValue={text}
367
+ {...dataTest}
368
+ finishEdit={(newVal, doNotStopEditing) => {
369
+ finishCellEdit(cellId, newVal, doNotStopEditing);
370
+ }}
371
+ dataTest={dataTest}
372
+ cancelEdit={cancelCellEdit}
373
+ />
374
+ );
375
+ }
376
+ if (column.type === "dropdown" || column.type === "dropdownMulti") {
377
+ return (
378
+ <DropdownCell
379
+ isMulti={dataTest.isMulti || column.type === "dropdownMulti"}
380
+ initialValue={dataTest.initialValue || text}
381
+ options={getVals(column.values)}
382
+ finishEdit={(newVal, doNotStopEditing) => {
383
+ finishCellEdit(cellId, newVal, doNotStopEditing);
384
+ }}
385
+ dataTest={dataTest}
386
+ cancelEdit={cancelCellEdit}
387
+ />
388
+ );
389
+ } else {
390
+ return (
391
+ <EditableCell
392
+ value={editableCellValue}
393
+ setValue={setEditableCellValue}
394
+ dataTest={dataTest}
395
+ cancelEdit={cancelCellEdit}
396
+ isNumeric={column.type === "number"}
397
+ initialValue={text}
398
+ finishEdit={newVal => {
399
+ finishCellEdit(cellId, newVal);
400
+ }}
401
+ />
402
+ );
403
+ }
404
+ }
405
+
406
+ //wrap the original tableColumn.Cell function in another div in order to add a title attribute
407
+ let title = text;
408
+ if (getCellHoverText) title = getCellHoverText(...args);
409
+ else if (column.getTitleAttr) title = column.getTitleAttr(...args);
410
+ const isSelectedCell = selectedCells?.[cellId];
411
+ const {
412
+ isRect,
413
+ selectionGrid,
414
+ lastRowIndex,
415
+ lastCellIndex,
416
+ entityMap,
417
+ pathToIndex
418
+ } = isSelectionARectangle();
419
+
420
+ return (
421
+ <>
422
+ <div
423
+ style={{
424
+ ...(!noEllipsis && {
425
+ textOverflow: "ellipsis",
426
+ overflow: "hidden"
427
+ })
428
+ }}
429
+ {...dataTest}
430
+ className="tg-cell-wrapper"
431
+ data-copy-text={text}
432
+ data-copy-json={JSON.stringify(
433
+ //tnw: eventually we'll parse these back out and use either the fullValue (for the generic selects) or the regular text vals for everything else
434
+ column.type === "genericSelect"
435
+ ? {
436
+ __strVal: fullValue,
437
+ __genSelCol: column.path
438
+ }
439
+ : { __strVal: text }
440
+ )}
441
+ title={title || undefined}
442
+ >
443
+ {val}
444
+ </div>
445
+ {isCellEditable &&
446
+ (column.type === "dropdown" ||
447
+ column.type === "dropdownMulti" ||
448
+ column.type === "genericSelect") && (
449
+ <Icon
450
+ icon="caret-down"
451
+ style={{
452
+ position: "absolute",
453
+ right: 5,
454
+ opacity: 0.3
455
+ }}
456
+ className="cell-edit-dropdown"
457
+ onClick={() => {
458
+ startCellEdit(cellId);
459
+ }}
460
+ />
461
+ )}
462
+
463
+ {isSelectedCell &&
464
+ (isRect
465
+ ? isBottomRightCornerOfRectangle({
466
+ cellId,
467
+ selectionGrid,
468
+ lastRowIndex,
469
+ lastCellIndex,
470
+ entityMap,
471
+ pathToIndex
472
+ })
473
+ : isSelectedCell === PRIMARY_SELECTED_VAL) && (
474
+ <CellDragHandle
475
+ key={cellId}
476
+ thisTable={tableRef.current.tableRef}
477
+ cellId={cellId}
478
+ isSelectionARectangle={isSelectionARectangle}
479
+ onDragEnd={onDragEnd}
480
+ />
481
+ )}
482
+ </>
367
483
  );
484
+ };
485
+
486
+ export const RenderColumns = props => {
487
+ const {
488
+ addFilters,
489
+ cellRenderer,
490
+ change,
491
+ columns,
492
+ currentParams,
493
+ compact,
494
+ editableCellValue,
495
+ editingCell,
496
+ editingCellSelectAll,
497
+ entities,
498
+ expandedEntityIdMap,
499
+ extraCompact,
500
+ filters,
501
+ getCellHoverText,
502
+ isCellEditable,
503
+ isEntityDisabled,
504
+ isLocalCall,
505
+ isSimple,
506
+ isSingleSelect,
507
+ isSelectionARectangle,
508
+ noDeselectAll,
509
+ noSelect,
510
+ noUserSelect,
511
+ onDeselect,
512
+ onMultiRowSelect,
513
+ onRowClick,
514
+ onRowSelect,
515
+ onSingleRowSelect,
516
+ order,
517
+ primarySelectedCellId,
518
+ reduxFormCellValidation,
519
+ reduxFormSelectedEntityIdMap,
520
+ refocusTable,
521
+ removeSingleFilter = noop,
522
+ schema,
523
+ selectedCells,
524
+ setEditableCellValue,
525
+ setEditingCell,
526
+ setExpandedEntityIdMap,
527
+ setNewParams,
528
+ setOrder = noop,
529
+ setSelectedCells,
530
+ shouldShowSubComponent,
531
+ startCellEdit,
532
+ SubComponent,
533
+ tableRef,
534
+ updateEntitiesHelper,
535
+ updateValidation,
536
+ withCheckboxes,
537
+ withExpandAndCollapseAllButton,
538
+ withFilter: _withFilter,
539
+ withSort = true
540
+ } = props;
541
+
368
542
  const withFilter = _withFilter === undefined ? !isSimple : _withFilter;
369
543
 
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];
544
+ const onDragEnd = cellsToSelect => {
545
+ const [primaryRowId, primaryCellPath] = primarySelectedCellId.split(":");
546
+ const pathToField = getFieldPathToField(schema);
547
+ const { selectedPaths, selectionGrid } = isSelectionARectangle();
548
+ let allSelectedPaths = selectedPaths;
549
+ if (!allSelectedPaths) {
550
+ allSelectedPaths = [primaryCellPath];
551
+ }
552
+
553
+ updateEntitiesHelper(entities, entities => {
554
+ let newSelectedCells;
555
+ if (selectedPaths) {
556
+ newSelectedCells = {
557
+ ...selectedCells
558
+ };
559
+ } else {
560
+ newSelectedCells = {
561
+ [primarySelectedCellId]: PRIMARY_SELECTED_VAL
562
+ };
378
563
  }
379
564
 
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
- }
565
+ const newCellValidate = {
566
+ ...reduxFormCellValidation
567
+ };
568
+ const entityMap = getEntityIdToEntity(entities);
569
+ const { e: selectedEnt } = entityMap[primaryRowId];
570
+ const firstCellToSelectRowIndex =
571
+ entityMap[cellsToSelect[0]?.split(":")[0]]?.i;
572
+ const pathToIndex = getFieldPathToIndex(schema);
391
573
 
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
- }
574
+ allSelectedPaths.forEach(selectedPath => {
575
+ const column = pathToField[selectedPath];
576
+
577
+ const selectedCellVal = getCellVal(selectedEnt, selectedPath, column);
578
+ const cellIndexOfSelectedPath = pathToIndex[selectedPath];
579
+ let incrementStart;
580
+ let incrementPrefix;
581
+ let incrementPad = 0;
582
+ if (column.type === "string" || column.type === "number") {
583
+ const cellNumStr = getNumberStrAtEnd(selectedCellVal);
584
+ const cellNum = Number(cellNumStr);
585
+ const entityAbovePrimaryCell =
586
+ entities[entityMap[primaryRowId].i - 1];
587
+ if (cellNumStr !== null && !isNaN(cellNum)) {
588
+ if (
589
+ entityAbovePrimaryCell &&
590
+ (!selectionGrid || selectionGrid.length <= 1)
591
+ ) {
592
+ const cellAboveVal = get(
593
+ entityAbovePrimaryCell,
594
+ selectedPath,
595
+ ""
596
+ );
597
+ const cellAboveNumStr = getNumberStrAtEnd(cellAboveVal);
598
+ const cellAboveNum = Number(cellAboveNumStr);
599
+ if (!isNaN(cellAboveNum)) {
600
+ const isIncremental = cellNum - cellAboveNum === 1;
601
+ if (isIncremental) {
602
+ const cellTextNoNum = stripNumberAtEnd(selectedCellVal);
603
+ const sameText =
604
+ stripNumberAtEnd(cellAboveVal) === cellTextNoNum;
605
+ if (sameText) {
606
+ incrementStart = cellNum + 1;
607
+ incrementPrefix = cellTextNoNum || "";
608
+ if (cellNumStr && cellNumStr.startsWith("0")) {
609
+ incrementPad = cellNumStr.length;
438
610
  }
439
611
  }
440
612
  }
441
613
  }
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
- }
614
+ }
615
+ if (incrementStart === undefined) {
616
+ const draggingDown =
617
+ firstCellToSelectRowIndex > selectionGrid?.[0][0].rowIndex;
618
+ if (selectedPaths && draggingDown) {
619
+ let checkIncrement;
620
+ let prefix;
621
+ let maybePad;
622
+ // determine if all the cells in this column of the selectionGrid are incrementing
623
+ const allAreIncrementing = selectionGrid.every(row => {
624
+ // see if cell is selected
625
+ const cellInfo = row[cellIndexOfSelectedPath];
626
+ if (!cellInfo) return false;
627
+ const { cellId } = cellInfo;
628
+ const [rowId] = cellId.split(":");
629
+ const cellVal = getCellVal(
630
+ entityMap[rowId].e,
631
+ selectedPath,
632
+ pathToField[selectedPath]
633
+ );
634
+ const cellNumStr = getNumberStrAtEnd(cellVal);
635
+ const cellNum = Number(cellNumStr);
636
+ const cellTextNoNum = stripNumberAtEnd(cellVal);
637
+ if (cellNumStr?.startsWith("0")) {
638
+ maybePad = cellNumStr.length;
639
+ }
640
+ if (cellTextNoNum && !prefix) {
641
+ prefix = cellTextNoNum;
642
+ }
643
+ if (cellTextNoNum && prefix !== cellTextNoNum) {
644
+ return false;
645
+ }
646
+ if (!isNaN(cellNum)) {
647
+ if (!checkIncrement) {
648
+ checkIncrement = cellNum;
649
+ return true;
480
650
  } else {
481
- return false;
651
+ return ++checkIncrement === cellNum;
482
652
  }
483
- });
484
-
485
- if (allAreIncrementing) {
486
- incrementStart = checkIncrement + 1;
487
- incrementPrefix = prefix || "";
488
- incrementPad = maybePad;
653
+ } else {
654
+ return false;
489
655
  }
656
+ });
657
+
658
+ if (allAreIncrementing) {
659
+ incrementStart = checkIncrement + 1;
660
+ incrementPrefix = prefix || "";
661
+ incrementPad = maybePad;
490
662
  }
491
663
  }
492
664
  }
493
665
  }
666
+ }
494
667
 
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
- }
668
+ let firstSelectedCellRowIndex;
669
+ if (selectionGrid) {
670
+ selectionGrid[0].some(cell => {
671
+ if (cell) {
672
+ firstSelectedCellRowIndex = cell.rowIndex;
673
+ return true;
674
+ }
675
+ return false;
676
+ });
677
+ }
539
678
 
540
- const [rowIdToCopy, cellPathToCopy] = cellIdToCopy.split(":");
541
- newVal = getCellVal(
542
- entityMap[rowIdToCopy].e,
543
- cellPathToCopy,
544
- pathToField[cellPathToCopy]
545
- );
679
+ cellsToSelect.forEach(cellId => {
680
+ const [rowId, cellPath] = cellId.split(":");
681
+ if (cellPath !== selectedPath) return;
682
+ newSelectedCells[cellId] = true;
683
+ const { e: entityToUpdate, i: rowIndex } = entityMap[rowId] || {};
684
+ if (entityToUpdate) {
685
+ delete entityToUpdate._isClean;
686
+ let newVal;
687
+ if (incrementStart !== undefined) {
688
+ const num = incrementStart++;
689
+ newVal = incrementPrefix + padStart(num, incrementPad, "0");
690
+ } else {
691
+ if (selectionGrid && selectionGrid.length > 1) {
692
+ // if there are multiple cells selected then we want to copy them repeating
693
+ // ex: if we have 1,2,3 selected and we drag for 5 more rows we want it to
694
+ // be 1,2,3,1,2 for the new row cells in this column
695
+ const draggingDown = rowIndex > firstSelectedCellRowIndex;
696
+ const cellIndex = pathToIndex[cellPath];
697
+ let cellIdToCopy;
698
+ if (draggingDown) {
699
+ const { cellId } = selectionGrid[
700
+ (rowIndex - firstSelectedCellRowIndex) %
701
+ selectionGrid.length
702
+ ].find(g => g && g.cellIndex === cellIndex);
703
+ cellIdToCopy = cellId;
546
704
  } else {
547
- newVal = selectedCellVal;
705
+ const lastIndexInGrid =
706
+ selectionGrid[selectionGrid.length - 1][0].rowIndex;
707
+ const { cellId } = selectionGrid[
708
+ (rowIndex + lastIndexInGrid + 1) % selectionGrid.length
709
+ ].find(g => g.cellIndex === cellIndex);
710
+ cellIdToCopy = cellId;
548
711
  }
712
+
713
+ const [rowIdToCopy, cellPathToCopy] = cellIdToCopy.split(":");
714
+ newVal = getCellVal(
715
+ entityMap[rowIdToCopy].e,
716
+ cellPathToCopy,
717
+ pathToField[cellPathToCopy]
718
+ );
719
+ } else {
720
+ newVal = selectedCellVal;
549
721
  }
550
- const { error } = editCellHelper({
551
- entity: entityToUpdate,
552
- path: cellPath,
553
- schema,
554
- newVal
555
- });
556
- newCellValidate[cellId] = error;
557
722
  }
558
- });
723
+ const { error } = editCellHelper({
724
+ entity: entityToUpdate,
725
+ path: cellPath,
726
+ schema,
727
+ newVal
728
+ });
729
+ newCellValidate[cellId] = error;
730
+ }
559
731
  });
560
-
561
- // select the new cells
562
- updateValidation(entities, newCellValidate);
563
- setSelectedCells(newSelectedCells);
564
732
  });
565
- },
566
- [
567
- entities,
568
- isSelectionARectangle,
569
- primarySelectedCellId,
570
- reduxFormCellValidation,
571
- schema,
572
- selectedCells,
573
- setSelectedCells,
574
- updateEntitiesHelper,
575
- updateValidation
576
- ]
577
- );
578
733
 
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
- }
734
+ // select the new cells
735
+ updateValidation(entities, newCellValidate);
736
+ setSelectedCells(newSelectedCells);
737
+ });
738
+ };
628
739
 
629
- const stringText = toString(text);
630
- if (stringText === "[object Object]") return "";
631
- return stringText;
632
- },
633
- [cellRenderer, currentParams, setNewParams]
634
- );
740
+ const getCopyTextForCell = (val, row = {}, column = {}) => {
741
+ // TODOCOPY we need a way to potentially omit certain columns from being added as a \t element (talk to taoh about this)
742
+ let text = typeof val !== "string" ? row.value : val;
635
743
 
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 />;
744
+ // We should try to take out the props from here, it produces
745
+ // unnecessary rerenders
746
+ const record = row.original;
747
+ if (column.getClipboardData) {
748
+ text = column.getClipboardData(row.value, record, row, props);
749
+ } else if (column.getValueToFilterOn) {
750
+ text = column.getValueToFilterOn(record, props);
751
+ } else if (column.render) {
752
+ text = column.render(row.value, record, row, props);
753
+ } else if (cellRenderer && cellRenderer[column.path]) {
754
+ text = cellRenderer[column.path](row.value, row.original, row, props);
755
+ } else if (text) {
756
+ text = isValidElement(text) ? text : String(text);
757
+ }
758
+ const getTextFromElementOrLink = text => {
759
+ if (isValidElement(text)) {
760
+ if (text.props?.to) {
761
+ // this will convert Link elements to url strings
762
+ return joinUrl(
763
+ window.location.origin,
764
+ window.frontEndConfig?.clientBasePath || "",
765
+ text.props.to
766
+ );
767
+ } else {
768
+ return getTextFromEl(text);
769
+ }
770
+ } else {
771
+ return text;
649
772
  }
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
- );
773
+ };
774
+ text = getTextFromElementOrLink(text);
692
775
 
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
- updateValidation(entities, {
709
- ...reduxFormCellValidation,
710
- [cellId]: error
711
- });
712
- });
713
- !doNotStopEditing && refocusTable();
714
- },
715
- [
716
- change,
717
- entities,
718
- reduxFormCellValidation,
719
- refocusTable,
720
- schema,
721
- updateEntitiesHelper,
722
- updateValidation
723
- ]
724
- );
776
+ if (Array.isArray(text)) {
777
+ let arrText = text.map(getTextFromElementOrLink).join(", ");
778
+ // because we sometimes insert commas after links when mapping over an array of elements we will have double ,'s
779
+ arrText = arrText.replace(/, ,/g, ",");
780
+ text = arrText;
781
+ }
725
782
 
726
- const cancelCellEdit = useCallback(() => {
727
- change("reduxFormEditingCell", null);
728
- refocusTable();
729
- }, [change, refocusTable]);
783
+ const stringText = toString(text);
784
+ if (stringText === "[object Object]") return "";
785
+ return stringText;
786
+ };
730
787
 
731
788
  if (!columns.length) {
732
789
  return columns;
@@ -791,6 +848,72 @@ export const useColumns = ({
791
848
  });
792
849
  }
793
850
 
851
+ const renderCheckboxCell = row => {
852
+ const rowIndex = row.index;
853
+ const checkedRows = getSelectedRowsFromEntities(
854
+ entities,
855
+ reduxFormSelectedEntityIdMap
856
+ );
857
+
858
+ const isSelected = checkedRows.some(rowNum => {
859
+ return rowNum === rowIndex;
860
+ });
861
+ if (rowIndex >= entities.length) {
862
+ return <div />;
863
+ }
864
+ const entity = entities[rowIndex];
865
+ return (
866
+ <Checkbox
867
+ name={`${getIdOrCodeOrIndex(entity, rowIndex)}-checkbox`}
868
+ disabled={noSelect || noUserSelect || isEntityDisabled(entity)}
869
+ onClick={e => {
870
+ rowClick(e, row, entities, {
871
+ reduxFormSelectedEntityIdMap,
872
+ isSingleSelect,
873
+ noSelect,
874
+ onRowClick,
875
+ isEntityDisabled,
876
+ withCheckboxes,
877
+ onDeselect,
878
+ onSingleRowSelect,
879
+ onMultiRowSelect,
880
+ noDeselectAll,
881
+ onRowSelect,
882
+ change
883
+ });
884
+ }}
885
+ checked={isSelected}
886
+ />
887
+ );
888
+ };
889
+
890
+ const finishCellEdit = (cellId, newVal, doNotStopEditing) => {
891
+ const [rowId, path] = cellId.split(":");
892
+ !doNotStopEditing && setEditingCell(null);
893
+ updateEntitiesHelper(entities, entities => {
894
+ const entity = entities.find((e, i) => {
895
+ return getIdOrCodeOrIndex(e, i) === rowId;
896
+ });
897
+ delete entity._isClean;
898
+ const { error } = editCellHelper({
899
+ entity,
900
+ path,
901
+ schema,
902
+ newVal
903
+ });
904
+ updateValidation(entities, {
905
+ ...reduxFormCellValidation,
906
+ [cellId]: error
907
+ });
908
+ });
909
+ !doNotStopEditing && refocusTable();
910
+ };
911
+
912
+ const cancelCellEdit = () => {
913
+ setEditingCell(null);
914
+ refocusTable();
915
+ };
916
+
794
917
  if (withCheckboxes) {
795
918
  columnsToRender.push({
796
919
  Header: renderCheckboxHeader({
@@ -824,7 +947,7 @@ export const useColumns = ({
824
947
  });
825
948
  }
826
949
 
827
- const tableColumns = columns.map(column => {
950
+ columns.forEach(column => {
828
951
  const tableColumn = {
829
952
  ...column,
830
953
  Header: RenderColumnHeader({
@@ -859,18 +982,17 @@ export const useColumns = ({
859
982
  }
860
983
  if (cellRenderer && cellRenderer[column.path]) {
861
984
  tableColumn.Cell = row => {
862
- const val = cellRenderer[column.path](row.value, row.original, row, {
863
- currentParams,
864
- setNewParams
865
- });
985
+ const val = cellRenderer[column.path](
986
+ row.value,
987
+ row.original,
988
+ row,
989
+ props
990
+ );
866
991
  return val;
867
992
  };
868
993
  } else if (column.render) {
869
994
  tableColumn.Cell = row => {
870
- const val = column.render(row.value, row.original, row, {
871
- currentParams,
872
- setNewParams
873
- });
995
+ const val = column.render(row.value, row.original, row, props);
874
996
  return val;
875
997
  };
876
998
  } else if (column.type === "timestamp") {
@@ -918,7 +1040,6 @@ export const useColumns = ({
918
1040
  tableColumn.Cell = (...args) => (
919
1041
  <RenderCell
920
1042
  oldFunc={oldFunc}
921
- formName={formName}
922
1043
  getCopyTextForCell={getCopyTextForCell}
923
1044
  column={column}
924
1045
  isCellEditable={isCellEditable}
@@ -927,6 +1048,8 @@ export const useColumns = ({
927
1048
  noEllipsis={noEllipsis}
928
1049
  editingCell={editingCell}
929
1050
  cancelCellEdit={cancelCellEdit}
1051
+ editableCellValue={editableCellValue}
1052
+ setEditableCellValue={setEditableCellValue}
930
1053
  editingCellSelectAll={editingCellSelectAll}
931
1054
  getCellHoverText={getCellHoverText}
932
1055
  selectedCells={selectedCells}
@@ -937,8 +1060,7 @@ export const useColumns = ({
937
1060
  args={args}
938
1061
  />
939
1062
  );
940
- return tableColumn;
1063
+ columnsToRender.push(tableColumn);
941
1064
  });
942
-
943
- return columnsToRender.concat(tableColumns);
1065
+ return columnsToRender;
944
1066
  };