@onehat/ui 0.2.68 → 0.2.70

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.2.68",
3
+ "version": "0.2.70",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "license": "UNLICENSED",
27
27
  "dependencies": {
28
- "@onehat/data": "^1.18.1",
28
+ "@onehat/data": "^1.18.7",
29
29
  "@hookform/resolvers": "^3.1.1",
30
30
  "@k-renwick/colour-mixer": "^1.2.1",
31
31
  "js-cookie": "^3.0.5",
@@ -881,7 +881,8 @@ export const WindowedGridEditor = withAlert(
881
881
  withPresetButtons(
882
882
  withContextMenu(
883
883
  Grid
884
- )
884
+ ),
885
+ true // isGrid
885
886
  )
886
887
  )
887
888
  )
@@ -901,7 +902,8 @@ export const InlineGridEditor = withAlert(
901
902
  withContextMenu(
902
903
  withFilters(
903
904
  Grid
904
- )
905
+ ),
906
+ true // isGrid
905
907
  )
906
908
  )
907
909
  )
@@ -22,7 +22,7 @@ const presetButtons = [
22
22
  // 'print',
23
23
  ];
24
24
 
25
- export default function withPresetButtons(WrappedComponent) {
25
+ export default function withPresetButtons(WrappedComponent, isGrid = false) {
26
26
  return (props) => {
27
27
  const {
28
28
  // extract and pass
@@ -37,10 +37,10 @@ export default function withPresetButtons(WrappedComponent) {
37
37
  disableAdd = false,
38
38
  disableEdit = false,
39
39
  disableDelete = false,
40
- disableView = false,
41
- disableCopy = false,
42
- disableDuplicate = false,
43
- disablePrint = false,
40
+ disableView = !isGrid,
41
+ disableCopy = !isGrid,
42
+ disableDuplicate = !isGrid,
43
+ disablePrint = !isGrid,
44
44
 
45
45
  // withEditor
46
46
  userCanEdit = true,
@@ -0,0 +1,18 @@
1
+ import * as React from "react"
2
+ import Svg, { G, Path } from "react-native-svg"
3
+ import { Icon } from 'native-base';
4
+
5
+ function SvgComponent(props) {
6
+ return (
7
+ <Icon
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ viewBox="0 0 508.3 508.87"
10
+ {...props}
11
+ >
12
+ <Path d="M253.87 387.44c73.46 0 133-59.55 133-133s-59.55-133-133-133-133 59.55-133 133 59.55 133 133 133z" />
13
+ <Path d="M0 0H508.3V508.87H0z" fill="none" />
14
+ </Icon>
15
+ )
16
+ }
17
+
18
+ export default SvgComponent
@@ -19,6 +19,7 @@ import {
19
19
  DROP_POSITION_BEFORE,
20
20
  DROP_POSITION_AFTER,
21
21
  } from '../../Constants/Tree.js';
22
+ import sleep from '@onehat/ui/src/Functions/sleep.js';
22
23
  import * as colourMixer from '@k-renwick/colour-mixer'
23
24
  import UiGlobals from '../../UiGlobals.js';
24
25
  import useForceUpdate from '../../Hooks/useForceUpdate.js';
@@ -38,7 +39,7 @@ import TreeNode, { ReorderableTreeNode } from './TreeNode.js';
38
39
  import FormPanel from '../Panel/FormPanel.js';
39
40
  import Input from '../Form/Field/Input.js';
40
41
  import IconButton from '../Buttons/IconButton.js';
41
- import Circle from '../Icons/Circle.js';
42
+ import Dot from '../Icons/Dot.js';
42
43
  import Collapse from '../Icons/Collapse.js';
43
44
  import FolderClosed from '../Icons/FolderClosed.js';
44
45
  import FolderOpen from '../Icons/FolderOpen.js';
@@ -51,54 +52,27 @@ import Toolbar from '../Toolbar/Toolbar.js';
51
52
  import _ from 'lodash';
52
53
 
53
54
 
54
- // Tree requires the use of HOC withSelection() whenever it's used.
55
- // The default export is *with* the HOC. A separate *raw* component is
56
- // exported which can be combined with many HOCs for various functionality.
57
-
58
-
59
55
  //////////////////////
60
56
  //////////////////////
61
57
 
62
- // I'm thinking if a repository senses that it's a tree, then at initial load
63
- // it should get the root node +1 level of children.
64
- //
65
- // How would it then subsequently get the proper children?
66
- // i.e. When a node gets its children, how will it do this
67
- // while maintaining the nodes that already exist there?
68
- // We don't want it to *replace* all exisitng nodes!
69
- //
70
- // And if the repository does a reload, should it just get root+1 again?
71
- // Changing filters would potentially change the tree structure.
72
- // Changing sorting would only change the ordering, not what is expanded/collapsed or visible/invisible.
73
-
74
-
75
-
76
58
  // Need to take into account whether using Repository or data.
77
59
  // If using data, everything exists at once. What format will data be in?
78
60
  // How does this interface with Repository?
79
61
  // Maybe if Repository is not AjaxRepository, everything needs to be present at once!
80
62
 
81
-
82
- // isRootVisible
83
-
84
63
  //////////////////////
85
64
  //////////////////////
86
65
 
87
66
 
88
-
89
-
90
-
91
-
92
67
  export function Tree(props) {
93
68
  const {
94
- isRootVisible = true,
95
- getAdditionalParams = () => { // URL params needed to get nodes from server (e.g, { venue_id: 1, getEquipment: true, getRentalEquipment: false, }), in addition to filters.
96
- return {};
97
- },
69
+ areRootsVisible = true,
70
+ extraParams = {}, // Additional params to send with each request ( e.g. { order: 'Categories.name ASC' })
98
71
  getNodeText = (item) => { // extracts model/data and decides what the row text should be
99
72
  return item.displayValue;
100
73
  },
101
74
  getNodeIcon = (item, isExpanded) => { // decides what icon to show for this node
75
+ // TODO: Allow for dynamic props on the icon (e.g. special color for some icons)
102
76
  let icon;
103
77
  if (item.hasChildren) {
104
78
  if (isExpanded) {
@@ -107,11 +81,11 @@ export function Tree(props) {
107
81
  icon = FolderClosed;
108
82
  }
109
83
  } else {
110
- icon = Circle;
84
+ icon = Dot;
111
85
  }
112
86
  return icon;
113
87
  },
114
- nodeProps = (item) => {
88
+ getNodeProps = (item) => {
115
89
  return {};
116
90
  },
117
91
  noneFoundText,
@@ -170,7 +144,12 @@ export function Tree(props) {
170
144
  [searchFormData, setSearchFormData] = useState([]),
171
145
  [dragNodeSlot, setDragNodeSlot] = useState(null),
172
146
  [dragNodeIx, setDragNodeIx] = useState(),
147
+ [treeSearchValue, setTreeSearchValue] = useState(''),
173
148
  onNodeClick = (item, e) => {
149
+ if (!setSelection) {
150
+ return;
151
+ }
152
+
174
153
  const
175
154
  {
176
155
  shiftKey,
@@ -243,13 +222,12 @@ export function Tree(props) {
243
222
  getHeaderToolbarItems = () => {
244
223
  const
245
224
  buttons = [
246
-
247
225
  {
248
226
  key: 'searchBtn',
249
227
  text: 'Search tree',
250
228
  handler: onSearchTree,
251
229
  icon: MagnifyingGlass,
252
- isDisabled: false,
230
+ isDisabled: !treeSearchValue.length,
253
231
  },
254
232
  {
255
233
  key: 'collapseBtn',
@@ -262,7 +240,7 @@ export function Tree(props) {
262
240
  if (canNodesReorder) {
263
241
  buttons.push({
264
242
  key: 'reorderBtn',
265
- text: 'Reorder tree',
243
+ text: 'Enter reorder mode',
266
244
  handler: () => setIsReorderMode(!isReorderMode),
267
245
  icon: isReorderMode ? NoReorderRows : ReorderRows,
268
246
  isDisabled: false,
@@ -271,10 +249,16 @@ export function Tree(props) {
271
249
  const items = _.map(buttons, getIconFromConfig);
272
250
 
273
251
  items.unshift(<Input // Add text input to beginning of header items
274
- key="searchTree"
252
+ key="searchNodes"
275
253
  flex={1}
276
- placeholder="Search all tree nodes"
277
- onChangeValue={onSearchTree}
254
+ placeholder="Find tree node"
255
+ onChangeText={(val) => setTreeSearchValue(val)}
256
+ onKeyPress={(e, value) => {
257
+ if (e.key === 'Enter') {
258
+ onSearchTree(value);
259
+ }
260
+ }}
261
+ value={treeSearchValue}
278
262
  autoSubmit={false}
279
263
  />);
280
264
 
@@ -292,11 +276,12 @@ export function Tree(props) {
292
276
  mx: 1,
293
277
  px: 3,
294
278
  },
295
- iconProps = {
279
+ _icon = {
296
280
  alignSelf: 'center',
297
281
  size: styles.TREE_TOOLBAR_ITEMS_ICON_SIZE,
298
282
  h: 20,
299
283
  w: 20,
284
+ color: isDisabled ? styles.TREE_TOOLBAR_ITEMS_DISABLED_COLOR : styles.TREE_TOOLBAR_ITEMS_COLOR,
300
285
  };
301
286
  let {
302
287
  key,
@@ -305,16 +290,11 @@ export function Tree(props) {
305
290
  icon = null,
306
291
  isDisabled = false,
307
292
  } = config;
308
- if (icon) {
309
- const thisIconProps = {
310
- color: isDisabled ? styles.TREE_TOOLBAR_ITEMS_DISABLED_COLOR : styles.TREE_TOOLBAR_ITEMS_COLOR,
311
- };
312
- icon = React.cloneElement(icon, {...iconProps, ...thisIconProps});
313
- }
314
293
  return <IconButton
315
294
  key={key || ix}
316
295
  onPress={handler}
317
296
  icon={icon}
297
+ _icon={_icon}
318
298
  isDisabled={isDisabled}
319
299
  tooltip={text}
320
300
  {...iconButtonProps}
@@ -326,16 +306,17 @@ export function Tree(props) {
326
306
  // renderTreeNode uses this to render the nodes.
327
307
  const
328
308
  isRoot = treeNode.isRoot,
329
- isLeaf = !treeNode.hasChildren,
309
+ children = buildTreeNodeData(treeNode.children), // recursively get data for children
330
310
  datum = {
331
311
  item: treeNode,
332
312
  text: getNodeText(treeNode),
333
- iconCollapsed: isLeaf ? null : getNodeIcon(treeNode, false),
334
- iconExpanded: isLeaf ? null : getNodeIcon(treeNode, true),
335
- iconLeaf: isLeaf ? getNodeIcon(treeNode) : null,
313
+ iconCollapsed: getNodeIcon(treeNode, false),
314
+ iconExpanded: getNodeIcon(treeNode, true),
315
+ iconLeaf: getNodeIcon(treeNode),
336
316
  isExpanded: isRoot, // all non-root treeNodes are not expanded by default
337
- isVisible: isRoot ? isRootVisible : true,
338
- children: buildTreeNodeData(treeNode.children), // recursively get data for children
317
+ isVisible: isRoot ? areRootsVisible : true,
318
+ isLoading: false,
319
+ children,
339
320
  };
340
321
 
341
322
  return datum;
@@ -348,7 +329,9 @@ export function Tree(props) {
348
329
  return data;
349
330
  },
350
331
  renderTreeNode = (datum) => {
351
- const item = datum.item;
332
+ const
333
+ item = datum.item,
334
+ depth = item.depth;
352
335
  if (item.isDestroyed) {
353
336
  return null;
354
337
  }
@@ -391,7 +374,11 @@ export function Tree(props) {
391
374
  e.preventDefault();
392
375
  }
393
376
  if (isReorderMode) {
394
- return
377
+ return;
378
+ }
379
+
380
+ if (!setSelection) {
381
+ return;
395
382
  }
396
383
 
397
384
  // context menu
@@ -402,7 +389,7 @@ export function Tree(props) {
402
389
  }
403
390
  }}
404
391
  flexDirection="row"
405
- flexGrow={1}
392
+ ml={((areRootsVisible ? depth : depth -1) * 20) + 'px'}
406
393
  >
407
394
  {({
408
395
  isHovered,
@@ -455,122 +442,125 @@ export function Tree(props) {
455
442
  </Pressable>;
456
443
  },
457
444
  renderTreeNodes = (data) => {
458
- const nodes = [];
445
+ let nodes = [];
459
446
  _.each(data, (datum) => {
460
- nodes.push(renderTreeNode(datum));
461
- });
462
- return nodes;
463
- },
464
- renderAllTreeNodes = () => {
465
- const nodes = [];
466
- _.each(treeNodeData, (datum) => {
467
447
  const node = renderTreeNode(datum);
468
- if (_.isEmpty(node)) {
469
- return;
470
- }
471
-
472
448
  nodes.push(node);
473
449
 
474
- if (_.isEmpty(datum.children)) {
475
- return;
450
+ if (datum.children.length && datum.isExpanded) {
451
+ const childTreeNodes = renderTreeNodes(datum.children); // recursion
452
+ nodes = nodes.concat(childTreeNodes);
476
453
  }
477
-
478
- const children = renderTreeNodes(datum.children);
479
- if (_.isEmpty(children)) {
480
- return;
481
- }
482
-
483
- nodes.concat(children);
484
454
  });
485
455
  return nodes;
486
456
  },
457
+ getDatumChildIds = (datum) => {
458
+ let ids = [];
459
+ _.each(datum.children, (childDatum) => {
460
+ ids.push(childDatum.item.id);
461
+ if (childDatum.children.length) {
462
+ const childIds = getDatumChildIds(childDatum);
463
+ ids = ids.concat(childIds);
464
+ const t = true;
465
+ }
466
+ });
467
+ return ids;
468
+ },
469
+ datumContainsSelection = (datum) => {
470
+ if (_.isEmpty(selection)) {
471
+ return false;
472
+ }
473
+ const
474
+ selectionIds = _.map(selection, (item) => item.id),
475
+ datumIds = getDatumChildIds(datum),
476
+ intersection = selectionIds.filter(x => datumIds.includes(x));
477
+
478
+ return !_.isEmpty(intersection);
479
+ },
487
480
 
488
481
  // Button handlers
489
482
  onToggle = (datum) => {
483
+ if (datum.isLoading) {
484
+ return;
485
+ }
486
+
490
487
  datum.isExpanded = !datum.isExpanded;
491
- forceUpdate();
492
488
 
493
- if (datum.item?.repository.isRemote && datum.item.hasChildren && !datum.item.isChildrenLoaded) {
489
+ if (datum.isExpanded && datum.item.repository?.isRemote && datum.item.hasChildren && !datum.item.areChildrenLoaded) {
494
490
  loadChildren(datum, 1);
491
+ return;
495
492
  }
493
+
494
+ if (!datum.isExpanded && datumContainsSelection(datum)) {
495
+ deselectAll();
496
+ }
497
+
498
+ forceUpdate();
496
499
  },
497
500
  loadChildren = async (datum, depth) => {
498
- // Helper for onToggle
499
-
500
- // TODO: Flesh this out
501
- // Show loading indicator (red bar at top? Spinner underneath current node?)
502
-
501
+ // Show loading indicator (spinner underneath current node?)
502
+ datum.isLoading = true;
503
+ forceUpdate();
503
504
 
504
- // Calls getAdditionalParams(), then submits to server
505
- // Server returns this for each node:
506
- // Build up treeNodeData for just these new nodes
507
-
505
+ try {
506
+
507
+ const children = await datum.item.loadChildren(1);
508
+ const tnd = buildTreeNodeData(children);
509
+ datum.children = tnd;
510
+
511
+ } catch (err) {
512
+ // TODO: how do I handle errors?
513
+ // Color parent node red
514
+ // Modal alert box?
515
+ // Inline error msg? I'm concerned about modals not stacking correctly, but if we put it inline, it'll work.
516
+ datum.isExpanded = false;
517
+ }
508
518
 
509
519
  // Hide loading indicator
510
-
520
+ datum.isLoading = false;
521
+ forceUpdate();
511
522
  },
512
523
  onCollapseAll = (setNewTreeNodeData = true) => {
513
524
  // Go through whole tree and collapse all nodes
514
525
  const newTreeNodeData = _.clone(treeNodeData);
515
-
516
- // Recursive method to collapse all children
517
- function collapseChildren(children) {
518
- _.each(children, (child) => {
519
- child.isExpanded = true;
520
- if (!_.isEmpty(child.children)) {
521
- collapseChildren(child.children);
522
- }
523
- });
524
- }
525
-
526
- collapseChildren(newTreeNodeData);
526
+ collapseNodes(newTreeNodeData);
527
527
 
528
528
  if (setNewTreeNodeData) {
529
529
  setTreeNodeData(newTreeNodeData);
530
530
  }
531
531
  return newTreeNodeData;
532
532
  },
533
+ collapseNodes = (nodes) => {
534
+ _.each(nodes, (node) => {
535
+ node.isExpanded = false;
536
+ if (!_.isEmpty(node.children)) {
537
+ collapseNodes(node.children);
538
+ }
539
+ });
540
+ },
533
541
  onSearchTree = async (value) => {
534
542
 
535
543
  let found = [];
536
544
  if (Repository?.isRemote) {
537
545
  // Search tree on server
538
- found = await Repository.searchTree(value);
546
+ found = await Repository.searchNodes(value);
539
547
  } else {
540
548
  // Search local tree data
541
549
  found = findTreeNodesByText(value);
542
550
  }
543
551
 
544
-
545
552
  const isMultipleHits = found.length > 1;
546
553
  let path = '';
547
554
  let searchFormData = [];
548
555
 
549
- if (Repository?.isRemote) {
550
- if (isMultipleHits) {
551
- // 'found' is the results from the server. Use these to show the modal and choose which node you want to select
552
-
553
-
554
-
555
-
556
- } else {
557
- // Search local tree data
558
- found = findTreeNodesByText(value);
559
- }
560
-
561
- // TODO: create searchFormData based on 'found' array
562
-
563
-
564
-
565
-
566
-
567
- setSearchFormData(searchFormData);
568
- setIsSearchModalShown(true);
569
-
570
- } else {
571
- // Expand that one path immediately
556
+ if (!isMultipleHits) {
557
+ path = found[0].path;
572
558
  expandPath(path);
559
+ return;
573
560
  }
561
+
562
+ setSearchFormData(searchFormData);
563
+ setIsSearchModalShown(true);
574
564
  },
575
565
  findTreeNodesByText = (text) => {
576
566
  // Helper for onSearchTree
@@ -625,14 +615,12 @@ export function Tree(props) {
625
615
  return nodes.join('/');
626
616
 
627
617
  },
628
- expandPath = (path) => {
618
+ expandPath = async (path) => {
629
619
  // Helper for onSearchTree
630
620
 
631
- // Drills down the tree based on path (usually given by server).
632
- // Path would be a list of sequential IDs (3/35/263/1024)
633
- // Initially, it closes thw whole tree.
634
-
635
- let newTreeNodeData = collapseAll(false); // false = don't set new treeNodeData
621
+ // First, close thw whole tree.
622
+ let newTreeNodeData = _.clone(treeNodeData);
623
+ collapseNodes(newTreeNodeData);
636
624
 
637
625
  // As it navigates down, it will expand the appropriate branches,
638
626
  // and then finally highlight & select the node in question
@@ -650,6 +638,13 @@ export function Tree(props) {
650
638
  currentDatum = _.find(currentLevelData, (treeNodeDatum) => {
651
639
  return treeNodeDatum.item.id === id;
652
640
  });
641
+
642
+ if (!currentDatum) {
643
+ // datum is not currently loaded, so load it
644
+
645
+ // LEFT OFF HERE
646
+ debugger;
647
+ }
653
648
 
654
649
  currentNode = currentDatum.item;
655
650
 
@@ -935,7 +930,9 @@ export function Tree(props) {
935
930
 
936
931
  let rootNodes;
937
932
  if (Repository) {
938
- rootNodes = await Repository.getRootNodes(true, 1, getAdditionalParams);
933
+ if (!Repository.areRootNodesLoaded) {
934
+ rootNodes = await Repository.getRootNodes(1);
935
+ }
939
936
  } else {
940
937
  // TODO: Make this work for data array
941
938
 
@@ -945,7 +942,15 @@ export function Tree(props) {
945
942
  setTreeNodeData(treeNodeData);
946
943
  }
947
944
 
945
+ function reloadTreeData() {
946
+ Repository.areRootNodesLoaded = false;
947
+ return buildAndSetTreeNodeData();
948
+ }
949
+
948
950
  if (!isReady) {
951
+ if (Repository) {
952
+ Repository.setBaseParams(extraParams);
953
+ }
949
954
  (async () => {
950
955
  await buildAndSetTreeNodeData();
951
956
  setIsReady(true);
@@ -955,29 +960,18 @@ export function Tree(props) {
955
960
  if (!Repository) {
956
961
  return () => {};
957
962
  }
958
-
963
+
959
964
  // set up @onehat/data repository
960
965
  const
961
966
  setTrue = () => setIsLoading(true),
962
- setFalse = () => setIsLoading(false),
963
- onChangeFilters = () => {
964
- if (!Repository.isAutoLoad) {
965
- Repository.reload();
966
- }
967
- },
968
- onChangeSorters = () => {
969
- if (!Repository.isAutoLoad) {
970
- Repository.reload();
971
- }
972
- };
973
-
967
+ setFalse = () => setIsLoading(false);
968
+
974
969
  Repository.on('beforeLoad', setTrue);
975
970
  Repository.on('load', setFalse);
976
971
  Repository.ons(['changePage', 'changePageSize',], deselectAll);
977
972
  Repository.ons(['changeData', 'change'], buildAndSetTreeNodeData);
978
- Repository.on('changeFilters', onChangeFilters);
979
- Repository.on('changeSorters', onChangeSorters);
980
-
973
+ Repository.on('changeFilters', reloadTreeData);
974
+ Repository.on('changeSorters', reloadTreeData);
981
975
 
982
976
  return () => {
983
977
  Repository.off('beforeLoad', setTrue);
@@ -1004,15 +998,13 @@ export function Tree(props) {
1004
998
  }, [selectorId, selectorSelected]);
1005
999
 
1006
1000
  const
1007
- headerToolbarItemComponents = useMemo(() => getHeaderToolbarItems(), []),
1008
- footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [additionalToolbarButtons, isReorderMode]);
1001
+ headerToolbarItemComponents = useMemo(() => getHeaderToolbarItems(), [treeSearchValue, treeNodeData]),
1002
+ footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [additionalToolbarButtons, isReorderMode, treeNodeData]);
1009
1003
 
1010
1004
  if (!isReady) {
1011
1005
  return null;
1012
1006
  }
1013
-
1014
- // Actual TreeNodes
1015
- const treeNodes = renderAllTreeNodes();
1007
+ const treeNodes = renderTreeNodes(treeNodeData);
1016
1008
 
1017
1009
  // headers & footers
1018
1010
  let treeFooterComponent = null;
@@ -1031,21 +1023,21 @@ export function Tree(props) {
1031
1023
  w="100%"
1032
1024
  >
1033
1025
  {topToolbar}
1034
- {headerToolbarItemComponents}
1026
+ {headerToolbarItemComponents?.length && <Row>{headerToolbarItemComponents}</Row>}
1035
1027
 
1036
- <Column w="100%" flex={1} borderTopWidth={isLoading ? 2 : 1} borderTopColor={isLoading ? '#f00' : 'trueGray.300'} onClick={() => {
1028
+ <Column w="100%" flex={1} p={2} borderTopWidth={isLoading ? 2 : 1} borderTopColor={isLoading ? '#f00' : 'trueGray.300'} onClick={() => {
1037
1029
  if (!isReorderMode) {
1038
1030
  deselectAll();
1039
1031
  }
1040
1032
  }}>
1041
- {!treeNodes.length ? <NoRecordsFound text={noneFoundText} onRefresh={onRefresh} /> :
1033
+ {!treeNodes?.length ? <NoRecordsFound text={noneFoundText} onRefresh={onRefresh} /> :
1042
1034
  treeNodes}
1043
1035
  </Column>
1044
1036
 
1045
1037
  {treeFooterComponent}
1046
1038
  </Column>
1047
1039
 
1048
- <Modal
1040
+ {/* <Modal
1049
1041
  isOpen={isSearchModalShown}
1050
1042
  onClose={() => setIsSearchModalShown(false)}
1051
1043
  >
@@ -1095,7 +1087,7 @@ export function Tree(props) {
1095
1087
  }}
1096
1088
  />
1097
1089
  </Column>
1098
- </Modal>
1090
+ </Modal> */}
1099
1091
  </>;
1100
1092
 
1101
1093
  }
@@ -1,7 +1,9 @@
1
1
  import { useState, useMemo, } from 'react';
2
2
  import {
3
3
  Box,
4
+ Icon,
4
5
  Row,
6
+ Spinner,
5
7
  Text,
6
8
  } from 'native-base';
7
9
  import {
@@ -16,24 +18,26 @@ import _ from 'lodash';
16
18
 
17
19
  export default function TreeNode(props) {
18
20
  const {
19
- nodeProps,
21
+ nodeProps = {},
20
22
  bg,
21
23
  datum,
22
24
  onToggle,
25
+ ...propsToPass
23
26
  } = props,
24
27
  styles = UiGlobals.styles,
25
28
  item = datum.item,
26
29
  isPhantom = item.isPhantom,
27
30
  isExpanded = datum.isExpanded,
28
- hasChildren = datum.hasChildren,
29
- depth = datum.depth,
31
+ isLoading = datum.isLoading,
32
+ hasChildren = item.hasChildren,
33
+ depth = item.depth,
30
34
  text = datum.text,
31
35
  iconCollapsed = datum.iconCollapsed,
32
36
  iconExpanded = datum.iconExpanded,
33
37
  iconLeaf = datum.iconLeaf,
34
38
  hash = item?.hash || item;
35
39
 
36
- const icon = hasChildren ? (isExpanded ? iconCollapsed : iconExpanded) : iconLeaf;
40
+ const icon = hasChildren ? (isExpanded ? iconExpanded : iconCollapsed) : iconLeaf;
37
41
 
38
42
  return useMemo(() => {
39
43
 
@@ -43,17 +47,14 @@ export default function TreeNode(props) {
43
47
  {...nodeProps}
44
48
  bg={bg}
45
49
  key={hash}
46
- pl={(depth * 10) + 'px'}
47
50
  >
48
51
  {isPhantom && <Box position="absolute" bg="#f00" h={2} w={2} t={0} l={0} />}
49
52
 
50
- <IconButton
51
- icon={icon}
52
- onPress={onToggle}
53
- />
53
+ {isLoading ?
54
+ <Spinner px={2} /> :
55
+ (hasChildren ? <IconButton icon={icon} onPress={() => onToggle(datum)} /> : <Icon as={icon} px={2} />)}
54
56
 
55
57
  <Text
56
- key={key}
57
58
  overflow="hidden"
58
59
  textOverflow="ellipsis"
59
60
  alignSelf="center"
@@ -79,6 +80,7 @@ export default function TreeNode(props) {
79
80
  text,
80
81
  icon,
81
82
  onToggle,
83
+ isLoading,
82
84
  ]);
83
85
  }
84
86