From fc2702ba260b7a8705ee9f2d1f606af8dfa768da Mon Sep 17 00:00:00 2001
From: Koren Lev <korenlev@gmail.com>
Date: Wed, 6 Sep 2017 19:47:54 +0300
Subject: ui updates

Change-Id: I2d3f87e34a74ce21bbb9e3df989b6527337b7228
Signed-off-by: Koren Lev <korenlev@gmail.com>
---
 .../attributes_for_hover_on_data.js                |  24 ++++
 ui/imports/api/clique-types/methods.js             |  12 +-
 ui/imports/api/configurations/configurations.js    |  29 +++++
 ui/imports/api/configurations/methods.js           |  39 +++++++
 .../api/configurations/server/publications.js      |  21 ++++
 ui/imports/api/environments/environments.js        |   6 +-
 ui/imports/api/inventories/server/methods.js       |  28 +----
 ui/imports/api/links/server/methods.js             |  31 +++++
 ui/imports/api/messages/server/methods.js          |   4 +-
 ui/imports/api/messages/server/publications.js     |  19 ++-
 ui/imports/lib/images-for-node-type.js             |  63 ++++++++--
 ui/imports/startup/client/index.js                 |   1 +
 ui/imports/startup/server/register-api.js          |   4 +
 .../ui/components/alarm-icons/alarm-icons.html     |  13 ++-
 .../ui/components/alarm-icons/alarm-icons.js       |  31 ++++-
 .../ui/components/clique-type/clique-type.js       |   6 +-
 .../ui/components/configuration/configuration.html |  31 +++++
 .../ui/components/configuration/configuration.js   | 114 ++++++++++++++++++
 .../ui/components/configuration/configuration.styl |  38 ++++++
 ui/imports/ui/components/dashboard/dashboard.js    |  18 +--
 .../environment-dashboard/environment-dashboard.js |  15 ++-
 .../ui/components/environment/environment.js       |   1 +
 .../graph-tooltip-window/graph-tooltip-window.html |   4 +-
 .../graph-tooltip-window/graph-tooltip-window.js   |  19 +++
 .../graph-tooltip-window/graph-tooltip-window.styl |  11 +-
 ui/imports/ui/components/index.styl                |   1 +
 .../ui/components/messages-modal/messages-modal.js |  54 ++++-----
 .../network-graph-manager/network-graph-manager.js |  48 +++++++-
 .../ui/components/network-graph/network-graph.js   | 130 ++++++++++++++-------
 .../ui/components/scans-list/scans-list.html       |   2 -
 .../components/top-navbar-menu/top-navbar-menu.js  |   2 +-
 ui/lib/router.js                                   |  15 ++-
 .../backup - ic_cloud_queue_black_48dp_2x.png      | Bin 0 -> 9845 bytes
 ui/public/ic_cloud_queue_black_48dp_2x-green.png   | Bin 0 -> 11727 bytes
 ui/public/ic_cloud_queue_black_48dp_2x-orange.png  | Bin 0 -> 9811 bytes
 ui/public/ic_cloud_queue_black_48dp_2x-red.png     | Bin 0 -> 11334 bytes
 ui/public/ic_computer_black_48dp_2x-green.png      | Bin 0 -> 5357 bytes
 ui/public/ic_computer_black_48dp_2x-orange.png     | Bin 0 -> 4628 bytes
 ui/public/ic_computer_black_48dp_2x-red.png        | Bin 0 -> 5315 bytes
 ui/public/ic_computer_black_48dp_2x.png            | Bin 5171 -> 3365 bytes
 ui/public/ic_dns_black_48dp_2x-green.png           | Bin 0 -> 8043 bytes
 ui/public/ic_dns_black_48dp_2x-orange.png          | Bin 0 -> 7033 bytes
 ui/public/ic_dns_black_48dp_2x-red.png             | Bin 0 -> 7900 bytes
 ui/public/ic_gamepad_black_48dp_2x-green.png       | Bin 0 -> 7635 bytes
 ui/public/ic_gamepad_black_48dp_2x-orange.png      | Bin 0 -> 6807 bytes
 ui/public/ic_gamepad_black_48dp_2x-red.png         | Bin 0 -> 7522 bytes
 .../ic_keyboard_return_black_48dp_2x-green.png     | Bin 0 -> 8306 bytes
 .../ic_keyboard_return_black_48dp_2x-orange.png    | Bin 0 -> 7176 bytes
 ui/public/ic_keyboard_return_black_48dp_2x-red.png | Bin 0 -> 7963 bytes
 ui/public/ic_lens_black_48dp_2x-green.png          | Bin 0 -> 9527 bytes
 ui/public/ic_lens_black_48dp_2x-orange.png         | Bin 0 -> 8058 bytes
 ui/public/ic_lens_black_48dp_2x-red.png            | Bin 0 -> 9336 bytes
 ...ettings_input_composite_black_48dp_2x-green.png | Bin 0 -> 7053 bytes
 ...ttings_input_composite_black_48dp_2x-orange.png | Bin 0 -> 6230 bytes
 ..._settings_input_composite_black_48dp_2x-red.png | Bin 0 -> 6984 bytes
 .../ic_settings_input_hdmi_black_48dp_2x-green.png | Bin 0 -> 7507 bytes
 ...ic_settings_input_hdmi_black_48dp_2x-orange.png | Bin 0 -> 6597 bytes
 .../ic_settings_input_hdmi_black_48dp_2x-red.png   | Bin 0 -> 7463 bytes
 ui/public/ic_storage_black_48dp_2x-green.png       | Bin 0 -> 6732 bytes
 ui/public/ic_storage_black_48dp_2x-orange.png      | Bin 0 -> 5958 bytes
 ui/public/ic_storage_black_48dp_2x-red.png         | Bin 0 -> 6634 bytes
 ui/run                                             |   1 +
 62 files changed, 683 insertions(+), 152 deletions(-)
 create mode 100644 ui/imports/api/configurations/configurations.js
 create mode 100644 ui/imports/api/configurations/methods.js
 create mode 100644 ui/imports/api/configurations/server/publications.js
 create mode 100644 ui/imports/api/links/server/methods.js
 create mode 100644 ui/imports/ui/components/configuration/configuration.html
 create mode 100644 ui/imports/ui/components/configuration/configuration.js
 create mode 100644 ui/imports/ui/components/configuration/configuration.styl
 create mode 100644 ui/public/backup - ic_cloud_queue_black_48dp_2x.png
 create mode 100644 ui/public/ic_cloud_queue_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_cloud_queue_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_cloud_queue_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_computer_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_computer_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_computer_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_dns_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_dns_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_dns_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_gamepad_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_gamepad_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_gamepad_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_keyboard_return_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_keyboard_return_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_keyboard_return_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_lens_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_lens_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_lens_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_settings_input_composite_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_settings_input_composite_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_settings_input_composite_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_settings_input_hdmi_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_settings_input_hdmi_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_settings_input_hdmi_black_48dp_2x-red.png
 create mode 100644 ui/public/ic_storage_black_48dp_2x-green.png
 create mode 100644 ui/public/ic_storage_black_48dp_2x-orange.png
 create mode 100644 ui/public/ic_storage_black_48dp_2x-red.png

diff --git a/ui/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data.js b/ui/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data.js
index ec2f6cd..13c877a 100644
--- a/ui/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data.js
+++ b/ui/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data.js
@@ -7,6 +7,30 @@
 // http://www.apache.org/licenses/LICENSE-2.0                                           /
 /////////////////////////////////////////////////////////////////////////////////////////
 import { Mongo } from 'meteor/mongo';
+import * as R from 'ramda';
 
 export const NodeHoverAttr = new Mongo.Collection(
   'attributes_for_hover_on_data', { idGeneration: 'MONGO' });
+
+export const calcAttrsForItem = function (node, attrsDefsRec) {
+  if (R.isNil(attrsDefsRec)) {
+    return [];
+  }
+
+  let attrsDefs = attrsDefsRec.attributes;
+
+  return R.reduce((acc, attrDef) => {
+    if (R.is(Array, attrDef)) {
+      let value = R.path(attrDef, node);
+      if (R.isNil(value)) { return acc; }
+      let name = R.join('.', attrDef);
+      return R.append(R.assoc(name, value, {}), acc);
+
+    } else {
+      return R.ifElse(R.isNil, 
+        R.always(acc), 
+        (attrVal) => R.append(R.assoc(attrDef, attrVal, {}), acc)
+      )(R.prop(attrDef, node));
+    }
+  }, [], attrsDefs);
+};
diff --git a/ui/imports/api/clique-types/methods.js b/ui/imports/api/clique-types/methods.js
index a62c22f..4257291 100644
--- a/ui/imports/api/clique-types/methods.js
+++ b/ui/imports/api/clique-types/methods.js
@@ -96,12 +96,12 @@ export const update = new ValidatedMethod({
       'focal_point_type',
       'link_types',
       'name', ], 
-      cliqueType), {
-        environment,
-        focal_point_type,
-        link_types,
-        name,
-      });
+    cliqueType), {
+      environment,
+      focal_point_type,
+      link_types,
+      name,
+    });
 
     CliqueTypes.update({ _id: _id }, { $set: cliqueType });
   }
