FEATURE displaying data tree
diff --git a/frontend/config/config.component.css b/frontend/config/config.component.css
index 30ccea5..c2336b0 100644
--- a/frontend/config/config.component.css
+++ b/frontend/config/config.component.css
@@ -13,6 +13,15 @@
     padding-right: 0.5em;
 }
 
+.tab-icon {
+    vertical-align: middle;
+    height: 1em;
+}
+
+.tab-add {
+    filter: invert(100%);
+}
+
 .tab-add:hover {
     color: green;
 }
@@ -23,14 +32,14 @@
     color: blue;
 }
 
-nav {
+#confignav {
     position: fixed;
     width: 100%;
 	background-color: #3B4257;
 	padding-left: 1em;
 }
 
-nav a {
+#confignav a {
     cursor: pointer;
 	text-decoration: none;
 	display: inline-block;
@@ -38,16 +47,18 @@
 	color: #FAFAFA;
 }
 
-nav a:visited, a:link {
+#confignav a:visited,
+#confignav a:link {
 	color: inherited;
 }
 
-nav a:hover, nav a.active {
+#confignav a:hover,
+#confignav a.active {
 	background-color: #FAFAFA;
-	color: #000
+	color: #000;
 }
 
-nav a.active:hover {
+#confignav a.active:hover {
 	cursor: default;	
 }
 
@@ -67,11 +78,14 @@
 }
 
 #config-data {
-    padding-left: 11em;
-    display: inline-block;
     width: 100%;
 }
 
+.item_action_expand,
+.item_action_collapse {
+    height: 1em;
+}
+
 .item_action_collapse:hover {
     color:red;
 }
diff --git a/frontend/config/config.component.html b/frontend/config/config.component.html
index 654b94c..8b398e5 100644
--- a/frontend/config/config.component.html
+++ b/frontend/config/config.component.html
@@ -1,20 +1,34 @@
-<nav #navbar>
-  <a *ngFor="let session of sessionsService.sessions" [class.active]="session.key==activeSession.key"
-      (click)="changeActiveSession(session.key)">{{session.device.hostname}}:{{session.device.port}}
-      <span *ngIf="session.key==activeSession.key" class="tab-reload tab-action-first" (click)="reloadData(session.key)">o</span>
-      <span class="tab-close tab-action-last" (click)="disconnect(session.key)">x</span>
-  </a><a (click)="addSession()"><span class="tab-add tab-action-first tab-action-last">+</span></a>
+<nav #confignav id="confignav">
+    <a *ngFor="let session of sessionsService.sessions" [class.active]="session.key==activeSession.key"
+        (click)="changeActiveSession(session.key)">{{session.device.hostname}}:{{session.device.port}}
+        <!--<span *ngIf="session.key==activeSession.key" class="tab-reload tab-action-first" (click)="reloadData(session.key)">o</span>-->
+        <img *ngIf="session.key==activeSession.key" class="tab-icon tab-reload tab-action-first" src="assets/netopeer/icons/reload.svg"  alt="o" title="reload"
+            onmouseover="this.src='assets/netopeer/icons/reload_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/reload.svg'" (click)="reloadData()"/>
+        <img class="tab-icon tab-close tab-action-last" src="assets/netopeer/icons/close.svg"  alt="x" title="disconnect"
+            onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/close.svg'" (click)="disconnect(session.key)"/>
+    </a><a (click)="addSession()" onmouseout="getElementById('tabadd').style.filter='invert(100%)'" onmouseover="getElementById('tabadd').style.filter='invert(0%)'">
+        <img id="tabadd" class="tab-icon tab-add tab-action-last" src="assets/netopeer/icons/add.svg" alt="+" title="add connection"
+            onmouseover="this.src='assets/netopeer/icons/add_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/add.svg'"/>
+    </a>
 </nav>
 
-<div class="netopeer-content" [style.padding-top]="'calc(' + navbar.offsetHeight + 'px - -0.7em)'">
+<div class="netopeer-content" [style.padding-top]="'calc(' + confignav.offsetHeight + 'px - -0.7em)'">
 <div *ngIf="sessionsService.activeSession">
