From 37fa0dbae7f9effb0db219f3a9bb7effb5fed998 Mon Sep 17 00:00:00 2001
From: pkupczyk <piotr.kupczyk@id.ethz.ch>
Date: Wed, 30 Jan 2019 19:56:25 +0100
Subject: [PATCH] Filter intermediate nodes that do not contain matching
 children and autoexpand those that do: - SSDM-7560 : NEW openBIS UI -
 User/Groups - Navigation Tree - In Memory Filter - SSDM-7567 : NEW openBIS UI
 - Types - Navigation Tree - In Memory Filter

---
 openbis_ng_ui/src/components/BrowserList.jsx  |  2 +-
 openbis_ng_ui/src/reducer/common/reducer.js   | 54 ++++++++++++-------
 openbis_ng_ui/src/reducer/database/reducer.js |  2 +-
 openbis_ng_ui/src/reducer/types/reducer.js    |  2 +-
 openbis_ng_ui/src/reducer/users/reducer.js    |  8 +--
 5 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/openbis_ng_ui/src/components/BrowserList.jsx b/openbis_ng_ui/src/components/BrowserList.jsx
index 422fba3dd83..20a7273c547 100644
--- a/openbis_ng_ui/src/components/BrowserList.jsx
+++ b/openbis_ng_ui/src/components/BrowserList.jsx
@@ -55,7 +55,7 @@ class BrowserList extends React.Component {
       <List className={classes.noPadding}>
         {
           this.props.nodes.map(node =>
-            (!node.filterable || node.filtered) &&
+            node.filtered &&
             <div key={node.id}>
               <ListItem
                 button
diff --git a/openbis_ng_ui/src/reducer/common/reducer.js b/openbis_ng_ui/src/reducer/common/reducer.js
index 3b02cced47c..5374d2da8d3 100644
--- a/openbis_ng_ui/src/reducer/common/reducer.js
+++ b/openbis_ng_ui/src/reducer/common/reducer.js
@@ -63,7 +63,7 @@ export function dirtyEntities(dirtyEntities, action) {
 
 export function browserExpandNode(browser, action) {
   let newBrowser = _.cloneDeep(browser)
-  visitNodes(newBrowser.nodes, node => {
+  getAllNodes(newBrowser.nodes).forEach(node => {
     if (node.id === action.node.id) {
       node.expanded = true
     }
@@ -73,7 +73,7 @@ export function browserExpandNode(browser, action) {
 
 export function browserCollapseNode(browser, action) {
   let newBrowser = _.cloneDeep(browser)
-  visitNodes(newBrowser.nodes, node => {
+  getAllNodes(newBrowser.nodes).forEach(node => {
     if (node.id === action.node.id) {
       node.expanded = false
     }
@@ -84,13 +84,23 @@ export function browserCollapseNode(browser, action) {
 export function browserSetFilter(browser, action) {
   let newBrowser = _.cloneDeep(browser)
   newBrowser.filter = action.filter
-  visitNodes(newBrowser.nodes, node => {
+  getAllNodes(newBrowser.nodes).reverse().forEach(node => {
     if (action.filter === null || action.filter.trim() === '') {
       node.filtered = true
     } else {
-      node.filtered = node.text.toLowerCase().indexOf(action.filter.toLowerCase()) !== -1
+      let filteredChildren = node.children !== undefined && node.children.some(node => {
+        return node.filtered
+      })
+
+      if (filteredChildren) {
+        node.filtered = true
+        node.expanded = true
+      } else {
+        node.filtered = node.text.toLowerCase().indexOf(action.filter.toLowerCase()) !== -1
+      }
     }
   })
+
   return newBrowser
 }
 
@@ -101,7 +111,6 @@ export function emptyTreeNode(values = {}) {
     type: null,
     text: null,
     selectable: false,
-    filterable: false,
     filtered: true,
     expanded: false,
     loading: false,
@@ -119,31 +128,38 @@ export function entityTreeNode(entity, values = {}) {
   }, values)
 }
 
-export const visitNodes = (nodes, visitor) => {
+export const getAllNodes = nodes => {
+  let levels = getAllNodesByLevel(nodes)
+  return _.concat(...levels)
+}
+
+export const getAllNodesByLevel = nodes => {
+  let levels = []
   let toVisit = []
-  let visited = {}
 
   toVisit.push(...nodes)
 
   while (toVisit.length > 0) {
-    let node = toVisit.shift()
+    let levelSize = toVisit.length
+    let level = []
 
-    if (!visited[node.id]) {
-      visited[node.id] = true
-      let result = visitor(node)
-      if (result) {
-        return result
+    for (let i = 0; i < levelSize; i++) {
+      let node = toVisit.shift()
+
+      level.push(node)
+
+      if (node.children !== undefined) {
+        node.children.forEach(child => {
+          toVisit.push(child)
+        })
       }
     }
 
-    if (node.children !== undefined) {
-      node.children.forEach((child) => {
-        toVisit.push(child)
-      })
-    }
+    levels.push(level)
   }
-}
 
+  return levels
+}
 
 export const sortBy = (arr, field) => {
   arr.sort((i1, i2) => {
diff --git a/openbis_ng_ui/src/reducer/database/reducer.js b/openbis_ng_ui/src/reducer/database/reducer.js
index 2578d2292c6..1d0be7b5390 100644
--- a/openbis_ng_ui/src/reducer/database/reducer.js
+++ b/openbis_ng_ui/src/reducer/database/reducer.js
@@ -153,7 +153,7 @@ function browser(browser = initialState.database.browser, action) {
   case 'SET-SPACES': {
     return {
       filter: browser.filter,
-      nodes: action.spaces.map(space => entityTreeNode(space, {selectable: true, filterable: true}))
+      nodes: action.spaces.map(space => entityTreeNode(space, {selectable: true}))
     }
   }
   case 'SET-PROJECTS': {
diff --git a/openbis_ng_ui/src/reducer/types/reducer.js b/openbis_ng_ui/src/reducer/types/reducer.js
index 67d1f22d8ec..4b1b3d620c7 100644
--- a/openbis_ng_ui/src/reducer/types/reducer.js
+++ b/openbis_ng_ui/src/reducer/types/reducer.js
@@ -54,7 +54,7 @@ function browserSetModeDoneTypeNodes(groupId, types) {
   let typeNodes = []
 
   types.forEach(type => {
-    typeNodes.push(entityTreeNode(type, {loaded: true, selectable: true, filterable: true}))
+    typeNodes.push(entityTreeNode(type, {loaded: true, selectable: true}))
   })
 
   sortBy(typeNodes, 'permId')
diff --git a/openbis_ng_ui/src/reducer/users/reducer.js b/openbis_ng_ui/src/reducer/users/reducer.js
index 1e92590e3c1..e7ee31796f8 100644
--- a/openbis_ng_ui/src/reducer/users/reducer.js
+++ b/openbis_ng_ui/src/reducer/users/reducer.js
@@ -63,12 +63,12 @@ function browserSetModeDoneUserNodes(users, groups) {
     let groupNodes = []
 
     userGroups.forEach(group => {
-      groupNodes.push(entityTreeNode(group, {loaded: true, selectable: true, filterable: true}))
+      groupNodes.push(entityTreeNode(group, {loaded: true, selectable: true}))
     })
 
     sortBy(groupNodes, 'permId')
 
-    userNodes.push(entityTreeNode(user, {loaded: true, selectable: true, filterable: true, children: groupNodes}))
+    userNodes.push(entityTreeNode(user, {loaded: true, selectable: true, children: groupNodes}))
   })
 
   sortBy(userNodes, 'permId')
@@ -88,12 +88,12 @@ function browserSetModeDoneGroupNodes(groups) {
     let userNodes = []
 
     group.getUsers().forEach(user => {
-      userNodes.push(entityTreeNode(user, {loaded: true, selectable: true, filterable: true}))
+      userNodes.push(entityTreeNode(user, {loaded: true, selectable: true}))
     })
 
     sortBy(userNodes, 'permId')
 
-    groupNodes.push(entityTreeNode(group, {loaded: true, selectable: true, filterable: true, children: userNodes}))
+    groupNodes.push(entityTreeNode(group, {loaded: true, selectable: true, children: userNodes}))
   })
 
   sortBy(groupNodes, 'permId')
-- 
GitLab