diff --git a/ui/imports/api/configurations/configurations.js b/ui/imports/api/configurations/configurations.js
new file mode 100644
index 0000000..067b69f
--- /dev/null
+++ b/ui/imports/api/configurations/configurations.js
@@ -0,0 +1,29 @@
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+//                                                                                      /
+// All rights reserved. This program and the accompanying materials                     /
+// are made available under the terms of the Apache License, Version 2.0                /
+// which accompanies this distribution, and is available at                             /
+// http://www.apache.org/licenses/LICENSE-2.0                                           /
+/////////////////////////////////////////////////////////////////////////////////////////
+import { Mongo } from 'meteor/mongo';
+import { SimpleSchema } from 'meteor/aldeed:simple-schema';
+//import * as R from 'ramda';
+
+export const Configurations = new Mongo.Collection('configurations', { idGeneration: 'MONGO' });
+
+let schema = {
+  _id: { type: { _str: { type: String, regEx: SimpleSchema.RegEx.Id } } },
+  user_id: {
+    type: String,
+  },
+  messages_view_backward_delta: {
+    type: Number,
+    minCount: 1,
+    defaultValue: '1209600000', // 2 weeks
+  }
+};
+
+let simpleSchema = new SimpleSchema(schema);
+Configurations.schema = simpleSchema;
+Configurations.attachSchema(Configurations.schema);
diff --git a/ui/imports/api/configurations/methods.js b/ui/imports/api/configurations/methods.js
new file mode 100644
index 0000000..7366e3e
--- /dev/null
+++ b/ui/imports/api/configurations/methods.js
@@ -0,0 +1,39 @@
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+//                                                                                      /
+// All rights reserved. This program and the accompanying materials                     /
+// are made available under the terms of the Apache License, Version 2.0                /
+// which accompanies this distribution, and is available at                             /
+// http://www.apache.org/licenses/LICENSE-2.0                                           /
+/////////////////////////////////////////////////////////////////////////////////////////
+import { ValidatedMethod } from 'meteor/mdg:validated-method';
+import { Configurations } from '/imports/api/configurations/configurations';
+import * as R from 'ramda';
+
+export const save = new ValidatedMethod({
+  name: 'configurations.save',
+  validate: Configurations.simpleSchema()
+    .pick([
+      'messages_view_backward_delta'
+    ]).validator({ clean: true, filter: false }),
+  run({
+    messages_view_backward_delta
+  }) {
+
+    let userId = this.userId;
+    let conf = Configurations.findOne({ user_id: userId });
+
+    if (conf) {
+      Configurations.update({ _id: conf._id}, { $set: {
+        messages_view_backward_delta: messages_view_backward_delta
+      }});
+    } else {
+      let item =  Configurations.schema.clean({});
+      item = R.merge(item, {
+        user_id: userId,
+        messages_view_backward_delta: messages_view_backward_delta
+      });
+      Configurations.insert(item);
+    }
+  }
+});
diff --git a/ui/imports/api/configurations/server/publications.js b/ui/imports/api/configurations/server/publications.js
new file mode 100644
index 0000000..fe9f6fd
--- /dev/null
+++ b/ui/imports/api/configurations/server/publications.js
@@ -0,0 +1,21 @@
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+//                                                                                      /
+// All rights reserved. This program and the accompanying materials                     /
+// are made available under the terms of the Apache License, Version 2.0                /
+// which accompanies this distribution, and is available at                             /
+// http://www.apache.org/licenses/LICENSE-2.0                                           /
+/////////////////////////////////////////////////////////////////////////////////////////
+import { Meteor } from 'meteor/meteor';
+
+import { Configurations } from '../configurations.js';
+
+Meteor.publish('configurations?user', function () {
+  console.log('server subscribtion: configurations?user');
+
+  let userId = this.userId;
+
+  let query = { user_id: userId };
+  console.log('-query: ', query);
+  return Configurations.find(query); 
+});
diff --git a/ui/imports/api/environments/environments.js b/ui/imports/api/environments/environments.js
index 5e3b4b2..22e49cf 100644
--- a/ui/imports/api/environments/environments.js
+++ b/ui/imports/api/environments/environments.js
@@ -32,7 +32,7 @@ export const requiredConfGroups = [
 ];
 
 export const optionalConfGroups = [
- // 'NFV_provider',
+  // 'NFV_provider',
   'AMQP',
   'Monitoring',
   'ACI',
@@ -335,8 +335,8 @@ function getSchemaForGroupName(groupName) {
     return CLISchema;
   case 'AMQP':
     return AMQPSchema;
-//  case 'NFV_provider':
-//    return NfvProviderSchema;
+  //  case 'NFV_provider':
+  //    return NfvProviderSchema;
   case 'ACI':
     return AciSchema;
   case 'Monitoring':
diff --git a/ui/imports/api/inventories/server/methods.js b/ui/imports/api/inventories/server/methods.js
index 3daf570..d7e3648 100644
--- a/ui/imports/api/inventories/server/methods.js
+++ b/ui/imports/api/inventories/server/methods.js
@@ -11,7 +11,8 @@ import * as R from 'ramda';
 import { Inventory } from '../inventories';
 import { Environments } from '/imports/api/environments/environments';
 import { regexEscape } from '/imports/lib/regex-utils';
-import { NodeHoverAttr } from '/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data';
+import { NodeHoverAttr, calcAttrsForItem } from '/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data';
+
 const AUTO_COMPLETE_RESULTS_LIMIT = 15;
 
 Meteor.methods({
@@ -125,7 +126,7 @@ Meteor.methods({
     let query = { _id: nodeId };
     let node = Inventory.findOne(query);
     let attrsDefs = NodeHoverAttr.findOne({ 'type': node.type });
-    let attributes = calcAttrsForNode(node, attrsDefs);
+    let attributes = calcAttrsForItem(node, attrsDefs);
 
     return {
       node: node,
@@ -134,26 +135,3 @@ Meteor.methods({
     };
   },
 });
-
-function calcAttrsForNode(node, attrsDefsRec) {
-  if (R.isNil(attrsDefsRec)) {
-    return [];
-  }
-
-  let attrsDefs = attrsDefsRec.attributes;
-
-  return R.reduce((acc, attrDef) => {
-    if (R.is(Array, attrDef)) {
-      let value = R.path(attrDef, node);
-      if (R.isNil(value)) { return acc; }
-      let name = R.join('.', attrDef);
-      return R.append(R.assoc(name, value, {}), acc);
-
-    } else {
-      return R.ifElse(R.isNil, 
-        R.always(acc), 
-        (attrVal) => R.append(R.assoc(attrDef, attrVal, {}), acc)
-      )(R.prop(attrDef, node));
-    }
-  }, [], attrsDefs);
-}
diff --git a/ui/imports/api/links/server/methods.js b/ui/imports/api/links/server/methods.js
new file mode 100644
index 0000000..8d3454b
--- /dev/null
+++ b/ui/imports/api/links/server/methods.js
@@ -0,0 +1,31 @@
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+//                                                                                      /
+// All rights reserved. This program and the accompanying materials                     /
+// are made available under the terms of the Apache License, Version 2.0                /
+// which accompanies this distribution, and is available at                             /
+// http://www.apache.org/licenses/LICENSE-2.0                                           /
+/////////////////////////////////////////////////////////////////////////////////////////
+
+import { Links } from '../links';
+import { NodeHoverAttr, calcAttrsForItem } from '/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data';
+import * as R from 'ramda';
+
+Meteor.methods({
+  'linksFind?DataAndAttrs': function (id) {
+    console.log(`method server: linksFind?DataAndAttrs. ${R.toString(id)}`);
+    //check(nodeId, ObjectId);
+    this.unblock();
+
+    let query = { _id: id };
+    let link = Links.findOne(query);
+    let attrsDefs = NodeHoverAttr.findOne({ 'type': 'link' });
+    let attributes = calcAttrsForItem(link, attrsDefs);
+
+    return {
+      link: link,
+      linkName: link.link_name,
+      attributes: attributes
+    };
+  },
+});
diff --git a/ui/imports/api/messages/server/methods.js b/ui/imports/api/messages/server/methods.js
index 119e6b0..540c0a1 100644
--- a/ui/imports/api/messages/server/methods.js
+++ b/ui/imports/api/messages/server/methods.js
@@ -11,7 +11,7 @@ import { Messages } from '/imports/api/messages/messages';
 
 Meteor.methods({
   'messages/get?level&env&page&amountPerPage&sortField&sortDirection': function (
-      level, env, page, amountPerPage, sortField, sortDirection) {
+    level, env, page, amountPerPage, sortField, sortDirection) {
 
     logMethodCall('messages/get?level&env&page&amountPerPage&sortField&sortDirection', 
       {level, env, page, amountPerPage});
@@ -27,7 +27,7 @@ Meteor.methods({
     query = R.ifElse(R.isNil, R.always(query),R.assoc('level', R.__, query))(level);
 
     sortParams = R.ifElse(R.isNil, R.always(sortParams), 
-        R.assoc(R.__, sortDirection, sortParams))(sortField);
+      R.assoc(R.__, sortDirection, sortParams))(sortField);
 
     console.log('sort params:', sortParams);
 
diff --git a/ui/imports/api/messages/server/publications.js b/ui/imports/api/messages/server/publications.js
index 13c7c50..6b147f0 100644
--- a/ui/imports/api/messages/server/publications.js
+++ b/ui/imports/api/messages/server/publications.js
@@ -88,11 +88,28 @@ Meteor.publish('messages/count?level', function (level) {
   return new Counter(counterName, Messages.find({ level: level }));
 });
 
+Meteor.publish('messages/count?backDelta&level', function (backDelta, level) {
+  const counterName = `messages/count?backDelta=${backDelta}&level=${level}`; 
+  console.log(`subscribe - counter: ${counterName}`);
+
+  let begining = moment().subtract(backDelta);
+  let query = { 
+    level: level,
+    timestamp: { $gte: begining.toDate() } 
+  };
+
+  console.log(`query: ${R.toString(query)}`);
+
+  return new Counter(counterName, Messages.find(query));
+});
+
 Meteor.publish('messages/count?level&env', function (level, env) {
   const counterName = `messages/count?level=${level}&env=${env}`; 
   console.log(`subscribe - counter: ${counterName}`);
 
   let query = { level: level };
   query = R.ifElse(R.isNil, R.always(query), R.assoc('environment', R.__, query))(env);
+  console.log(`query: ${R.toString(query)}`);
 
-  return new Counter(counterName, Messages.find(query)); });
+  return new Counter(counterName, Messages.find(query)); 
+});
diff --git a/ui/imports/lib/images-for-node-type.js b/ui/imports/lib/images-for-node-type.js
index fb8e582..19be6ac 100644
--- a/ui/imports/lib/images-for-node-type.js
+++ b/ui/imports/lib/images-for-node-type.js
@@ -1,14 +1,59 @@
 export let imagesForNodeType = {
-  'instance': 'ic_computer_black_48dp_2x.png',
-  'pnic': 'ic_dns_black_48dp_2x.png',
-  'vconnector': 'ic_settings_input_composite_black_48dp_2x.png',
+  'instance': {
+    default: 'ic_computer_black_48dp_2x.png',
+    ok: 'ic_computer_black_48dp_2x-green.png',
+    warning: 'ic_computer_black_48dp_2x-orange.png',
+    error: 'ic_computer_black_48dp_2x-red.png',
+  },
+  'pnic': { 
+    default: 'ic_dns_black_48dp_2x.png',
+    ok: 'ic_dns_black_48dp_2x-green.png',
+    warning: 'ic_dns_black_48dp_2x-orange.png',
+    error: 'ic_dns_black_48dp_2x-red.png',
+  },
+  'vconnector': {
+    default: 'ic_settings_input_composite_black_48dp_2x.png',
+    ok: 'ic_settings_input_composite_black_48dp_2x-green.png',
+    warning: 'ic_settings_input_composite_black_48dp_2x-orange.png',
+    error: 'ic_settings_input_composite_black_48dp_2x-red.png',
+  },
   // 'network': 'ic_cloud_queue_black_48dp_2x.png',
-  'network': 'ic_cloud_queue_black_48dp_2x.png',
-  'vedge': 'ic_gamepad_black_48dp_2x.png',
-  'vservice': 'ic_storage_black_48dp_2x.png',
-  'vnic': 'ic_settings_input_hdmi_black_48dp_2x.png',
-  'otep':'ic_keyboard_return_black_48dp_2x.png',
+  'network': {
+    default: 'ic_cloud_queue_black_48dp_2x.png',
+    ok: 'ic_cloud_queue_black_48dp_2x-green.png',
+    warning: 'ic_cloud_queue_black_48dp_2x-orange.png',
+    error: 'ic_cloud_queue_black_48dp_2x-red.png',
+  },
+  'vedge': {
+    default: 'ic_gamepad_black_48dp_2x.png',
+    ok: 'ic_gamepad_black_48dp_2x-green.png',
+    warning: 'ic_gamepad_black_48dp_2x-orange.png',
+    error: 'ic_gamepad_black_48dp_2x-red.png',
+  },
+  'vservice': {
+    default: 'ic_storage_black_48dp_2x.png',
+    ok: 'ic_storage_black_48dp_2x-green.png',
+    warning: 'ic_storage_black_48dp_2x-orange.png',
+    error: 'ic_storage_black_48dp_2x-red.png',
+  },
+  'vnic': {
+    default: 'ic_settings_input_hdmi_black_48dp_2x.png',
+    ok: 'ic_settings_input_hdmi_black_48dp_2x-green.png',
+    warning: 'ic_settings_input_hdmi_black_48dp_2x-orange.png',
+    error: 'ic_settings_input_hdmi_black_48dp_2x-red.png',
+  },
+  'otep': {
+    default: 'ic_keyboard_return_black_48dp_2x.png',
+    ok: 'ic_keyboard_return_black_48dp_2x-green.png',
+    warning: 'ic_keyboard_return_black_48dp_2x-orange.png',
+    error: 'ic_keyboard_return_black_48dp_2x-red.png',
+  },
 };
 
-export let defaultNodeTypeImage = 'ic_lens_black_48dp_2x.png';
+export let defaultNodeTypeImage = {
+  default: 'ic_lens_black_48dp_2x.png',
+  ok: 'ic_lens_black_48dp_2x-green.png',
+  warning: 'ic_lens_black_48dp_2x-orange.png',
+  error: 'ic_lens_black_48dp_2x-red.png',
+};
 
diff --git a/ui/imports/startup/client/index.js b/ui/imports/startup/client/index.js
index 93da904..6ac478c 100644
--- a/ui/imports/startup/client/index.js
+++ b/ui/imports/startup/client/index.js
@@ -36,3 +36,4 @@ import '/imports/ui/components/messages-list/messages-list';
 import '/imports/ui/components/message/message';
 import '/imports/ui/components/dashboard/dashboard';
 import '/imports/ui/components/new-scanning/new-scanning';
+import '/imports/ui/components/configuration/configuration';
diff --git a/ui/imports/startup/server/register-api.js b/ui/imports/startup/server/register-api.js
index 3475c53..71d6887 100644
--- a/ui/imports/startup/server/register-api.js
+++ b/ui/imports/startup/server/register-api.js
@@ -31,6 +31,7 @@ import '../../api/cliques/methods.js';
 
 import '../../api/links/server/publications';
 import '../../api/links/methods.js';
+import '../../api/links/server/methods';
 
 import '../../api/statistics/server/publications';
 import '../../api/statistics/methods.js';
@@ -53,4 +54,7 @@ import '../../api/accounts/methods';
 import '../../api/supported_environments/server/publications';
 import '../../api/supported_environments/methods';
 
+import '../../api/configurations/server/publications';
+import '../../api/configurations/methods';
+
 import '../../api/migrations/migrations';
diff --git a/ui/imports/ui/components/alarm-icons/alarm-icons.html b/ui/imports/ui/components/alarm-icons/alarm-icons.html
index d584990..e59414e 100644
--- a/ui/imports/ui/components/alarm-icons/alarm-icons.html
+++ b/ui/imports/ui/components/alarm-icons/alarm-icons.html
@@ -15,34 +15,37 @@
        
         <div class="dropdown">
             <div class="material-icons mdl-badge mdl-badge--overlap dropdown-toggle" 
-              data-badge="{{countOf 'messages/count?level=info'}}" 
+              data-badge="{{ countOf (msgCounterName 'info') }}" 
               type="button" 
               id="dropdownMenu1" 
               data-toggle="modal" 
               data-target="#messagesModalGlobal"
               data-message-level="info"
+              title="Info messages"
               >notifications</div>
         </div>
 
         <div class="dropdown">
             <div class="material-icons mdl-badge mdl-badge--overlap dropdown-toggle" 
-              data-badge="{{countOf 'messages/count?level=warning'}}" 
+              data-badge="{{ countOf (msgCounterName 'warning') }}" 
               type="button" 
               id="dropdownMenu1" 
               data-toggle="modal" 
               data-target="#messagesModalGlobal"
               data-message-level="warning"
+              title="Warning messages"
               >warning</div>
         </div>
 
         <div class="dropdown">
             <div class="material-icons mdl-badge mdl-badge--overlap dropdown-toggle" 
-              data-badge="{{countOf 'messages/count?level=error'}}" 
+              data-badge="{{ countOf (msgCounterName 'error') }}" 
               type="button" 
               id="dropdownMenu1" 
               data-toggle="modal" 
               data-target="#messagesModalGlobal"
               data-message-level="error"
+              title="Error messages"
               >error</div>
         </div>
 
@@ -69,6 +72,10 @@
                   <a href="{{pathFor route='user-list' query=''}}">Users</a>
                 </li> 
                 {{/if }}
+
+                <li class="dropdown-header">
+                  <a href="{{pathFor route='configuration' query=''}}" >Configuration</a>
+                </li>
             </ul>
         </div>
 
diff --git a/ui/imports/ui/components/alarm-icons/alarm-icons.js b/ui/imports/ui/components/alarm-icons/alarm-icons.js
index 5c7af31..e86f8d8 100644
--- a/ui/imports/ui/components/alarm-icons/alarm-icons.js
+++ b/ui/imports/ui/components/alarm-icons/alarm-icons.js
@@ -13,6 +13,9 @@
 import '/imports/ui/components/breadcrumb/breadcrumb';
 import { Messages } from '/imports/api/messages/messages';
 import { Roles } from 'meteor/alanning:roles';
+import { ReactiveDict } from 'meteor/reactive-dict';
+
+import { Configurations } from '/imports/api/configurations/configurations';
 
 import './alarm-icons.html';     
 
@@ -23,10 +26,24 @@ import './alarm-icons.html';
 Template.alarmIcons.onCreated(function () {
   let instance = this;
 
+  instance.state = new ReactiveDict();
+  instance.state.setDefault({
+    msgsViewBackDelta: 1
+  });
+
   instance.autorun(function () {
-    instance.subscribe('messages/count?level', 'info');
-    instance.subscribe('messages/count?level', 'warning');
-    instance.subscribe('messages/count?level', 'error');
+    instance.subscribe('configurations?user');
+    Configurations.find({user_id: Meteor.userId()}).forEach((conf) => {
+      instance.state.set('msgsViewBackDelta', conf.messages_view_backward_delta); 
+    });
+  });
+
+  instance.autorun(function () {
+    let msgsViewBackDelta = instance.state.get('msgsViewBackDelta');
+
+    instance.subscribe('messages/count?backDelta&level', msgsViewBackDelta, 'info');
+    instance.subscribe('messages/count?backDelta&level', msgsViewBackDelta, 'warning');
+    instance.subscribe('messages/count?backDelta&level', msgsViewBackDelta, 'error');
   });
 });
 
@@ -50,4 +67,12 @@ Template.alarmIcons.helpers({
   errorsCount: function(){
     return Messages.find({level:'error'}).count();
   },
+
+  msgCounterName: function (level) {
+    let instance = Template.instance();
+    let msgsViewBackDelta = instance.state.get('msgsViewBackDelta');
+    let counterName = `messages/count?backDelta=${msgsViewBackDelta}&level=${level}`;
+
+    return counterName;
+  }
 });
diff --git a/ui/imports/ui/components/clique-type/clique-type.js b/ui/imports/ui/components/clique-type/clique-type.js
index ae50b94..9b21442 100644
--- a/ui/imports/ui/components/clique-type/clique-type.js
+++ b/ui/imports/ui/components/clique-type/clique-type.js
@@ -130,7 +130,7 @@ Template.CliqueType.helpers({
 
   objectTypesList: function () {
     return R.ifElse(R.isNil, R.always([]), R.prop('data')
-      )(Constants.findOne({ name: 'object_types_for_links' }));
+    )(Constants.findOne({ name: 'object_types_for_links' }));
   },
 
   linkTypesList: function () {
@@ -280,7 +280,7 @@ function submitItem(
   focal_point_type, 
   link_types, 
   name 
- ) {
+) {
 
   let action = instance.state.get('action');
 
@@ -316,7 +316,7 @@ function submitItem(
     break;
 
   default:
-      // todo
+    // todo
     break;
   }
 }
diff --git a/ui/imports/ui/components/configuration/configuration.html b/ui/imports/ui/components/configuration/configuration.html
new file mode 100644
index 0000000..f381453
--- /dev/null
+++ b/ui/imports/ui/components/configuration/configuration.html
@@ -0,0 +1,31 @@
+<template name="Configuration">
+<div class="os-configuration cards white">
+  <h3>Configurations</h3>
+  <form>
+    <div class="cl-field-group">
+      <label class="cl-field-label">Message view backward delta</label>
+      <input name="msgsViewBackDelta" 
+        value="{{ getModelField 'messages_view_backward_delta' }}"     
+        class="cl-msgs-view-back-delta cl-input" 
+        type="number" 
+        placeholder="" />
+      <div class="cl-field-desc">Backward duration of {{ durationHumanize (getModelField 'messages_view_backward_delta') }} from current date (miliseconds)</div>
+    </div>
+
+    <button type="button" 
+      class="js-submit-button mdl-button mdl-js-button mdl-button--raised 
+        mdl-js-ripple-effect mdl-button--colored"
+      >Save</button>
+  </form>
+
+  {{#if (getState 'message') }}
+  <div class="js-message-panel alert 
+      {{#if isActionError}}alert-danger{{/if}}
+      {{#if isActionSuccess}}alert-success{{/if}}" 
+      role="alert">
+    {{ getState 'message' }}
+  </div>
+  {{/if }}
+
+</div>
+</template>
diff --git a/ui/imports/ui/components/configuration/configuration.js b/ui/imports/ui/components/configuration/configuration.js
new file mode 100644
index 0000000..493cc36
--- /dev/null
+++ b/ui/imports/ui/components/configuration/configuration.js
@@ -0,0 +1,114 @@
+/*
+ * Template Component: Configuration 
+ */
+    
+//import { Meteor } from 'meteor/meteor'; 
+import { Template } from 'meteor/templating';
+import { ReactiveDict } from 'meteor/reactive-dict';
+//import { SimpleSchema } from 'meteor/aldeed:simple-schema';
+import * as R from 'ramda';
+
+import { save } from '/imports/api/configurations/methods';
+import { Configurations } from '/imports/api/configurations/configurations';
+        
+import './configuration.html';     
+    
+/*  
+ * Lifecycles
+ */   
+  
+Template.Configuration.onCreated(function() {
+  let instance = this;
+  instance.state = new ReactiveDict();
+  instance.state.setDefault({
+    model: Configurations.schema.clean({}),
+    actionResult: 'none',
+    message: null,
+  });
+
+  /*
+  instance.autorun(function () {
+    let data = Template.currentData();
+
+    new SimpleSchema({
+    }).validate(data);
+  });
+  */
+
+  instance.autorun(function () {
+    instance.subscribe('configurations?user');
+    Configurations.find({user_id: Meteor.userId()}).forEach((conf) => {
+      instance.state.set('model', conf);
+    });
+  });
+});  
+
+/*
+Template.Configuration.rendered = function() {
+};  
+*/
+
+/*
+ * Events
+ */
+
+Template.Configuration.events({
+  'click .js-submit-button': function (event, instance) {
+    event.preventDefault(); 
+    let msgsViewBackDelta = instance.$('.cl-msgs-view-back-delta')[0].value;
+    saveForm(instance, msgsViewBackDelta);
+  }
+});
+   
+/*  
+ * Helpers
+ */
+
+Template.Configuration.helpers({    
+  getModelField: function (fieldName) {
+    let instance = Template.instance();
+    return R.path([fieldName], instance.state.get('model'));
+  },
+
+  getState: function (key) {
+    let instance = Template.instance();
+    return instance.state.get(key);
+  },
+
+  isActionError: function () {
+    let instance = Template.instance();
+    return instance.state.get('actionResult') === 'error';
+  },
+
+  isActionSuccess: function () {
+    let instance = Template.instance();
+    return instance.state.get('actionResult') === 'success';
+  },
+
+  durationHumanize: function (duration) {
+    return moment.duration(duration).humanize();
+  }
+}); // end: helpers
+
+function saveForm(instance, msgsViewBackDelta) {
+  instance.state.set('actionResult', 'none');
+  instance.state.set('message', null);
+
+  save.call({
+    messages_view_backward_delta: msgsViewBackDelta
+  }, (error) => {
+    if (error) {
+      instance.state.set('actionResult', 'error');
+      if (typeof error === 'string') {
+        instance.state.set('message', error);
+      } else {
+        instance.state.set('message', error.message);
+      }
+
+      return;
+    } 
+
+    instance.state.set('actionResult', 'success');
+    instance.state.set('message', 'record has been updated succesfuly');
+  });
+}
diff --git a/ui/imports/ui/components/configuration/configuration.styl b/ui/imports/ui/components/configuration/configuration.styl
new file mode 100644
index 0000000..b8be180
--- /dev/null
+++ b/ui/imports/ui/components/configuration/configuration.styl
@@ -0,0 +1,38 @@
+/* Set the component style here */
+// "Configuration"
+.os-configuration
+  display: flex;
+  flex-flow: column nowrap;
+  margin: 20px;
+
+  .cl-field-group
+    display: flex;
+    flex-flow: row nowrap;
+    align-items: center;
+    padding: 5px 0;
+
+    .cl-field-label
+      width: 120px;
+      margin: 0 5px;
+
+    >.cl-input
+      display: block;
+      width: 100%;
+      min-height: 34px;
+      padding: 6px 12px;
+      font-size: 14px;
+      line-height: 1.42857143;
+      color: #555;
+      background-color: #fff;
+      background-image: none;
+      border: 1px solid #ccc;
+      border-radius: 4px;
+      box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+      width: 400px;
+      margin: 0 5px;
+
+    .cl-field-desc
+      margin: 0 5px;
+
+  .js-message-panel
+    margin-top: 20px;
diff --git a/ui/imports/ui/components/dashboard/dashboard.js b/ui/imports/ui/components/dashboard/dashboard.js
index 85cede8..6fdc184 100644
--- a/ui/imports/ui/components/dashboard/dashboard.js
+++ b/ui/imports/ui/components/dashboard/dashboard.js
@@ -13,8 +13,8 @@
 //import * as R from 'ramda';
 import * as _ from 'lodash';
 import { Environments } from '/imports/api/environments/environments';
-import { //Messages, 
-  calcIconForMessageLevel, lastMessageTimestamp, calcColorClassForMessagesInfoBox 
+import { //Messages,
+  calcIconForMessageLevel, lastMessageTimestamp, calcColorClassForMessagesInfoBox
 } from '/imports/api/messages/messages';
 import { Template } from 'meteor/templating';
 import { Inventory } from '/imports/api/inventories/inventories';
@@ -27,7 +27,7 @@ import { setMainAppSelectedEnvironment } from '/imports/ui/actions/main-app.acti
 import '/imports/ui/components/messages-info-box/messages-info-box';
 import '/imports/ui/components/environment-box/environment-box';
 
-import './dashboard.html';     
+import './dashboard.html';
 
 /*
  * Lifecycle methods
@@ -212,10 +212,10 @@ Template.Dashboard.helpers({
       icon: calcIconForMessageLevel(boxDef.level),
       colorClass: calcColorClassForMessagesInfoBox(boxDef.level),
       onMoreDetailsReq: function () {
-        $('#messagesModalGlobal').modal('show', { 
+        $('#messagesModalGlobal').modal('show', {
           dataset: {
             messageLevel: boxDef.level,
-          } 
+          }
         });
       }
     };
@@ -223,10 +223,10 @@ Template.Dashboard.helpers({
 
   argsEnvBox: function (
     environmentName,
-    regionsCount, 
-    regions, 
-    projectsCount, 
-    projects, 
+    regionsCount,
+    regions,
+    projectsCount,
+    projects,
     instancesCount,
     vservicesCount,
     vconnectorsCount,
diff --git a/ui/imports/ui/components/environment-dashboard/environment-dashboard.js b/ui/imports/ui/components/environment-dashboard/environment-dashboard.js
index 433096e..82fbb52 100644
--- a/ui/imports/ui/components/environment-dashboard/environment-dashboard.js
+++ b/ui/imports/ui/components/environment-dashboard/environment-dashboard.js
@@ -26,6 +26,7 @@ import { calcIconForMessageLevel, lastMessageTimestamp, calcColorClassForMessage
 import { Counts } from 'meteor/tmeasday:publish-counts';
 import { Roles } from 'meteor/alanning:roles';
 //import { idToStr } from '/imports/lib/utilities';
+import { Counter } from 'meteor/natestrauser:publish-performant-counts';
         
 import '/imports/ui/components/data-cubic/data-cubic';
 import '/imports/ui/components/icon/icon';
@@ -123,9 +124,10 @@ Template.EnvironmentDashboard.onCreated(function() {
       instance.subscribe('inventory?env+type', env.name, 'vconnector');
       instance.subscribe('inventory?env+type', env.name, 'project');
       instance.subscribe('inventory?env+type', env.name, 'region');
-      instance.subscribe('messages?env+level', env.name, 'info');
-      instance.subscribe('messages?env+level', env.name, 'warning');
-      instance.subscribe('messages?env+level', env.name, 'error');
+
+      instance.subscribe('messages/count?level&env', 'info', env.name);
+      instance.subscribe('messages/count?level&env', 'warning', env.name);
+      instance.subscribe('messages/count?level&env', 'error', env.name);
 
       let vConnectorCounterName = 'inventory?env+type!counter?env=' +
         env.name + '&type=' + 'vconnector';
@@ -316,8 +318,11 @@ Template.EnvironmentDashboard.helpers({
       };
     }
 
-    let count =  Counts.get('messages?env+level!counter?env=' +
-       envName + '&level=' + boxDef.level);
+    let counterName = `messages/count?level=${boxDef.level}&env=${envName}`;
+    let count = Counter.get(counterName);
+
+    //let count =  Counts.get('messages?env+level!counter?env=' +
+    //   envName + '&level=' + boxDef.level);
 
     let title = _.capitalize(boxDef.level);
 
diff --git a/ui/imports/ui/components/environment/environment.js b/ui/imports/ui/components/environment/environment.js
index 83574f2..1f0e723 100644
--- a/ui/imports/ui/components/environment/environment.js
+++ b/ui/imports/ui/components/environment/environment.js
@@ -157,6 +157,7 @@ Template.Environment.onCreated(function () {
     new SimpleSchema({
       _id: _idFieldDef, 
       selectedNodeId: R.assoc('optional', true, _idFieldDef),
+      refresh: { type: String, optional: true }, 
     }).validate(data);
 
     store.dispatch(setEnvEnvId(data._id));
diff --git a/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.html b/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.html
index 53537ca..4ce9787 100644
--- a/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.html
+++ b/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.html
@@ -9,8 +9,8 @@
 ########################################################################################
  -->
 <template name="GraphTooltipWindow">
-  <div class="os-graph-tooltip-window {{#if show}}cl-visible{{/if}}" 
-       style="top: {{ top }}px; left: {{ left }}px;">   
+<div class="os-graph-tooltip-window {{#if show}}cl-visible{{/if}}" 
+     style="top: {{ top }}px; left: {{ left }}px;">   
   <div class="sm-label"><u>{{ label }}</u></div>
   <div class="sm-title">{{{ title }}}</div>
 </div>
diff --git a/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.js b/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.js
index 48b1903..dbeb55c 100644
--- a/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.js
+++ b/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.js
@@ -14,6 +14,8 @@
 import { Template } from 'meteor/templating';
 //import { ReactiveDict } from 'meteor/reactive-dict';
 import { SimpleSchema } from 'meteor/aldeed:simple-schema';
+import { store } from '/imports/ui/store/store';
+import { closeGraphTooltipWindow } from '/imports/ui/actions/graph-tooltip-window.actions';
         
 import './graph-tooltip-window.html';     
     
@@ -45,6 +47,23 @@ Template.GraphTooltipWindow.rendered = function() {
  */
 
 Template.GraphTooltipWindow.events({
+  'mouseout .os-graph-tooltip-window': function(_e, _instance) {
+    /*
+    if (!instance.data.show) { return; }
+
+    e.preventDefault();
+    e.stopPropagation();
+    store.dispatch(closeGraphTooltipWindow());
+    */
+  },
+
+  'click .os-graph-tooltip-window': function(e, instance) {
+    if (!instance.data.show) { return; }
+
+    e.preventDefault();
+    e.stopPropagation();
+    store.dispatch(closeGraphTooltipWindow());
+  },
 });
    
 /*  
diff --git a/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.styl b/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.styl
index ec94023..1bbb9d5 100644
--- a/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.styl
+++ b/ui/imports/ui/components/graph-tooltip-window/graph-tooltip-window.styl
@@ -3,23 +3,26 @@
 .os-graph-tooltip-window
   visibility: hidden;
 
+  max-height: 300px;
+  overflow: auto;
   position: absolute;
   text-align: left;
   opacity: 0
-  font: normal 18px sans-serif !important;
+  font: normal 16px sans-serif;
   /* width: 60px; */
   /* height: 28px; */
   padding: 20px;
-  font: 16px sans-serif;
   background: dk-gray1;
   color white
   border: 2px solid stark-blue
-  pointer-events: none;
+  // pointer-events: none;
 
   transition: visibility 0.5s, opacity 0.5s linear
 
+  .sm-label
+    font-weight: bold;
+
 .os-graph-tooltip-window.cl-visible 
   visibility: visible
   opacity: 0.9
   transition: visibility 0.2s, opacity 0.2s linear
-
diff --git a/ui/imports/ui/components/index.styl b/ui/imports/ui/components/index.styl
index 2b2b2d3..877d68b 100644
--- a/ui/imports/ui/components/index.styl
+++ b/ui/imports/ui/components/index.styl
@@ -56,3 +56,4 @@
 @import 'network-graph-manager/*';
 @import 'network-graph/*';
 @import 'environment-box/*';
+@import 'configuration/*';
diff --git a/ui/imports/ui/components/messages-modal/messages-modal.js b/ui/imports/ui/components/messages-modal/messages-modal.js
index 59a6ec7..713e8e9 100644
--- a/ui/imports/ui/components/messages-modal/messages-modal.js
+++ b/ui/imports/ui/components/messages-modal/messages-modal.js
@@ -7,10 +7,10 @@
 // http://www.apache.org/licenses/LICENSE-2.0                                           /
 /////////////////////////////////////////////////////////////////////////////////////////
 /*
- * Template Component: MessagesModal 
+ * Template Component: MessagesModal
  */
-    
-//import { Meteor } from 'meteor/meteor'; 
+
+//import { Meteor } from 'meteor/meteor';
 import { Template } from 'meteor/templating';
 import { ReactiveDict } from 'meteor/reactive-dict';
 import { Counter } from 'meteor/natestrauser:publish-performant-counts';
@@ -18,15 +18,15 @@ import * as R from 'ramda';
 //import { Messages } from '/imports/api/messages/messages';
 import { Environments } from '/imports/api/environments/environments';
 import { idToStr } from '/imports/lib/utilities';
-        
+
 import '/imports/ui/components/pager/pager';
 
-import './messages-modal.html';     
-    
-/*  
+import './messages-modal.html';
+
+/*
  * Lifecycles
- */   
-  
+ */
+
 Template.MessagesModal.onCreated(function() {
   let instance = this;
   instance.state = new ReactiveDict();
@@ -41,7 +41,7 @@ Template.MessagesModal.onCreated(function() {
   });
 
   instance.autorun(function () {
- 
+
     //let amountPerPage = instance.state.get('amountPerPage');
     //let page = instance.state.get('page');
     let envName = instance.state.get('envName');
@@ -77,11 +77,11 @@ Template.MessagesModal.onCreated(function() {
       instance.state.set('messages', res);
     });
   });
-});  
+});
 
 /*
 Template.MessagesModal.rendered = function() {
-};  
+};
 */
 
 /*
@@ -107,9 +107,9 @@ Template.MessagesModal.events({
     ], {
       wait: false
     }, function (err, resp) {
-      if (err) { 
+      if (err) {
         console.error(R.toString(err));
-        return; 
+        return;
       }
 
       if (R.isNil(resp.node)) {
@@ -117,12 +117,12 @@ Template.MessagesModal.events({
         return;
       }
 
-      Router.go('environment', { 
-        _id: idToStr(environment._id) 
-      }, { 
+      Router.go('environment', {
+        _id: idToStr(environment._id)
+      }, {
         query: {
           selectedNodeId: idToStr(resp.node._id)
-        } 
+        }
       });
 
       instance.$('#messagesModalGlobal').modal('hide');
@@ -131,12 +131,12 @@ Template.MessagesModal.events({
 
   }
 });
-   
-/*  
+
+/*
  * Helpers
  */
 
-Template.MessagesModal.helpers({    
+Template.MessagesModal.helpers({
   iconType: function () {
     let instance = Template.instance();
     return instance.state.get('iconType');
@@ -186,17 +186,17 @@ Template.MessagesModal.helpers({
     return {
       disableNext: currentPage * amountPerPage > totalMessages,
       disablePrev: currentPage == 1,
-      totalPages: totalPages,      
+      totalPages: totalPages,
       currentPage: currentPage,
       onReqNext: function () {
         console.log('next');
         let page = (currentPage * amountPerPage > totalMessages) ? currentPage : currentPage + 1;
-        instance.state.set('page', page); 
+        instance.state.set('page', page);
       },
       onReqPrev: function () {
         console.log('prev');
         let page = (currentPage == 1) ? currentPage : currentPage - 1;
-        instance.state.set('page', page); 
+        instance.state.set('page', page);
       },
       onReqFirst: function () {
         console.log('req first');
@@ -209,9 +209,9 @@ Template.MessagesModal.helpers({
       onReqPage: function (pageNumber) {
         console.log('req page');
         let page;
-        if (pageNumber <= 1) { 
-          page = 1; 
-        } else if (pageNumber > Math.ceil(totalMessages / amountPerPage)) { 
+        if (pageNumber <= 1) {
+          page = 1;
+        } else if (pageNumber > Math.ceil(totalMessages / amountPerPage)) {
           page = totalPages;
         } else {
           page = pageNumber;
diff --git a/ui/imports/ui/components/network-graph-manager/network-graph-manager.js b/ui/imports/ui/components/network-graph-manager/network-graph-manager.js
index 16637ea..ed556c0 100644
--- a/ui/imports/ui/components/network-graph-manager/network-graph-manager.js
+++ b/ui/imports/ui/components/network-graph-manager/network-graph-manager.js
@@ -37,7 +37,8 @@ Template.NetworkGraphManager.onCreated(function() {
       links: [],
       nodes: [],
       groups: [],
-    }
+    },
+    itemOfInterest: null
   };
 
   instance.autorun(function () {
@@ -95,6 +96,13 @@ Template.NetworkGraphManager.helpers({
           return;
         }
 
+        if (instance.simpleState.itemOfInterest === nodeId) {
+          instance.simpleState.itemOfInterest = null;
+          return;
+        }
+
+        instance.simpleState.itemOfInterest = nodeId;
+
         Meteor.apply('inventoryFindNode?DataAndAttrs', [ nodeId ], 
           { wait: false }, function (err, res) {
             if (err) {
@@ -103,11 +111,11 @@ Template.NetworkGraphManager.helpers({
             }
 
             store.dispatch(
-              activateGraphTooltipWindow(res.nodeName, res.attributes, x, y));
+              activateGraphTooltipWindow(res.nodeName, res.attributes, x - 30, y - 10));
           });
       },
       onNodeOut: function (_nodeId) {
-        store.dispatch(closeGraphTooltipWindow());
+        //store.dispatch(closeGraphTooltipWindow());
       },
       onNodeClick: function (_nodeId) {
       },
@@ -118,6 +126,33 @@ Template.NetworkGraphManager.helpers({
       onDragEnd: function () {
         isDragging = false;
       },
+      onGroupOver: function () {
+        instance.simpleState.itemOfInterest = null;
+        store.dispatch(closeGraphTooltipWindow());
+      },
+      onLinkOver: function (linkId, x, y) {
+        if (isDragging) {
+          return;
+        }
+
+        if (instance.simpleState.itemOfInterest === linkId) {
+          instance.simpleState.itemOfInterest = null;
+          return;
+        }
+
+        instance.simpleState.itemOfInterest = linkId;
+
+        Meteor.apply('linksFind?DataAndAttrs', [ linkId ], 
+          { wait: false }, function (err, res) {
+            if (err) {
+              console.error(`error fetching attrs for link for showing: ${R.toString(err)}`);
+              return;
+            }
+
+            store.dispatch(
+              activateGraphTooltipWindow(res.linkName, res.attributes, x - 30, y - 10));
+          });
+      },
     };
   },
 
@@ -180,7 +215,11 @@ function addLinkToGraph(link, graphData) {
     sourceId: link.source, 
     targetId: link.target, 
     label: link.link_name,
-    _osid: link._id
+    _osid: link._id,
+    _osmeta: {
+      status: link.status,
+      linkId: link._id
+    }
   };
 
   let links = R.unionWith(R.eqBy(R.prop('_osid')), graphData.links, [newLink]);
@@ -215,6 +254,7 @@ function addNodeToGraph(node, graphData) {
     _osmeta: {
       type: node.type,
       nodeId: node._id,
+      status: node.status,
     },
     width: 60,
     height: 40,
diff --git a/ui/imports/ui/components/network-graph/network-graph.js b/ui/imports/ui/components/network-graph/network-graph.js
index 04a33b0..68b3a57 100644
--- a/ui/imports/ui/components/network-graph/network-graph.js
+++ b/ui/imports/ui/components/network-graph/network-graph.js
@@ -9,6 +9,7 @@ import { SimpleSchema } from 'meteor/aldeed:simple-schema';
 import * as R from 'ramda';
 import * as cola from 'webcola';
 import { imagesForNodeType, defaultNodeTypeImage } from '/imports/lib/images-for-node-type';
+import * as _ from 'lodash';
         
 import './network-graph.html';     
     
@@ -37,6 +38,8 @@ Template.NetworkGraph.onCreated(function() {
       onNodeClick: { type: Function, optional: true },
       onDragStart: { type: Function, optional: true },
       onDragEnd: { type: Function, optional: true },
+      onGroupOver: { type: Function, optional: true },
+      onLinkOver: { type: Function, optional: true },
     }).validate(data);
 
     instance.simpleState.graphData = data.graphData;
@@ -46,6 +49,8 @@ Template.NetworkGraph.onCreated(function() {
     instance.onNodeClick = R.defaultTo(() => {}, data.onNodeClick);
     instance.onDragStart = R.defaultTo(() => {}, data.onDragStart);
     instance.onDragEnd = R.defaultTo(() => {}, data.onDragEnd);
+    instance.onGroupOver = R.defaultTo(() => {}, data.onGroupOver);
+    instance.onLinkOver = R.defaultTo(() => {}, data.onLinkOver);
   });
 });  
 
@@ -66,7 +71,9 @@ Template.NetworkGraph.rendered = function() {
       instance.onNodeOut, 
       instance.onNodeClick,
       instance.onDragStart,
-      instance.onDragEnd
+      instance.onDragEnd,
+      instance.onGroupOver,
+      instance.onLinkOver
     );
   });
 };  
@@ -129,7 +136,9 @@ function renderGraph(
   onNodeOut, 
   onNodeClick,
   onDragStart,
-  onDragEnd
+  onDragEnd,
+  onGroupOver,
+  onLinkOver
 ) {
 
   let force = genForceCola(cola, d3, w, h);
@@ -167,10 +176,15 @@ function renderGraph(
   nodesEl,
   linksEl,
   drag, zoom, config, 
-  onNodeOver, onNodeOut, onNodeClick);
+  onNodeOver, 
+  onNodeOut, 
+  onNodeClick,
+  onGroupOver,
+  onLinkOver
+  );
 }
 
- // d3.select(window).on('resize', resize);
+// d3.select(window).on('resize', resize);
 
 function genSvg(d3, mainElement) {
   let svg = d3.select(mainElement).append('svg');
@@ -183,17 +197,24 @@ function genSvg(d3, mainElement) {
   return svg;
 }
 
-function genSvgLinks(g, links, nominal_stroke, default_link_color, initialLinkLabelsFontSize) {
+function genSvgLinks(
+  g, 
+  links, 
+  nominal_stroke, 
+  default_link_color, 
+  initialLinkLabelsFontSize,
+  onLinkOver
+) {
   let svgLinks = g.selectAll('.link-group')
     .data(links, (d) => d._osid);
 
   let svgLinksEnter = svgLinks
     .enter()
-      .append('g')
-        .attr('class', 'link-group')
-        .attr('data-link-id', function (d) {
-          return d._osid;
-        })
+    .append('g')
+    .attr('class', 'link-group')
+    .attr('data-link-id', function (d) {
+      return d._osid;
+    })
   ;
 
   //let svgLinksExit = 
@@ -205,9 +226,24 @@ function genSvgLinks(g, links, nominal_stroke, default_link_color, initialLinkLa
     .attr('class', 'link-line')
     .style('stroke-width', nominal_stroke)
     .style('stroke', 
-    function(_d) { 
-      return default_link_color;
-    });
+      function(d) { 
+        let status = R.defaultTo('', R.path(['_osmeta', 'status'], d));
+        status = _.toLower(status);
+        switch(status) {
+        case 'ok': 
+          return 'green';
+        case 'warning':
+          return 'orange';
+        case 'error':
+          return 'red';
+        default:
+          return default_link_color;
+        }
+      })
+    .on('mouseover', function (d) {
+      onLinkOver(d._osmeta.linkId, d3.event.pageX, d3.event.pageY);
+    })
+  ;
 
   let svgLinkLabels = svgLinksEnter
     .append('text')
@@ -232,9 +268,9 @@ function genSvgNodes(g, nodes, drag, onNodeOver, onNodeOut, onNodeClick, onGroup
   let svgNodesEnter = svgNodes
     .enter()
     .append('g')
-      .attr('class', 'node')
-      .attr('data-node-id', (d) => d._osid)
-      .call(drag);
+    .attr('class', 'node')
+    .attr('data-node-id', (d) => d._osid)
+    .call(drag);
 
   //let svgNodesExit = 
   svgNodes
@@ -244,7 +280,9 @@ function genSvgNodes(g, nodes, drag, onNodeOver, onNodeOut, onNodeClick, onGroup
   let svgImages = svgNodesEnter.append('image')
     .attr('class', 'node-image')
     .attr('xlink:href', function(d) {
-      return `/${calcImageForNodeType(d._osmeta.type)}`;
+      let status = R.defaultTo('', R.path(['_osmeta', 'status'], d));
+      status = _.toLower(status);
+      return `/${calcImageForNodeType(d._osmeta.type, status)}`;
     })
     .attr('x', -(Math.floor(imageLength / 2)))
     .attr('y', -(Math.floor(imageLength / 2)))
@@ -268,8 +306,13 @@ function genSvgNodes(g, nodes, drag, onNodeOver, onNodeOut, onNodeClick, onGroup
   //return [svgNodes];
 }
 
-function calcImageForNodeType(nodeType) {
-  return R.defaultTo(defaultNodeTypeImage, R.prop(nodeType, imagesForNodeType));
+function calcImageForNodeType(nodeType, status) {
+  let image = R.defaultTo(defaultNodeTypeImage, R.prop(nodeType, imagesForNodeType));
+  if (typeof image === 'object') {
+    image = R.defaultTo(image.default, image[status]);
+  }
+
+  return image;
 }
 
 function genZoomBehavior(d3, config) {
@@ -292,7 +335,7 @@ function genForceD3(d3, w, h) {
 function genForceCola(cola, d3, w, h) {
   let force = cola.d3adaptor(d3)
     .convergenceThreshold(0.1)
-  //  .convergenceThreshold(1e-9)
+    //.convergenceThreshold(1e-9)
     .linkDistance(120)
     .size([w,h]);
 
@@ -308,7 +351,7 @@ function activateForce(force, nodes, links, groups) {
     .handleDisconnected(true)
     .avoidOverlaps(true)
     .start(50, 100, 200);
-    //.start();
+  //.start();
 }
 
 /*
@@ -340,7 +383,10 @@ function renderView(force,
   config, 
   onNodeOver, 
   onNodeOut, 
-  onNodeClick) {
+  onNodeClick,
+  onGroupOver,
+  onLinkOver
+) {
 
   state.viewGraph = calcViewGraph(state.graph, state.viewGraph);
 
@@ -348,13 +394,14 @@ function renderView(force,
 
   zoom.on('zoom', zoomFn);
 
-  genSvgGroups(groupsEl, state.viewGraph.groups, drag, onRenderViewReq);
+  genSvgGroups(groupsEl, state.viewGraph.groups, drag, onRenderViewReq, onGroupOver);
 
   genSvgLinks(
     linksEl, state.viewGraph.links, 
     config.nominal_stroke, 
     config.default_link_color,
-    config.initialLinkLabelsFontSize
+    config.initialLinkLabelsFontSize,
+    onLinkOver
   );
 
   genSvgNodes(
@@ -366,7 +413,7 @@ function renderView(force,
       state.viewGraph = renderView(force, state, 
         mainEl, groupsEl, nodesEl, linksEl,
         drag, zoom, config, 
-        onNodeOver, onNodeOut, onNodeClick);
+        onNodeOver, onNodeOut, onNodeClick, onGroupOver, onLinkOver);
     }); 
 
   force.on('tick', tickFn);
@@ -375,7 +422,7 @@ function renderView(force,
     state.viewGraph = renderView(force, state, 
       mainEl, groupsEl, nodesEl, linksEl,
       drag, zoom, config, 
-      onNodeOver, onNodeOut, onNodeClick);
+      onNodeOver, onNodeOut, onNodeClick, onGroupOver, onLinkOver);
   }
 
   function tickFn() {
@@ -477,30 +524,33 @@ function renderView(force,
   return state.viewGraph;
 }
 
-function genSvgGroups(g, groups, drag, onRenderViewReq) {
+function genSvgGroups(g, groups, drag, onRenderViewReq, onGroupOver) {
   let svgGroups = g.selectAll('.group')
-      .data(groups, (d) => d._osid);
+    .data(groups, (d) => d._osid);
 
   let enterGroups = svgGroups.enter();
 
   let groupsContainers = 
     enterGroups
       .append('g')
-        .attr('class', 'group')
-        .attr('data-group-id', (d) => d._osid)
-        .call(drag)
-        .on('click', function (d) {
-          console.log('click', d);
-          d.isExpanded = !d.isExpanded;
-          onRenderViewReq();
-        });
+      .attr('class', 'group')
+      .attr('data-group-id', (d) => d._osid)
+      .call(drag)
+      .on('mouseover', function (_d) {
+        onGroupOver();
+      })
+      .on('click', function (d) {
+        console.log('click', d);
+        d.isExpanded = !d.isExpanded;
+        onRenderViewReq();
+      });
 
   groupsContainers
     .append('rect')
-      .attr('class', 'group-shape')
-      .attr('rx', 8)
-      .attr('ry', 8)
-      .style('fill', function (_d, _i) { return 'lightblue'; })
+    .attr('class', 'group-shape')
+    .attr('rx', 8)
+    .attr('ry', 8)
+    .style('fill', function (_d, _i) { return 'lightblue'; })
   ;
 
   groupsContainers
diff --git a/ui/imports/ui/components/scans-list/scans-list.html b/ui/imports/ui/components/scans-list/scans-list.html
index f8998dd..6466068 100644
--- a/ui/imports/ui/components/scans-list/scans-list.html
+++ b/ui/imports/ui/components/scans-list/scans-list.html
@@ -27,7 +27,6 @@
           <th>Scan Only Iventory</th>
           <th>Scan Only Links</th>
           <th>Scan Only Cliques</th>
-          <th>Scan Completed</th>
           <th>
             <a class="sm-table-header" 
                  data-is-sortable="true" 
@@ -63,7 +62,6 @@
           <td>{{ scan.scan_only_inventory }}</td>
           <td>{{ scan.scan_only_links }}</td>
           <td>{{ scan.scan_only_cliques }}</td>
-          <td>{{ scan.scan_completed }}</td>
           <td>{{ scan.submit_timestamp }}</td>
           <td>{{ scan.start_timestamp }}</td>
           <td>{{ scan.end_timestamp }}</td>
diff --git a/ui/imports/ui/components/top-navbar-menu/top-navbar-menu.js b/ui/imports/ui/components/top-navbar-menu/top-navbar-menu.js
index 6968060..1b86cad 100644
--- a/ui/imports/ui/components/top-navbar-menu/top-navbar-menu.js
+++ b/ui/imports/ui/components/top-navbar-menu/top-navbar-menu.js
@@ -121,7 +121,7 @@ Template.TopNavbarMenu.helpers({
     return {
       selectedEnvironment: selectedEnvironment,
       onEnvSelected: function (env) {
-        Router.go('environment', { _id: idToStr(env._id) }, { });
+        Router.go('environment', { _id: idToStr(env._id) }, { query: `r=${Date.now()}` });
       }
     };
   }
diff --git a/ui/lib/router.js b/ui/lib/router.js
index 37e8195..0a6e7f1 100644
--- a/ui/lib/router.js
+++ b/ui/lib/router.js
@@ -87,7 +87,7 @@ Router.route('/', {
     if (this.ready())
       this.layout('landing');
     else
-        this.render('loading');
+      this.render('loading');
   }
 });
 
@@ -115,8 +115,8 @@ Router.route('home', {
                   }
       */
 
-  // if the sub handle returned from waitOn ready() method returns
-  // true then we're ready to go ahead and render the page.
+      // if the sub handle returned from waitOn ready() method returns
+      // true then we're ready to go ahead and render the page.
       this.render('home');
 
     }
@@ -186,6 +186,10 @@ Router.route('/messages-list', function () {
   this.render('MessagesList');
 }, { });
 
+Router.route('/configuration', function () {
+  this.render('Configuration');
+}, { });
+
 Router.route('/message', function () {
   let that = this;
   let params = that.params;
@@ -317,6 +321,11 @@ Router.route('environment', {
       data = R.assoc('selectedNodeId', selectedNodeId, data);
     }
 
+    let refresh = that.params.query.r;
+    if (! R.isNil(refresh)) {
+      data = R.assoc('refresh', refresh, data);
+    }
+
     return data;
   }
 });
diff --git a/ui/public/backup - ic_cloud_queue_black_48dp_2x.png b/ui/public/backup - ic_cloud_queue_black_48dp_2x.png
new file mode 100644
index 0000000..ce8ffa5
Binary files /dev/null and b/ui/public/backup - ic_cloud_queue_black_48dp_2x.png differ
diff --git a/ui/public/ic_cloud_queue_black_48dp_2x-green.png b/ui/public/ic_cloud_queue_black_48dp_2x-green.png
new file mode 100644
index 0000000..d5e5f77
Binary files /dev/null and b/ui/public/ic_cloud_queue_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_cloud_queue_black_48dp_2x-orange.png b/ui/public/ic_cloud_queue_black_48dp_2x-orange.png
new file mode 100644
index 0000000..9c43478
Binary files /dev/null and b/ui/public/ic_cloud_queue_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_cloud_queue_black_48dp_2x-red.png b/ui/public/ic_cloud_queue_black_48dp_2x-red.png
new file mode 100644
index 0000000..f39b8b0
Binary files /dev/null and b/ui/public/ic_cloud_queue_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_computer_black_48dp_2x-green.png b/ui/public/ic_computer_black_48dp_2x-green.png
new file mode 100644
index 0000000..5787e46
Binary files /dev/null and b/ui/public/ic_computer_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_computer_black_48dp_2x-orange.png b/ui/public/ic_computer_black_48dp_2x-orange.png
new file mode 100644
index 0000000..37fa788
Binary files /dev/null and b/ui/public/ic_computer_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_computer_black_48dp_2x-red.png b/ui/public/ic_computer_black_48dp_2x-red.png
new file mode 100644
index 0000000..f32361e
Binary files /dev/null and b/ui/public/ic_computer_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_computer_black_48dp_2x.png b/ui/public/ic_computer_black_48dp_2x.png
index 04755ea..02741f7 100644
Binary files a/ui/public/ic_computer_black_48dp_2x.png and b/ui/public/ic_computer_black_48dp_2x.png differ
diff --git a/ui/public/ic_dns_black_48dp_2x-green.png b/ui/public/ic_dns_black_48dp_2x-green.png
new file mode 100644
index 0000000..442d543
Binary files /dev/null and b/ui/public/ic_dns_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_dns_black_48dp_2x-orange.png b/ui/public/ic_dns_black_48dp_2x-orange.png
new file mode 100644
index 0000000..351e3af
Binary files /dev/null and b/ui/public/ic_dns_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_dns_black_48dp_2x-red.png b/ui/public/ic_dns_black_48dp_2x-red.png
new file mode 100644
index 0000000..a43fddd
Binary files /dev/null and b/ui/public/ic_dns_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_gamepad_black_48dp_2x-green.png b/ui/public/ic_gamepad_black_48dp_2x-green.png
new file mode 100644
index 0000000..3646650
Binary files /dev/null and b/ui/public/ic_gamepad_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_gamepad_black_48dp_2x-orange.png b/ui/public/ic_gamepad_black_48dp_2x-orange.png
new file mode 100644
index 0000000..bde33ea
Binary files /dev/null and b/ui/public/ic_gamepad_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_gamepad_black_48dp_2x-red.png b/ui/public/ic_gamepad_black_48dp_2x-red.png
new file mode 100644
index 0000000..3b44378
Binary files /dev/null and b/ui/public/ic_gamepad_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_keyboard_return_black_48dp_2x-green.png b/ui/public/ic_keyboard_return_black_48dp_2x-green.png
new file mode 100644
index 0000000..932e31a
Binary files /dev/null and b/ui/public/ic_keyboard_return_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_keyboard_return_black_48dp_2x-orange.png b/ui/public/ic_keyboard_return_black_48dp_2x-orange.png
new file mode 100644
index 0000000..7fc6134
Binary files /dev/null and b/ui/public/ic_keyboard_return_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_keyboard_return_black_48dp_2x-red.png b/ui/public/ic_keyboard_return_black_48dp_2x-red.png
new file mode 100644
index 0000000..06b650a
Binary files /dev/null and b/ui/public/ic_keyboard_return_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_lens_black_48dp_2x-green.png b/ui/public/ic_lens_black_48dp_2x-green.png
new file mode 100644
index 0000000..249ccd6
Binary files /dev/null and b/ui/public/ic_lens_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_lens_black_48dp_2x-orange.png b/ui/public/ic_lens_black_48dp_2x-orange.png
new file mode 100644
index 0000000..238b3fc
Binary files /dev/null and b/ui/public/ic_lens_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_lens_black_48dp_2x-red.png b/ui/public/ic_lens_black_48dp_2x-red.png
new file mode 100644
index 0000000..2ff3df7
Binary files /dev/null and b/ui/public/ic_lens_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_settings_input_composite_black_48dp_2x-green.png b/ui/public/ic_settings_input_composite_black_48dp_2x-green.png
new file mode 100644
index 0000000..9c11848
Binary files /dev/null and b/ui/public/ic_settings_input_composite_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_settings_input_composite_black_48dp_2x-orange.png b/ui/public/ic_settings_input_composite_black_48dp_2x-orange.png
new file mode 100644
index 0000000..b5b1e54
Binary files /dev/null and b/ui/public/ic_settings_input_composite_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_settings_input_composite_black_48dp_2x-red.png b/ui/public/ic_settings_input_composite_black_48dp_2x-red.png
new file mode 100644
index 0000000..4a2e25f
Binary files /dev/null and b/ui/public/ic_settings_input_composite_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_settings_input_hdmi_black_48dp_2x-green.png b/ui/public/ic_settings_input_hdmi_black_48dp_2x-green.png
new file mode 100644
index 0000000..5261c19
Binary files /dev/null and b/ui/public/ic_settings_input_hdmi_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_settings_input_hdmi_black_48dp_2x-orange.png b/ui/public/ic_settings_input_hdmi_black_48dp_2x-orange.png
new file mode 100644
index 0000000..89630b4
Binary files /dev/null and b/ui/public/ic_settings_input_hdmi_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_settings_input_hdmi_black_48dp_2x-red.png b/ui/public/ic_settings_input_hdmi_black_48dp_2x-red.png
new file mode 100644
index 0000000..e7cf657
Binary files /dev/null and b/ui/public/ic_settings_input_hdmi_black_48dp_2x-red.png differ
diff --git a/ui/public/ic_storage_black_48dp_2x-green.png b/ui/public/ic_storage_black_48dp_2x-green.png
new file mode 100644
index 0000000..c3b5170
Binary files /dev/null and b/ui/public/ic_storage_black_48dp_2x-green.png differ
diff --git a/ui/public/ic_storage_black_48dp_2x-orange.png b/ui/public/ic_storage_black_48dp_2x-orange.png
new file mode 100644
index 0000000..fe3c9dc
Binary files /dev/null and b/ui/public/ic_storage_black_48dp_2x-orange.png differ
diff --git a/ui/public/ic_storage_black_48dp_2x-red.png b/ui/public/ic_storage_black_48dp_2x-red.png
new file mode 100644
index 0000000..cb1074a
Binary files /dev/null and b/ui/public/ic_storage_black_48dp_2x-red.png differ
diff --git a/ui/run b/ui/run
index ec4aa7c..a4e2a39 100755
--- a/ui/run
+++ b/ui/run
@@ -1,2 +1,3 @@
 # run meteor with different mongo 
 MONGO_URL=mongodb://localhost:27017/osdna meteor run
+# MONGO_URL=mongodb://calipso:calipso_default@64.103.124.119:27017/calipso meteor run
-- 
cgit