-    <p class="msg-failure msg-rounded" *ngIf="err_msg"><span class="msg-close" (click)="err_msg=''">x</span>{{err_msg}}</p>
-
+    <p class="msg-failure msg-rounded" *ngIf="err_msg"><img class="msg-close" (click)="err_msg=''" src="assets/netopeer/icons/close_active.svg" alt="x" title="close"/>{{err_msg}}</p>
     <table class="items">
         <tr class="item_header">
             <th class="item_left item_actions" [ngSwitch]="activeSession.cpbltsVisibility">
-                <span *ngSwitchCase="false" class="item_action_expand" (click)="getCapabilities(activeSession.key);activeSession.cpbltsVisibility=true">v</span>
-                <span *ngSwitchCase="true" class="item_action_collapse" (click)="activeSession.cpbltsVisibility=false">x</span>
+                <img *ngSwitchCase="false" class="item_action_expand" (click)="getCapabilities(activeSession.key);activeSession.cpbltsVisibility=true"
+                    src="assets/netopeer/icons/show.svg" alt="v" title="show"
+                    onmouseover="this.src='assets/netopeer/icons/show_active.svg'"
+                    onmouseout="this.src='assets/netopeer/icons/show.svg'"/>
+                <img *ngSwitchCase="true" class="item_action_collapse" (click)="activeSession.cpbltsVisibility=false"
+                    src="assets/netopeer/icons/close.svg" alt="x" title="close"
+                    onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+                    onmouseout="this.src='assets/netopeer/icons/close.svg'"/>
             </th>
             <th>Capability / Module</th>
             <th class="item_right">Version</th>
@@ -30,24 +44,29 @@
 
     <table class="items">
         <tr class="item_header">
-            <th class="item_left item_actions" [ngSwitch]="activeSession.dataVisibility">
-                <span *ngSwitchCase="false" class="item_action_expand" (click)="rpcGet(activeSession.key);activeSession.dataVisibility=true">v</span>
-                <span *ngSwitchCase="true" class="item_action_collapse" (click)="activeSession.dataVisibility=false">x</span>
-            </th>
-            <th class="item_right">Data</th>
+            <th class="item_left item_actions" style="cursor: default;">&nbsp;</th>
+            <th class="item_right" >Data</th>
         </tr>
     </table>
-    <ng-container *ngIf="activeSession.dataVisibility==true && activeSession.data">
-<!--
-    <div id="config-toc">
-        <div class="config-toc-item" [ngSwitch]="activeSession.dataVisibility">
-            <a *ngSwitchCase="false" (click)="rpcGet(activeSession.key);activeSession.dataVisibility=true">show data</a>
-            <a *ngSwitchCase="true" (click)="activeSession.dataVisibility=false">hide data</a>
-        </div>
-    </div>
--->
+    <div>
+        <img *ngIf="activeSession.dataVisibility!='root'" class="icon_action" (click)="rpcGet(false);activeSession.dataVisibility='root'"
+            src="assets/netopeer/icons/show_children.svg" alt="v" title="expand roots"
+            onmouseover="this.src='assets/netopeer/icons/show_children_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/show_children.svg'"/>
+        <img *ngIf="activeSession.dataVisibility!='all'" class="icon_action" (click)="rpcGet(true);activeSession.dataVisibility='all'"
+            src="assets/netopeer/icons/show_all.svg" alt="w" title="expand all"
+            onmouseover="this.src='assets/netopeer/icons/show_all_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/show_all.svg'"/>
+        <img *ngIf="activeSession.dataVisibility!='none'" class="icon_action" (click)="activeSession.dataVisibility='none'"
+            src="assets/netopeer/icons/close.svg" alt="x" title="close"
+            onmouseover="this.src='assets/netopeer/icons/close_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/close.svg'"/>
+        <span><input type="checkbox" name="statusVisibility" [checked]="activeSession.statusVisibility" (change)="activeSession.statusVisibility = !activeSession.statusVisibility"/> include status data</span>
+    </div><br/>
+    <ng-container *ngIf="activeSession.dataVisibility!='none' && activeSession.data">
     <div id="config-data">
