diff --git a/app/components/containersNetwork/containersNetwork.html b/app/components/containersNetwork/containersNetwork.html index 67fe230bf..e9bce03de 100644 --- a/app/components/containersNetwork/containersNetwork.html +++ b/app/components/containersNetwork/containersNetwork.html @@ -1,7 +1,23 @@

Containers Network

-
- +
+
+ + +
+
+
+
+ + + + +
+
+
+
diff --git a/app/components/containersNetwork/containersNetworkController.js b/app/components/containersNetwork/containersNetworkController.js index b015488f9..3219a0951 100644 --- a/app/components/containersNetwork/containersNetworkController.js +++ b/app/components/containersNetwork/containersNetworkController.js @@ -1,29 +1,14 @@ angular.module('containersNetwork', ['ngVis']) .controller('ContainersNetworkController', ['$scope', '$location', 'Container', 'Messages', 'VisDataSet', function($scope, $location, Container, Messages, VisDataSet) { - $scope.options = { - navigation: true, - keyboard: true, - height: '500px', width: '700px', - nodes: { - shape: 'box' - }, - edges: { - style: 'arrow' - }, - physics: { - barnesHut : { - springLength: 200 - } - } - }; function ContainerNode(data) { this.Id = data.Id; // names have the following format: /Name this.Name = data.Name.substring(1); + this.Image = data.Config.Image; var dataLinks = data.HostConfig.Links; if (dataLinks != null) { - this.Links = []; + this.Links = {}; for (var i = 0; i < dataLinks.length; i++) { // links have the following format: /TargetContainerName:/SourceContainerName/LinkAlias var link = dataLinks[i].split(":"); @@ -38,64 +23,227 @@ angular.module('containersNetwork', ['ngVis']) var dataVolumes = data.HostConfig.VolumesFrom; //converting array into properties for simpler and faster access if (dataVolumes != null) { - this.VolumesFrom = []; + this.VolumesFrom = {}; for (var j = 0; j < dataVolumes.length; j++) { this.VolumesFrom[dataVolumes[j]] = true; } } } - function ContainersNetwork() { - this.containers = []; + function ContainersNetworkData() { this.nodes = new VisDataSet(); this.edges = new VisDataSet(); - this.add = function(data) { - var container = new ContainerNode(data); - this.containers.push(container); - this.nodes.add({id: container.Id, label: container.Name}); - for (var i = 0; i < this.containers.length; i++) { - var otherContainer = this.containers[i]; - this.addLinkEdgeIfExists(container, otherContainer); - this.addLinkEdgeIfExists(otherContainer, container); - this.addVolumeEdgeIfExists(container, otherContainer); - this.addVolumeEdgeIfExists(otherContainer, container); - } + this.addContainerNode = function(container) { + this.nodes.add({ + id: container.Id, + label: container.Name, + title: ""}); }; this.addLinkEdgeIfExists = function(from, to) { if (from.Links != null && from.Links[to.Name] != null) { - this.edges.add({ from: from.Id, to: to.Id, label: from.Links[to.Name] }); + this.edges.add({ + from: from.Id, + to: to.Id, + label: from.Links[to.Name] }); } }; this.addVolumeEdgeIfExists = function(from, to) { if (from.VolumesFrom != null && from.VolumesFrom[to.Id] != null) { - this.edges.add({ from: from.Id, to: to.Id, color: { color: '#A0A0A0', highlight: '#A0A0A0', hover: '#848484'}}); + this.edges.add({ + from: from.Id, + to: to.Id, + color: { color: '#A0A0A0', highlight: '#A0A0A0', hover: '#848484'}}); } }; + + this.removeContainersNodes = function(containersIds) { + this.nodes.remove(containersIds); + }; } - $scope.data = new ContainersNetwork(); - $scope.events = { - doubleClick : function(event) { - $scope.$apply( function() { - $location.path('/containers/' + event.nodes[0]); - }); - } - }; + function ContainersNetwork() { + this.data = new ContainersNetworkData(); + this.containers = {}; + this.selectedContainersIds = []; + this.shownContainersIds = []; + this.events = { + select : function(event) { + $scope.network.selectedContainersIds = event.nodes; + $scope.$apply( function() { + $scope.query = ''; + }); + }, + doubleClick : function(event) { + $scope.$apply( function() { + $location.path('/containers/' + event.nodes[0]); + }); + } + }; + this.options = { + navigation: true, + keyboard: true, + height: '500px', width: '700px', + nodes: { + shape: 'box' + }, + edges: { + style: 'arrow' + }, + physics: { + barnesHut : { + springLength: 200 + } + } + }; + + this.addContainer = function(data) { + var container = new ContainerNode(data); + this.containers[container.Id] = container; + this.shownContainersIds.push(container.Id); + this.data.addContainerNode(container); + for (var otherContainerId in this.containers) { + var otherContainer = this.containers[otherContainerId]; + this.data.addLinkEdgeIfExists(container, otherContainer); + this.data.addLinkEdgeIfExists(otherContainer, container); + this.data.addVolumeEdgeIfExists(container, otherContainer); + this.data.addVolumeEdgeIfExists(otherContainer, container); + } + }; + + this.selectContainers = function(query) { + if (this.component != null) { + this.selectedContainersIds = this.searchContainers(query); + this.component.selectNodes(this.selectedContainersIds); + } + }; + + this.searchContainers = function(query) { + if (query.trim() === "") { + return []; + } + var selectedContainersIds = []; + for (var i=0; i < this.shownContainersIds.length; i++) { + var container = this.containers[this.shownContainersIds[i]]; + if (container.Name.indexOf(query) > -1 || + container.Image.indexOf(query) > -1 || + container.Id.indexOf(query) > -1) { + selectedContainersIds.push(container.Id); + } + } + return selectedContainersIds; + }; + + this.hideSelected = function() { + var i=0; + while ( i < this.shownContainersIds.length ) { + if (this.selectedContainersIds.indexOf(this.shownContainersIds[i]) > -1) { + this.shownContainersIds.splice(i, 1); + } else { + i++; + } + } + this.data.removeContainersNodes(this.selectedContainersIds); + $scope.query = ''; + this.selectedContainersIds = []; + }; + + this.searchDownstream = function(containerId, downstreamContainersIds) { + if (downstreamContainersIds.indexOf(containerId) > -1) { + return; + } + downstreamContainersIds.push(containerId); + var container = this.containers[containerId]; + if (container.Links == null && container.VolumesFrom == null) { + return; + } + for (var otherContainerId in this.containers) { + var otherContainer = this.containers[otherContainerId]; + if (container.Links != null && container.Links[otherContainer.Name] != null) { + this.searchDownstream(otherContainer.Id, downstreamContainersIds); + } else if (container.VolumesFrom != null && + container.VolumesFrom[otherContainer.Id] != null) { + this.searchDownstream(otherContainer.Id, downstreamContainersIds); + } + } + }; + + this.updateShownContainers = function(newShownContainersIds) { + for (var containerId in this.containers) { + if (newShownContainersIds.indexOf(containerId) > -1 && + this.shownContainersIds.indexOf(containerId) === -1) { + this.data.addContainerNode(this.containers[containerId]); + } else if (newShownContainersIds.indexOf(containerId) === -1 && + this.shownContainersIds.indexOf(containerId) > -1) { + this.data.removeContainersNodes(containerId); + } + } + this.shownContainersIds = newShownContainersIds; + }; + + this.showSelectedDownstream = function() { + var downstreamContainersIds = []; + for (var i=0; i < this.selectedContainersIds.length; i++) { + this.searchDownstream(this.selectedContainersIds[i], downstreamContainersIds); + } + this.updateShownContainers(downstreamContainersIds); + }; + + this.searchUpstream = function(containerId, upstreamContainersIds) { + if (upstreamContainersIds.indexOf(containerId) > -1) { + return; + } + upstreamContainersIds.push(containerId); + var container = this.containers[containerId]; + for (var otherContainerId in this.containers) { + var otherContainer = this.containers[otherContainerId]; + if (otherContainer.Links != null && otherContainer.Links[container.Name] != null) { + this.searchUpstream(otherContainer.Id, upstreamContainersIds); + } else if (otherContainer.VolumesFrom != null && + otherContainer.VolumesFrom[container.Id] != null) { + this.searchUpstream(otherContainer.Id, upstreamContainersIds); + } + } + }; + + this.showSelectedUpstream = function() { + var upstreamContainersIds = []; + for (var i=0; i < this.selectedContainersIds.length; i++) { + this.searchUpstream(this.selectedContainersIds[i], upstreamContainersIds); + } + this.updateShownContainers(upstreamContainersIds); + }; + + this.showAll = function() { + for (var containerId in this.containers) { + if (this.shownContainersIds.indexOf(containerId) === -1) { + this.data.addContainerNode(this.containers[containerId]); + this.shownContainersIds.push(containerId); + } + } + }; + + } + + $scope.network = new ContainersNetwork(); var showFailure = function (event) { - Messages.error('Failure', e.data); + Messages.error('Failure', e.data); }; var addContainer = function (container) { - $scope.data.add(container); + $scope.network.addContainer(container); }; Container.query({all: 0}, function(d) { for (var i = 0; i < d.length; i++) { Container.get({id: d[i].Id}, addContainer, showFailure); } - }); + }); + }]); diff --git a/assets/font/glyphicons-halflings-regular.eot b/assets/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from assets/font/glyphicons-halflings-regular.eot rename to assets/fonts/glyphicons-halflings-regular.eot diff --git a/assets/font/glyphicons-halflings-regular.svg b/assets/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from assets/font/glyphicons-halflings-regular.svg rename to assets/fonts/glyphicons-halflings-regular.svg diff --git a/assets/font/glyphicons-halflings-regular.ttf b/assets/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from assets/font/glyphicons-halflings-regular.ttf rename to assets/fonts/glyphicons-halflings-regular.ttf diff --git a/assets/font/glyphicons-halflings-regular.woff b/assets/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from assets/font/glyphicons-halflings-regular.woff rename to assets/fonts/glyphicons-halflings-regular.woff diff --git a/assets/js/angular-vis.js b/assets/js/angular-vis.js index 71b967867..4d594a00b 100755 --- a/assets/js/angular-vis.js +++ b/assets/js/angular-vis.js @@ -19,7 +19,8 @@ angular.module('ngVis', []) scope: { data: '=', options: '=', - events: '=' + events: '=', + component: '=' }, link: function (scope, element, attr) { var timelineEvents = [ @@ -46,6 +47,7 @@ angular.module('ngVis', []) // Create the timeline object timeline = new vis.Timeline(element[0]); + scope.component = timeline; // Attach an event handler if defined angular.forEach(scope.events, function (callback, event) { @@ -92,7 +94,8 @@ angular.module('ngVis', []) scope: { data: '=', options: '=', - events: '=' + events: '=', + component: '=' }, link: function (scope, element, attr) { var networkEvents = [ @@ -103,6 +106,7 @@ angular.module('ngVis', []) ]; var network = new vis.Network(element[0], scope.data, scope.options); + scope.component = network; scope.$watch('data', function () { // Sanity check @@ -118,6 +122,7 @@ angular.module('ngVis', []) // Create the graph2d object network = new vis.Network(element[0]); + scope.component = network; // Attach an event handler if defined angular.forEach(scope.events, function (callback, event) { @@ -166,7 +171,8 @@ angular.module('ngVis', []) scope: { data: '=', options: '=', - events: '=' + events: '=', + component: '=' }, link: function (scope, element, attr) { var graphEvents = [ @@ -178,6 +184,7 @@ angular.module('ngVis', []) // Create the chart var graph = new vis.Graph2d(element[0]); + scope.component = graph; scope.$watch('data', function () { // Sanity check @@ -193,6 +200,7 @@ angular.module('ngVis', []) // Create the graph2d object graph = new vis.Graph2d(element[0]); + scope.component = graph; // Attach an event handler if defined angular.forEach(scope.events, function (callback, event) {