@onehat/ui 0.4.65 → 0.4.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Components/Fab/DynamicFab.js +16 -10
- package/src/Components/Form/Form.js +32 -27
- package/src/Components/Grid/Grid.js +43 -10
- package/src/Components/Grid/GridHeaderRow.js +3 -3
- package/src/Components/Grid/GridRow.js +35 -4
- package/src/Components/Grid/RowDragHandle.js +1 -1
- package/src/Components/Grid/RowSelectHandle.js +3 -3
- package/src/Components/Hoc/withAlert.js +4 -0
- package/src/Components/Hoc/withDnd.js +54 -57
- package/src/Components/Hoc/withDraggable.js +8 -4
- package/src/Components/Hoc/withEditor.js +7 -1
- package/src/Components/Icons/Arcs.js +10 -0
- package/src/Components/Tree/Tree.js +365 -328
- package/src/Components/Tree/TreeNode.js +103 -29
- package/src/Components/Tree/TreeNodeDragHandle.js +33 -0
- package/src/Components/index.js +2 -0
- package/src/Constants/Styles.js +2 -0
- package/src/PlatformImports/Web/Attachments.js +19 -4
|
@@ -21,12 +21,18 @@ import {
|
|
|
21
21
|
EXPANDED,
|
|
22
22
|
LEAF,
|
|
23
23
|
} from '../../Constants/Tree.js';
|
|
24
|
+
import {
|
|
25
|
+
UI_MODE_WEB,
|
|
26
|
+
UI_MODE_NATIVE,
|
|
27
|
+
CURRENT_MODE,
|
|
28
|
+
} from '../../Constants/UiModes.js';
|
|
24
29
|
import UiGlobals from '../../UiGlobals.js';
|
|
25
30
|
import useForceUpdate from '../../Hooks/useForceUpdate.js';
|
|
26
31
|
import withContextMenu from '../Hoc/withContextMenu.js';
|
|
27
32
|
import withAlert from '../Hoc/withAlert.js';
|
|
28
33
|
import withComponent from '../Hoc/withComponent.js';
|
|
29
34
|
import withData from '../Hoc/withData.js';
|
|
35
|
+
import { withDropTarget } from '../Hoc/withDnd.js';
|
|
30
36
|
import withEvents from '../Hoc/withEvents.js';
|
|
31
37
|
import withSideEditor from '../Hoc/withSideEditor.js';
|
|
32
38
|
import withFilters from '../Hoc/withFilters.js';
|
|
@@ -41,19 +47,15 @@ import inArray from '../../Functions/inArray.js';
|
|
|
41
47
|
import testProps from '../../Functions/testProps.js';
|
|
42
48
|
import CenterBox from '../Layout/CenterBox.js';
|
|
43
49
|
import ReloadButton from '../Buttons/ReloadButton.js';
|
|
44
|
-
import TreeNode, {
|
|
50
|
+
import TreeNode, { DragSourceDropTargetTreeNode, DragSourceTreeNode, DropTargetTreeNode } from './TreeNode.js';
|
|
45
51
|
import FormPanel from '../Panel/FormPanel.js';
|
|
46
52
|
import Input from '../Form/Field/Input.js';
|
|
47
53
|
import Xmark from '../Icons/Xmark.js';
|
|
48
54
|
import Dot from '../Icons/Dot.js';
|
|
49
55
|
import Collapse from '../Icons/Collapse.js';
|
|
50
56
|
import Expand from '../Icons/Expand.js';
|
|
51
|
-
import FolderClosed from '../Icons/FolderClosed.js';
|
|
52
|
-
import FolderOpen from '../Icons/FolderOpen.js';
|
|
53
57
|
import Gear from '../Icons/Gear.js';
|
|
54
58
|
import MagnifyingGlass from '../Icons/MagnifyingGlass.js';
|
|
55
|
-
import NoReorderRows from '../Icons/NoReorderRows.js';
|
|
56
|
-
import ReorderRows from '../Icons/ReorderRows.js';
|
|
57
59
|
import PaginationToolbar from '../Toolbar/PaginationToolbar.js';
|
|
58
60
|
import NoRecordsFound from '../Grid/NoRecordsFound.js';
|
|
59
61
|
import Toolbar from '../Toolbar/Toolbar.js';
|
|
@@ -68,6 +70,8 @@ const
|
|
|
68
70
|
DOUBLE_CLICK = 2,
|
|
69
71
|
TRIPLE_CLICK = 3;
|
|
70
72
|
|
|
73
|
+
// NOTE: If using TreeComponent with getCustomDragProxy, ensure that <GlobalDragProxy /> exists in App.js
|
|
74
|
+
|
|
71
75
|
function TreeComponent(props) {
|
|
72
76
|
const {
|
|
73
77
|
areRootsVisible = true,
|
|
@@ -87,21 +91,9 @@ function TreeComponent(props) {
|
|
|
87
91
|
getDisplayTextFromSearchResults = (item) => {
|
|
88
92
|
return item.id
|
|
89
93
|
},
|
|
90
|
-
getNodeIcon = (
|
|
94
|
+
getNodeIcon = (item) => {
|
|
91
95
|
// TODO: Allow for dynamic props on the icon (e.g. special color for some icons)
|
|
92
|
-
|
|
93
|
-
switch(which) {
|
|
94
|
-
case COLLAPSED:
|
|
95
|
-
icon = FolderClosed;
|
|
96
|
-
break;
|
|
97
|
-
case EXPANDED:
|
|
98
|
-
icon = FolderOpen;
|
|
99
|
-
break;
|
|
100
|
-
case LEAF:
|
|
101
|
-
icon = Dot;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
return icon;
|
|
96
|
+
return Dot;
|
|
105
97
|
},
|
|
106
98
|
getNodeProps = (item) => {
|
|
107
99
|
return {};
|
|
@@ -110,7 +102,9 @@ function TreeComponent(props) {
|
|
|
110
102
|
disableLoadingIndicator = false,
|
|
111
103
|
disableSelectorSelected = false,
|
|
112
104
|
showHovers = true,
|
|
113
|
-
|
|
105
|
+
showSelectHandle = true,
|
|
106
|
+
isNodeSelectable = true,
|
|
107
|
+
isNodeHoverable = true,
|
|
114
108
|
allowToggleSelection = true, // i.e. single click with no shift key toggles the selection of the node clicked on
|
|
115
109
|
disableBottomToolbar = false,
|
|
116
110
|
bottomToolbar = null,
|
|
@@ -122,11 +116,24 @@ function TreeComponent(props) {
|
|
|
122
116
|
canRecordBeEdited,
|
|
123
117
|
onTreeLoad,
|
|
124
118
|
onLayout,
|
|
125
|
-
|
|
126
119
|
selectorId,
|
|
127
120
|
selectorSelected,
|
|
128
121
|
selectorSelectedField = 'id',
|
|
129
122
|
|
|
123
|
+
// DND
|
|
124
|
+
canNodesMoveInternally = false,
|
|
125
|
+
canNodeMoveInternally, // optional fn to customize whether each node can be dragged INternally
|
|
126
|
+
canNodeMoveExternally, // optional fn to customize whether each node can be dragged EXternally
|
|
127
|
+
canNodeAcceptDrop, // optional fn to customize whether each node can accept a dropped item: (targetItem, draggedItem) => boolean
|
|
128
|
+
getCustomDragProxy, // optional fn to render custom drag preview: (item, selection) => ReactElement
|
|
129
|
+
dragPreviewOptions, // optional object for drag preview positioning options
|
|
130
|
+
areNodesDragSource = false,
|
|
131
|
+
nodeDragSourceType,
|
|
132
|
+
getNodeDragSourceItem,
|
|
133
|
+
areNodesDropTarget = false,
|
|
134
|
+
dropTargetAccept,
|
|
135
|
+
onNodeDrop,
|
|
136
|
+
|
|
130
137
|
// withComponent
|
|
131
138
|
self,
|
|
132
139
|
|
|
@@ -161,6 +168,12 @@ function TreeComponent(props) {
|
|
|
161
168
|
// withPermissions
|
|
162
169
|
canUser,
|
|
163
170
|
|
|
171
|
+
// withDnd
|
|
172
|
+
isDropTarget,
|
|
173
|
+
canDrop,
|
|
174
|
+
isOver,
|
|
175
|
+
dropTargetRef,
|
|
176
|
+
|
|
164
177
|
// withSelection
|
|
165
178
|
selection,
|
|
166
179
|
setSelection,
|
|
@@ -173,19 +186,15 @@ function TreeComponent(props) {
|
|
|
173
186
|
noSelectorMeansNoResults = false,
|
|
174
187
|
|
|
175
188
|
} = props,
|
|
176
|
-
styles = UiGlobals.styles,
|
|
177
189
|
forceUpdate = useForceUpdate(),
|
|
178
190
|
treeRef = useRef(),
|
|
179
191
|
treeNodeData = useRef(),
|
|
192
|
+
dragSelectionRef = useRef([]),
|
|
180
193
|
[isReady, setIsReady] = useState(false),
|
|
181
194
|
[isLoading, setIsLoading] = useState(false),
|
|
182
|
-
[rowToDatumMap, setRowToDatumMap] = useState({}),
|
|
183
195
|
[searchResults, setSearchResults] = useState([]),
|
|
184
196
|
[searchFormData, setSearchFormData] = useState([]),
|
|
185
197
|
[highlitedDatum, setHighlitedDatum] = useState(null),
|
|
186
|
-
[isDragMode, setIsDragMode] = useState(false),
|
|
187
|
-
[dragNodeId, setDragNodeId] = useState(null),
|
|
188
|
-
[dropRowIx, setDropRowIx] = useState(null),
|
|
189
198
|
[treeSearchValue, setTreeSearchValue] = useState(''),
|
|
190
199
|
|
|
191
200
|
// state getters & setters
|
|
@@ -270,7 +279,7 @@ function TreeComponent(props) {
|
|
|
270
279
|
}
|
|
271
280
|
const
|
|
272
281
|
parent = selection[0],
|
|
273
|
-
parentDatum =
|
|
282
|
+
parentDatum = getDatumById(parent.id);
|
|
274
283
|
|
|
275
284
|
if (parent.hasChildren && !parent.areChildrenLoaded) {
|
|
276
285
|
await loadChildren(parentDatum);
|
|
@@ -284,7 +293,7 @@ function TreeComponent(props) {
|
|
|
284
293
|
// Add the entity to the tree, show parent as hasChildren and expanded
|
|
285
294
|
const
|
|
286
295
|
parent = selection[0],
|
|
287
|
-
parentDatum =
|
|
296
|
+
parentDatum = getDatumById(parent.id);
|
|
288
297
|
if (!parent.hasChildren) {
|
|
289
298
|
parent.hasChildren = true; // since we're adding a new child
|
|
290
299
|
}
|
|
@@ -292,7 +301,6 @@ function TreeComponent(props) {
|
|
|
292
301
|
parentDatum.isExpanded = true;
|
|
293
302
|
}
|
|
294
303
|
|
|
295
|
-
buildRowToDatumMap();
|
|
296
304
|
forceUpdate();
|
|
297
305
|
},
|
|
298
306
|
onAfterAddSave = (entities) => {
|
|
@@ -307,7 +315,7 @@ function TreeComponent(props) {
|
|
|
307
315
|
// Refresh the node's display
|
|
308
316
|
const
|
|
309
317
|
node = entities[0],
|
|
310
|
-
existingDatum =
|
|
318
|
+
existingDatum = getDatumById(node.id), // TODO: Make this work for >1 entity
|
|
311
319
|
newDatum = buildTreeNodeDatum(node);
|
|
312
320
|
|
|
313
321
|
// copy the updated data to existingDatum
|
|
@@ -317,7 +325,7 @@ function TreeComponent(props) {
|
|
|
317
325
|
|
|
318
326
|
if (node.parent?.id) {
|
|
319
327
|
const
|
|
320
|
-
existingParentDatum =
|
|
328
|
+
existingParentDatum = getDatumById(node.parent.id),
|
|
321
329
|
newParentDatum = buildTreeNodeDatum(node.parent);
|
|
322
330
|
_.assign(existingParentDatum, newParentDatum);
|
|
323
331
|
existingParentDatum.isExpanded = true;
|
|
@@ -331,7 +339,7 @@ function TreeComponent(props) {
|
|
|
331
339
|
onBeforeSave = (entities) => {
|
|
332
340
|
const
|
|
333
341
|
node = entities[0],
|
|
334
|
-
datum =
|
|
342
|
+
datum = getDatumById(node.id); // TODO: Make this work for >1 entity
|
|
335
343
|
|
|
336
344
|
datum.isLoading = true;
|
|
337
345
|
forceUpdate();
|
|
@@ -339,9 +347,7 @@ function TreeComponent(props) {
|
|
|
339
347
|
onAfterDelete = async (entities) => {
|
|
340
348
|
const parent = entities[0].parent;
|
|
341
349
|
if (parent) {
|
|
342
|
-
await reloadNode(parent);
|
|
343
|
-
} else {
|
|
344
|
-
buildRowToDatumMap();
|
|
350
|
+
await reloadNode(parent);
|
|
345
351
|
}
|
|
346
352
|
},
|
|
347
353
|
onToggle = async (datum, e) => {
|
|
@@ -376,7 +382,6 @@ function TreeComponent(props) {
|
|
|
376
382
|
}
|
|
377
383
|
|
|
378
384
|
forceUpdate();
|
|
379
|
-
buildRowToDatumMap();
|
|
380
385
|
},
|
|
381
386
|
onCollapseAll = () => {
|
|
382
387
|
const newTreeNodeData = _.clone(getTreeNodeData());
|
|
@@ -473,35 +478,50 @@ function TreeComponent(props) {
|
|
|
473
478
|
});
|
|
474
479
|
},
|
|
475
480
|
|
|
476
|
-
//
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
if (!_.isEmpty(node.children)) {
|
|
483
|
-
let found1 = null;
|
|
484
|
-
_.each(node.children, (node2) => {
|
|
485
|
-
const found2 = findNodeById(node2);
|
|
486
|
-
if (found2) {
|
|
487
|
-
found1 = found2;
|
|
488
|
-
return false; // break loop
|
|
489
|
-
}
|
|
490
|
-
})
|
|
491
|
-
return found1
|
|
492
|
-
}
|
|
493
|
-
return false;
|
|
481
|
+
// internal DND
|
|
482
|
+
onInternalNodeDrop = async (droppedOn, droppedItem) => {
|
|
483
|
+
let selectedNodes = [];
|
|
484
|
+
if (droppedItem.getSelection) {
|
|
485
|
+
selectedNodes = droppedItem.getSelection();
|
|
494
486
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
487
|
+
if (_.isEmpty(selectedNodes)) {
|
|
488
|
+
selectedNodes = [droppedItem.item];
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// filter out nodes that would already be moved by others in the selection
|
|
492
|
+
const selectedNodesClone = [...selectedNodes];
|
|
493
|
+
selectedNodes = selectedNodes.filter((node) => {
|
|
494
|
+
let isDescendant = false;
|
|
495
|
+
_.each(selectedNodesClone, (otherNode) => {
|
|
496
|
+
if (node.id === otherNode.id) {
|
|
497
|
+
return false; // skip self
|
|
498
|
+
}
|
|
499
|
+
isDescendant = isDescendantOf(node, otherNode);
|
|
500
|
+
if (isDescendant) {
|
|
501
|
+
return false; // found descendant; break loop
|
|
502
|
+
}
|
|
503
|
+
isDescendant = isDescendantOf(otherNode, node);
|
|
504
|
+
if (isDescendant) {
|
|
505
|
+
return false; // found ancestor; break loop
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
return !isDescendant;
|
|
502
509
|
});
|
|
503
|
-
|
|
510
|
+
|
|
511
|
+
const isMultiSelection = selectedNodes.length > 1;
|
|
512
|
+
if (isMultiSelection) {
|
|
513
|
+
alert('moving multiple disparate nodes not yet implemented');
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const selectedNode = selectedNodes[0];
|
|
518
|
+
const commonAncestorId = await Repository.moveTreeNode(selectedNode, droppedOn.id);
|
|
519
|
+
const commonAncestorDatum = getDatumById(commonAncestorId);
|
|
520
|
+
reloadNode(commonAncestorDatum.item);
|
|
521
|
+
|
|
504
522
|
},
|
|
523
|
+
|
|
524
|
+
// utilities
|
|
505
525
|
buildTreeNodeDatum = (treeNode, defaultToExpanded = false) => {
|
|
506
526
|
// Build the data-representation of one node and its children,
|
|
507
527
|
// caching text & icon, keeping track of the state for whole tree
|
|
@@ -511,11 +531,10 @@ function TreeComponent(props) {
|
|
|
511
531
|
children = buildTreeNodeData(treeNode.children, defaultToExpanded), // recursively get data for children
|
|
512
532
|
datum = {
|
|
513
533
|
item: treeNode,
|
|
534
|
+
treeRef,
|
|
514
535
|
text: getNodeText(treeNode),
|
|
515
536
|
content: getNodeContent ? getNodeContent(treeNode) : null,
|
|
516
|
-
|
|
517
|
-
iconExpanded: getNodeIcon(EXPANDED, treeNode),
|
|
518
|
-
iconLeaf: getNodeIcon(LEAF, treeNode),
|
|
537
|
+
icon: getNodeIcon(treeNode),
|
|
519
538
|
isExpanded: treeNode.isExpanded || defaultToExpanded || isRoot, // all non-root treeNodes are collapsed by default
|
|
520
539
|
isVisible: isRoot ? areRootsVisible : true,
|
|
521
540
|
isLoading: false,
|
|
@@ -548,37 +567,39 @@ function TreeComponent(props) {
|
|
|
548
567
|
const treeNodeData = buildTreeNodeData(nodes);
|
|
549
568
|
setTreeNodeData(treeNodeData);
|
|
550
569
|
|
|
551
|
-
buildRowToDatumMap();
|
|
552
|
-
|
|
553
570
|
if (onTreeLoad) {
|
|
554
571
|
onTreeLoad(self);
|
|
555
572
|
}
|
|
556
573
|
return treeNodeData;
|
|
557
574
|
},
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Add this datum's id
|
|
568
|
-
rowToDatumMap[ix] = datum;
|
|
569
|
-
ix++;
|
|
575
|
+
buildAndSetOneTreeNodeData = (entity) => {
|
|
576
|
+
|
|
577
|
+
if (!entity || !entity.parent) {
|
|
578
|
+
// If no parent, it might be a root node, so rebuild the tree
|
|
579
|
+
buildAndSetTreeNodeData();
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
570
582
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
583
|
+
const parentDatum = getDatumById(entity.parent.id);
|
|
584
|
+
if (!parentDatum) {
|
|
585
|
+
// Parent not found in current tree structure, rebuild
|
|
586
|
+
buildAndSetTreeNodeData();
|
|
587
|
+
return;
|
|
576
588
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
589
|
+
|
|
590
|
+
// Create datum for the new entity and add it to parent's children
|
|
591
|
+
const newDatum = buildTreeNodeDatum(entity);
|
|
592
|
+
parentDatum.children.push(newDatum);
|
|
580
593
|
|
|
581
|
-
|
|
594
|
+
// Update parent to show it has children and expand if needed
|
|
595
|
+
if (!entity.parent.hasChildren) {
|
|
596
|
+
entity.parent.hasChildren = true;
|
|
597
|
+
}
|
|
598
|
+
if (!parentDatum.isExpanded) {
|
|
599
|
+
parentDatum.isExpanded = true;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
forceUpdate();
|
|
582
603
|
},
|
|
583
604
|
datumContainsSelection = (datum) => {
|
|
584
605
|
if (_.isEmpty(selection)) {
|
|
@@ -698,13 +719,38 @@ function TreeComponent(props) {
|
|
|
698
719
|
|
|
699
720
|
return treeNodes;
|
|
700
721
|
},
|
|
722
|
+
belongsToThisTree = (treeNode) => {
|
|
723
|
+
if (!treeNode) {
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
const datum = getDatumById(treeNode.id);
|
|
727
|
+
if (!datum) {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
return datum.treeRef === treeRef;
|
|
731
|
+
},
|
|
732
|
+
isDescendantOf = (potentialDescendant, potentialAncestor) => {
|
|
733
|
+
// Check if potentialDescendant is a descendant of potentialAncestor
|
|
734
|
+
// by walking up the parent chain from potentialDescendant
|
|
735
|
+
let currentTreeNode = potentialDescendant;
|
|
736
|
+
while(currentTreeNode) {
|
|
737
|
+
if (currentTreeNode.id === potentialAncestor.id) {
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
currentTreeNode = currentTreeNode.parent;
|
|
741
|
+
}
|
|
742
|
+
return false;
|
|
743
|
+
},
|
|
744
|
+
isChildOf = (potentialChild, potentialParent) => {
|
|
745
|
+
return potentialChild.parent?.id === potentialParent.id;
|
|
746
|
+
},
|
|
701
747
|
reloadTree = () => {
|
|
702
748
|
Repository.areRootNodesLoaded = false;
|
|
703
749
|
return buildAndSetTreeNodeData();
|
|
704
750
|
},
|
|
705
751
|
reloadNode = async (node) => {
|
|
706
752
|
// mark node as loading
|
|
707
|
-
const existingDatum =
|
|
753
|
+
const existingDatum = getDatumById(node.id);
|
|
708
754
|
existingDatum.isLoading = true;
|
|
709
755
|
forceUpdate();
|
|
710
756
|
|
|
@@ -718,8 +764,6 @@ function TreeComponent(props) {
|
|
|
718
764
|
_.assign(existingDatum, _.omit(newDatum, ['isExpanded']));
|
|
719
765
|
existingDatum.isLoading = false;
|
|
720
766
|
forceUpdate();
|
|
721
|
-
|
|
722
|
-
buildRowToDatumMap();
|
|
723
767
|
},
|
|
724
768
|
loadChildren = async (datum, depth = 1) => {
|
|
725
769
|
|
|
@@ -755,12 +799,9 @@ function TreeComponent(props) {
|
|
|
755
799
|
// Hide loading indicator
|
|
756
800
|
datum.isLoading = false;
|
|
757
801
|
forceUpdate();
|
|
758
|
-
|
|
759
|
-
buildRowToDatumMap();
|
|
760
802
|
},
|
|
761
803
|
collapseNodes = (nodes) => {
|
|
762
804
|
collapseNodesRecursive(nodes);
|
|
763
|
-
buildRowToDatumMap();
|
|
764
805
|
},
|
|
765
806
|
collapseNodesRecursive = (nodes) => {
|
|
766
807
|
_.each(nodes, (node) => {
|
|
@@ -779,7 +820,6 @@ function TreeComponent(props) {
|
|
|
779
820
|
|
|
780
821
|
// expand them in UI
|
|
781
822
|
expandNodesRecursive(nodes);
|
|
782
|
-
buildRowToDatumMap();
|
|
783
823
|
},
|
|
784
824
|
expandNodesRecursive = (nodes) => {
|
|
785
825
|
_.each(nodes, (node) => {
|
|
@@ -846,7 +886,6 @@ function TreeComponent(props) {
|
|
|
846
886
|
}
|
|
847
887
|
|
|
848
888
|
setTreeNodeData(newTreeNodeData);
|
|
849
|
-
buildRowToDatumMap();
|
|
850
889
|
},
|
|
851
890
|
scrollToNode = (node) => {
|
|
852
891
|
// Helper for expandPath
|
|
@@ -907,17 +946,6 @@ function TreeComponent(props) {
|
|
|
907
946
|
isDisabled: false,
|
|
908
947
|
},
|
|
909
948
|
];
|
|
910
|
-
if (canNodesReorder) {
|
|
911
|
-
buttons.push({
|
|
912
|
-
key: 'reorderBtn',
|
|
913
|
-
text: (isDragMode ? 'Exit' : 'Enter') + ' reorder mode',
|
|
914
|
-
handler: () => {
|
|
915
|
-
setIsDragMode(!isDragMode);
|
|
916
|
-
},
|
|
917
|
-
icon: isDragMode ? NoReorderRows : ReorderRows,
|
|
918
|
-
isDisabled: false,
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
949
|
if (isNodeTextConfigurable && editDisplaySettings) {
|
|
922
950
|
buttons.push({
|
|
923
951
|
key: 'editNodeTextBtn',
|
|
@@ -978,9 +1006,6 @@ function TreeComponent(props) {
|
|
|
978
1006
|
if (e.preventDefault && e.cancelable) {
|
|
979
1007
|
e.preventDefault();
|
|
980
1008
|
}
|
|
981
|
-
if (isDragMode) {
|
|
982
|
-
return
|
|
983
|
-
}
|
|
984
1009
|
switch (e.detail) {
|
|
985
1010
|
case SIMULATED_CLICK:
|
|
986
1011
|
case SINGLE_CLICK:
|
|
@@ -1014,9 +1039,6 @@ function TreeComponent(props) {
|
|
|
1014
1039
|
if (e.preventDefault && e.cancelable) {
|
|
1015
1040
|
e.preventDefault();
|
|
1016
1041
|
}
|
|
1017
|
-
if (isDragMode) {
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
1042
|
|
|
1021
1043
|
if (!setSelection) {
|
|
1022
1044
|
return;
|
|
@@ -1030,6 +1052,8 @@ function TreeComponent(props) {
|
|
|
1030
1052
|
}
|
|
1031
1053
|
}}
|
|
1032
1054
|
className={`
|
|
1055
|
+
Pressable
|
|
1056
|
+
Node
|
|
1033
1057
|
flex-row
|
|
1034
1058
|
`}
|
|
1035
1059
|
style={{
|
|
@@ -1041,32 +1065,197 @@ function TreeComponent(props) {
|
|
|
1041
1065
|
focused,
|
|
1042
1066
|
pressed,
|
|
1043
1067
|
}) => {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
if (
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1068
|
+
const nodeDragProps = {};
|
|
1069
|
+
let WhichNode = TreeNode;
|
|
1070
|
+
if (CURRENT_MODE === UI_MODE_WEB) { // DND is currently web-only TODO: implement for RN
|
|
1071
|
+
// Create a method that gets an always-current copy of the selection ids
|
|
1072
|
+
dragSelectionRef.current = selection;
|
|
1073
|
+
const getSelection = () => dragSelectionRef.current;
|
|
1074
|
+
|
|
1075
|
+
const userHasPermissionToDrag = (!canUser || canUser(EDIT));
|
|
1076
|
+
if (userHasPermissionToDrag) {
|
|
1077
|
+
// NOTE: The Tree can either drag nodes internally or externally, but not both at the same time!
|
|
1078
|
+
|
|
1079
|
+
// assign event handlers
|
|
1080
|
+
if (canNodesMoveInternally) {
|
|
1081
|
+
// internal drag/drop
|
|
1082
|
+
const nodeDragSourceType = 'internal';
|
|
1083
|
+
WhichNode = DragSourceDropTargetTreeNode;
|
|
1084
|
+
nodeDragProps.isDragSource = !item.isRoot; // Root nodes cannot be dragged
|
|
1085
|
+
nodeDragProps.dragSourceType = nodeDragSourceType;
|
|
1086
|
+
nodeDragProps.dragSourceItem = {
|
|
1087
|
+
id: item.id,
|
|
1088
|
+
item,
|
|
1089
|
+
getSelection,
|
|
1090
|
+
type: nodeDragSourceType,
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
// Prevent root nodes from being dragged, and use custom logic if provided
|
|
1094
|
+
nodeDragProps.canDrag = (monitor) => {
|
|
1095
|
+
const currentSelection = getSelection();
|
|
1096
|
+
|
|
1097
|
+
// Check if any selected node is a root node (can't drag root nodes)
|
|
1098
|
+
const hasRootNode = currentSelection.some(node => node.isRoot);
|
|
1099
|
+
if (hasRootNode) {
|
|
1100
|
+
return false;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// Use custom drag validation if provided
|
|
1104
|
+
if (canNodeMoveInternally) {
|
|
1105
|
+
// In multi-selection, all nodes must be draggable
|
|
1106
|
+
return currentSelection.every(node => canNodeMoveInternally(node));
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
return true;
|
|
1110
|
+
};
|
|
1111
|
+
|
|
1112
|
+
// Add custom drag preview options
|
|
1113
|
+
if (dragPreviewOptions) {
|
|
1114
|
+
nodeDragProps.dragPreviewOptions = dragPreviewOptions;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Add drag preview rendering
|
|
1118
|
+
nodeDragProps.getDragProxy = getCustomDragProxy ?
|
|
1119
|
+
(dragItem) => getCustomDragProxy(item, getSelection()) :
|
|
1120
|
+
null; // Let GlobalDragProxy handle the default case
|
|
1121
|
+
|
|
1122
|
+
const dropTargetAccept = 'internal';
|
|
1123
|
+
nodeDragProps.isDropTarget = true;
|
|
1124
|
+
nodeDragProps.dropTargetAccept = dropTargetAccept;
|
|
1125
|
+
|
|
1126
|
+
// Define validation logic once for reuse
|
|
1127
|
+
const validateDrop = (draggedItem) => {
|
|
1128
|
+
if (!draggedItem) {
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
const currentSelection = getSelection();
|
|
1133
|
+
|
|
1134
|
+
// Always include the dragged item itself in validation
|
|
1135
|
+
// If no selection exists, the dragged item is what we're moving
|
|
1136
|
+
const nodesToValidate = currentSelection.length > 0 ? currentSelection : [draggedItem.item];
|
|
1137
|
+
|
|
1138
|
+
// validate that the dropped item is not already a direct child of the target node
|
|
1139
|
+
if (isChildOf(draggedItem.item, item)) {
|
|
1140
|
+
return false;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
// Validate that none of the nodes being moved can be dropped into the target location
|
|
1144
|
+
for (const nodeToMove of nodesToValidate) {
|
|
1145
|
+
if (nodeToMove.id === item.id) {
|
|
1146
|
+
// Cannot drop a node onto itself
|
|
1147
|
+
return false;
|
|
1148
|
+
}
|
|
1149
|
+
if (isDescendantOf(item, nodeToMove)) {
|
|
1150
|
+
// Cannot drop a node into its own descendants
|
|
1151
|
+
return false;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
if (canNodeAcceptDrop && typeof canNodeAcceptDrop === 'function') {
|
|
1156
|
+
// custom business logic
|
|
1157
|
+
return canNodeAcceptDrop(item, draggedItem);
|
|
1158
|
+
}
|
|
1159
|
+
return true;
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
// Use the validation function for React DnD
|
|
1163
|
+
nodeDragProps.canDrop = (draggedItem, monitor) => validateDrop(draggedItem);
|
|
1164
|
+
|
|
1165
|
+
// Pass the same validation function for visual feedback
|
|
1166
|
+
nodeDragProps.validateDrop = validateDrop;
|
|
1167
|
+
|
|
1168
|
+
nodeDragProps.onDrop = (droppedItem) => {
|
|
1169
|
+
if (belongsToThisTree(droppedItem)) {
|
|
1170
|
+
onInternalNodeDrop(item, droppedItem);
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
} else {
|
|
1174
|
+
// external drag/drop
|
|
1175
|
+
if (areNodesDragSource) {
|
|
1176
|
+
WhichNode = DragSourceTreeNode;
|
|
1177
|
+
nodeDragProps.isDragSource = !item.isRoot; // Root nodes cannot be dragged
|
|
1178
|
+
nodeDragProps.dragSourceType = nodeDragSourceType;
|
|
1179
|
+
if (getNodeDragSourceItem) {
|
|
1180
|
+
nodeDragProps.dragSourceItem = getNodeDragSourceItem(item, getSelection, nodeDragSourceType);
|
|
1181
|
+
} else {
|
|
1182
|
+
nodeDragProps.dragSourceItem = {
|
|
1183
|
+
id: item.id,
|
|
1184
|
+
item,
|
|
1185
|
+
getSelection,
|
|
1186
|
+
type: nodeDragSourceType,
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
if (canNodeMoveExternally) {
|
|
1190
|
+
nodeDragProps.canDrag = canNodeMoveExternally;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// Add custom drag preview options
|
|
1194
|
+
if (dragPreviewOptions) {
|
|
1195
|
+
nodeDragProps.dragPreviewOptions = dragPreviewOptions;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// Add drag preview rendering
|
|
1199
|
+
nodeDragProps.getDragProxy = getCustomDragProxy ?
|
|
1200
|
+
(dragItem) => getCustomDragProxy(item, getSelection()) :
|
|
1201
|
+
null; // Let GlobalDragProxy handle the default case
|
|
1202
|
+
}
|
|
1203
|
+
if (areNodesDropTarget) {
|
|
1204
|
+
WhichNode = DropTargetTreeNode;
|
|
1205
|
+
nodeDragProps.isDropTarget = true;
|
|
1206
|
+
nodeDragProps.dropTargetAccept = dropTargetAccept;
|
|
1207
|
+
nodeDragProps.canDrop = (droppedItem, monitor) => {
|
|
1208
|
+
// Check if the drop operation would be valid based on business rules
|
|
1209
|
+
if (canNodeAcceptDrop && typeof canNodeAcceptDrop === 'function') {
|
|
1210
|
+
return canNodeAcceptDrop(item, droppedItem);
|
|
1211
|
+
}
|
|
1212
|
+
// Default: allow external drops
|
|
1213
|
+
return true;
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
// Define validation logic once for reuse
|
|
1217
|
+
const validateDrop = (draggedItem) => {
|
|
1218
|
+
if (!draggedItem) {
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (canNodeAcceptDrop && typeof canNodeAcceptDrop === 'function') {
|
|
1223
|
+
// custom business logic
|
|
1224
|
+
return canNodeAcceptDrop(item, draggedItem);
|
|
1225
|
+
}
|
|
1226
|
+
return true;
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
// Use the validation function for React DnD
|
|
1230
|
+
nodeDragProps.canDrop = (draggedItem, monitor) => validateDrop(draggedItem);
|
|
1231
|
+
|
|
1232
|
+
// Pass the same validation function for visual feedback
|
|
1233
|
+
nodeDragProps.validateDrop = validateDrop;
|
|
1234
|
+
|
|
1235
|
+
nodeDragProps.onDrop = (droppedItem) => {
|
|
1236
|
+
// NOTE: item is sometimes getting destroyed, but it still has the id, so you can still use it
|
|
1237
|
+
onNodeDrop(item, droppedItem);
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
if (areNodesDragSource && areNodesDropTarget) {
|
|
1241
|
+
WhichNode = DragSourceDropTargetTreeNode;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1059
1245
|
}
|
|
1060
1246
|
|
|
1061
|
-
return <
|
|
1247
|
+
return <WhichNode
|
|
1062
1248
|
datum={datum}
|
|
1063
1249
|
nodeProps={nodeProps}
|
|
1064
1250
|
onToggle={onToggle}
|
|
1251
|
+
isNodeSelectable={isNodeSelectable}
|
|
1252
|
+
isNodeHoverable={isNodeHoverable}
|
|
1065
1253
|
isSelected={isSelected}
|
|
1066
1254
|
isHovered={hovered}
|
|
1067
|
-
|
|
1255
|
+
showHovers={showHovers}
|
|
1256
|
+
showSelectHandle={showSelectHandle}
|
|
1068
1257
|
isHighlighted={highlitedDatum === datum}
|
|
1069
|
-
{...
|
|
1258
|
+
{...nodeDragProps}
|
|
1070
1259
|
|
|
1071
1260
|
// fields={fields}
|
|
1072
1261
|
/>;
|
|
@@ -1088,154 +1277,6 @@ function TreeComponent(props) {
|
|
|
1088
1277
|
}
|
|
1089
1278
|
});
|
|
1090
1279
|
return nodes;
|
|
1091
|
-
},
|
|
1092
|
-
|
|
1093
|
-
// drag/drop
|
|
1094
|
-
getDragProxy = (node) => {
|
|
1095
|
-
|
|
1096
|
-
// TODO: Maybe the proxy should grab itself and all descendants??
|
|
1097
|
-
|
|
1098
|
-
const
|
|
1099
|
-
row = node,
|
|
1100
|
-
rowRect = row.getBoundingClientRect(),
|
|
1101
|
-
parent = row.parentElement,
|
|
1102
|
-
parentRect = parent.getBoundingClientRect(),
|
|
1103
|
-
proxy = row.cloneNode(true),
|
|
1104
|
-
top = rowRect.top - parentRect.top,
|
|
1105
|
-
rows = _.filter(parent.children, (childNode) => {
|
|
1106
|
-
if (childNode.getBoundingClientRect().height === 0 && childNode.style.visibility !== 'hidden') {
|
|
1107
|
-
return false; // Skip zero-height children
|
|
1108
|
-
}
|
|
1109
|
-
if (childNode === proxy) {
|
|
1110
|
-
return false;
|
|
1111
|
-
}
|
|
1112
|
-
return true;
|
|
1113
|
-
}),
|
|
1114
|
-
dragRowIx = Array.from(rows).indexOf(row),
|
|
1115
|
-
dragRowRecord = rowToDatumMap[dragRowIx].item;
|
|
1116
|
-
|
|
1117
|
-
setDragNodeId(dragRowRecord.id); // the id of which record is being dragged
|
|
1118
|
-
|
|
1119
|
-
proxy.style.top = top + 'px';
|
|
1120
|
-
proxy.style.left = (dragRowRecord.depth * DEPTH_INDENT_PX) + 'px';
|
|
1121
|
-
proxy.style.height = rowRect.height + 'px';
|
|
1122
|
-
proxy.style.width = rowRect.width + 'px';
|
|
1123
|
-
proxy.style.display = 'flex';
|
|
1124
|
-
proxy.style.position = 'absolute';
|
|
1125
|
-
proxy.style.border = '1px solid #bbb';
|
|
1126
|
-
return proxy;
|
|
1127
|
-
},
|
|
1128
|
-
onDrag = (info, e, proxy, node) => {
|
|
1129
|
-
// console.log('onDrag', info, e, proxy, node);
|
|
1130
|
-
const
|
|
1131
|
-
proxyRect = proxy.getBoundingClientRect(),
|
|
1132
|
-
row = node,
|
|
1133
|
-
parent = row.parentElement,
|
|
1134
|
-
parentRect = parent.getBoundingClientRect(),
|
|
1135
|
-
rows = _.filter(parent.children, (childNode) => {
|
|
1136
|
-
if (childNode.getBoundingClientRect().height === 0 && childNode.style.visibility !== 'hidden') {
|
|
1137
|
-
return false; // Skip zero-height children
|
|
1138
|
-
}
|
|
1139
|
-
if (childNode === proxy) {
|
|
1140
|
-
return false;
|
|
1141
|
-
}
|
|
1142
|
-
return true;
|
|
1143
|
-
}),
|
|
1144
|
-
currentY = proxyRect.top - parentRect.top; // top position of pointer, relative to page
|
|
1145
|
-
|
|
1146
|
-
// Figure out which row the user wants as a parentId
|
|
1147
|
-
let newIx = 0; // default to root being new parentId
|
|
1148
|
-
_.each(rows, (child, ix, all) => {
|
|
1149
|
-
const
|
|
1150
|
-
rect = child.getBoundingClientRect(), // rect of the row of this iteration
|
|
1151
|
-
{
|
|
1152
|
-
top,
|
|
1153
|
-
bottom,
|
|
1154
|
-
height,
|
|
1155
|
-
} = rect,
|
|
1156
|
-
compensatedBottom = bottom - parentRect.top;
|
|
1157
|
-
|
|
1158
|
-
if (child === proxy) {
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
if (ix === 0) {
|
|
1162
|
-
// first row
|
|
1163
|
-
if (currentY < compensatedBottom) {
|
|
1164
|
-
newIx = 0;
|
|
1165
|
-
return false;
|
|
1166
|
-
}
|
|
1167
|
-
return;
|
|
1168
|
-
} else if (ix === all.length -1) {
|
|
1169
|
-
// last row
|
|
1170
|
-
if (currentY < compensatedBottom) {
|
|
1171
|
-
newIx = ix;
|
|
1172
|
-
return false;
|
|
1173
|
-
}
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
// all other rows
|
|
1178
|
-
if (currentY < compensatedBottom) {
|
|
1179
|
-
newIx = ix;
|
|
1180
|
-
return false;
|
|
1181
|
-
}
|
|
1182
|
-
});
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
const
|
|
1186
|
-
dragDatum = getDatumById(dragNodeId),
|
|
1187
|
-
dragDatumChildIds = getDatumChildIds(dragDatum),
|
|
1188
|
-
dropRowDatum = rowToDatumMap[newIx],
|
|
1189
|
-
dropRowRecord = dropRowDatum.item,
|
|
1190
|
-
dropNodeId = dropRowRecord.id,
|
|
1191
|
-
dragNodeContainsDropNode = inArray(dropNodeId, dragDatumChildIds) || dropRowRecord.id === dragNodeId;
|
|
1192
|
-
|
|
1193
|
-
if (dragNodeContainsDropNode) {
|
|
1194
|
-
// the node can be a child of any node except itself or its own descendants
|
|
1195
|
-
setDropRowIx(null);
|
|
1196
|
-
setHighlitedDatum(null);
|
|
1197
|
-
|
|
1198
|
-
} else {
|
|
1199
|
-
// console.log('setDropRowIx', newIx);
|
|
1200
|
-
setDropRowIx(newIx);
|
|
1201
|
-
|
|
1202
|
-
// highlight the drop node
|
|
1203
|
-
setHighlitedDatum(dropRowDatum);
|
|
1204
|
-
|
|
1205
|
-
// shift proxy's depth
|
|
1206
|
-
const depth = (dropRowRecord.id === dragNodeId) ? dropRowRecord.depth : dropRowRecord.depth + 1;
|
|
1207
|
-
proxy.style.left = (depth * DEPTH_INDENT_PX) + 'px';
|
|
1208
|
-
}
|
|
1209
|
-
},
|
|
1210
|
-
onDragStop = async (delta, e, config) => {
|
|
1211
|
-
// console.log('onDragStop', delta, e, config);
|
|
1212
|
-
|
|
1213
|
-
if (_.isNil(dropRowIx)) {
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const
|
|
1218
|
-
dragDatum = getDatumById(dragNodeId),
|
|
1219
|
-
dragRowRecord = dragDatum.item,
|
|
1220
|
-
dropRowDatum = rowToDatumMap[dropRowIx],
|
|
1221
|
-
dropRowRecord = dropRowDatum.item;
|
|
1222
|
-
|
|
1223
|
-
if (Repository) {
|
|
1224
|
-
if (!Repository.isDestroyed) {
|
|
1225
|
-
const commonAncestorId = await Repository.moveTreeNode(dragRowRecord, dropRowRecord.id);
|
|
1226
|
-
const commonAncestorDatum = getDatumById(commonAncestorId);
|
|
1227
|
-
reloadNode(commonAncestorDatum.item);
|
|
1228
|
-
}
|
|
1229
|
-
} else {
|
|
1230
|
-
|
|
1231
|
-
throw Error('Not yet implemented');
|
|
1232
|
-
// function arrayMove(arr, fromIndex, toIndex) {
|
|
1233
|
-
// var element = arr[fromIndex];
|
|
1234
|
-
// arr.splice(fromIndex, 1);
|
|
1235
|
-
// arr.splice(toIndex, 0, element);
|
|
1236
|
-
// }
|
|
1237
|
-
// arrayMove(data, dragNodeIx, finalDropIx);
|
|
1238
|
-
}
|
|
1239
1280
|
};
|
|
1240
1281
|
|
|
1241
1282
|
useEffect(() => {
|
|
@@ -1268,7 +1309,7 @@ function TreeComponent(props) {
|
|
|
1268
1309
|
Repository.on('load', setFalse);
|
|
1269
1310
|
Repository.on('loadRootNodes', setFalse);
|
|
1270
1311
|
Repository.on('loadRootNodes', buildAndSetTreeNodeData);
|
|
1271
|
-
Repository.on('add',
|
|
1312
|
+
Repository.on('add', buildAndSetOneTreeNodeData);
|
|
1272
1313
|
Repository.on('changeFilters', reloadTree);
|
|
1273
1314
|
Repository.on('changeSorters', reloadTree);
|
|
1274
1315
|
|
|
@@ -1284,7 +1325,7 @@ function TreeComponent(props) {
|
|
|
1284
1325
|
Repository.off('load', setFalse);
|
|
1285
1326
|
Repository.off('loadRootNodes', setFalse);
|
|
1286
1327
|
Repository.off('loadRootNodes', buildAndSetTreeNodeData);
|
|
1287
|
-
Repository.off('add',
|
|
1328
|
+
Repository.off('add', buildAndSetOneTreeNodeData);
|
|
1288
1329
|
Repository.off('changeFilters', reloadTree);
|
|
1289
1330
|
Repository.off('changeSorters', reloadTree);
|
|
1290
1331
|
};
|
|
@@ -1331,8 +1372,8 @@ function TreeComponent(props) {
|
|
|
1331
1372
|
}
|
|
1332
1373
|
|
|
1333
1374
|
const
|
|
1334
|
-
headerToolbarItemComponents = useMemo(() => getHeaderToolbarItems(), [Repository?.hash, treeSearchValue,
|
|
1335
|
-
footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons,
|
|
1375
|
+
headerToolbarItemComponents = useMemo(() => getHeaderToolbarItems(), [Repository?.hash, treeSearchValue, getTreeNodeData()]),
|
|
1376
|
+
footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons, getTreeNodeData()]);
|
|
1336
1377
|
|
|
1337
1378
|
if (!isReady) {
|
|
1338
1379
|
return <CenterBox>
|
|
@@ -1365,18 +1406,10 @@ function TreeComponent(props) {
|
|
|
1365
1406
|
w-full
|
|
1366
1407
|
min-w-[300px]
|
|
1367
1408
|
`;
|
|
1368
|
-
if (
|
|
1369
|
-
className +=
|
|
1370
|
-
${styles.GRID_REORDER_BORDER_COLOR}
|
|
1371
|
-
${styles.GRID_REORDER_BORDER_WIDTH}
|
|
1372
|
-
${styles.GRID_REORDER_BORDER_STYLE}
|
|
1373
|
-
`;
|
|
1409
|
+
if (isLoading) {
|
|
1410
|
+
className += ' border-t-2 border-[#f00]';
|
|
1374
1411
|
} else {
|
|
1375
|
-
|
|
1376
|
-
className += ' border-t-2 border-[#f00]';
|
|
1377
|
-
} else {
|
|
1378
|
-
className += ' border-t-1 border-grey-300';
|
|
1379
|
-
}
|
|
1412
|
+
className += ' border-t-1 border-grey-300';
|
|
1380
1413
|
}
|
|
1381
1414
|
if (props.className) {
|
|
1382
1415
|
className += ' ' + props.className;
|
|
@@ -1394,9 +1427,7 @@ function TreeComponent(props) {
|
|
|
1394
1427
|
<VStack
|
|
1395
1428
|
ref={treeRef}
|
|
1396
1429
|
onClick={() => {
|
|
1397
|
-
|
|
1398
|
-
deselectAll();
|
|
1399
|
-
}
|
|
1430
|
+
deselectAll();
|
|
1400
1431
|
}}
|
|
1401
1432
|
className="Tree-deselector w-full flex-1 p-1 bg-white"
|
|
1402
1433
|
>
|
|
@@ -1426,15 +1457,17 @@ export const Tree = withComponent(
|
|
|
1426
1457
|
withEvents(
|
|
1427
1458
|
withData(
|
|
1428
1459
|
withPermissions(
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1460
|
+
withDropTarget(
|
|
1461
|
+
// withMultiSelection(
|
|
1462
|
+
withSelection(
|
|
1463
|
+
withFilters(
|
|
1464
|
+
withContextMenu(
|
|
1465
|
+
TreeComponent
|
|
1466
|
+
)
|
|
1434
1467
|
)
|
|
1435
1468
|
)
|
|
1436
|
-
)
|
|
1437
|
-
|
|
1469
|
+
// )
|
|
1470
|
+
)
|
|
1438
1471
|
)
|
|
1439
1472
|
)
|
|
1440
1473
|
)
|
|
@@ -1446,20 +1479,22 @@ export const SideTreeEditor = withComponent(
|
|
|
1446
1479
|
withEvents(
|
|
1447
1480
|
withData(
|
|
1448
1481
|
withPermissions(
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1482
|
+
withDropTarget(
|
|
1483
|
+
// withMultiSelection(
|
|
1484
|
+
withSelection(
|
|
1485
|
+
withSideEditor(
|
|
1486
|
+
withFilters(
|
|
1487
|
+
withPresetButtons(
|
|
1488
|
+
withContextMenu(
|
|
1489
|
+
TreeComponent
|
|
1490
|
+
)
|
|
1456
1491
|
)
|
|
1457
|
-
)
|
|
1458
|
-
|
|
1459
|
-
|
|
1492
|
+
),
|
|
1493
|
+
true // isTree
|
|
1494
|
+
)
|
|
1460
1495
|
)
|
|
1461
|
-
)
|
|
1462
|
-
|
|
1496
|
+
// )
|
|
1497
|
+
)
|
|
1463
1498
|
)
|
|
1464
1499
|
)
|
|
1465
1500
|
)
|
|
@@ -1471,20 +1506,22 @@ export const WindowedTreeEditor = withComponent(
|
|
|
1471
1506
|
withEvents(
|
|
1472
1507
|
withData(
|
|
1473
1508
|
withPermissions(
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1509
|
+
withDropTarget(
|
|
1510
|
+
// withMultiSelection(
|
|
1511
|
+
withSelection(
|
|
1512
|
+
withWindowedEditor(
|
|
1513
|
+
withFilters(
|
|
1514
|
+
withPresetButtons(
|
|
1515
|
+
withContextMenu(
|
|
1516
|
+
TreeComponent
|
|
1517
|
+
)
|
|
1481
1518
|
)
|
|
1482
|
-
)
|
|
1483
|
-
|
|
1484
|
-
|
|
1519
|
+
),
|
|
1520
|
+
true // isTree
|
|
1521
|
+
)
|
|
1485
1522
|
)
|
|
1486
|
-
)
|
|
1487
|
-
|
|
1523
|
+
// )
|
|
1524
|
+
)
|
|
1488
1525
|
)
|
|
1489
1526
|
)
|
|
1490
1527
|
)
|