diff --git a/vitragedashboard/static/dashboard/project/entities/entities.html b/vitragedashboard/static/dashboard/project/entities/entities.html
index 5d5112a..c5a175e 100644
--- a/vitragedashboard/static/dashboard/project/entities/entities.html
+++ b/vitragedashboard/static/dashboard/project/entities/entities.html
@@ -7,6 +7,7 @@
+
diff --git a/vitragedashboard/static/dashboard/project/entities/entities.scss b/vitragedashboard/static/dashboard/project/entities/entities.scss
index c68c8ec..1d80805 100644
--- a/vitragedashboard/static/dashboard/project/entities/entities.scss
+++ b/vitragedashboard/static/dashboard/project/entities/entities.scss
@@ -1,5 +1,5 @@
.entities {
.panel-body {
- padding: 3px;
+ padding: 6px;
}
}
diff --git a/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.directive.js b/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.directive.js
index d693336..983b780 100644
--- a/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.directive.js
+++ b/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.directive.js
@@ -24,14 +24,34 @@ function hzEntitiesGraph() {
linkWidth = 1,
circleRadius = 14,
circlePadding = 1,
- pinned = horizon.cookies.get('pinned') || [],
zoom = d3.behavior.zoom().scaleExtent([minZoom, maxZoom]),
ellipsisWidth = 80,
+ hightlightDepth = 2,
+ heightOffset,
+ pinned,
graphCreated,
node,
link,
+ linksMap,
content;
+ (function() {
+ var p = $('.panel.panel-primary');
+ heightOffset = (p.length ? p.offset().top : 180) + 75;
+
+ pinned = horizon.cookies.get('pinned') || [];
+ if (_.isString(pinned)) {
+ try {
+ pinned = JSON.parse(pinned);
+ }
+ catch(ex) {
+ pinned = [];
+ console.error('Failed to parse the pinned cookie');
+ }
+ }
+ })();
+
+
scope.$watch('data.ts', function(newVal, oldVal) {
if (newVal) {
prepareData();
@@ -44,6 +64,22 @@ function hzEntitiesGraph() {
}
});
+ scope.$on('toolbox-pin', function () {
+ pinAll();
+ });
+
+ scope.$on('toolbox-unpin', function () {
+ unpinAll();
+ })
+
+ scope.$on('toolbox-zoom-to-fit', function () {
+ console.log('on toolbox-pin', arguments)
+ });
+
+ scope.$on('toolbox-toggle-fullscreen', function () {
+ console.log('on toolbox-unpin', arguments)
+ })
+
scope.isEmpty = function() {
return scope.data && scope.data.nodes && scope.data.nodes.length === 0;
};
@@ -90,7 +126,7 @@ function hzEntitiesGraph() {
d3.select(window).on('resize', resize);
function resize() {
- svg.attr('height', window.innerHeight - 168 + 'px')
+ svg.attr('height', window.innerHeight - heightOffset + 'px')
force.size([angular.element(svg[0]).width(),
angular.element(svg[0]).height()])
.resume();
@@ -108,6 +144,11 @@ function hzEntitiesGraph() {
node.y = pin.y;
}
})
+
+ linksMap = {};
+ _.each(scope.data.links, function(link) {
+ linksMap[link.source.id + ',' + link.target.id] = true;
+ });
}
function createGraph() {
@@ -228,6 +269,7 @@ function hzEntitiesGraph() {
}
window.drawGraph = drawGraph;
+ window.dforce = force;
function drawGraph() {
link = link.data(force.links(), function(d) { return d.source.id + '-' + d.target.id; });
@@ -275,28 +317,47 @@ function hzEntitiesGraph() {
.attr('dominant-baseline', 'central')
.attr('transform', 'scale(1)')
.attr('class', function(d) {
- var cls = '';
- var severity = d.operational_severity;
- if (severity) {
- switch (severity.toLowerCase()) {
- case 'critical':
- cls = 'red';
- break;
- case 'severe':
- cls = 'orange';
- break;
- case 'warning':
- cls = 'yellow';
- break;
- case 'ok':
- cls = 'green';
- break;
- case 'n/a':
- cls = 'gray';
- break;
- default: //'DISABLED', 'UNKNOWN', 'UNDEFINED'
- cls = 'gray';
- break;
+ var category = d.category,
+ cls = '';
+
+ if (category && category.toLowerCase() === 'alarm') {
+ var severity = d.operational_severity;
+ if (severity) {
+ switch (severity.toLowerCase()) {
+ case 'critical':
+ cls = 'red';
+ break;
+ case 'severe':
+ cls = 'orange';
+ break;
+ case 'warning':
+ cls = 'yellow';
+ break;
+ case 'ok':
+ cls = 'green';
+ break;
+ case 'n/a':
+ cls = 'gray';
+ break;
+ default: //'DISABLED', 'UNKNOWN', 'UNDEFINED'
+ cls = 'gray';
+ break;
+ }
+ }
+ } else {
+ var state = d.operational_state;
+ if (state) {
+ switch (state.toLowerCase()) {
+ case 'error':
+ cls = 'red';
+ break;
+ case 'suboptimal':
+ cls = 'yellow';
+ break;
+ case 'n/a':
+ cls = 'gray';
+ break;
+ }
}
}
return cls;
@@ -440,15 +501,48 @@ function hzEntitiesGraph() {
if ($(this).is('.node')) {
- d3.select(this).classed('selected', true);
+ //d3.select(this).classed('selected', true);
+
+ findHighlight(d);
}
}
+ function findHighlight(rootNode) {
+
+ _.each(scope.data.nodes, function(node) {
+ node.high = false;
+ })
+
+ var depth = hightlightDepth;
+
+ findNodes(rootNode, depth, scope.data.nodes, linksMap);
+
+ _.each(scope.data.links, function(link) {
+ link.high = false;
+ })
+
+ svg_g.selectAll('.node')
+ .classed('selected', function(d) {
+ return d.high;
+ })
+ .select('circle')
+ .style('stroke-width', function(d) {
+ return d.high ? (Math.max(d.highDepth + 1, 1) * 2) : null;
+ })
+
+ svg_g.selectAll('.link').classed('selected', function(d) {
+ return d.source.high && d.target.high;
+ })
+ }
+
function selectNone(d) {
nodeClick(null);
}
function pinNode(d) {
+ d3.event.stopImmediatePropagation();
+ d3.event.preventDefault();
+
var node;
if ($(this).is('.node')) {
@@ -463,9 +557,6 @@ function hzEntitiesGraph() {
updatePinnedCookie(d);
}
- d3.event.stopImmediatePropagation();
- d3.event.preventDefault();
-
//fixing some bug with unpinning
/*setTimeout(function() {
force.resume()
@@ -476,7 +567,7 @@ function hzEntitiesGraph() {
var pinIndex = -1;
pinned.forEach(function(pin, i) {
if (pin.id === d.id) {
- pinIndex = i
+ pinIndex = i;
}
})
@@ -488,7 +579,7 @@ function hzEntitiesGraph() {
pinned.push({id: d.id, x: d.x, y: d.y});
}
- horizon.cookies.put('pinned', pinned);
+ horizon.cookies.put('pinned', JSON.stringify(pinned));
}
function nodeDragend(d) {
@@ -497,6 +588,39 @@ function hzEntitiesGraph() {
}
}
+ function pinAll() {
+ pinned = [];
+
+ svg_g.selectAll('.node')
+ .classed('pinned', true)
+ .each(function(d) {
+ d.fixed = true;
+ pinned.push({id: d.id, x: d.x, y: d.y});
+ })
+
+ horizon.cookies.put('pinned', JSON.stringify(pinned));
+ }
+
+ function unpinAll() {
+ pinned = [];
+
+ svg_g.selectAll('.node')
+ .classed('pinned', false)
+ .each(function(d) {
+ d.fixed = false;
+ })
+
+ horizon.cookies.put('pinned', JSON.stringify([]));
+
+ setTimeout(function() {
+ force.resume()
+ }, 100)
+ }
+
+ function pinAllNodes(isPin) {
+
+ }
+
function setEllipsis(el, text, width) {
el.textContent = text;
@@ -516,6 +640,30 @@ function hzEntitiesGraph() {
}
};
+ function findNodes(rootNode, depth, allNodes, linksMap) {
+ if (rootNode) {
+ rootNode.high = true;
+ rootNode.highDepth = depth;
+ depth--;
+
+ _.each(allNodes, function(node) {
+ if (linksMap[node.id + ',' + rootNode.id] || linksMap[rootNode.id + ',' + node.id]) {
+
+ if (depth > -1 && !node.high) {
+ findNodes(node, depth, allNodes, linksMap);
+ } else if (depth <= -1) {
+ //Always find 'depth' + alarms & (sdns + alarms)
+ if (node.category.toLowerCase() === 'alarm') {
+ node.high = true;
+ node.highDepth = 0;
+ } else if (!node.high && node.type && node.type.toLowerCase() === 'sdn_controller') {
+ findNodes(node, depth, allNodes, linksMap);
+ }
+ }
+ }
+ });
+ }
+ }
/*function nodeDragstart(d) {
d3.select(this).classed('pinned', d.fixed = true);
diff --git a/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.scss b/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.scss
index 176b3f6..0a0182f 100644
--- a/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.scss
+++ b/vitragedashboard/static/dashboard/project/entities/graph/entities-graph.scss
@@ -27,6 +27,11 @@ $dark_gray: darkgray;
.link {
stroke-opacity: 0.8;
+
+ &.selected {
+ stroke: $blue;
+ stroke-width: 2 !important;
+ }
}
.node {
diff --git a/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.directive.js b/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.directive.js
new file mode 100644
index 0000000..eab78b2
--- /dev/null
+++ b/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.directive.js
@@ -0,0 +1,24 @@
+angular
+ .module('horizon.dashboard.project.vitrage')
+ .directive('hzEntitiesToolbox', hzEntitiesToolbox);
+
+hzEntitiesToolbox.$inject = ['$rootScope'];
+
+function hzEntitiesToolbox($rootScope) {
+ var directive = {
+ link: link,
+ templateUrl: STATIC_URL + 'dashboard/project/entities/toolbox/entities-toolbox.html',
+ restrict: 'E',
+ scope: {
+ item: '='
+ }
+ };
+ return directive;
+
+ function link(scope, element, attrs) {
+ scope.broadcast = function(event) {
+ console.log('click', event);
+ $rootScope.$broadcast('toolbox-' + event);
+ }
+ }
+}
diff --git a/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.html b/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.html
new file mode 100644
index 0000000..c82fe50
--- /dev/null
+++ b/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.html
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.scss b/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.scss
new file mode 100644
index 0000000..1f20790
--- /dev/null
+++ b/vitragedashboard/static/dashboard/project/entities/toolbox/entities-toolbox.scss
@@ -0,0 +1,17 @@
+.entities-toolbox {
+ position: absolute;
+ right: 18px;
+ margin: 12px;
+ padding:8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ background: rgba(255, 255, 255, 0.8);
+
+ .btn-group {
+ margin-right: 6px;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/vitragedashboard/static/dashboard/project/vitrage.scss b/vitragedashboard/static/dashboard/project/vitrage.scss
index 7e2ea50..b2b1a27 100644
--- a/vitragedashboard/static/dashboard/project/vitrage.scss
+++ b/vitragedashboard/static/dashboard/project/vitrage.scss
@@ -10,6 +10,7 @@
@import 'components/information/information';
@import 'entities/graph/entities-graph.scss';
@import 'entities/info/entities-info.scss';
+@import 'entities/toolbox/entities-toolbox.scss';
@import 'entities/entities.scss';
.red {