-        <pre >{{activeSession.data | json}}</pre>
+        <tree-view [treeData]="activeSession.data"></tree-view>
+        <!--<pre>{{activeSession.data | json}}</pre>-->
     </div>
     </ng-container>
 </div>
diff --git a/frontend/config/config.component.ts b/frontend/config/config.component.ts
index 0618771..7adf96d 100644
--- a/frontend/config/config.component.ts
+++ b/frontend/config/config.component.ts
@@ -3,12 +3,11 @@
 
 import {SessionsService} from './sessions.service';
 import {Session} from './session';
-import {Device} from '../inventory/device';
 
 @Component({
     selector: 'netopeer-config',
     templateUrl: './config.component.html',
-    styleUrls: ['../netopeer.css', './config.component.css', '../inventory/inventory.component.css']
+    styleUrls: ['../netopeer.css', './config.component.css', './tree.component.css', '../inventory/inventory.component.css']
 })
 
 export class ConfigComponent implements OnInit, OnDestroy {
@@ -16,15 +15,20 @@
     activeSession: Session;
     err_msg = "";
 
+    objectKeys = Object.keys;
     constructor(private sessionsService: SessionsService, private router: Router) {}
 
     addSession() {
         this.router.navigateByUrl('/netopeer/inventory/devices');
     }
 
-    reloadData(key: string) {
+    reloadData() {
         this.activeSession.data = null;
-        this.rpcGet(key);
+        if (this.activeSession.dataVisibility == 'all') {
+            this.rpcGet(true);
+        } else if(this.activeSession.dataVisibility == 'root') {
+            this.rpcGet(false);
+        }
     }
 
     disconnect(key: string) {
@@ -45,9 +49,10 @@
         }
         this.sessionsService.getCpblts(key).subscribe(result => {
             if (result['success']) {
-                this.activeSession.cpblts = result['capabilities']
+                this.activeSession.cpblts = result['capabilities'];
             } else {
-                this.err_msg = result['error-msg']
+                this.activeSession.cpbltsVisibility = false;
+                this.err_msg = result['error-msg'];
             }
         });
     }
@@ -105,17 +110,23 @@
         return version;
     }
 
