You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2017/10/23 21:47:05 UTC
[03/45] qpid-dispatch git commit: DISPATCH-834 Initial commit of
config file editor
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/93b9fa51/console/config/js/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/config/js/qdrTopology.js b/console/config/js/qdrTopology.js
new file mode 100644
index 0000000..152bf4d
--- /dev/null
+++ b/console/config/js/qdrTopology.js
@@ -0,0 +1,1649 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+/**
+ * @module QDR
+ */
+var QDR = (function(QDR) {
+
+ /**
+ * @method TopologyController
+ *
+ * Controller that handles the QDR topology page
+ */
+ QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'QDRService', '$location', '$timeout', '$uibModal',
+ function($scope, $rootScope, QDRService, $location, $timeout, $uibModal) {
+
+ var settings = {baseName: "A", http_port: 5673, normal_port: 22000, internal_port: 2000, default_host: "0.0.0.0", artemis_port: 61616, qpid_port: 5672}
+ var sections = ['log', 'connector', 'sslProfile', 'listener']
+
+ $scope.Publish = function () {
+ doPublish()
+ }
+ var doPublish = function (nodeIndex, callback) {
+ var l = []
+ links.forEach( function (link) {
+ if (link.source.nodeType === 'inter-router' && link.target.nodeType === 'inter-router')
+ l.push({source: link.source.index,
+ target: link.target.index,
+ cls: link.cls})
+ })
+ var props = {nodes: nodes, links: l, topology: $scope.mockTopologyDir, settings: settings}
+ if (angular.isDefined(nodeIndex)) {
+ op = "SHOW-CONFIG"
+ props.nodeIndex = nodeIndex
+ } else {
+ op = "PUBLISH"
+ }
+ QDRService.sendMethod(op, props, function (response) {
+ if (!angular.isDefined(nodeIndex)) {
+ Core.notification('info', props.topology + " published");
+ QDR.log.info("published " + $scope.mockTopologyDir)
+ } else {
+ callback(response)
+ }
+ })
+ }
+ $scope.showConfig = function (node) {
+ doPublish(node.index, function (response) {
+ doShowConfigDialog(response)
+ })
+ }
+
+ $scope.$watch('mockTopologyDir', function(newVal, oldVal) {
+ if (oldVal != newVal) {
+ switchTopology(newVal)
+ }
+ })
+ var switchTopology = function (topology) {
+ var props = {topology: topology}
+ QDRService.sendMethod("SWITCH", props, function (response) {
+ if ($scope.mockTopologies.indexOf(topology) == -1) {
+ $timeout(function () {$scope.mockTopologies.push(topology)})
+ }
+ nodes = []
+ links = []
+ var savedPositions = localStorage[topology] ? angular.fromJson(localStorage[topology]) : undefined
+ for (var i=0; i<response.nodes.length; ++i) {
+ var node = response.nodes[i]
+ var x = 100+i*90
+ var y = 200+(i % 2 ? -100 : 100)
+ if (savedPositions && node.name in savedPositions) {
+ x = savedPositions[node.name].x
+ y = savedPositions[node.name].y
+ }
+ var anode = aNode(node.key, node.name, node.nodeType, undefined, nodes.length, x, y, undefined, false)
+ if (node['host'])
+ anode['host'] = node['host']
+ sections.forEach( function (section) {
+ if (node[section+'s']) {
+ anode[section+'s'] = node[section+'s']
+ }
+ })
+ nodes.push(anode)
+ }
+ for (var i=0; i<response.links.length; ++i) {
+ var link = response.links[i]
+ getLink(link.source, link.target, link.dir, "", link.source + '.' + link.target);
+ }
+
+ for (var i=0; i<nodes.length; ++i) {
+ var node = nodes[i]
+ sections.forEach( function (section) {
+ if (node[section+'s'] && section !== 'log') {
+ for (var key in node[section+'s']) {
+ var type = section
+ if (section === 'listener' && key == settings.http_port)
+ type = 'console'
+ if (section === 'connector' && key == settings.artemis_port && node['connectors'][settings.artemis_port+'']['role'] === 'route-container')
+ type = 'artemis'
+ if (section === 'connector' && key == settings.qpid_port && node['connectors'][settings.qpid_port+'']['role'] === 'route-container')
+ type = 'qpid'
+ var sub = genNodeToAdd(node, type, key)
+ nodes.push(sub)
+ var source = node.id
+ var target = nodes.length-1
+ getLink(source, target, sub.cdir, "small", source + '.' + target);
+ }
+ }
+ })
+ }
+
+ animate = true
+ QDR.log.info("switched to " + topology)
+ initForceGraph()
+ Core.notification('info', "switched to " + props.topology);
+ })
+ }
+
+ $scope.Clear = function () {
+ nodes = []
+ links = []
+ $scope.selected_node = null
+ resetMouseVars()
+ force.nodes(nodes).links(links).start();
+ restart();
+ }
+
+ $scope.delNode = function (node, skipinit) {
+ // loop through all the nodes
+ if (node.nodeType !== 'inter-router') {
+ var n = findParentNode(node)
+ if (n)
+ delete n[node.entity+'s'][node.entityKey]
+ } else {
+ var sub_nodes = []
+ for (var x=0; x<sections.length; x++) {
+ var section = sections[x]
+ if (node[section+'s']) {
+ for (var sectionKey in node[section+'s']) {
+ var n = findChildNode(section, sectionKey, node.name)
+ if (n)
+ sub_nodes.push(n)
+ }
+ }
+ }
+ for (var x=0; x<sub_nodes.length; x++) {
+ $scope.delNode(sub_nodes[x], true)
+ }
+ }
+ // find the index of the node
+ var index = nodes.findIndex( function (n) {return n.name === node.name})
+ nodes.splice(index, 1)
+
+ nodes.forEach( function (n, i) {
+ n.id = i
+ n.index = i
+ })
+
+ var i = links.length
+ while (i--) {
+ if (links[i].source.name === node.name || links[i].target.name === node.name) {
+ links.splice(i, 1)
+ }
+ }
+ links.forEach( function (l, i) {
+ l.uid = l.source.id + "." + l.target.id
+ })
+
+ if (!skipinit) {
+ animate = true
+ initGraph()
+ initForce()
+ restart();
+ }
+ }
+
+ $scope.showActions = function (e) {
+ $(document).click();
+ e.stopPropagation()
+ var position = $('#action_button').position()
+ position.top += $('#action_button').height() + 8
+ position['display'] = "block"
+ $('#action_menu').css(position)
+ }
+
+ var genNodeToAdd = function (contextNode, type, entityKey) {
+ var id = contextNode.key
+ var clients = nodes.filter ( function (node) {
+ return node.nodeType !== 'inter-router' && node.routerId === contextNode.name
+ })
+ var clientLen = 0
+ clients.forEach (function (client) {
+ clientLen += client.normals.length
+ })
+ var dir = "out"
+ if (type === 'listener')
+ dir = "in"
+ else if (type === 'console' || type === 'sslProfile')
+ dir = "both"
+ var name = contextNode.name + "." + (clientLen + 1)
+ nodeType = "normal"
+ var properties = type === 'console' ? {console_identifier: "Dispatch console"} : {}
+ if (type === 'artemis') {
+ properties = {product: 'apache-activemq-artemis'}
+ nodeType = "route-container"
+ }
+ if (type === 'qpid') {
+ properties = {product: 'qpid-cpp'}
+ nodeType = "route-container"
+ }
+ var node = aNode(id, name, nodeType, undefined, nodes.length, contextNode.x, contextNode.y - radius - radiusNormal,
+ contextNode.id, false, properties)
+ var entity = type === 'console' ? 'listener' : type
+ entity = (type === 'artemis' || type === 'qpid') ? 'connector' : entity
+ node.user = "anonymous"
+ node.isEncrypted = false
+ node.connectionId = node.id
+ node.cdir = dir
+ node.entity = entity
+ node.entityKey = entityKey
+ node.normals = [{name: node.name}]
+
+ return node
+ }
+
+ var addToNode = function (contextNode, type, key) {
+ var node = genNodeToAdd(contextNode, type, key)
+ nodes.push(node)
+
+ var uid = "connection/" + node.host + ":" + node.connectionId
+ getLink(contextNode.id, nodes.length-1, node.cdir, "small", uid);
+ force.nodes(nodes).links(links).start();
+ restart();
+ }
+
+ $scope.addingNode = {
+ step: 0,
+ hasLink: false,
+ trigger: ''
+ };
+
+ $scope.cancel = function() {
+ $scope.addingNode.step = 0;
+ }
+
+ $scope.selected_node = null
+ // mouse event vars
+ var selected_link = null,
+ mousedown_link = null,
+ mousedown_node = null,
+ mouseover_node = null,
+ mouseup_node = null,
+ initial_mouse_down_position = null;
+
+ $scope.hasConsoleListener = function (node) {
+ if (!node) {
+ for (var i=0; i<nodes.length; i++) {
+ var n = nodes[i]
+ var found = n.listeners ? Object.keys(n.listeners).some(function (key) {return key == settings.http_port}) : false
+ if (found)
+ return true
+ }
+ return false
+ }
+ return node.listeners ? Object.keys(node.listeners).some(function (key) {return key == settings.http_port}) : false
+ }
+ // return a list of keys in a node's extra entities maps
+ // called from the template to construct the context menu for nodes
+ $scope.getSectionList = function (node, section) {
+ if (node && node[section+'s']) {
+ if (section === 'listener')
+ return node && node.listeners ? Object.keys(node.listeners).filter( function (key) {
+ return !node.listeners[key].http
+ }) : []
+ else
+ return Object.keys(node[section+'s'])
+ }
+ return []
+ }
+
+ $scope.addConsoleListener = function (node) {
+ if (!node.listeners)
+ node.listeners = {}
+ var host = node.host || settings.default_host
+ node.listeners[settings.http_port] = {name: 'Console Listener', http: true, port: settings.http_port, host: host, saslMechanisms: 'ANONYMOUS'}
+ addToNode(node, "console", settings.http_port)
+ }
+ $scope.delConsoleListener = function (node) {
+ // find the actual console listener
+ var n = findChildNode('listener', settings.http_port, node.name)
+ if (n)
+ $scope.delNode(n)
+ }
+
+ var yoffset = 1; // toggles between 1 and -1. used to position new nodes
+ $scope.addAnotherNode = function (calc) {
+ resetMouseVars();
+ // add a new node
+ var x = radiusNormal * 4;
+ var y = x;;
+ var offset = $('#topology').offset();
+ if (calc) {
+ var w = $('#topology').width()
+ var h = $('#topology').height()
+ var x = (w + offset.left) / 4
+ var y = (h + offset.top) / 4 + yoffset * radiusNormal
+ yoffset *= -1
+ var overlap = true
+ while (overlap) {
+ overlap = false
+ for (var i=0; i<nodes.length; i++) {
+ if ((Math.abs(nodes[i].x - x) < radiusNormal * 2) &&
+ (Math.abs(nodes[i].y - y) < radiusNormal * 2)) {
+ overlap = true
+ x += radiusNormal
+ if (x + radiusNormal/2 >= offset.left + w) {
+ x = offset.left + radiusNormal/2
+ y += radiusNormal
+ if (y + radiusNormal/2 >= offset.top + h) {
+ x = offset.left + radiusNormal
+ y = offset.top + radiusNormal
+ }
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ x = mouseX - offset.left + $(document).scrollLeft();
+ y = mouseY - offset.top + $(document).scrollTop();;
+ }
+ var name = genNewName()
+ var nextId = nodes.length //maxNodeIndex() + 1
+ var id = "amqp:/_topo/0/" + name + "/$management";
+ var node = aNode(id, name, "inter-router", undefined, nextId, x, y, undefined, false)
+ node.host = settings.default_host
+ nodes.push(node);
+ $scope.selected_node = node
+ force.nodes(nodes).links(links).start();
+ restart(false);
+ }
+
+ var maxNodeIndex = function () {
+ var maxIndex = -1
+ nodes.forEach( function (node) {
+ if (node.nodeType === "inter-router") {
+ if (node.id > maxIndex)
+ maxIndex = node.id
+ }
+ })
+ return maxIndex;
+ }
+
+ // generate unique name for router and containerName
+ var genNewName = function() {
+ var re = /./g;
+ for (var i=0, newName = '', found = true; found; ++i) {
+ newName = i.toString(26).replace(re, function (m) {
+ var ccode = m.charCodeAt(0)
+ if (ccode >= 48 && ccode <= 57)
+ return String.fromCharCode(ccode+17)
+ return String.fromCharCode(ccode-22)
+ })
+ found = nodes.some( function (n) {return n.name === newName})
+ }
+ return newName
+ }
+
+ $scope.doSettings = function () {
+ doSettingsDialog(settings);
+ };
+ $scope.showNewDlg = function () {
+ doNewDialog();
+ }
+ $scope.reverseLink = function() {
+ if (!mousedown_link)
+ return;
+ var d = mousedown_link;
+ for (var i=0; i<links.length; i++) {
+ if (links[i].source.index === d.source.index && links[i].target.index === d.target.index ) {
+ var tmp = links[i].source
+ links[i].source = links[i].target
+ links[i].target = tmp
+ }
+ }
+ restart(false);
+ tick();
+ }
+ $scope.removeLink = function() {
+ if (!mousedown_link)
+ return;
+ var d = mousedown_link;
+ links.every(function(l, i) {
+ if (l.source.id == d.source.id && l.target.id == d.target.id) {
+ links.splice(i, 1);
+ force.links(links).start();
+ return false; // exit the 'every' loop
+ }
+ return true;
+ });
+ restart(false);
+ tick();
+ }
+
+ var findChildNode = function (entity, entityKey, name) {
+ // find the node that has entity and entityKey
+ for (var i=0; i<nodes.length; i++) {
+ if (nodes[i].entity === entity && nodes[i].entityKey == entityKey && nodes[i].routerId === name)
+ return nodes[i]
+ }
+ }
+ var findParentNode = function (node) {
+ // find the node that contains the entity[entityKey] of this node
+ for (var i=0; i<nodes.length; i++) {
+ if (nodes[i][node.entity+'s'] && node.entityKey in nodes[i][node.entity+'s'])
+ return nodes[i]
+ }
+ }
+ // menu item of router to set host of all listeners
+ $scope.setRouterHost = function (node) {
+ doSetRouterHostDialog(node)
+ }
+ // menu item of router to edit one of its sub-entities
+ $scope.editSection = function (node, type, section) {
+ doEditDialog(node, type, section)
+ }
+ // menu item of sub-entity to edit itself
+ $scope.editThisSection = function (node) {
+ var n = findParentNode(node)
+ if (n)
+ doEditDialog(n, node.entity, node.entityKey)
+ }
+
+ var mouseX, mouseY;
+ var relativeMouse = function () {
+ var offset = $('#main-container').offset();
+ return {left: (mouseX + $(document).scrollLeft()) - 1,
+ top: (mouseY + $(document).scrollTop()) - 1,
+ offset: offset
+ }
+ }
+ // event handlers for popup context menu
+ $(document).mousemove(function(e) {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ });
+ $(document).mousemove();
+ $(document).click(function(e) {
+ $("#svg_context_menu").fadeOut(200);
+ $("#action_menu").fadeOut(200);
+ $("#link_context_menu").fadeOut(200);
+ $("#client_context_menu").fadeOut(200);
+ });
+ function clearPopups() {
+ d3.select("#crosssection").style("display", "none");
+ $('.hastip').empty();
+ d3.select("#multiple_details").style("display", "none")
+ d3.select("#link_details").style("display", "none")
+ d3.select('#action_menu').style('display', 'none');
+ d3.select('#svg_context_menu').style('display', 'none');
+ d3.select('#link_context_menu').style('display', 'none');
+ d3.select('#client_context_menu').style('display', 'none');
+ }
+
+ var radii = {
+ 'inter-router': 25,
+ 'normal': 15,
+ 'on-demand': 15,
+ 'route-container': 15
+ };
+ var radius = 25;
+ var radiusNormal = 15;
+ var svg, lsvg;
+ var force;
+ var animate = false; // should the force graph organize itself when it is displayed
+ var path, circle;
+ var savedKeys = {};
+ var dblckickPos = [0, 0];
+ var width = 0;
+ var height = 0;
+
+ var getSizes = function() {
+ var legendWidth = 143;
+ var gap = 5;
+ var width = $('#topology').width() - gap - legendWidth;
+ var top = $('#topology').offset().top
+ var height = Math.max(window.innerHeight, top) - top - gap;
+ if (width < 10) {
+ QDR.log.info("page width and height are abnormal w:" + width + " height:" + height)
+ return [0, 0];
+ }
+ return [width, height]
+ }
+ var resize = function() {
+ if (!svg)
+ return;
+ var sizes = getSizes();
+ width = sizes[0]
+ height = sizes[1]
+ if (width > 0) {
+ // set attrs and 'resume' force
+ svg.attr('width', width);
+ svg.attr('height', height);
+ force.size(sizes).resume();
+ }
+ }
+ window.addEventListener('resize', resize);
+ var sizes = getSizes()
+ width = sizes[0]
+ height = sizes[1]
+ if (width <= 0 || height <= 0)
+ return
+
+ // set up initial nodes and links
+ // - nodes are known by 'id', not by index in array.
+ // - selected edges are indicated on the node (as a bold red circle).
+ // - links are always source < target; edge directions are set by 'left' and 'right'.
+ var nodes = [];
+ var links = [];
+
+ var aNode = function(id, name, nodeType, nodeInfo, nodeIndex, x, y, resultIndex, fixed, properties) {
+ for (var i=0; i<nodes.length; ++i) {
+ if (nodes[i].name === name)
+ return nodes[i]
+ }
+ properties = properties || {};
+ var routerId = QDRService.nameFromId(id)
+ return {
+ key: id,
+ name: name,
+ nodeType: nodeType,
+ properties: properties,
+ routerId: routerId,
+ x: x,
+ y: y,
+ id: nodeIndex,
+ host: '0.0.0.0',
+ resultIndex: resultIndex,
+ cls: ''
+ };
+ };
+
+
+ var initForm = function(attributes, results, entityType, formFields) {
+
+ while (formFields.length > 0) {
+ // remove all existing attributes
+ formFields.pop();
+ }
+
+ for (var i = 0; i < attributes.length; ++i) {
+ var name = attributes[i];
+ var val = results[i];
+ var desc = "";
+ if (entityType.attributes[name])
+ if (entityType.attributes[name].description)
+ desc = entityType.attributes[name].description;
+
+ formFields.push({
+ 'attributeName': name,
+ 'attributeValue': val,
+ 'description': desc
+ });
+ }
+ }
+
+ var savePositions = function () {
+ var positions = {}
+ nodes.forEach( function (d) {
+ positions[d.name] = {
+ x: Math.round(d.x),
+ y: Math.round(d.y)
+ };
+ })
+ localStorage[$scope.mockTopologyDir] = angular.toJson(positions)
+ }
+
+ // vary the following force graph attributes based on nodeCount
+ // <= 6 routers returns min, >= 80 routers returns max, interpolate linearly
+ var forceScale = function(nodeCount, min, max) {
+ var count = nodeCount
+ if (nodeCount < 6) count = 6
+ if (nodeCount > 200) count = 200
+ var x = d3.scale.linear()
+ .domain([6,200])
+ .range([min, max]);
+//QDR.log.debug("forceScale(" + nodeCount + ", " + min + ", " + max + " returns " + x(count) + " " + x(nodeCount))
+ return x(count)
+ }
+ var linkDistance = function (d, nodeCount) {
+ if (d.target.nodeType === 'inter-router')
+ return forceScale(nodeCount, 150, 20)
+ return forceScale(nodeCount, 75, 10)
+ }
+ var charge = function (d, nodeCount) {
+ if (d.nodeType === 'inter-router')
+ return forceScale(nodeCount, -1800, -200)
+ return -900
+ }
+ var gravity = function (d, nodeCount) {
+ return forceScale(nodeCount, 0.0001, 0.1)
+ }
+
+ var initGraph = function () {
+ d3.select("#SVG_ID").remove();
+ svg = d3.select('#topology')
+ .append('svg')
+ .attr("id", "SVG_ID")
+ .attr('width', width)
+ .attr('height', height)
+ .on("contextmenu", function(d) {
+ if (d3.event.defaultPrevented)
+ return;
+ d3.event.preventDefault();
+
+ //if ($scope.addingNode.step != 0)
+ // return;
+ if (d3.select('#svg_context_menu').style('display') !== 'block')
+ $(document).click();
+ var rm = relativeMouse()
+ d3.select('#svg_context_menu')
+ .style('left', (rm.left - 16) + "px")
+ .style('top', (rm.top - rm.offset.top) + "px")
+ .style('display', 'block');
+ })
+
+ svg.append("svg:defs").selectAll('marker')
+ .data(["end-arrow", "end-arrow-selected", "end-arrow-small", "end-arrow-highlighted"]) // Different link/path types can be defined here
+ .enter().append("svg:marker") // This section adds in the arrows
+ .attr("id", String)
+ .attr("viewBox", "0 -5 10 10")
+ .attr("markerWidth", 4)
+ .attr("markerHeight", 4)
+ .attr("orient", "auto")
+ .classed("small", function (d) {return d.indexOf('small') > -1})
+ .append("svg:path")
+ .attr('d', 'M 0 -5 L 10 0 L 0 5 z')
+
+ svg.append("svg:defs").selectAll('marker')
+ .data(["start-arrow", "start-arrow-selected", "start-arrow-small", "start-arrow-highlighted"]) // Different link/path types can be defined here
+ .enter().append("svg:marker") // This section adds in the arrows
+ .attr("id", String)
+ .attr("viewBox", "0 -5 10 10")
+ .attr("refX", 5)
+ .attr("markerWidth", 4)
+ .attr("markerHeight", 4)
+ .attr("orient", "auto")
+ .append("svg:path")
+ .attr('d', 'M 10 -5 L 0 0 L 10 5 z');
+
+ // handles to link and node element groups
+ path = svg.append('svg:g').selectAll('path')
+ circle = svg.append('svg:g').selectAll('g')
+
+ }
+
+ var initLegend = function () {
+ // the legend
+ d3.select("#svg_legend svg").remove();
+ lsvg = d3.select("#svg_legend")
+ .append('svg')
+ .attr('id', 'svglegend')
+ lsvg = lsvg.append('svg:g')
+ .attr('transform', 'translate(' + (radii['inter-router'] + 2) + ',' + (radii['inter-router'] + 2) + ')')
+ .selectAll('g');
+ }
+
+ var initForce = function () {
+ // convert link source/target into node index numbers
+ links.forEach( function (link, i) {
+ if (link.source.id) {
+ link.source = link.source.id
+ link.target = link.target.id
+ }
+ })
+ var routerCount = nodes.filter(function (n) {
+ return n.nodeType === 'inter-router'
+ }).length
+
+ force = d3.layout.force()
+ .nodes(nodes)
+ .links(links)
+ .size([width, height])
+ .linkDistance(function(d) { return linkDistance(d, routerCount) })
+ .charge(function(d) { return charge(d, routerCount) })
+ .friction(.10)
+ .gravity(function(d) { return gravity(d, routerCount) })
+ .on('tick', tick)
+ .on('end', function () {savePositions()})
+ .start()
+ }
+ // initialize the nodes and links array from the QDRService.topology._nodeInfo object
+ var initForceGraph = function() {
+
+ mouseover_node = null;
+ $scope.selected_node = null;
+ selected_link = null;
+
+ initGraph()
+ initLegend()
+
+ // mouse event vars
+ mousedown_link = null;
+ mousedown_node = null;
+ mouseup_node = null;
+
+ savePositions()
+ // init D3 force layout
+ initForce()
+
+ // app starts here
+ restart(false);
+ force.start();
+ tick();
+ }
+
+ function getContainerIndex(_id, nodeInfo) {
+ var nodeIndex = 0;
+ for (var id in nodeInfo) {
+ if (QDRService.nameFromId(id) === _id)
+ return nodeIndex;
+ ++nodeIndex;
+ }
+ return -1;
+ }
+
+ function getLink(_source, _target, dir, cls, uid) {
+ for (var i = 0; i < links.length; i++) {
+ var s = links[i].source,
+ t = links[i].target;
+ if (typeof links[i].source == "object") {
+ s = s.id;
+ t = t.id;
+ }
+ if (s == _source && t == _target) {
+ return i;
+ }
+ // same link, just reversed
+ if (s == _target && t == _source) {
+ return -i;
+ }
+ }
+
+ var link = {
+ source: _source,
+ target: _target,
+ left: dir != "out",
+ right: (dir == "out" || dir == "both"),
+ cls: cls,
+ uid: uid,
+ };
+ return links.push(link) - 1;
+ }
+
+
+ function resetMouseVars() {
+ mousedown_node = null;
+ mouseover_node = null;
+ mouseup_node = null;
+ mousedown_link = null;
+ }
+
+ // update force layout (called automatically each iteration)
+ function tick() {
+ circle.attr('transform', function(d) {
+ var cradius;
+ if (d.nodeType == "inter-router") {
+ cradius = d.left ? radius + 8 : radius;
+ } else {
+ cradius = d.left ? radiusNormal + 18 : radiusNormal;
+ }
+ d.x = Math.max(d.x, radiusNormal * 2);
+ d.y = Math.max(d.y, radiusNormal * 2);
+ d.x = Math.max(0, Math.min(width - cradius, d.x))
+ d.y = Math.max(0, Math.min(height - cradius, d.y))
+ return 'translate(' + d.x + ',' + d.y + ')';
+ });
+
+ // draw directed edges with proper padding from node centers
+ path.attr('d', function(d) {
+ var sourcePadding, targetPadding, r;
+
+ if (d.target.nodeType == "inter-router") {
+ r = radius;
+ // right arrow left line start
+ sourcePadding = d.left ? radius + 8 : radius;
+ // left arrow right line start
+ targetPadding = d.right ? radius + 16 : radius;
+ } else {
+ r = radiusNormal - 18;
+ sourcePadding = d.left ? radiusNormal + 18 : radiusNormal;
+ targetPadding = d.right ? radiusNormal + 16 : radiusNormal;
+ }
+ var dtx = Math.max(targetPadding, Math.min(width - r, d.target.x)),
+ dty = Math.max(targetPadding, Math.min(height - r, d.target.y)),
+ dsx = Math.max(sourcePadding, Math.min(width - r, d.source.x)),
+ dsy = Math.max(sourcePadding, Math.min(height - r, d.source.y));
+
+ var deltaX = dtx - dsx,
+ deltaY = dty - dsy,
+ dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
+ normX = deltaX / dist,
+ normY = deltaY / dist;
+ var sourceX = dsx + (sourcePadding * normX),
+ sourceY = dsy + (sourcePadding * normY),
+ targetX = dtx - (targetPadding * normX),
+ targetY = dty - (targetPadding * normY);
+ sourceX = Math.max(0, Math.min(width, sourceX))
+ sourceY = Math.max(0, Math.min(width, sourceY))
+ targetX = Math.max(0, Math.min(width, targetX))
+ targetY = Math.max(0, Math.min(width, targetY))
+
+ return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
+ });
+
+ if (!animate) {
+ animate = true;
+ force.stop();
+ }
+ }
+
+ function nodeFor(name) {
+ for (var i = 0; i < nodes.length; ++i) {
+ if (nodes[i].name == name)
+ return nodes[i];
+ }
+ return null;
+ }
+
+ function genLinkName(d1, d2) {
+ return d1.id + "." + d2.id
+ }
+ function linkFor(source, target) {
+ for (var i = 0; i < links.length; ++i) {
+ if ((links[i].source == source) && (links[i].target == target))
+ return links[i];
+ if ((links[i].source == target) && (links[i].target == source))
+ return links[i];
+ }
+ return null;
+ }
+
+ function hideLinkDetails() {
+ d3.select("#link_details").transition()
+ .duration(500)
+ .style("opacity", 0)
+ .each("end", function(d) {
+ d3.select("#link_details").style("display", "none")
+ })
+ }
+
+ function clerAllHighlights() {
+ for (var i = 0; i < links.length; ++i) {
+ links[i]['highlighted'] = false;
+ }
+ for (var i=0; i<nodes.length; ++i) {
+ nodes[i]['highlighted'] = false;
+ }
+ }
+
+ // takes the nodes and links array of objects and adds svg elements for everything that hasn't already
+ // been added
+ function restart(start) {
+ circle.call(force.drag);
+
+ // path (link) group
+ path = path.data(links, function(d) {return d.uid});
+
+ // update existing links
+ path.classed('selected', function(d) {
+ return d === selected_link;
+ })
+ .classed('highlighted', function(d) {
+ return d.highlighted;
+ })
+ .classed('temp', function(d) {
+ return d.cls == 'temp';
+ })
+ .attr('marker-start', function(d) {
+ var sel = d === selected_link ? '-selected' : (d.cls === 'small' ? '-small' : '');
+ if (d.highlighted)
+ sel = "-highlighted"
+ return d.left ? 'url(#start-arrow' + sel + ')' : '';
+ })
+ .attr('marker-end', function(d) {
+ var sel = d === selected_link ? '-selected' : (d.cls === 'small' ? '-small' : '');
+ if (d.highlighted)
+ sel = "-highlighted"
+ return d.right ? 'url(#end-arrow' + sel + ')' : '';
+ })
+
+
+ // add new links. if links[] is longer than the existing paths, add a new path for each new element
+ path.enter().append('svg:path')
+ .attr('class', 'link')
+ .attr('marker-start', function(d) {
+ var sel = d === selected_link ? '-selected' : (d.cls === 'small' ? '-small' : '');
+ return d.left ? 'url(#start-arrow' + sel + ')' : '';
+ })
+ .attr('marker-end', function(d) {
+ var sel = d === selected_link ? '-selected' : (d.cls === 'small' ? '-small' : '');
+ return d.right ? 'url(#end-arrow' + sel + ')' : '';
+ })
+ .classed('temp', function(d) {
+ return d.cls == 'temp';
+ })
+ .classed('small', function(d) {
+ return d.cls == 'small';
+ })
+ .on('mouseover', function(d) { // mouse over a path
+ if ($scope.addingNode.step > 0) {
+ if (d.cls == 'temp') {
+ d3.select(this).classed('over', true);
+ }
+ return;
+ }
+
+ mousedown_link = d;
+ selected_link = mousedown_link;
+ restart();
+ })
+ .on('mouseout', function(d) { // mouse out of a path
+ if ($scope.addingNode.step > 0) {
+ if (d.cls == 'temp') {
+ d3.select(this).classed('over', false);
+ }
+ return;
+ }
+ selected_link = null;
+ restart();
+ })
+ .on("contextmenu", function(d) { // right click a path
+ $(document).click();
+ d3.event.preventDefault();
+
+ mousedown_link = d;
+ var rm = relativeMouse()
+ d3.select('#link_context_menu')
+ .style('left', rm.left + "px")
+ .style('top', (rm.top - rm.offset.top) + "px")
+ .style('display', 'block');
+ })
+ // left click a path
+ .on("click", function (d) {
+ var clickPos = d3.mouse(this);
+ d3.event.stopPropagation();
+ clearPopups();
+ })
+ // remove old links
+ path.exit().remove();
+
+ // circle (node) group
+ // nodes are known by id
+ circle = circle.data(nodes, function(d) { return d.name });
+
+ var appendTitle = function(g) {
+ g.append("svg:title").text(function(d) {
+ if (QDRService.isConsole(d)) {
+ return 'Dispatch console'
+ }
+ if (d.properties.product == 'qpid-cpp') {
+ return 'Broker - Qpid'
+ }
+ if (QDRService.isArtemis(d)) {
+ return 'Broker - Artemis'
+ }
+ if (d.cdir === 'in')
+ return 'Listener on port ' + d.entityKey
+ if (d.cdir === 'out')
+ return 'Connector to ' + d.host + ':' + d.entityKey
+ if (d.cdir === 'both')
+ return 'sslProfile'
+ return d.nodeType == 'normal' ? 'client' : (d.nodeType == 'route-container' ? 'broker' : 'Router ' + d.name)
+ })
+ }
+
+ // update existing nodes visual states
+ circle.selectAll('circle')
+ .classed('highlighted', function(d) {
+ return d.highlighted;
+ })
+ .classed('selected', function(d) {
+ return (d === $scope.selected_node)
+ })
+ // add 'multiple' class to existing <g> elements as needed
+ .each(function (d) {
+ if (d.normals && d.normals.length > 1) {
+ // add the "multiple" class to the parent <g>
+ var d3g = d3.select(this.parentElement)
+ d3g.attr('class', 'multiple')
+ d3g.select('title').remove()
+ appendTitle(d3g)
+ }
+ })
+
+ // add new circle nodes. if nodes[] is longer than the existing paths, add a new path for each new element
+ var g = circle.enter().append('svg:g')
+ .classed('multiple', function(d) {
+ return (d.normals && d.normals.length > 1)
+ })
+
+ var appendCircle = function(g) {
+ // add new circles and set their attr/class/behavior
+ return g.append('svg:circle')
+ .attr('class', 'node')
+ .attr('r', function(d) {
+ return radii[d.nodeType]
+ })
+ .classed('normal', function(d) {
+ return d.nodeType == 'normal' || QDRService.isConsole(d)
+ })
+ .classed('in', function(d) {
+ return d.cdir == 'in'
+ })
+ .classed('out', function(d) {
+ return d.cdir == 'out'
+ })
+ .classed('selected', function (d) {
+ return $scope.selected_node === d
+ })
+ .classed('inout', function(d) {
+ return d.cdir == 'both'
+ })
+ .classed('inter-router', function(d) {
+ return d.nodeType == 'inter-router'
+ })
+ .classed('on-demand', function(d) {
+ return d.nodeType == 'route-container'
+ })
+ .classed('console', function(d) {
+ return QDRService.isConsole(d)
+ })
+ .classed('artemis', function(d) {
+ return QDRService.isArtemis(d)
+ })
+ .classed('qpid-cpp', function(d) {
+ return QDRService.isQpid(d)
+ })
+ .classed('route-container', function (d) {
+ return (!QDRService.isArtemis(d) && !QDRService.isQpid(d) && d.nodeType === 'route-container')
+ })
+ .classed('client', function(d) {
+ return d.nodeType === 'normal' && !d.properties.console_identifier
+ })
+ }
+ appendCircle(g)
+ .on('mouseover', function(d) { // mouseover a circle
+ if ($scope.addingNode.step > 0) {
+ d3.select(this).attr('transform', 'scale(1.1)');
+ return;
+ }
+
+ if (d === mousedown_node)
+ return;
+ // enlarge target node
+ d3.select(this).attr('transform', 'scale(1.1)');
+ mousedown_node = null;
+
+ if (!$scope.selected_node) {
+ return;
+ }
+ clerAllHighlights()
+ })
+ .on('mouseout', function(d) { // mouse out for a circle
+ // unenlarge target node
+ d3.select(this).attr('transform', '');
+ clerAllHighlights()
+ mouseover_node = null;
+ restart();
+ })
+ .on('mousedown', function(d) { // mouse down for circle
+ if (d3.event.button !== 0) { // ignore all but left button
+ return;
+ }
+ mousedown_node = d;
+ // mouse position relative to svg
+ initial_mouse_down_position = d3.mouse(this.parentElement.parentElement.parentElement).slice();
+ })
+ .on('mouseup', function(d) { // mouse up for circle
+ if (!mousedown_node)
+ return;
+
+ selected_link = null;
+ // unenlarge target node
+ d3.select(this).attr('transform', '');
+
+ // check for drag
+ mouseup_node = d;
+ var mySvg = this.parentElement.parentElement.parentElement;
+ // if we dragged the node, don't do anything
+ var cur_mouse = d3.mouse(mySvg);
+ if (Math.abs(cur_mouse[0] - initial_mouse_down_position[0]) > 4 ||
+ Math.abs(cur_mouse[1] - initial_mouse_down_position[1]) > 4) {
+ return
+ }
+ // we want a link between the selected_node and this node
+ if ($scope.selected_node && d !== $scope.selected_node) {
+ if (d.nodeType !== 'inter-router')
+ return;
+
+ // add a link from the clicked node to the selected node
+ var source = nodes.findIndex( function (n) {
+ return (n.key === d.key && n.nodeType === 'inter-router')
+ })
+ var target = nodes.findIndex( function (n) {
+ return (n.key === $scope.selected_node.key && n.nodeType === 'inter-router')
+ })
+ var curLinkCount = links.length
+ var newIndex = getLink(source, target, "in", "", genLinkName(d, $scope.selected_node));
+ // there was already a link from selected to clicked node
+ if (newIndex != curLinkCount) {
+ $scope.selected_node = d
+ restart();
+ return;
+ }
+ // add new elements to the svg
+ force.links(links).start();
+ restart();
+ return;
+
+ }
+
+ // if this node was selected, unselect it
+ if (mousedown_node === $scope.selected_node) {
+ $scope.selected_node = null;
+ } else {
+ if (d.nodeType !== 'normal' && d.nodeType !== 'on-demand')
+ $scope.selected_node = mousedown_node;
+ }
+ clerAllHighlights()
+ mousedown_node = null;
+ if (!$scope.$$phase) $scope.$apply()
+ restart(false);
+
+ })
+ .on("contextmenu", function(d) { // circle
+ clearPopups();
+
+ d3.event.preventDefault();
+ $scope.selected_node = d;
+ if (!$scope.$$phase) $scope.$apply() // we just changed a scope variable during an async event
+ var rm = relativeMouse()
+ var menu = d.nodeType === 'inter-router' ? 'action_menu' : 'client_context_menu'
+ d3.select('#'+menu)
+ .style('left', rm.left + "px")
+ .style('top', (rm.top - rm.offset.top) + "px")
+ .style('display', 'block');
+ })
+ .on("click", function(d) { // circle
+ if (!mouseup_node)
+ return;
+ // clicked on a circle
+ clearPopups();
+ clickPos = d3.mouse(this);
+ d3.event.stopPropagation();
+ })
+ //.attr("transform", function (d) {return "scale(" + (d.nodeType === 'normal' ? .5 : 1) + ")"})
+ //.transition().duration(function (d) {return d.nodeType === 'normal' ? 3000 : 0}).ease("elastic").attr("transform", "scale(1)")
+
+ var appendContent = function(g) {
+ // show node IDs
+ g.append('svg:text')
+ .attr('x', 0)
+ .attr('y', function(d) {
+ var y = 7;
+ if (QDRService.isArtemis(d))
+ y = 8;
+ else if (QDRService.isQpid(d))
+ y = 9;
+ else if (d.nodeType === 'inter-router')
+ y = 4;
+ return y;
+ })
+ .attr('class', 'id')
+ .classed('console', function(d) {
+ return QDRService.isConsole(d)
+ })
+ .classed('normal', function(d) {
+ return d.nodeType === 'normal'
+ })
+ .classed('on-demand', function(d) {
+ return d.nodeType === 'on-demand'
+ })
+ .classed('artemis', function(d) {
+ return QDRService.isArtemis(d)
+ })
+ .classed('qpid-cpp', function(d) {
+ return QDRService.isQpid(d)
+ })
+ .text(function(d) {
+ if (QDRService.isConsole(d)) {
+ return '\uf108'; // icon-desktop for this console
+ } else if (QDRService.isArtemis(d)) {
+ return '\ue900'
+ } else if (QDRService.isQpid(d)) {
+ return '\ue901';
+ } else if (d.nodeType === 'route-container') {
+ return d.properties.product ? d.properties.product[0].toUpperCase() : 'S'
+ } else if (d.nodeType === 'normal' && d.cdir === "in") // listener
+ return '\uf2a0'; // phone top
+ else if (d.nodeType === 'normal' && d.cdir === "out") // connector
+ return '\uf2a0'; // phone top (will be rotated)
+ else if (d.nodeType === 'normal' && d.cdir === "both") // not used
+ return '\uf023'; // icon-laptop for clients
+
+ return d.name.length > 7 ? d.name.substr(0, 6) + '...' : d.name;
+ })
+ // rotatie the listener icon 180 degrees to use as the connector icon
+ .attr("transform", function (d) {
+ var nAngle = 0
+ if (d.nodeType === 'normal' && d.cdir === "out")
+ nAngle = 180
+ return "rotate("+nAngle+")"
+ });
+ }
+
+ appendContent(g)
+ appendTitle(g);
+
+ // remove old nodes
+ circle.exit().remove();
+
+ // add subcircles
+ svg.selectAll('.more').remove();
+ svg.selectAll('.multiple')
+ .append('svg:path')
+ .attr('d', "M1.5,-1 V4 M-1,1.5 H4")
+ .attr('class', 'more')
+ .attr('transform', "translate(18, -3) scale(2)")
+
+ // dynamically create the legend based on which node types are present
+ // the legend
+ d3.select("#svg_legend svg").remove();
+ lsvg = d3.select("#svg_legend")
+ .append('svg')
+ .attr('id', 'svglegend')
+ lsvg = lsvg.append('svg:g')
+ .attr('transform', 'translate(' + (radii['inter-router'] + 2) + ',' + (radii['inter-router'] + 2) + ')')
+ .selectAll('g');
+ var legendNodes = [];
+ legendNodes.push(aNode("Router", "", "inter-router", undefined, 0, 0, 0, 0, false, {}))
+
+ if (!svg.selectAll('circle.console').empty()) {
+ legendNodes.push(aNode("Console", "", "normal", undefined, 1, 0, 0, 0, false, {
+ console_identifier: 'Dispatch console'
+ }))
+ }
+ if (!svg.selectAll('circle.client.in').empty()) {
+ var node = aNode("Listener", "", "normal", undefined, 2, 0, 0, 0, false, {})
+ node.cdir = "in"
+ legendNodes.push(node)
+ }
+ if (!svg.selectAll('circle.client.out').empty()) {
+ var node = aNode("Connector", "", "normal", undefined, 3, 0, 0, 0, false, {})
+ node.cdir = "out"
+ legendNodes.push(node)
+ }
+ if (!svg.selectAll('circle.client.inout').empty()) {
+ var node = aNode("sslProfile", "", "normal", undefined, 4, 0, 0, 0, false, {})
+ node.cdir = "both"
+ legendNodes.push(node)
+ }
+ if (!svg.selectAll('circle.qpid-cpp').empty()) {
+ legendNodes.push(genNodeToAdd({key:'Qpid broker', name:'legend', x:0, y:0, id:'legend'}, 'qpid', ''))
+ }
+ if (!svg.selectAll('circle.artemis').empty()) {
+ legendNodes.push(genNodeToAdd({key:'Artemis broker', name:'legend', x:0, y:0, id:'legend'}, 'artemis', ''))
+ }
+ if (!svg.selectAll('circle.route-container').empty()) {
+ legendNodes.push(aNode("Service", "", "route-container", 'external-service', undefined, 7, 0, 0, 0, false,
+ {product: ' External Service'}))
+ }
+ lsvg = lsvg.data(legendNodes, function(d) {
+ return d.key;
+ });
+ var lg = lsvg.enter().append('svg:g')
+ .attr('transform', function(d, i) {
+ // 45px between lines and add 10px space after 1st line
+ return "translate(0, " + (45 * i + (i > 0 ? 10 : 0)) + ")"
+ })
+
+ appendCircle(lg)
+ appendContent(lg)
+ appendTitle(lg)
+ lg.append('svg:text')
+ .attr('x', 35)
+ .attr('y', 6)
+ .attr('class', "label")
+ .text(function(d) {
+ return d.key
+ })
+ lsvg.exit().remove();
+ var svgEl = document.getElementById('svglegend')
+ if (svgEl) {
+ var bb;
+ // firefox can throw an exception on getBBox on an svg element
+ try {
+ bb = svgEl.getBBox();
+ } catch (e) {
+ bb = {
+ y: 0,
+ height: 200,
+ x: 0,
+ width: 200
+ }
+ }
+ svgEl.style.height = (bb.y + bb.height) + 'px';
+ svgEl.style.width = (bb.x + bb.width) + 'px';
+ }
+
+ if (!mousedown_node || !$scope.selected_node)
+ return;
+
+ if (!start)
+ return;
+ // set the graph in motion
+ force.start();
+
+ }
+
+ function mousedown() {
+ // prevent I-bar on drag
+ //d3.event.preventDefault();
+
+ // because :active only works in WebKit?
+ svg.classed('active', true);
+ }
+
+ // we are about to leave the page, save the node positions
+ $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
+ savePositions()
+ });
+ // When the DOM element is removed from the page,
+ // AngularJS will trigger the $destroy event on
+ // the scope
+ $scope.$on("$destroy", function(event) {
+ savePositions();
+ d3.select("#SVG_ID").remove();
+ window.removeEventListener('resize', resize);
+ });
+
+ $scope.mockTopologies = []
+ $scope.mockTopologyDir = ""
+ QDRService.sendMethod("GET-TOPOLOGY-LIST", {}, function (response) {
+ $scope.mockTopologies = response.sort()
+ QDRService.sendMethod("GET-TOPOLOGY", {}, function (response) {
+ // this will trigger the watch on this variable which will get the topology
+ $timeout(function () {
+ $scope.mockTopologyDir = response
+ })
+ })
+ })
+
+ function doShowConfigDialog(config) {
+ var d = $uibModal.open({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.ShowConfigDialogController',
+ templateUrl: 'show-config-template.html',
+ resolve: {
+ config: function() {
+ return config;
+ }
+ }
+ });
+ }
+
+ function doSetRouterHostDialog(node) {
+ var d = $uibModal.open({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.SetRouterHostDialogController',
+ templateUrl: 'set-router-host.html',
+ resolve: {
+ host: function() {
+ var host = node.host || '0.0.0.0'
+ return host;
+ }
+ }
+ });
+ $timeout(function () {
+ d.result.then(function(result) {
+ if (result) {
+ node.host = result.host
+ // loop through all listeners and set the host
+ if (node.listeners) {
+ for (var listener in node.listeners) {
+ node.listeners[listener].host = result.host
+ }
+ }
+ }
+ });
+ })
+ }
+
+ function doNewDialog() {
+ var d = $uibModal.open({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.NewDialogController',
+ templateUrl: 'new-config-template.html',
+ resolve: {
+ list: function() {
+ return $scope.mockTopologies;
+ }
+ }
+ });
+ $timeout(function () {
+ d.result.then(function(result) {
+ if (result) {
+ // append the new topology to the list of configs and switch to the new one
+ if ($scope.mockTopologies.indexOf(result.newTopology) < 0) {
+ $scope.mockTopologies.push(result.newTopology)
+ $scope.mockTopologies.sort()
+ }
+ $scope.mockTopologyDir = result.newTopology
+ }
+ });
+ })
+ };
+ function doSettingsDialog(opts) {
+ var d = $uibModal.open({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.SettingsDialogController',
+ templateUrl: 'settings-template.html',
+ resolve: {
+ settings: function() {
+ return opts
+ }
+ }
+ });
+ $timeout(function () {
+ d.result.then(function(result) {
+ if (result) {
+ Object.assign(settings, result)
+ }
+ });
+ })
+ };
+ function valFromMapArray(ar, key, val) {
+ for (var i=0; i<ar.length; i++) {
+ if (ar[i][key] && ar[i][key] === val)
+ return ar[i]
+ }
+ return undefined
+ }
+
+ function doEditDialog(node, entity, context) {
+ var entity2key = {router: 'name', log: 'module', sslProfile: 'name', connector: 'port', listener: 'port'}
+ var d = $uibModal.open({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.NodeDialogController',
+ templateUrl: 'node-config-template.html',
+ resolve: {
+ node: function() {
+ return node;
+ },
+ entityType: function() {
+ return entity
+ },
+ context: function () {
+ return context
+ },
+ entityKey: function () {
+ return entity2key[entity]
+ },
+ hasLinks: function () {
+ return links.some(function (l) {
+ return l.source.key === node.key || l.target.key === node.key
+ })
+ },
+ maxPort: function () {
+ var maxPort = settings.normal_port
+ nodes.forEach(function (node) {
+ if (node.entity === 'listener' || node.entity === 'connector') {
+ if (node.entityKey !== 'amqp' && node.entityKey != settings.artemis_port && node.entityKey != settings.qpid_port)
+ if (parseInt(node.entityKey) > maxPort)
+ maxPort = parseInt(node.entityKey)
+ }
+ })
+ return maxPort
+ }
+ }
+ });
+ $timeout(function () {
+ d.result.then(function(result) {
+ if (result) {
+ if (entity === 'router') {
+ var router = valFromMapArray(result.entities, "actualName", "router")
+ if (router) {
+ var r = new FormValues(router)
+ r.name(router)
+ Object.assign(node, r.node)
+ initGraph()
+ initForce()
+ restart();
+ }
+ }
+ else {
+ var key = entity2key[entity]
+ var nodeObj = node[entity+'s']
+ if ('del' in result) {
+ // find the 'normal' node that is associated with this entry
+ var n = findChildNode(entity, context, node.name)
+ if (n)
+ $scope.delNode(n)
+ } else {
+ var rVals = valFromMapArray(result.entities, "actualName", entity)
+ if (rVals) {
+ var o = new FormValues(rVals)
+ if (!angular.isDefined(nodeObj)) {
+ node[entity+'s'] = {}
+ nodeObj = node[entity+'s']
+ }
+ // we were editing an existing section and the key for that section was changed
+ else if (o.node[key] !== context && (context !== 'new' && context !== 'artemis' && context != 'qpid')) {
+ delete nodeObj[context]
+ }
+ nodeObj[o.node[key]] = o.node
+ if (entity === 'log' || entity === 'sslProfile')
+ return
+ if (context === 'new' || context === 'artemis' || context === 'qpid') {
+ if (context !== 'new')
+ entity = context
+ addToNode(node, entity, o.node[key])
+ }
+ }
+ }
+ }
+ }
+ });
+ })
+ };
+
+ var FormValues = function (entity) {
+ this.node = {};
+ for (var i=0; i<entity.attributes.length; i++) {
+ var attr = entity.attributes[i]
+ if (typeof attr.rawtype === 'object' && attr['selected'])
+ attr['value'] = attr['selected']
+ this.node[attr['name']] = attr['value']
+ }
+ };
+
+ FormValues.prototype.name = function (entity) {
+ var name = valFromMapArray(entity.attributes, "name", "name")
+ if (name) {
+ name = name.value
+ this.node['name'] = name
+ this.node['routerId'] = name
+ this.node['key'] = "amqp:/_topo/0/" + name + "/$management"
+ }
+ };
+
+
+ }
+ ]);
+
+ QDR.module.controller("QDR.SetRouterHostDialogController", function ($scope, $uibModalInstance, host) {
+ $scope.host = host
+ $scope.setSettings = function () {
+ $uibModalInstance.close({host: $scope.host});
+ }
+
+ $scope.cancel = function () {
+ $uibModalInstance.close()
+ }
+ })
+
+ QDR.module.controller("QDR.ShowConfigDialogController", function ($scope, $uibModalInstance, config) {
+ $scope.config = config
+ $scope.ok = function () {
+ $uibModalInstance.close()
+ }
+ })
+
+ QDR.module.controller("QDR.NewDialogController", function($scope, $uibModalInstance, list) {
+ $scope.newTopology = ""
+ $scope.exclude = list
+ $scope.inList = function () {
+ return $scope.exclude.indexOf($scope.newTopology) >= 0
+ }
+
+ $scope.setSettings = function () {
+ $uibModalInstance.close({
+ newTopology: $scope.newTopology
+ });
+ }
+ $scope.cancel = function () {
+ $uibModalInstance.close()
+ }
+ })
+
+ QDR.module.controller("QDR.SettingsDialogController", function($scope, $uibModalInstance, settings) {
+ var local_settings = {}
+ Object.assign(local_settings, settings)
+ $scope.entity = {description: "Settings",
+ attributes: [
+ {name: "baseName", humanName: "Starting router name", input: "input", type: "text", value: local_settings.baseName, required: true},
+ {name: "http", humanName: "Port for console listeners", input: "input", type: "text", value: local_settings.http_port, required: true},
+ {name: "normal_port", humanName: "Starting port for normal listeners/connectors", input: "input", type: "text", value: local_settings.normal_port, required: true},
+ {name: "internal_port", humanName: "Starting port for inter-router listeners/connectors", input: "input", type: "text", value: local_settings.internal_port, required: true},
+ {name: "default_host", humanName: "Default host for inter-router listeners/connectors", input: "input", type: "text", value: local_settings.default_host, required: true},
+ ]}
+
+ $scope.setSettings = function () {
+ var newSettings = {}
+ $scope.entity.attributes.forEach( function (attr) {
+ newSettings[attr.name] = attr.value
+ })
+ $uibModalInstance.close(newSettings);
+ }
+
+ $scope.cancel = function () {
+ $uibModalInstance.close()
+ }
+
+ })
+
+
+ return QDR;
+}(QDR || {}));
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org