Add function for counting tree node children
[arvados-workbench2.git] / src / models / tree.ts
index 613601109a44efd0ba69feb517f8ae347380573b..bec2f758a478335e6ef437afe6592dde144ce729 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { pipe } from 'lodash/fp';
+import { pipe, map, reduce } from 'lodash/fp';
 export type Tree<T> = Record<string, TreeNode<T>>;
 
 export const TREE_ROOT_ID = '';
@@ -24,10 +24,23 @@ export enum TreeNodeStatus {
     LOADED = 'LOADED',
 }
 
+export enum TreePickerId {
+    PROJECTS = 'Projects',
+    SHARED_WITH_ME = 'Shared with me',
+    FAVORITES = 'Favorites'
+}
+
 export const createTree = <T>(): Tree<T> => ({});
 
 export const getNode = (id: string) => <T>(tree: Tree<T>): TreeNode<T> | undefined => tree[id];
 
+export const appendSubtree = <T>(id: string, subtree: Tree<T>) => (tree: Tree<T>) =>
+    pipe(
+        getNodeDescendants(''),
+        map(node => node.parent === '' ? { ...node, parent: id } : node),
+        reduce((newTree, node) => setNode(node)(newTree), tree)
+    )(subtree) as Tree<T>;
+
 export const setNode = <T>(node: TreeNode<T>) => (tree: Tree<T>): Tree<T> => {
     return pipe(
         (tree: Tree<T>) => getNode(node.id)(tree) === node
@@ -82,6 +95,12 @@ export const getNodeAncestorsIds = (id: string) => <T>(tree: Tree<T>): string[]
 export const getNodeDescendants = (id: string, limit = Infinity) => <T>(tree: Tree<T>) =>
     mapIdsToNodes(getNodeDescendantsIds(id, limit)(tree))(tree);
 
+export const countNodes = <T>(tree: Tree<T>) =>
+    getNodeDescendantsIds('')(tree).length;
+
+export const countChildren = (id: string) => <T>(tree: Tree<T>) =>
+    getNodeChildren('')(tree).length;
+
 export const getNodeDescendantsIds = (id: string, limit = Infinity) => <T>(tree: Tree<T>): string[] => {
     const node = getNode(id)(tree);
     const children = node ? node.children :
@@ -107,19 +126,19 @@ export const mapIdsToNodes = (ids: string[]) => <T>(tree: Tree<T>) =>
     ids.map(id => getNode(id)(tree)).filter((node): node is TreeNode<T> => node !== undefined);
 
 export const activateNode = (id: string) => <T>(tree: Tree<T>) =>
-    mapTree(node => node.id === id ? { ...node, active: true } : { ...node, active: false })(tree);
+    mapTree((node: TreeNode<T>) => node.id === id ? { ...node, active: true } : { ...node, active: false })(tree);
 
 export const deactivateNode = <T>(tree: Tree<T>) =>
-    mapTree(node => node.active ? { ...node, active: false } : node)(tree);
+    mapTree((node: TreeNode<T>) => node.active ? { ...node, active: false } : node)(tree);
 
 export const expandNode = (...ids: string[]) => <T>(tree: Tree<T>) =>
-    mapTree(node => ids.some(id => id === node.id) ? { ...node, expanded: true } : node)(tree);
+    mapTree((node: TreeNode<T>) => ids.some(id => id === node.id) ? { ...node, expanded: true } : node)(tree);
 
 export const collapseNode = (...ids: string[]) => <T>(tree: Tree<T>) =>
-    mapTree(node => ids.some(id => id === node.id) ? { ...node, expanded: false } : node)(tree);
+    mapTree((node: TreeNode<T>) => ids.some(id => id === node.id) ? { ...node, expanded: false } : node)(tree);
 
 export const toggleNodeCollapse = (...ids: string[]) => <T>(tree: Tree<T>) =>
-    mapTree(node => ids.some(id => id === node.id) ? { ...node, expanded: !node.expanded } : node)(tree);
+    mapTree((node: TreeNode<T>) => ids.some(id => id === node.id) ? { ...node, expanded: !node.expanded } : node)(tree);
 
 export const setNodeStatus = (id: string) => (status: TreeNodeStatus) => <T>(tree: Tree<T>) => {
     const node = getNode(id)(tree);
@@ -162,6 +181,10 @@ export const deselectNodes = (id: string | string[]) => <T>(tree: Tree<T>) => {
     return ids.reduce((tree, id) => deselectNode(id)(tree), tree);
 };
 
+export const getSelectedNodes = <T>(tree: Tree<T>) =>
+    getNodeDescendants('')(tree)
+        .filter(node => node.selected);
+
 export const initTreeNode = <T>(data: Pick<TreeNode<T>, 'id' | 'value'> & { parent?: string }): TreeNode<T> => ({
     children: [],
     active: false,