-    rpcGet(key: string) {
+    rpcGet(all: boolean) {
         if (this.activeSession.data) {
-            return;
+            if ((all && this.activeSession.dataVisibility == 'all') ||
+                (!all && this.activeSession.dataVisibility == 'root')) {
+                return;
+            }
         }
-        this.sessionsService.rpcGet(key).subscribe(result => {
+        this.sessionsService.rpcGetSubtree(this.activeSession.key, all).subscribe(result => {
             if (result['success']) {
-                this.activeSession.data = result['data']
-            } else if ('error-msg' in result) {
-                this.err_msg = result['error-msg']
+                this.activeSession.data = result['data'];
             } else {
-                this.err_msg = result['error'][0]['message']
+                this.activeSession.dataVisibility = 'none';
+                if ('error-msg' in result) {
+                    this.err_msg = result['error-msg'];
+                } else {
+                    this.err_msg = result['error'][0]['message'];
+                }
             }
         });
     }
diff --git a/frontend/config/session.ts b/frontend/config/session.ts
index 1ca2c3c..9f56289 100644
--- a/frontend/config/session.ts
+++ b/frontend/config/session.ts
@@ -4,9 +4,10 @@
   constructor (
     public key: string,
     public device: Device,
-    public data: string = "",
+    public data = null,
     public cpblts: string = "",
-    public dataVisibility: boolean = false,
-    public cpbltsVisibility: boolean = false
+    public dataVisibility: string = 'none',
+    public statusVisibility: boolean = true,
+    public cpbltsVisibility: boolean = false,
   ) {}
 }
diff --git a/frontend/config/sessions.service.ts b/frontend/config/sessions.service.ts
index a947a4f..83d99f9 100644
--- a/frontend/config/sessions.service.ts
+++ b/frontend/config/sessions.service.ts
@@ -84,9 +84,13 @@
             .catch((err: Response | any) => Observable.throw(err));
     }
 
-    rpcGet(key: string): Observable<string[]> {
+    rpcGetSubtree(key: string, all: boolean, path: string = ""): Observable<string[]> {
         let params = new URLSearchParams();
         params.set('key', key);
+        params.set('recursive', String(all));
+        if (path.length) {
+            params.set('path', path);
+        }
         let options = new RequestOptions({ search: params });
         return this.http.get('/netopeer/session/rpcGet', options)
             .map((resp: Response) => resp.json())
@@ -127,7 +131,7 @@
             .map((resp: Response) => resp.json())
             .do(resp => {
                 if (resp['success']) {
-                    this.sessions.push(new Session(resp['session-key'], dev, "", "", false, false));
+                    this.sessions.push(new Session(resp['session-key'], dev));
                     this.activeSession = resp['session-key'];
                     localStorage.setItem('sessions', JSON.stringify(this.sessions));
                     localStorage.setItem('activeSession', this.activeSession);
diff --git a/frontend/config/tree.component.css b/frontend/config/tree.component.css
new file mode 100644
index 0000000..9534da8
--- /dev/null
+++ b/frontend/config/tree.component.css
@@ -0,0 +1,46 @@
+.subtree {
+    cursor: default;
+    display: block;
+    width: 100%;
+}
+
+.node {
+    width: 100%;
+}
+.node:hover {
+    background-color: #e1e1e1
+}
+.node div {
+    display: inline-block;
+}
+
+.status {
+    color: grey;
+}
+
+.icon,
+.icon_action {
+    font-size: xx-small;
+    height: 2em;
+}
+
+.icon_action {
+    cursor: pointer;
+}
+
+.module_name {
+    float: right;
+}
+
+.children {
+    padding-left: 0em;
+}
+
+.value {
+    display: inline-block;
+    padding-left: 1.5em;
+}
+
+.indentation {
+    height: 1.7em;
+}
\ No newline at end of file
diff --git a/frontend/config/tree.component.html b/frontend/config/tree.component.html
new file mode 100644
index 0000000..22e7b75
--- /dev/null
+++ b/frontend/config/tree.component.html
@@ -0,0 +1,44 @@
+<ng-container *ngFor="let node of treeData">
+<div class="subtree" *ngIf="node['info']['config'] || activeSession.statusVisibility" [class.status]="!node['info']['config']">
+    <div class="node">
+        <ng-container *ngFor="let indent of indentation">
+            <img *ngIf="!indent" class="indentation" src="assets/netopeer/icons/tree_cont.svg"/>
+            <img *ngIf="indent" class="indentation" src="assets/netopeer/icons/tree_empty.svg"/>
+        </ng-container>
+        <img *ngIf="node['last']" class="indentation" src="assets/netopeer/icons/tree_last_branch.svg"/>
+        <img *ngIf="!node['last']" class="indentation" src="assets/netopeer/icons/tree_branch.svg"/>
+        <ng-container [ngSwitch]="node['info']['type']">
+            <img *ngSwitchCase="1" class="icon" src="assets/netopeer/icons/container.svg" alt="container" title="container"/>
+            <img *ngSwitchCase="4" class="icon" src="assets/netopeer/icons/leaf.svg" alt="leaf" title="leaf"/>
+            <img *ngSwitchCase="8" class="icon" src="assets/netopeer/icons/leaflist.svg" alt="leaf-list" title="leaf-list"/>
+            <img *ngSwitchCase="16" class="icon" src="assets/netopeer/icons/container.svg" alt="list" title="list"/>
+            <img *ngSwitchCase="32800" class="icon" src="assets/netopeer/icons/anydata.svg" alt="anydata" title="anydata"/>
+        </ng-container>
+        <img class="icon" src="assets/netopeer/icons/info.svg"
+            onmouseover="this.src='assets/netopeer/icons/info_active.svg'"
+            onmouseout="this.src='assets/netopeer/icons/info.svg'" alt="info" title="{{node['info']['dsc']}}"/>
+        <ng-container *ngIf="expandable(node)">
+            <img *ngIf="hasHiddenChild(node)" (click)="getSubtree(node, true)"
+                class="icon_action" src="assets/netopeer/icons/show_all.svg"
+                onmouseover="this.src='assets/netopeer/icons/show_all_active.svg'"
+                onmouseout="this.src='assets/netopeer/icons/show_all.svg'" alt="show-all" title="expand subtree"/>
+            <img *ngIf="!node['children']" (click)="getSubtree(node, false)"
+                class="icon_action" src="assets/netopeer/icons/show_children.svg"
+                onmouseover="this.src='assets/netopeer/icons/show_children_active.svg'"
+                onmouseout="this.src='assets/netopeer/icons/show_children.svg'" alt="show-children" title="expand children"/>
+            <img *ngIf="node['children']" (click)="collapse(node)"
+                class="icon_action" src="assets/netopeer/icons/collapse.svg"  alt="collapse" title="collapse"
+                onmouseover="this.src='assets/netopeer/icons/collapse_active.svg'"
+                onmouseout="this.src='assets/netopeer/icons/collapse.svg'"/>
+        </ng-container>
+        <div>{{node['info']['name']}}</div>
+        <ng-container *ngIf="node['value']">
+            :<div class="value" >{{node['value']}}</div>
+        </ng-container>
+        <div class="module_name">{{node['info']['module']}}</div>
+    </div>
+    <div class="children" *ngIf="node['children']">
+        <tree-view [treeData]="node['children']" [indentation]="inheritIndentation(node)"></tree-view>
+    </div>
+</div>
+</ng-container>
\ No newline at end of file
diff --git a/frontend/config/tree.component.ts b/frontend/config/tree.component.ts
new file mode 100644
index 0000000..99b6cec
--- /dev/null
+++ b/frontend/config/tree.component.ts
@@ -0,0 +1,92 @@
+import {Component, Input, OnInit} from '@angular/core';
+
+import {Session} from './session';
+import {SessionsService} from './sessions.service';
+
+@Component({
+    selector: 'tree-view',
+    templateUrl: './tree.component.html',
+    styleUrls: ['../netopeer.css', './tree.component.css']
+})
+
+export class TreeView implements OnInit {
+    @Input() treeData;
+    @Input() indentation;
+    c = 1; i = 1;
+    activeSession: Session;
+    objectKeys = Object.keys;
+    constructor(private sessionsService: SessionsService) {}
+
+    ngOnInit(): void {
+        this.activeSession = this.sessionsService.getActiveSession(this.sessionsService.activeSession);
+    }
+
+    getSubtree(node, all: boolean) {
+        this.sessionsService.rpcGetSubtree(this.activeSession.key, all, node['path']).subscribe(result => {
+            if (result['success']) {
+                node['children'] = result['data']['children'];
+            }
+        });
+    }
+
+    getType(object) {
+        let result = 'data';
+        if (typeof object == 'object') {
+            if (object instanceof Array) {
+                result = 'array';
+            } else {
+                result = 'object';
+            }
+        }
+        return result;
+    }
+
+    expandable(node): boolean {
+        if (node['info']['type'] == 1 || /* container */
+            node['info']['type'] == 16) { /* list */
+                return true;
+        }
+        return false;
+    }
+
+    hasHiddenChild(node, clean=false): boolean {
+        if (!clean && 'hasHiddenChild' in node) {
+            return node['hasHiddenChild'];
+        }
+        node['hasHiddenChild'] = false;
+        if (!node['children']) {
+            node['hasHiddenChild'] = true;
+        } else {
+            for (let child of node['children']) {
+                if (!('children' in child) || this.hasHiddenChild(child, clean)) {
+                    node['hasHiddenChild'] = true;
+                    break;
+                }
+            }
+        }
+        return node['hasHiddenChild'];
+    }
+
+    inheritIndentation(node) {
+        let newIndent;
+        if (node['last']) {
+            newIndent = [true];
+        } else {
+            newIndent = [false];
+        }
+
+        if (!this.indentation) {
+            return newIndent;
+        } else {
+            return this.indentation.concat(newIndent);
+        }
+    }
+
+    collapse(node) {
+        node['children'] = null;
+        this.activeSession.dataVisibility = 'mixed';
+        for (let iter of this.activeSession.data) {
+            this.hasHiddenChild(iter, true);
+        }
+    }
+}