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/04/19 12:17:20 UTC
[1/4] qpid-dispatch git commit: DISPATCH-745 Remove symlinks from
hawtio to stand-alone
Repository: qpid-dispatch
Updated Branches:
refs/heads/master 4c14b0a49 -> 6a1e66322
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/navbar.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/navbar.js b/console/stand-alone/plugin/js/navbar.js
index 5125748..0d7baf9 100644
--- a/console/stand-alone/plugin/js/navbar.js
+++ b/console/stand-alone/plugin/js/navbar.js
@@ -34,38 +34,44 @@ var QDR = (function (QDR) {
content: '<i class="icon-cogs"></i> Connect',
title: "Connect to a router",
isValid: function () { return true; },
- href: "#" + QDR.pluginRoot + "/connect"
+ href: "#!" + QDR.pluginRoot + "/connect",
+ name: "Connect"
},
{
- content: '<i class="icon-home"></i> Overview',
+ content: '<i class="pficon-home"></i> Overview',
title: "View router overview",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#" + QDR.pluginRoot + "/overview"
+ href: "#!" + QDR.pluginRoot + "/overview",
+ name: "Overview"
},
{
content: '<i class="icon-list "></i> Entities',
title: "View the attributes of the router entities",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#" + QDR.pluginRoot + "/list"
+ href: "#!" + QDR.pluginRoot + "/list",
+ name: "Entities"
},
{
content: '<i class="icon-star-empty"></i> Topology',
title: "View router network topology",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#" + QDR.pluginRoot + "/topology"
+ href: "#!" + QDR.pluginRoot + "/topology",
+ name: "Topology"
},
{
content: '<i class="icon-bar-chart"></i> Charts',
title: "View charts",
isValid: function (QDRService, $location) { return QDRService.isConnected() && QDR.isStandalone; },
- href: "#/charts"
+ href: "#!/charts",
+ name: "Charts"
},
{
content: '<i class="icon-align-left"></i> Schema',
title: "View dispatch schema",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#" + QDR.pluginRoot + "/schema",
- right: true
+ href: "#!" + QDR.pluginRoot + "/schema",
+ right: true,
+ name: "Schema"
}
];
/**
@@ -77,17 +83,22 @@ var QDR = (function (QDR) {
* The controller for this plugin's navigation bar
*
*/
- QDR.module.controller("QDR.NavBarController", ['$scope', 'QDRService', 'QDRChartService', '$routeParams', '$location', function($scope, QDRService, QDRChartService, $routeParams, $location) {
+ QDR.module.controller("QDR.NavBarController", ['$rootScope', '$scope', 'QDRService', 'QDRChartService', '$routeParams', '$location', function($rootScope, $scope, QDRService, QDRChartService, $routeParams, $location) {
$scope.breadcrumbs = QDR.breadcrumbs;
$scope.isValid = function(link) {
+ if ($scope.isActive(link.href))
+ $rootScope.$broadcast("setCrumb", {name: link.name, title: link.content})
return link.isValid(QDRService, $location);
};
$scope.isActive = function(href) {
- // highlight the connect tab if we are on the root page
- if (($location.path() === QDR.pluginRoot) && (href.split("#")[1] === QDR.pluginRoot + "/connect"))
- return true
- return href.split("#")[1] == $location.path();
+//QDR.log.info("isActive(" + href + ") location.path() is " + $location.path())
+ // highlight the connect tab if we are on the root page
+ if (($location.path() === QDR.pluginRoot) && (href.split("#")[1] === QDR.pluginRoot + "/connect")) {
+//QDR.log.info("isActive is returning true for connect page")
+ return true
+ }
+ return href.split("#")[1] === '!' + $location.path();
};
$scope.isRight = function (link) {
@@ -123,7 +134,7 @@ var QDR = (function (QDR) {
}]);
// controller for the edit/configure chart dialog
- QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, dialog, chart, updateTick, dashboard, adding) {
+ QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, $uibModalInstance, chart, updateTick, dashboard, adding) {
var dialogSvgChart = null;
$scope.svgDivId = "dialogEditChart"; // the div id for the svg chart
@@ -166,7 +177,7 @@ var QDR = (function (QDR) {
$scope.showChartsPage = function () {
cleanup();
- dialog.close(true);
+ $uibModalInstance.close(true);
$location.path(QDR.pluginRoot + "/charts");
};
@@ -180,7 +191,7 @@ var QDR = (function (QDR) {
}
$scope.okClick = function () {
cleanup();
- dialog.close(true);
+ $uibModalInstance.close(true);
};
var initRateSlider = function () {
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/qdrList.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrList.js b/console/stand-alone/plugin/js/qdrList.js
index ec2efb2..0e5ee8f 100644
--- a/console/stand-alone/plugin/js/qdrList.js
+++ b/console/stand-alone/plugin/js/qdrList.js
@@ -28,8 +28,8 @@ var QDR = (function(QDR) {
*
* Controller for the main interface
*/
- QDR.module.controller("QDR.ListController", ['$scope', '$location', '$dialog', '$filter', '$timeout', 'QDRService', 'QDRChartService',
- function ($scope, $location, $dialog, $filter, $timeout, QDRService, QDRChartService) {
+ QDR.module.controller("QDR.ListController", ['$scope', '$location', '$uibModal', '$filter', '$timeout', 'QDRService', 'QDRChartService',
+ function ($scope, $location, $uibModal, $filter, $timeout, QDRService, QDRChartService) {
var updateIntervalHandle = undefined;
var updateInterval = 5000;
@@ -675,7 +675,7 @@ var QDR = (function(QDR) {
}
function doDialog(tmpl, chart) {
- var d = $dialog.dialog({
+ var d = $uibModal.open({
backdrop: true,
keyboard: true,
backdropClick: true,
@@ -691,7 +691,7 @@ var QDR = (function(QDR) {
}
});
- d.open().then(function(result) { console.log("d.open().then"); });
+ d.result.then(function(result) { console.log("d.open().then"); });
};
@@ -744,6 +744,7 @@ var QDR = (function(QDR) {
var e = new Folder(entity)
e.typeName = "entity"
e.key = entity
+ e.isFolder = true
e.expand = (expandedList.indexOf(entity) > -1)
var placeHolder = new Folder("loading...")
placeHolder.addClass = "loading"
@@ -769,6 +770,10 @@ var QDR = (function(QDR) {
autoCollapse: $scope.largeNetwork,
activeVisible: !$scope.largeNetwork,
debugLevel: 0,
+ classNames: {
+ expander: 'fa-angle',
+ connector: 'dynatree-no-connector'
+ },
children: entityTreeChildren
})
restartUpdate()
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/qdrListChart.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrListChart.js b/console/stand-alone/plugin/js/qdrListChart.js
index 93391f1..0e5ee8f 100644
--- a/console/stand-alone/plugin/js/qdrListChart.js
+++ b/console/stand-alone/plugin/js/qdrListChart.js
@@ -21,121 +21,772 @@ under the License.
*/
var QDR = (function(QDR) {
- QDR.module.controller('QDR.ListChartController', function ($scope, dialog, $dialog, $location, QDRChartService, chart, nodeName) {
- $scope.chart = chart;
- $scope.dialogSvgChart = null;
- var updateTimer = null;
- $scope.svgDivId = "dialogChart"; // the div id for the svg chart
-
- $scope.showChartsPage = function () {
- cleanup();
- dialog.close(true);
- $location.path(QDR.pluginRoot + "/charts");
- };
+ /**
+ * @method ListController
+ * @param $scope
+ * @param QDRService
+ *
+ * Controller for the main interface
+ */
+ QDR.module.controller("QDR.ListController", ['$scope', '$location', '$uibModal', '$filter', '$timeout', 'QDRService', 'QDRChartService',
+ function ($scope, $location, $uibModal, $filter, $timeout, QDRService, QDRChartService) {
- $scope.addHChart = function () {
- QDRChartService.addHDash($scope.chart);
- cleanup();
- dialog.close(true);
- }
-
- $scope.addToDashboardLink = function () {
- var href = "#/" + QDR.pluginName + "/charts";
- var size = angular.toJson({
- size_x: 2,
- size_y: 2
- });
-
- var params = angular.toJson({chid: $scope.chart.id()});
- var title = "Dispatch - " + nodeName;
- return "/hawtio/#/dashboard/add?tab=dashboard" +
- "&href=" + encodeURIComponent(href) +
- "&routeParams=" + encodeURIComponent(params) +
- "&title=" + encodeURIComponent(title) +
- "&size=" + encodeURIComponent(size);
- };
+ var updateIntervalHandle = undefined;
+ var updateInterval = 5000;
+ var ListExpandedKey = "QDRListExpanded";
+ $scope.details = {};
+
+ $scope.tmplListTree = QDR.templatePath + 'tmplListTree.html';
+ $scope.selectedEntity = localStorage['QDRSelectedEntity'] || "address";
+ $scope.selectedNode = localStorage['QDRSelectedNode'];
+ $scope.selectedNodeId = localStorage['QDRSelectedNodeId'];
+ $scope.selectedRecordName = localStorage['QDRSelectedRecordName'];
+ $scope.nodes = []
+ $scope.currentNode = undefined;
+ $scope.modes = [
+ {
+ content: '<a><i class="icon-list"></i> Attributes</a>',
+ id: 'attributes',
+ op: 'READ',
+ title: "View router attributes",
+ isValid: function () { return true; }
+ },
+ {
+ content: '<a><i class="icon-edit"></i> Update</a>',
+ id: 'operations',
+ op: 'UPDATE',
+ title: "Update this attribute",
+ isValid: function () {
+ //QDR.log.debug("isValid UPDAATE? " + this.op)
+ //console.dump($scope.operations)
+ return $scope.operations.indexOf(this.op) > -1
+ }
+ },
+ {
+ content: '<a><i class="icon-plus"></i> Create</a>',
+ id: 'operations',
+ op: 'CREATE',
+ title: "Create a new attribute",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-remove"></i> Delete</a>',
+ id: 'delete',
+ op: 'DELETE',
+ title: "Delete",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-eye-open"></i> Fetch</a>',
+ id: 'log',
+ op: 'GET-LOG',
+ title: "Fetch recent log entries",
+ isValid: function () { return ($scope.selectedEntity === 'log') }
+ }
+ ];
+ $scope.operations = []
+ $scope.currentMode = $scope.modes[0];
+ $scope.isModeSelected = function (mode) {
+ return mode === $scope.currentMode;
+ }
+ $scope.fetchingLog = false;
+ $scope.selectMode = function (mode) {
+ $scope.currentMode = mode;
+ if (mode.id === 'log') {
+ $scope.logResults = [];
+ $scope.fetchingLog = true;
+ var entity; // undefined since it is not supported in the GET-LOG call
+ QDRService.sendMethod($scope.currentNode.id, entity, {}, $scope.currentMode.op, {}, function (nodeName, entity, response, context) {
+ $scope.fetchingLog = false;
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ //QDR.log.debug(context.message.application_properties.statusDescription)
+ return;
+ }
+ $scope.logResults = response.filter( function (entry) {
+ return entry[0] === $scope.detailsObject.module
+ }).sort( function (a, b) {
+ return b[5] - a[5]
+ }).map( function (entry) {
+ return {
+ type: entry[1],
+ message: entry[2],
+ source: entry[3],
+ line: entry[4],
+ time: Date(entry[5]).toString()
+ }
+ })
+ $scope.$apply();
+ })
+ }
+ }
+ $scope.isValid = function (mode) {
+ return mode.isValid()
+ }
+
+ $scope.expandAll = function () {
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.expand(true);
+ });
+ }
+ $scope.contractAll = function () {
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.expand(false);
+ });
+ }
+
+ if (!QDRService.connected) {
+ // we are not connected. we probably got here from a bookmark or manual page reload
+ QDRService.redirectWhenConnected("list");
+ return;
+ }
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("list")
+ $scope.$apply();
+ })
+
+ $scope.nodes = []
+ var excludedEntities = ["management", "org.amqp.management", "operationalEntity", "entity", "configurationEntity", "dummy", "console"];
+ var aggregateEntities = ["router.address"];
+ var classOverrides = {
+ "connection": function (row, nodeId) {
+ var isConsole = QDRService.isAConsole (row.properties.value, row.identity.value, row.role.value, nodeId)
+ return isConsole ? "console" : row.role.value === "inter-router" ? "inter-router" : "external";
+ },
+ "router.link": function (row, nodeId) {
+ var link = {nodeId: nodeId, connectionId: row.connectionId.value}
+ var isConsole = QDRService.isConsoleLink(link)
+ return isConsole ? "console" : row.linkType.value;
+ },
+ "router.address": function (row) {
+ var identity = QDRService.identity_clean(row.identity.value)
+ var address = QDRService.addr_text(identity)
+ var cls = QDRService.addr_class(identity)
+ if (address === "$management")
+ cls = "internal " + cls
+ return cls
+ }
+ }
+
+ var lookupOperations = function () {
+ var ops = QDRService.schema.entityTypes[$scope.selectedEntity].operations.filter( function (op) { return op !== 'READ'});
+ $scope.operation = ops.length ? ops[0] : "";
+ return ops;
+ }
+
+ var entityTreeChildren = [];
+ var expandedList = angular.fromJson(localStorage[ListExpandedKey]) || [];
+ var onTreeNodeExpanded = function (expanded, node) {
+ // save the list of entities that are expanded
+ var tree = $("#entityTree").dynatree("getTree");
+ var list = [];
+ tree.visit( function (tnode) {
+ if (tnode.isExpanded()) {
+ list.push(tnode.data.key)
+ }
+ })
+ localStorage[ListExpandedKey] = JSON.stringify(list)
+
+ if (expanded)
+ onTreeSelected(node);
+ }
+ // a tree node was selected
+ var onTreeSelected = function (selectedNode) {
+ $timeout( function () {
+ if ($scope.currentMode.id === 'operations')
+ $scope.currentMode = $scope.modes[0];
+ else if ($scope.currentMode.id === 'log')
+ $scope.selectMode($scope.currentMode)
+ else if ($scope.currentMode.id === 'delete') {
+ // clicked on a tree node while on the delete screen -> switch to attribute screen
+ $scope.currentMode = $scope.modes[0];
+ }
+ if (selectedNode.data.typeName === "entity") {
+ $scope.selectedEntity = selectedNode.data.key;
+ $scope.operations = lookupOperations()
+ } else if (selectedNode.data.typeName === 'attribute') {
+ $scope.selectedEntity = selectedNode.parent.data.key;
+ $scope.operations = lookupOperations()
+ $scope.selectedRecordName = selectedNode.data.key;
+ updateDetails(selectedNode.data.details); // update the table on the right
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.select(false);
+ });
+ selectedNode.select();
+ }
+ })
+ }
+
+ // fill in an empty results recoord based on the entities schema
+ var fromSchema = function (entityName) {
+ var row = {}
+ var schemaEntity = QDRService.schema.entityTypes[entityName]
+ for (attr in schemaEntity.attributes) {
+ var entity = schemaEntity.attributes[attr]
+ var value = ""
+ if (angular.isDefined(entity['default']))
+ value = entity['default']
+ row[attr] = {
+ value: value,
+ type: entity.type,
+ graph: false,
+ title: entity.description,
+ aggregate: false,
+ aggregateTip: '',
+ 'default': entity['default']
+ }
+ }
+ return row;
+ }
+ $scope.hasCreate = function () {
+ var schemaEntity = QDRService.schema.entityTypes[$scope.selectedEntity]
+ return (schemaEntity.operations.indexOf("CREATE") > -1)
+ }
+
+ var stopUpdating = function () {
+ if (angular.isDefined(updateIntervalHandle)) {
+ clearInterval(updateIntervalHandle);
+ }
+ updateIntervalHandle = undefined;
+ }
+
+ // the data for the selected entity is available, populate the tree
+ var updateEntityChildren = function (entity, tableRows, expand) {
+ var tree = $("#entityTree").dynatree("getTree");
+ if (!tree.getNodeByKey) {
+ return stopUpdating()
+ }
+ var node = tree.getNodeByKey(entity)
+ var updatedDetails = false;
+ var scrollTreeDiv = $('.qdr-attributes.pane.left .pane-viewport')
+ var scrollTop = scrollTreeDiv.scrollTop();
+ node.removeChildren();
+ if (tableRows.length == 0) {
+ node.addChild({
+ addClass: "no-data",
+ typeName: "none",
+ title: "no data",
+ key: node.data.key + ".1"
+ })
+ if (expand) {
+ updateDetails(fromSchema(entity));
+ $scope.selectedRecordName = entity;
+ }
+ } else {
+ tableRows.forEach( function (row) {
+ var addClass = entity;
+ if (classOverrides[entity]) {
+ addClass += " " + classOverrides[entity](row, $scope.currentNode.id);
+ }
+ var child = {
+ typeName: "attribute",
+ addClass: addClass,
+ tooltip: addClass,
+ key: row.name.value,
+ title: row.name.value,
+ details: row
+ }
+ if (row.name.value === $scope.selectedRecordName) {
+ if (expand)
+ updateDetails(row); // update the table on the right
+ child.select = true;
+ updatedDetails = true;
+ }
+ node.addChild(child)
+ })
+ }
+ // if the selectedRecordName was not found, select the 1st one
+ if (expand && !updatedDetails && tableRows.length > 0) {
+ var row = tableRows[0];
+ $scope.selectedRecordName = row.name.value;
+ var node = tree.getNodeByKey($scope.selectedRecordName);
+ node.select(true);
+ updateDetails(row) // update the table on the right
+ }
+ scrollTreeDiv.scrollTop(scrollTop)
+ }
+
+ var schemaProps = function (entityName, key, currentNode) {
+ var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean', map: 'textarea'};
+
+ var entity = QDRService.schema.entityTypes[entityName]
+ var value = entity.attributes[key]
+ // skip identity and depricated fields
+ if (!value)
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ var description = value.description || ""
+ var val = value['default'];
+ var disabled = (key == 'identity' || description.startsWith('Deprecated'))
+ // special cases
+ if (entityName == 'log' && key == 'module') {
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ }
+ if (entityName === 'linkRoutePattern' && key === 'connector') {
+ // turn input into a select. the values will be populated later
+ value.type = []
+ // find all the connector names and populate the select
+ QDRService.fetchEntity(currentNode.id, '.connector', ['name'], function (nodeName, dotentity, response) {
+ $scope.detailFields.some( function (field) {
+ if (field.name === 'connector') {
+ field.rawtype = response.results.map (function (result) {return result[0]})
+ return true;
+ }
+ })
+ });
+ }
+ return { name: key,
+ humanName: QDRService.humanify(key),
+ description:value.description,
+ type: disabled ? 'disabled' : typeMap[value.type],
+ rawtype: value.type,
+ input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input'
+ : 'select',
+ selected: val ? val : undefined,
+ 'default': value['default'],
+ value: val,
+ required: value.required,
+ unique: value.unique,
+ disabled: disabled
+ };
+ }
+ $scope.getAttributeValue = function (attribute) {
+ var value = attribute.attributeValue;
+ if ($scope.currentMode.op === "CREATE" && attribute.name === 'identity')
+ value = "<assigned by system>"
+ return value;
+ }
+
+ // update the table on the right
+ var updateDetails = function (row) {
+ var details = [];
+ $scope.detailsObject = {};
+ var attrs = Object.keys(row).sort();
+ attrs.forEach( function (attr) {
+ var changed = $scope.detailFields.filter(function (old) {
+ return (old.name === attr) ? old.graph && old.rawValue != row[attr].value : false;
+ })
+ var schemaEntity = schemaProps($scope.selectedEntity, attr, $scope.currentNode)
+ details.push( {
+ attributeName: QDRService.humanify(attr),
+ attributeValue: attr === 'port' ? row[attr].value : QDRService.pretty(row[attr].value),
+ name: attr,
+ changed: changed.length,
+ rawValue: row[attr].value,
+ graph: row[attr].graph,
+ title: row[attr].title,
+ aggregateValue: QDRService.pretty(row[attr].aggregate),
+ aggregateTip: row[attr].aggregateTip,
+
+ input: schemaEntity.input,
+ type: schemaEntity.type,
+ required: schemaEntity.required,
+ selected: schemaEntity.selected,
+ rawtype: schemaEntity.rawtype,
+ disabled: schemaEntity.disabled,
+ 'default': schemaEntity['default']
+ })
+ $scope.detailsObject[attr] = row[attr].value;
+ })
+ setTimeout(applyDetails, 1, details)
+ }
+
+ var applyDetails = function (details) {
+ $scope.detailFields = details;
+ aggregateColumn();
+ $scope.$apply();
+ // ng-grid bug? the entire table doesn't always draw unless a reflow is triggered;
+ $(window).trigger('resize');
+ }
+ var restartUpdate = function () {
+ stopUpdating();
+ updateTableData($scope.selectedEntity, true);
+ updateIntervalHandle = setInterval(updateExpandedEntities, updateInterval);
+ }
+ var updateExpandedEntities = function () {
+ var tree = $("#entityTree").dynatree("getTree");
+ if (tree.visit) {
+ tree.visit( function (node) {
+ if (node.isExpanded()) {
+ updateTableData(node.data.key, node.data.key === $scope.selectedEntity)
+ }
+ })
+ } else {
+ stopUpdating();
+ }
+ }
- $scope.addChartsPage = function () {
- QDRChartService.addDashboard($scope.chart);
+ $scope.selectNode = function(node) {
+ $scope.selectedNode = node.name;
+ $scope.selectedNodeId = node.id;
+ setCurrentNode();
+ restartUpdate();
};
+ $scope.$watch('selectedEntity', function(newValue, oldValue) {
+ if (newValue !== oldValue) {
+ localStorage['QDRSelectedEntity'] = $scope.selectedEntity;
+ restartUpdate();
+ $scope.operations = lookupOperations()
+ }
+ })
+ $scope.$watch('selectedNode', function(newValue, oldValue) {
+ if (newValue !== oldValue) {
+ localStorage['QDRSelectedNode'] = $scope.selectedNode;
+ localStorage['QDRSelectedNodeId'] = $scope.selectedNodeId;
+ }
+ })
+ $scope.$watch('selectedRecordName', function(newValue, oldValue) {
+ if (newValue != oldValue) {
+ localStorage['QDRSelectedRecordName'] = $scope.selectedRecordName;
+ }
+ })
+
+ /* Called periodically to refresh the data on the page */
+ var updateTableData = function (entity, expand) {
+ if (!QDRService.connected) {
+ // we are no longer connected. bail back to the connect page
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', "list");
+ return;
+ }
+ // don't update the data when on the operations tab
+ if ($scope.currentMode.id === 'operations') {
+ return;
+ }
+
+ var gotNodeInfo = function (nodeName, dotentity, response) {
+ var tableRows = [];
+ var records = response.results;
+ var aggregates = response.aggregates;
+ var attributeNames = response.attributeNames;
+ // If !attributeNmes then there was an error getting the records for this entity
+ if (attributeNames) {
+ var nameIndex = attributeNames.indexOf("name");
+ var identityIndex = attributeNames.indexOf("identity");
+ var ent = QDRService.schema.entityTypes[entity];
+ for (var i=0; i<records.length; ++i) {
+ var record = records[i];
+ var aggregate = aggregates ? aggregates[i] : undefined;
+ var row = {};
+ var rowName;
+ if (nameIndex > -1) {
+ rowName = record[nameIndex];
+ if (!rowName && identityIndex > -1) {
+ rowName = record[nameIndex] = (dotentity + '/' + record[identityIndex])
+ }
+ }
+ if (!rowName) {
+ QDR.log.error("response attributeNames did not contain a name field");
+ console.dump(response.attributeNames);
+ return;
+ }
+ for (var j=0; j<attributeNames.length; ++j) {
+ var col = attributeNames[j];
+ row[col] = {value: record[j], type: undefined, graph: false, title: '', aggregate: '', aggregateTip: ''};
+ if (ent) {
+ var att = ent.attributes[col];
+ if (att) {
+ row[col].type = att.type;
+ row[col].graph = att.graph;
+ row[col].title = att.description;
+
+ if (aggregate) {
+ if (att.graph) {
+ row[col].aggregate = att.graph ? aggregate[j].sum : '';
+ var tip = [];
+ aggregate[j].detail.forEach( function (line) {
+ tip.push(line);
+ })
+ row[col].aggregateTip = angular.toJson(tip);
+ }
+ }
+ }
+ }
+ }
+ tableRows.push(row);
+ }
+ }
- $scope.delChartsPage = function () {
- QDRChartService.delDashboard($scope.chart);
+ tableRows.sort( function (a, b) { return a.name.value.localeCompare(b.name.value) })
+ setTimeout(selectRow, 0, {entity: dotentity, rows: tableRows, expand: expand});
+ }
+ // if this entity should show an aggregate column, send the request to get the info for this entity from all the nedes
+ if (aggregateEntities.indexOf(entity) > -1) {
+ var nodeInfo = QDRService.topology.nodeInfo();
+ QDRService.getMultipleNodeInfo(Object.keys(nodeInfo), entity, [], gotNodeInfo, $scope.selectedNodeId);
+ } else {
+ QDRService.fetchEntity($scope.selectedNodeId, entity, [], gotNodeInfo);
+ }
};
- $scope.isOnChartsPage = function () {
- return $scope.chart.dashboard;
+ // tableRows are the records that were returned, this populates the left hand table on the page
+ var selectRow = function (info) {
+ updateEntityChildren(info.entity, info.rows, info.expand);
+ fixTooltips();
}
- var showChart = function () {
- // the chart divs are generated by angular and aren't available immediately
- var div = angular.element("#" + $scope.svgDivId);
- if (!div.width()) {
- setTimeout(showChart, 100);
+ var titleFromAlt = function (alt) {
+ if (alt && alt.length) {
+ var data = angular.fromJson(alt);
+ var table = "<table class='tiptable'><tbody>";
+ data.forEach (function (row) {
+ table += "<tr>";
+ table += "<td>" + row.node + "</td><td align='right'>" + QDRService.pretty(row.val) + "</td>";
+ table += "</tr>"
+ })
+ table += "</tbody></table>"
+ return table;
+ }
+ return '';
+ }
+
+ var fixTooltips = function () {
+ if ($('.hastip').length == 0) {
+ setTimeout(fixTooltips, 100);
return;
}
- dialogSvgChart = new QDRChartService.AreaChart($scope.chart);
- $scope.dialogSvgChart = dialogSvgChart;
- updateDialogChart();
+ $('.hastip').each( function (i, tip) {
+ var tipset = tip.getAttribute('tipset')
+ if (!tipset) {
+ $(tip).tipsy({html: true, className: 'subTip', opacity: 1, title: function () {
+ return titleFromAlt(this.getAttribute('alt'))
+ } });
+ tip.setAttribute('tipset', true)
+ } else {
+ var title = titleFromAlt(tip.getAttribute('alt'))
+ tip.setAttribute('original-title', title)
+ }
+ })
}
- showChart();
- var updateDialogChart = function () {
- if ($scope.dialogSvgChart)
- $scope.dialogSvgChart.tick($scope.svgDivId);
- if (updateTimer)
- clearTimeout(updateTimer)
- updateTimer = setTimeout(updateDialogChart, 1000);
+ $scope.detailFields = [];
+
+ $scope.addToGraph = function(rowEntity) {
+ var chart = QDRChartService.registerChart(
+ {nodeId: $scope.selectedNodeId,
+ entity: "." + $scope.selectedEntity,
+ name: $scope.selectedRecordName,
+ attr: rowEntity.name,
+ forceCreate: true});
+ doDialog('tmplListChart.html', chart);
+ }
+
+ $scope.addAllToGraph = function(rowEntity) {
+ var chart = QDRChartService.registerChart({
+ nodeId: $scope.selectedNodeId,
+ entity: $scope.selectedEntity,
+ name: $scope.selectedRecordName,
+ attr: rowEntity.name,
+ type: "rate",
+ rateWindow: updateInterval,
+ visibleDuration: 1,
+ forceCreate: true,
+ aggregate: true});
+ doDialog('tmplListChart.html', chart);
}
- var cleanup = function () {
- if (updateTimer) {
- clearTimeout(updateTimer);
- updateTimer = null;
+ $scope.detailCols = [];
+ var aggregateColumn = function () {
+ if ((aggregateEntities.indexOf($scope.selectedEntity) > -1 && $scope.detailCols.length != 3) ||
+ (aggregateEntities.indexOf($scope.selectedEntity) == -1 && $scope.detailCols.length != 2)) {
+ // column defs have to be reassigned and not spliced, so no push/pop
+ $scope.detailCols = [
+ {
+ field: 'attributeName',
+ displayName: 'Attribute',
+ cellTemplate: '<div title="{{row.entity.title}}" class="listAttrName">{{row.entity[col.field]}}<i ng-if="row.entity.graph" ng-click="addToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>'
+ },
+ {
+ field: 'attributeValue',
+ displayName: 'Value',
+ cellTemplate: '<div class="ngCellText" ng-class="{\'changed\': row.entity.changed == 1}"><span>{{row.getProperty(col.field)}}</span></div>'
+ }
+ ]
+ if (aggregateEntities.indexOf($scope.selectedEntity) > -1) {
+ $scope.detailCols.push(
+ {
+ width: '10%',
+ field: 'aggregateValue',
+ displayName: 'Aggregate',
+ cellTemplate: '<div class="hastip" alt="{{row.entity.aggregateTip}}"><span ng-class="{\'changed\': row.entity.changed == 1}">{{row.entity[col.field]}}</span><i ng-if="row.entity.graph" ng-click="addAllToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>',
+ cellClass: 'aggregate'
+ }
+ )
+ }
}
- if (!$scope.chart.hdash && !$scope.chart.dashboard)
- QDRChartService.unRegisterChart($scope.chart); // remove the chart
+ if ($scope.selectedRecordName === "")
+ $scope.detailCols = [];
+ }
+ // the table on the right of the page contains a row for each field in the selected record in the table on the left
+ $scope.details = {
+ data: 'detailFields',
+ columnDefs: "detailCols",
+ enableColumnResize: true,
+ multiSelect: false,
+ beforeSelectionChange: function() {
+ return false;
+ }
+ };
+ $scope.$on("$destroy", function( event ) {
+ //QDR.log.debug("scope destroyed for qdrList");
+ stopUpdating();
+ });
+
+ function gotMethodResponse (nodeName, entity, response, context) {
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ //QDR.log.debug(context.message.application_properties.statusDescription)
+ } else {
+ var note = entity + " " + $filter('Pascalcase')($scope.currentMode.op) + "d"
+ Core.notification('success', note);
+ $scope.selectMode($scope.modes[0]);
+ restartUpdate();
+ }
}
$scope.ok = function () {
- cleanup();
- dialog.close(true);
- };
-
- $scope.editChart = function () {
- doDialog('tmplChartConfig.html', chart)
- }
-
- function doDialog(template, chart) {
-
- $dialog.dialog({
- backdrop: true,
- keyboard: true,
- backdropClick: true,
- templateUrl: QDR.templatePath + template,
- controller: "QDR.ChartDialogController",
- resolve: {
- chart: function() {
- return chart;
- },
- updateTick: function () {
- return function () {};
- },
- dashboard: function () {
- return $scope;
- },
- adding: function () {
- return true
+ var attributes = {}
+ $scope.detailFields.forEach( function (field) {
+ var value = field.rawValue;
+ if (field.input === 'input') {
+ if (field.type === 'text' || field.type === 'disabled')
+ value = field.attributeValue;
+ } else if (field.input === 'select') {
+ value = field.selected;
+ } else if (field.input === 'boolean') {
+ value = field.rawValue
+ }
+ if (value === "")
+ value = undefined;
+
+ if ((value && value != field['default']) || field.required || (field.name === 'role')) {
+ if (field.name !== 'identity')
+ attributes[field.name] = value
+ }
+ })
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, undefined, gotMethodResponse)
+ }
+ $scope.remove = function () {
+ var attributes = {type: $scope.selectedEntity, name: $scope.selectedRecordName}
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, undefined, gotMethodResponse)
+ }
+
+ function doDialog(tmpl, chart) {
+ var d = $uibModal.open({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ templateUrl: QDR.templatePath + tmpl,
+ controller: "QDR.ListChartController",
+ resolve: {
+ chart: function() {
+ return chart
+ },
+ nodeName: function () {
+ return $scope.selectedNode
+ }
+ }
+ });
+
+ d.result.then(function(result) { console.log("d.open().then"); });
+
+ };
+
+ var setCurrentNode = function () {
+ $scope.nodes.some( function (node, i) {
+ if (node.name === $scope.selectedNode) {
+ $scope.currentNode = $scope.nodes[i]
+ return true;
+ }
+ })
+ }
+
+ var treeReady = false;
+ var serviceReady = false;
+ $scope.largeNetwork = QDRService.isLargeNetwork()
+ // called after we know for sure the schema is fetched and the routers are all ready
+ QDRService.addUpdatedAction("initList", function () {
+ QDRService.stopUpdating();
+ QDRService.delUpdatedAction("initList")
+
+ $scope.nodes = QDRService.nodeList().sort(function (a, b) { return a.name.toLowerCase() > b.name.toLowerCase()});
+ // unable to get node list? Bail.
+ if ($scope.nodes.length == 0) {
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', "list");
+ }
+ if (!angular.isDefined($scope.selectedNode)) {
+ //QDR.log.debug("selectedNode was " + $scope.selectedNode);
+ if ($scope.nodes.length > 0) {
+ $scope.selectedNode = $scope.nodes[0].name;
+ $scope.selectedNodeId = $scope.nodes[0].id;
+ //QDR.log.debug("forcing selectedNode to " + $scope.selectedNode);
+ }
+ }
+ setCurrentNode();
+ if ($scope.currentNode == undefined) {
+ if ($scope.nodes.length > 0) {
+ $scope.selectedNode = $scope.nodes[0].name;
+ $scope.selectedNodeId = $scope.nodes[0].id;
+ $scope.currentNode = $scope.nodes[0];
}
}
- }).open().then(function(result) {
- $scope.ok()
- });
+ var sortedEntities = Object.keys(QDRService.schema.entityTypes).sort();
+ sortedEntities.forEach( function (entity) {
+ if (excludedEntities.indexOf(entity) == -1) {
+ if (!angular.isDefined($scope.selectedEntity)) {
+ $scope.selectedEntity = entity;
+ $scope.operations = lookupOperations()
+ }
+ var e = new Folder(entity)
+ e.typeName = "entity"
+ e.key = entity
+ e.isFolder = true
+ e.expand = (expandedList.indexOf(entity) > -1)
+ var placeHolder = new Folder("loading...")
+ placeHolder.addClass = "loading"
+ e.children = [placeHolder]
+ entityTreeChildren.push(e)
+ }
+ })
+ serviceReady = true;
+ initTree();
+ })
+ $scope.treeReady = function () {
+ treeReady = true;
+ initTree();
+ }
+
+ var initTree = function () {
+ if (!treeReady || !serviceReady)
+ return;
+ $('#entityTree').dynatree({
+ onActivate: onTreeSelected,
+ onExpand: onTreeNodeExpanded,
+ selectMode: 1,
+ autoCollapse: $scope.largeNetwork,
+ activeVisible: !$scope.largeNetwork,
+ debugLevel: 0,
+ classNames: {
+ expander: 'fa-angle',
+ connector: 'dynatree-no-connector'
+ },
+ children: entityTreeChildren
+ })
+ restartUpdate()
+ updateExpandedEntities();
};
+ QDRService.ensureAllEntities({entity: ".connection"}, function () {
+ QDRService.setUpdateEntities([".connection"])
+ QDRService.startUpdating();
+ })
+
- });
+ }]);
- return QDR;
+ return QDR;
} (QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/qdrNewNode.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrNewNode.js b/console/stand-alone/plugin/js/qdrNewNode.js
index f6d035a..48af70f 100644
--- a/console/stand-alone/plugin/js/qdrNewNode.js
+++ b/console/stand-alone/plugin/js/qdrNewNode.js
@@ -21,7 +21,7 @@ under the License.
*/
var QDR = (function(QDR) {
- QDR.module.controller("QDR.NodeDialogController", function($scope, QDRService, dialog, newname) {
+ QDR.module.controller("QDR.NodeDialogController", function($scope, QDRService, $uibModalInstance, newname) {
var schema = QDRService.schema;
var myEntities = ['router', 'log', 'listener'];
var typeMap = {
@@ -298,13 +298,13 @@ var QDR = (function(QDR) {
// handle the download button click
// copy the dialog's values to the original node
$scope.download = function() {
- dialog.close({
+ $uibModalInstance.close({
entities: $scope.entities,
annotations: annotations
});
}
$scope.cancel = function() {
- dialog.close()
+ $uibModalInstance.close()
};
$scope.selectAnnotationTab = function(tabName) {
@@ -327,7 +327,7 @@ var QDR = (function(QDR) {
});
- QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, dialog, results) {
+ QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, $uibModalInstance, results) {
var result = results.entities;
var annotations = results.annotations;
var annotationKeys = Object.keys(annotations);
@@ -437,7 +437,7 @@ var QDR = (function(QDR) {
}
$scope.done = function() {
- dialog.close();
+ $uibModalInstance.close();
}
});
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/qdrOverview.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrOverview.js b/console/stand-alone/plugin/js/qdrOverview.js
index d9f9367..303a91d 100644
--- a/console/stand-alone/plugin/js/qdrOverview.js
+++ b/console/stand-alone/plugin/js/qdrOverview.js
@@ -34,7 +34,7 @@ var QDR = (function (QDR) {
*
* Controller that handles the QDR overview page
*/
- QDR.module.controller("QDR.OverviewController", ['$scope', 'QDRService', '$location', '$timeout', '$dialog', function($scope, QDRService, $location, $timeout, $dialog) {
+ QDR.module.controller("QDR.OverviewController", ['$scope', 'QDRService', '$location', '$timeout', '$uibModal', function($scope, QDRService, $location, $timeout, $uibModal) {
console.log("QDR.OverviewControll started with location of " + $location.path() + " and connection of " + QDRService.connected);
var COLUMNSTATEKEY = 'QDRColumnKey.';
@@ -69,8 +69,8 @@ var QDR = (function (QDR) {
$scope.isActive = function (nav) {
return nav == $scope.activeTab;
}
- $scope.filteredLinkFields = []
- $scope.Link = null;
+ $scope.linkFields = []
+ $scope.link = null;
var refreshInterval = 5000
$scope.modes = [
{title: 'Overview', name: 'Overview', right: false}
@@ -208,6 +208,25 @@ var QDR = (function (QDR) {
loadColState($scope.allRouters)
}
+ $scope.routerFields = []
+ $scope.routerGrid = {
+ saveKey: 'routerGrid',
+ data: 'routerFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: 'routerGrid',
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
+ }
+
$scope.router = null;
// get info for a single router
var routerInfo = function (node) {
@@ -459,20 +478,19 @@ var QDR = (function (QDR) {
}
return include;
})
- QDR.log.debug("setting linkFields in updateLinkGrid filteredLinks.length=" + filteredLinks.length)
- $scope.filteredLinkFields = filteredLinks;
+ QDR.log.debug("setting linkFields in updateLinkGrid")
+ $scope.linkFields = filteredLinks;
getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
// if we have a selected link
- if ($scope.Link) {
+ if ($scope.link) {
// find the selected link in the array of all links
- var links = $scope.filteredLinkFields.filter(function (link) {
- return link.name === $scope.Link.data.fields.name;
+ var links = $scope.linkFields.filter(function (link) {
+ return link.name === $scope.link.data.fields.name;
})
if (links.length > 0) {
// linkInfo() is the function that is called by dynatree when a link is selected
// It is passed a dynatree node. We need to simulate that node type to update the link grid
- $scope.Link.data.info({data: {title: links[0].title, fields: links[0]}})
- //linkInfo({data: {title: links[0].title, fields: links[0]}})
+ linkInfo({data: {title: links[0].title, fields: links[0]}})
}
}
}
@@ -484,9 +502,9 @@ var QDR = (function (QDR) {
currentPage: 1
};
var getLinkPagedData = function (pageSize, page) {
- $scope.totalLinks = $scope.filteredLinkFields.length
+ $scope.totalLinks = $scope.linkFields.length
$scope.linksGrid.showFooter = $scope.totalLinks > 50
- $scope.pagedLinkData = $scope.filteredLinkFields.slice((page - 1) * pageSize, page * pageSize);
+ $scope.pagedLinkData = $scope.linkFields.slice((page - 1) * pageSize, page * pageSize);
}
$scope.$watch('linkPagingOptions', function (newVal, oldVal) {
if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
@@ -497,6 +515,16 @@ var QDR = (function (QDR) {
$scope.totalLinks = 0;
$scope.pagedLinkData = []
$scope.selectedLinks = []
+
+ var linkRowTmpl = `
+ <div ng-class="{linkDirIn: row.getProperty('linkDir') == 'in', linkDirOut: row.getProperty('linkDir') == 'out'}">
+ <div ng-style="{ 'cursor': row.cursor }" ng-repeat="col in renderedColumns" ng-class="col.colIndex()" class="ngCell {{col.cellClass}}">
+ <div class="ngVerticalBar" ng-style="{height: rowHeight}" ng-class="{ ngVerticalBarVisible: !$last }"> </div>
+ <div ng-cell></div>
+ </div>
+ </div>
+ `;
+
$scope.linksGrid = {
saveKey: 'linksGrid',
data: 'pagedLinkData',
@@ -573,8 +601,7 @@ var QDR = (function (QDR) {
enableColumnResize: true,
enableColumnReordering: true,
showColumnMenu: true,
- rowTemplate: 'linkRowTemplate.html',
- // aggregateTemplate: "linkAggTemplate.html",
+ rowTemplate: linkRowTmpl,
multiSelect: false,
selectedItems: $scope.selectedLinks,
plugins: [new ngGridFlexibleHeightPlugin()],
@@ -598,6 +625,7 @@ var QDR = (function (QDR) {
})
var loadColState = function (grid) {
+return;
if (!grid)
return;
var columns = localStorage.getItem(COLUMNSTATEKEY+grid.saveKey);
@@ -626,17 +654,17 @@ var QDR = (function (QDR) {
}
var getAllLinkFields = function (completionCallbacks, selectionCallback) {
- if (!$scope.filteredLinkFields) {
- QDR.log.info("$scope.filteredLinkFields was not defined")
+ if (!$scope.linkFields) {
+ QDR.log.info("$scope.linkFields was not defined")
return;
}
var nodeIds = QDRService.nodeIdList()
var linkFields = []
var now = Date.now()
var rate = function (linkName, response, result) {
- if (!$scope.filteredLinkFields)
+ if (!$scope.linkFields)
return 0;
- var oldname = $scope.filteredLinkFields.filter(function (link) {
+ var oldname = $scope.linkFields.filter(function (link) {
return link.link === linkName
})
if (oldname.length === 1) {
@@ -895,10 +923,8 @@ var QDR = (function (QDR) {
})
if (expected === ++received) {
connectionFields.sort ( function (a,b) { return a.host < b.host ? -1 : a.host > b.host ? 1 : 0})
- $timeout( function () {
- callbacks.forEach( function (cb) {
- cb(connectionFields)
- })
+ callbacks.forEach( function (cb) {
+ cb(connectionFields)
})
}
}
@@ -907,14 +933,56 @@ var QDR = (function (QDR) {
})
}
- var SingleEntityGrid = function (name) {
- this.saveKey = name
- this.data = name
- this.columnDefs = [
+ $scope.addressFields = []
+ $scope.addressGrid = {
+ saveKey: 'addGrid',
+ data: 'addressFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: 'addGrid',
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
+ }
+
+ // get info for a single address
+ var addressInfo = function (address) {
+ $scope.address = address
+ var currentEntity = getCurrentLinksEntity();
+ // we are viewing the addressLinks page
+ if (currentEntity === 'Address' && entityModes[currentEntity].currentModeId === 'links') {
+ updateModeLinks()
+ scheduleNextUpdate()
+ return;
+ }
+
+ $scope.addressFields = [];
+ var fields = Object.keys(address.data.fields)
+ fields.forEach( function (field) {
+ if (field != "title" && field != "uid")
+ $scope.addressFields.push({attribute: field, value: address.data.fields[field]})
+ })
+ scheduleNextUpdate()
+ loadColState($scope.addressGrid);
+ }
+
+ $scope.singleLinkFields = []
+ $scope.linkGrid = {
+ saveKey: 'linkGrid',
+ data: 'singleLinkFields',
+ columnDefs: [
{
field: 'attribute',
displayName: 'Attribute',
- saveKey: this.saveKey,
width: '40%'
},
{
@@ -922,43 +990,28 @@ var QDR = (function (QDR) {
displayName: 'Value',
width: '40%'
}
- ]
- this.enableColumnResize = true
- this.multiSelect = false
+ ],
+ enableColumnResize: true,
+ multiSelect: false
}
- $scope.addressFields = []
- $scope.addressGrid = new SingleEntityGrid('addressFields')
- $scope.connectionFields = []
- $scope.connectionGrid = new SingleEntityGrid('connectionFields')
- $scope.routerFields = []
- $scope.routerGrid = new SingleEntityGrid('routerFields')
- $scope.linkFields = []
- $scope.linkGrid = new SingleEntityGrid('linkFields')
-
- var SingleEntityInfo = function (entityName) {
- return function (entity) {
- if (!entity)
- return
- $scope[entityName] = entity
- var currentEntity = getCurrentLinksEntity()
- if (currentEntity === entityName && entityModes[currentEntity] && entityModes[currentEntity].currentModeId === 'links') {
- updateModeLinks()
- scheduleNextUpdate()
- return
- }
- var filteredFields = []
- var fields = Object.keys(entity.data.fields)
- fields.forEach( function (field) {
- if (field != "title" && field != "uid")
- filteredFields.push({attribute: field, value: entity.data.fields[field]})
- })
- $timeout(() => $scope[entityName.toLowerCase()+'Fields'] = filteredFields)
- //$scope[entityName.toLowerCase()+'Fields'] = filteredFields
- console.log("-------------- " + entityName + "Fields -----------")
- console.dump(filteredFields)
- scheduleNextUpdate()
- loadColState($scope[entityName.toLowerCase()+'Grid']);
+
+ // display the grid detail info for a single link
+ var linkInfo = function (link) {
+QDR.log.debug("linkInfo called for " + link.data.key)
+ if (!link) {
+ return;
}
+ $scope.link = link
+
+ $scope.singleLinkFields = [];
+ var fields = Object.keys(link.data.fields)
+ var excludeFields = ["title", "uid", "uncounts", "rawDeliveryCount", "timestamp", "rawAddress"]
+ fields.forEach( function (field) {
+ if (excludeFields.indexOf(field) == -1)
+ $scope.singleLinkFields.push({attribute: field, value: link.data.fields[field]})
+ })
+ scheduleNextUpdate()
+ loadColState($scope.linkGrid);
}
// get info for a single connection
@@ -987,15 +1040,15 @@ var QDR = (function (QDR) {
currentModeId: savedModeIds.Address,
filter: function (response, result) {
var owningAddr = QDRService.valFor(response.attributeNames, result, "owningAddr")
- var id = $scope.Address.data.fields.uid
- return (owningAddr === $scope.Address.data.fields.uid)
+ var id = $scope.address.data.fields.uid
+ return (owningAddr === $scope.address.data.fields.uid)
}
},
Connection: {
currentModeId: savedModeIds.Connection,
filter: function (response, result) {
var connectionId = QDRService.valFor(response.attributeNames, result, "connectionId")
- return (connectionId === $scope.Connection.data.fields.identity)
+ return (connectionId === $scope.connection.data.fields.identity)
}
}
}
@@ -1006,7 +1059,7 @@ var QDR = (function (QDR) {
saveModeIds();
if (mode.id === 'links') {
QDR.log.debug("setting linkFields to [] in selectMode")
- $scope.filteredLinkFields = [];
+ $scope.linkFields = [];
getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
updateModeLinks();
}
@@ -1021,7 +1074,7 @@ QDR.log.debug("setting linkFields to [] in selectMode")
var updateEntityLinkGrid = function (linkFields) {
$timeout(function () {
QDR.log.debug("setting linkFields in updateEntityLinkGrid");
- $scope.filteredLinkFields = linkFields
+ $scope.linkFields = linkFields
getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
})
}
@@ -1072,6 +1125,50 @@ QDR.log.debug("setting linkFields to [] in selectMode")
node.expand(false);
})
}
+ $scope.connectionFields = []
+ $scope.connectionGrid = {
+ saveKey: 'connGrid',
+ data: 'connectionFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: 'connGrid',
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
+ }
+
+ var connectionInfo = function (connection) {
+ if (!connection)
+ return;
+ $scope.connection = connection
+
+ var currentEntity = getCurrentLinksEntity();
+ // we are viewing the connectionLinks page
+ if (currentEntity === 'Connection' && entityModes[currentEntity].currentModeId === 'links') {
+ updateModeLinks()
+ scheduleNextUpdate()
+ return;
+ }
+
+ $scope.connectionFields = [];
+ var fields = Object.keys(connection.data.fields)
+ fields.forEach( function (field) {
+ if (field != "title" && field != "uid")
+ $scope.connectionFields.push({attribute: field, value: connection.data.fields[field]})
+ })
+ // this is missing an argument?
+ loadColState($scope.connectionGrid);
+ }
+
var logModuleCellTemplate = '<div ng-click="logInfoFor(row, col)" class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text>{{COL_FIELD | pretty}}</span></div>'
$scope.logModule = {}
@@ -1149,29 +1246,32 @@ QDR.log.debug("setting linkFields to [] in selectMode")
}
function logDialog(row, col) {
- var d = $dialog.dialog({
- backdrop: false,
- keyboard: true,
- backdropClick: false,
- templateUrl: 'viewLogs.html',
- controller: "QDR.OverviewLogsController",
- resolve: {
- nodeName: function () {
- return row.entity.nodeName
- },
- module: function () {
- return row.entity.name
- },
- level: function () {
- return col.displayName
- },
- nodeId: function () {
- return row.entity.nodeId
- },
- }
- });
- d.open().then(function(result) { console.log("d.open().then"); });
- };
+ var d = $uibModal.open({
+ animation: true,
+ templateUrl: 'viewLogs.html',
+ controller: 'QDR.OverviewLogsController',
+ resolve: {
+ nodeName: function () {
+ return row.entity.nodeName
+ },
+ module: function () {
+ return row.entity.name
+ },
+ level: function () {
+ return col.displayName
+ },
+ nodeId: function () {
+ return row.entity.nodeId
+ },
+ }
+ });
+
+ d.result.then(function (result) {
+ console.log("d.open().then");
+ }, function () {
+ console.log('Modal dismissed at: ' + new Date());
+ });
+ };
var numberTemplate = '<div class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text>{{COL_FIELD | pretty}}</span></div>'
$scope.allLogFields = []
@@ -1420,12 +1520,7 @@ QDR.log.debug("setting linkFields to [] in selectMode")
}
// loads list that was saved
var loadExpandedNodeList = function () {
- try {
- return angular.fromJson(localStorage[OVERVIEWEXPANDEDKEY]) || [];
- } catch (e) {
- QDR.log.debug("localStorage[OVERVIEWEXPANDEDKEY]=" + localStorage[OVERVIEWEXPANDEDKEY])
- return ["Routers"]
- }
+ return angular.fromJson(localStorage[OVERVIEWEXPANDEDKEY]) || [];
}
// called when a node is expanded
// here we save the expanded node so it can be restored when the page reloads
@@ -1442,6 +1537,7 @@ QDR.log.debug("setting linkFields to [] in selectMode")
})
$scope.template = template[0];
}
+ $scope.template = $scope.templates[0]
// activated is called each time a tree node is clicked
// based on which node is clicked, load the correct data grid template and start getting the data
var activated = function (node) {
@@ -1476,7 +1572,8 @@ QDR.log.debug("setting linkFields to [] in selectMode")
// we are currently connected. setup a handler to get notified if we are ever disconnected
QDRService.addDisconnectAction( function () {
- $timeout( () => QDRService.redirectWhenConnected("overview") )
+ QDRService.redirectWhenConnected("overview")
+ $scope.$apply();
})
/* --------------------------------------------------
@@ -1525,6 +1622,7 @@ QDR.log.debug("newly created node needs to be activated")
routers.key = "Routers"
routers.parent = "Routers"
routers.addClass = "routers"
+ routers.isFolder = true
topLevelChildren.push(routers)
// called when the list of routers changes
var updateRouterTree = function (nodes) {
@@ -1553,12 +1651,12 @@ QDR.log.debug("newly created node needs to be activated")
addresses.key = "Addresses"
addresses.parent = "Addresses"
addresses.addClass = "addresses"
+ addresses.isFolder = true
topLevelChildren.push(addresses)
var updateAddressTree = function (addressFields) {
- var info = SingleEntityInfo('Address')
var worker = function (address) {
var a = new Folder(address.title)
- a.info = info
+ a.info = addressInfo
a.key = address.uid
a.fields = address
a.type = "Address"
@@ -1595,15 +1693,15 @@ QDR.log.debug("newly created node needs to be activated")
links.key = "Links"
links.parent = "Links"
links.addClass = "links"
+ links.isFolder = true
topLevelChildren.push(links)
// called both before the tree is created and whenever a background update is done
var updateLinkTree = function (linkFields) {
- var info = SingleEntityInfo('Link')
var worker = function (link) {
var l = new Folder(link.title)
var isConsole = QDRService.isConsoleLink(link)
- l.info = info
+ l.info = linkInfo
l.key = link.uid
l.fields = link
l.type = "Link"
@@ -1628,15 +1726,15 @@ QDR.log.debug("newly created node needs to be activated")
connections.key = "Connections"
connections.parent = "Connections"
connections.addClass = "connections"
+ connections.isFolder = true
topLevelChildren.push(connections)
updateConnectionTree = function (connectionFields) {
- var info = SingleEntityInfo('Connection')
var worker = function (connection) {
var c = new Folder(connection.host)
var isConsole = QDRService.isAConsole (connection.properties, connection.identity, connection.role, connection.routerId)
c.type = "Connection"
- c.info = info
+ c.info = connectionInfo
c.key = connection.uid
c.fields = connection
if (isConsole)
@@ -1676,6 +1774,7 @@ QDR.log.debug("newly created node needs to be activated")
logs.clickFolderMode = 1
logs.key = "Logs"
logs.parent = "Logs"
+ logs.isFolder = true
if (QDRService.versionCheck('0.8.0'))
topLevelChildren.push(logs)
var initTreeAndGrid = function () {
@@ -1693,6 +1792,10 @@ QDR.log.debug("newly created node needs to be activated")
activeVisible: !$scope.largeNetwork,
selectMode: 1,
debugLevel: 0,
+ classNames: {
+ expander: 'fa-angle',
+ connector: 'dynatree-no-connector'
+ },
children: topLevelChildren
})
treeRoot = $("#overtree").dynatree("getRoot");
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/qdrOverviewLogsController.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrOverviewLogsController.js b/console/stand-alone/plugin/js/qdrOverviewLogsController.js
index fed1e3d..832d8aa 100644
--- a/console/stand-alone/plugin/js/qdrOverviewLogsController.js
+++ b/console/stand-alone/plugin/js/qdrOverviewLogsController.js
@@ -21,7 +21,7 @@ under the License.
*/
var QDR = (function(QDR) {
- QDR.module.controller('QDR.OverviewLogsController', function ($scope, dialog, QDRService, $timeout, nodeName, nodeId, module, level) {
+ QDR.module.controller('QDR.OverviewLogsController', function ($scope, $uibModalInstance, QDRService, $timeout, nodeName, nodeId, module, level) {
var gotLogInfo = function (nodeId, entity, response, context) {
var statusCode = context.message.application_properties.statusCode;
@@ -58,7 +58,7 @@ var QDR = (function(QDR) {
$scope.nodeName = nodeName
$scope.logFields = []
$scope.ok = function () {
- dialog.close(true);
+ $uibModalInstance.close(true);
};
});
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/stand-alone/plugin/js/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrTopology.js b/console/stand-alone/plugin/js/qdrTopology.js
index 9899393..23da1bb 100644
--- a/console/stand-alone/plugin/js/qdrTopology.js
+++ b/console/stand-alone/plugin/js/qdrTopology.js
@@ -21,8 +21,9 @@ under the License.
*/
var QDR = (function(QDR) {
- QDR.module.controller('QDR.TopologyFormController', function($scope, QDRService) {
+ QDR.module.controller('QDR.TopologyFormController', function($scope, $rootScope, $timeout, QDRService) {
+ $scope.panelVisible = true // show/hide the panel on the left
$scope.attributes = []
var nameTemplate = '<div title="{{row.entity.description}}" class="ngCellText {{row.entity.cls}}"><span>{{row.entity.attributeName}}</span></div>';
var valueTemplate = '<div title="{{row.entity.attributeValue}}" class="ngCellText {{row.entity.cls}}"><span>{{row.entity.attributeValue}}</span></div>';
@@ -40,18 +41,18 @@ var QDR = (function(QDR) {
cellTemplate: valueTemplate
}]
};
- $scope.form = ''
+ $scope.form = 'router'
$scope.$on('showEntityForm', function(event, args) {
var attributes = args.attributes;
var entityTypes = QDRService.schema.entityTypes[args.entity].attributes;
attributes.forEach(function(attr) {
attr.cls = ''
-QDR.log.debug("attr.description " + attr.description)
if (attr.attributeName === 'Listening on')
attr.cls = 'listening-on'
if (entityTypes[attr.attributeName] && entityTypes[attr.attributeName].description) {
attr.description = entityTypes[attr.attributeName].description
}
+ //QDR.log.debug("attr.description " + attr.description)
})
$scope.attributes = attributes;
$scope.form = args.entity;
@@ -59,6 +60,41 @@ QDR.log.debug("attr.description " + attr.description)
$scope.$on('showAddForm', function(event) {
$scope.form = 'add';
})
+
+ $scope.hideLeftPane = function () {
+ d3.select(".qdr-topology-form")
+ .transition().duration(300).ease("sin-in")
+ .style("left" , "-309px")
+ .each("end", function () {
+ $timeout(function () {
+ QDR.log.debug("done with transition. setting scope ");
+ $scope.panelVisible = false
+ $rootScope.$broadcast('panel-resized')
+ })
+/*
+ d3.select(".qdr-topology-svg")
+ .transition().duration(300).ease("sin-in")
+ .style("margin-left", "30px")
+ .each("end", function () {
+ resize()
+ $timeout(function () {QDR.log.debug("done with transition. setting scope ");$scope.panelVisible = false})
+ })
+*/
+ })}
+
+ $scope.showLeftPane = function () {
+ d3.select(".qdr-topology-form")
+ .transition().duration(300).ease("sin-out")
+ .style("left" , "0px")
+
+ d3.select(".qdr-topology-svg")
+ .transition().duration(300).ease("sin-out")
+ .style("margin-left", "430px")
+ .each("end", function () {
+ resize()
+ $timeout(function () {QDR.log.debug("done with transition. setting scope ");$scope.panelVisible = true})
+ })
+ }
})
/**
@@ -66,41 +102,14 @@ QDR.log.debug("attr.description " + attr.description)
*
* Controller that handles the QDR topology page
*/
- QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'QDRService', '$location', '$timeout', '$dialog',
- function($scope, $rootScope, QDRService, $location, $timeout, $dialog) {
+ QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'QDRService', '$location', '$timeout', '$uibModal',
+ function($scope, $rootScope, QDRService, $location, $timeout, $uibModal) {
- $scope.panelVisible = true // show/hide the panel on the left
$scope.multiData = []
$scope.selectedClient = [];
$scope.quiesceState = {}
var dontHide = false;
- $scope.hideLeftPane = function () {
- d3.select(".qdr-topology.pane.left")
- .transition().duration(300).ease("sin-in")
- .style("left" , "-380px")
-
- d3.select(".panel-adjacent")
- .transition().duration(300).ease("sin-in")
- .style("margin-left", "30px")
- .each("end", function () {
- resize()
- $timeout(function () {QDR.log.debug("done with transition. setting scope ");$scope.panelVisible = false})
- })
- }
- $scope.showLeftPane = function () {
- d3.select(".qdr-topology.pane.left")
- .transition().duration(300).ease("sin-out")
- .style("left" , "0px")
-
- d3.select(".panel-adjacent")
- .transition().duration(300).ease("sin-out")
- .style("margin-left", "430px")
- .each("end", function () {
- resize()
- $timeout(function () {QDR.log.debug("done with transition. setting scope ");$scope.panelVisible = true})
- })
- }
$scope.quiesceConnection = function(row) {
var entity = row.entity;
var state = $scope.quiesceState[entity.connectionId].state;
@@ -335,7 +344,6 @@ QDR.log.debug("attr.description " + attr.description)
];
$scope.mode = "Diagram";
$scope.contextNode = null; // node that is associated with the current context menu
-
$scope.isModeActive = function(name) {
if ((name == 'Add Router' || name == 'Diagram') && $scope.addingNode.step > 0)
return true;
@@ -547,6 +555,10 @@ QDR.log.debug("attr.description " + attr.description)
force.size(sizes).resume();
}
}
+
+ $scope.$on('panel-resized', function () {
+ resize()
+ })
window.addEventListener('resize', resize);
var sizes = getSizes()
width = sizes[0]
@@ -990,7 +1002,7 @@ QDR.log.debug("attr.description " + attr.description)
});
}
}
- $scope.$broadcast('showEntityForm', {
+ $rootScope.$broadcast('showEntityForm', {
entity: entity,
attributes: attributes
})
@@ -2113,7 +2125,7 @@ QDR.log.debug("attr.description " + attr.description)
function doAddDialog(NewRouterName) {
QDRService.ensureAllEntities({entity: ".listener"}, function () {
- var d = $dialog.dialog({
+ var d = $uibModal.open({
dialogClass: "modal dlg-large",
backdrop: true,
keyboard: true,
@@ -2127,7 +2139,7 @@ QDR.log.debug("attr.description " + attr.description)
}
});
$timeout(function () {
- d.open().then(function(result) {
+ d.result.then(function(result) {
if (result)
doDownloadDialog(result);
});
@@ -2136,7 +2148,7 @@ QDR.log.debug("attr.description " + attr.description)
};
function doDownloadDialog(result) {
- d = $dialog.dialog({
+ d = $uibModal.open({
backdrop: true,
keyboard: true,
backdropClick: true,
@@ -2148,7 +2160,7 @@ QDR.log.debug("attr.description " + attr.description)
}
}
});
- d.open().then(function(result) {
+ d.result.then(function(result) {
//QDR.log.debug("download dialog done")
})
if (!$scope.$$phase) $scope.$apply()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[3/4] qpid-dispatch git commit: DISPATCH-745 Remove symlinks from
hawtio to stand-alone
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
deleted file mode 120000
index de6a7a1..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/qdrOverview.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
new file mode 100644
index 0000000..d9f9367
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
@@ -0,0 +1,1766 @@
+/*
+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
+ */
+/**
+ * @module QDR
+ */
+var QDR = (function (QDR) {
+
+ /**
+ * @method OverviewController
+ * @param $scope
+ * @param QDRService
+ * @param QDRChartServer
+ * dialogServer
+ * $location
+ *
+ * Controller that handles the QDR overview page
+ */
+ QDR.module.controller("QDR.OverviewController", ['$scope', 'QDRService', '$location', '$timeout', '$dialog', function($scope, QDRService, $location, $timeout, $dialog) {
+
+ console.log("QDR.OverviewControll started with location of " + $location.path() + " and connection of " + QDRService.connected);
+ var COLUMNSTATEKEY = 'QDRColumnKey.';
+ var OVERVIEWEXPANDEDKEY = "QDROverviewExpanded"
+ var OVERVIEWACTIVATEDKEY = "QDROverviewActivated"
+ var FILTERKEY = "QDROverviewFilters"
+ var OVERVIEWMODEIDS = "QDROverviewModeIds"
+ var treeRoot; // the dynatree root node. initialized once log data is received
+
+ // we want attributes to be listed first, so add it at index 0
+ $scope.subLevelTabs = [{
+ content: '<i class="icon-list"></i> Attributes',
+ title: "View the attribute values on your selection",
+ isValid: function (workspace) { return true; },
+ href: function () { return "#/" + QDR.pluginName + "/attributes"; },
+ index: 0
+ },
+ {
+ content: '<i class="icon-leaf"></i> Operations',
+ title: "Execute operations on your selection",
+ isValid: function (workspace) { return true; },
+ href: function () { return "#/" + QDR.pluginName + "/operations"; },
+ index: 1
+ }]
+ $scope.activeTab = $scope.subLevelTabs[0];
+ $scope.setActive = function (nav) {
+ $scope.activeTab = nav;
+ }
+ $scope.isValid = function (nav) {
+ return nav.isValid()
+ }
+ $scope.isActive = function (nav) {
+ return nav == $scope.activeTab;
+ }
+ $scope.filteredLinkFields = []
+ $scope.Link = null;
+ var refreshInterval = 5000
+ $scope.modes = [
+ {title: 'Overview', name: 'Overview', right: false}
+ ];
+
+ $scope.tmplOverviewTree = QDR.templatePath + 'tmplOverviewTree.html';
+ $scope.templates = [
+ { name: 'Routers', url: 'routers.html'},
+ { name: 'Router', url: 'router.html'},
+ { name: 'Addresses', url: 'addresses.html'},
+ { name: 'Address', url: 'address.html'},
+ { name: 'Links', url: 'links.html'},
+ { name: 'Link', url: 'link.html'},
+ { name: 'Connections', url: 'connections.html'},
+ { name: 'Connection', url: 'connection.html'},
+ { name: 'Logs', url: 'logs.html'},
+ { name: 'Log', url: 'logModule.html'}
+ ];
+ var topLevelChildren = [];
+
+ $scope.allRouterSelected = function (row ) {
+ console.log("row selected" + row)
+ }
+ function afterSelectionChange(rowItem, checkAll) {
+ var nodeId = rowItem.entity.nodeId;
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+
+ $scope.routerPagingOptions = {
+ pageSizes: [50, 100, 500],
+ pageSize: 50,
+ currentPage: 1
+ };
+ var getPagedData = function (pageSize, page) {
+ $scope.totalRouters = $scope.allRouterFields.length
+ $scope.allRouters.showFooter = $scope.totalRouters > 50
+ $scope.pagedRouterFields = $scope.allRouterFields.slice((page - 1) * pageSize, page * pageSize);
+ }
+ $scope.$watch('pagingOptions', function (newVal, oldVal) {
+ if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
+ getPagedData($scope.routerPagingOptions.pageSize, $scope.routerPagingOptions.currentPage);
+ }
+ }, true);
+
+ $scope.totalRouters = 0;
+ $scope.allRouterFields = [];
+ $scope.pagedRouterFields = [];
+ $scope.allRouterSelections = [];
+ $scope.allRouters = {
+ saveKey: 'allRouters',
+ data: 'pagedRouterFields',
+ columnDefs: [
+ {
+ field: 'id',
+ saveKey: 'allRouters',
+ displayName: 'Router'
+ },
+ {
+ field: 'area',
+ displayName: 'Area'
+ },
+ {
+ field: 'mode',
+ displayName: 'Mode'
+ },
+ {
+ field: 'connections',
+ displayName: 'External connections'
+ },
+ {
+ field: 'addrCount',
+ displayName: 'Address count'
+ },
+ {
+ field: 'linkCount',
+ displayName: 'Link count'
+ }
+ ],
+ enableColumnResize: true,
+ enablePaging: true,
+ showFooter: $scope.totalRouters > 50,
+ totalServerItems: 'totalRouters',
+ pagingOptions: $scope.routerPagingOptions,
+ multiSelect: false,
+ selectedItems: $scope.allRouterSelections,
+ plugins: [new ngGridFlexibleHeightPlugin()],
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = $scope.allRouterSelections[0]
+ var nodeId = selItem.nodeId
+ // activate Routers->nodeId in the tree
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
+
+ // get info for all routers
+ var allRouterInfo = function () {
+ var nodes = {}
+ // gets called each node/entity response
+ var gotNode = function (nodeName, entity, response) {
+ if (!nodes[nodeName])
+ nodes[angular.copy(nodeName)] = {}
+ nodes[nodeName][entity] = angular.copy(response);
+ }
+ // send the requests for all connection and router info for all routers
+ QDRService.fetchAllEntities([{entity: ".connection", attrs: ["role"]}], function () {
+ QDRService.fetchAllEntities([{entity: ".router"}], function () {
+ // we have all the data now in the nodes object
+ var allRouterFields = []
+ for (var node in nodes) {
+ var connections = 0
+ for (var i=0; i<nodes[node][".connection"].results.length; ++i) {
+ // we only requested "role" so it will be at [0]
+ if (nodes[node][".connection"].results[i][0] === 'inter-router')
+ ++connections
+ }
+ var routerRow = {connections: connections, nodeId: node, id: QDRService.nameFromId(node)}
+ nodes[node][".router"].attributeNames.forEach( function (routerAttr, i) {
+ if (routerAttr !== "routerId" && routerAttr !== "id")
+ routerRow[routerAttr] = nodes[node][".router"].results[0][i]
+ })
+ allRouterFields.push(routerRow)
+ }
+ $timeout(function () {
+ $scope.allRouterFields = allRouterFields
+ getPagedData($scope.routerPagingOptions.pageSize, $scope.routerPagingOptions.currentPage);
+ updateRouterTree(nodeIds)
+ scheduleNextUpdate()
+ //if ($scope.router)
+ // routerInfo($scope.router)
+ })
+ }, gotNode)
+ }, gotNode)
+ loadColState($scope.allRouters)
+ }
+
+ $scope.router = null;
+ // get info for a single router
+ var routerInfo = function (node) {
+ $scope.router = node
+
+ var routerFields = [];
+ $scope.allRouterFields.some( function (field) {
+ if (field.id === node.data.title) {
+ Object.keys(field).forEach ( function (key) {
+ if (key !== '$$hashKey') {
+ var attr = (key === 'connections') ? 'External connections' : key
+ routerFields.push({attribute: attr, value: field[key]})
+ }
+ })
+ return true
+ }
+ })
+ $timeout(function () {$scope.routerFields = routerFields})
+ scheduleNextUpdate()
+ loadColState($scope.routerGrid);
+ }
+
+ $scope.addressPagingOptions = {
+ pageSizes: [50, 100, 500],
+ pageSize: 50,
+ currentPage: 1
+ };
+ var getAddressPagedData = function (pageSize, page) {
+ $scope.totalAddresses = $scope.addressesData.length
+ $scope.addressesGrid.showFooter = $scope.totalAddresses > 50
+ $scope.pagedAddressesData = $scope.addressesData.slice((page - 1) * pageSize, page * pageSize);
+ }
+ $scope.$watch('addressPagingOptions', function (newVal, oldVal) {
+ if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
+ getAddressPagedData($scope.addressPagingOptions.pageSize, $scope.addressPagingOptions.currentPage);
+ }
+ }, true);
+
+ $scope.totalAddresses = 0;
+ $scope.pagedAddressesData = []
+ $scope.addressesData = []
+ $scope.selectedAddresses = []
+ $scope.addressesGrid = {
+ saveKey: 'addressesGrid',
+ data: 'pagedAddressesData',
+ columnDefs: [
+ {
+ field: 'address',
+ saveKey: 'addressesGrid',
+ displayName: 'address'
+ },
+ {
+ field: 'class',
+ displayName: 'class'
+ },
+ {
+ field: 'phase',
+ displayName: 'phase',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'inproc',
+ displayName: 'in-proc'
+ },
+ {
+ field: 'local',
+ displayName: 'local',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'remote',
+ displayName: 'remote',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'in',
+ displayName: 'in',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'out',
+ displayName: 'out',
+ cellClass: 'grid-align-value'
+ }
+ ],
+ enablePaging: true,
+ showFooter: $scope.totalAddresses > 50,
+ totalServerItems: 'totalAddresses',
+ pagingOptions: $scope.addressPagingOptions,
+ enableColumnResize: true,
+ multiSelect: false,
+ selectedItems: $scope.selectedAddresses,
+ plugins: [new ngGridFlexibleHeightPlugin()],
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = data.entity;
+ var nodeId = selItem.uid
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
+
+ // get info for all addresses
+ var allAddressInfo = function () {
+ var nodes = {}
+ // gets called each node/entity response
+ var gotNode = function (nodeName, entity, response) {
+ if (!nodes[nodeName])
+ nodes[nodeName] = {}
+ nodes[nodeName][entity] = angular.copy(response);
+ }
+ var addr_class = function (addr) {
+ if (!addr) return "-"
+ if (addr[0] == 'M') return "mobile"
+ if (addr[0] == 'R') return "router"
+ if (addr[0] == 'A') return "area"
+ if (addr[0] == 'L') return "local"
+ if (addr[0] == 'C') return "link-incoming"
+ if (addr[0] == 'D') return "link-outgoing"
+ if (addr[0] == 'T') return "topo"
+ return "unknown: " + addr[0]
+ }
+ var addr_phase = function (addr) {
+ if (!addr)
+ return "-"
+ if (addr[0] == 'M')
+ return addr[1]
+ return ''
+ }
+ var prettyVal = function (val) {
+ return QDRService.pretty(val || "-")
+ }
+ var addressFields = []
+ var addressObjs = {}
+ // send the requests for all connection and router info for all routers
+ QDRService.fetchAllEntities({entity: ".router.address"}, function () {
+ for (var node in nodes) {
+ var response = nodes[node][".router.address"]
+ response.results.forEach( function (result) {
+ var address = QDRService.flatten(response.attributeNames, result)
+
+ var addNull = function (oldVal, newVal) {
+ if (oldVal != null && newVal != null)
+ return oldVal + newVal
+ if (oldVal != null)
+ return oldVal
+ return newVal
+ }
+
+ var uid = address.identity
+ var identity = QDRService.identity_clean(uid)
+
+ if (!addressObjs[QDRService.addr_text(identity)+QDRService.addr_class(identity)])
+ addressObjs[QDRService.addr_text(identity)+QDRService.addr_class(identity)] = {
+ address: QDRService.addr_text(identity),
+ 'class': QDRService.addr_class(identity),
+ phase: addr_phase(identity),
+ inproc: address.inProcess,
+ local: address.subscriberCount,
+ remote: address.remoteCount,
+ 'in': address.deliveriesIngress,
+ out: address.deliveriesEgress,
+ thru: address.deliveriesTransit,
+ toproc: address.deliveriesToContainer,
+ fromproc:address.deliveriesFromContainer,
+ uid: uid
+ }
+ else {
+ var sumObj = addressObjs[QDRService.addr_text(identity)+QDRService.addr_class(identity)]
+ sumObj.inproc = addNull(sumObj.inproc, address.inproc)
+ sumObj.local = addNull(sumObj.local, address.local)
+ sumObj.remote = addNull(sumObj.remote, address.remote)
+ sumObj['in'] = addNull(sumObj['in'], address['in'])
+ sumObj.out = addNull(sumObj.out, address.out)
+ sumObj.thru = addNull(sumObj.thru, address.thru)
+ sumObj.toproc = addNull(sumObj.toproc, address.toproc)
+ sumObj.fromproc = addNull(sumObj.fromproc, address.fromproc)
+ }
+/*
+ addressFields.push({
+ address: QDRService.addr_text(identity),
+ 'class': QDRService.addr_class(identity),
+ phase: addr_phase(identity),
+ inproc: prettySum("inProcess"),
+ local: prettySum("subscriberCount"),
+ remote: prettySum("remoteCount"),
+ 'in': prettySum("deliveriesIngress"),
+ out: prettySum("deliveriesEgress"),
+ thru: prettySum("deliveriesTransit"),
+ toproc: prettySum("deliveriesToContainer"),
+ fromproc:prettySum("deliveriesFromContainer"),
+ uid: uid
+ })
+*/
+ })
+ }
+ for (var obj in addressObjs) {
+ addressObjs[obj].inproc = prettyVal(addressObjs[obj].inproc)
+ addressObjs[obj].local = prettyVal(addressObjs[obj].local)
+ addressObjs[obj].remote = prettyVal(addressObjs[obj].remote)
+ addressObjs[obj]['in'] = prettyVal(addressObjs[obj]['in'])
+ addressObjs[obj].out = prettyVal(addressObjs[obj].out)
+ addressObjs[obj].thru = prettyVal(addressObjs[obj].thru)
+ addressObjs[obj].toproc = prettyVal(addressObjs[obj].toproc)
+ addressObjs[obj].fromproc = prettyVal(addressObjs[obj].fromproc)
+ addressFields.push(addressObjs[obj])
+ }
+ if (addressFields.length === 0)
+ return;
+ // update the grid's data
+ addressFields.sort ( function (a,b) {
+ return a.address + a['class'] < b.address + b['class'] ? -1 : a.address + a['class'] > b.address + b['class'] ? 1 : 0}
+ )
+ // callapse all records with same addres+class
+ for (var i=1; i<addressFields.length; ++i) {
+
+ }
+ addressFields[0].title = addressFields[0].address
+ for (var i=1; i<addressFields.length; ++i) {
+ // if this address is the same as the previous address, add a class to the display titles
+ if (addressFields[i].address === addressFields[i-1].address) {
+ addressFields[i-1].title = addressFields[i-1].address + " (" + addressFields[i-1]['class'] + ")"
+ addressFields[i].title = addressFields[i].address + " (" + addressFields[i]['class'] + ")"
+ } else
+ addressFields[i].title = addressFields[i].address
+ }
+ $timeout(function () {
+ $scope.addressesData = addressFields
+ getAddressPagedData($scope.addressPagingOptions.pageSize, $scope.addressPagingOptions.currentPage);
+ // repopulate the tree's child nodes
+ updateAddressTree(addressFields)
+ scheduleNextUpdate()
+ })
+ }, gotNode)
+ loadColState($scope.addressesGrid);
+ }
+
+ var updateLinkGrid = function ( linkFields ) {
+ // apply the filter
+ var filteredLinks = linkFields.filter( function (link) {
+ var include = true;
+ if ($scope.filter.endpointsOnly === "true") {
+ if (link.linkType !== 'endpoint')
+ include = false;
+ }
+ if ($scope.filter.hideConsoles) {
+ if (QDRService.isConsoleLink(link))
+ include = false;
+ }
+ return include;
+ })
+ QDR.log.debug("setting linkFields in updateLinkGrid filteredLinks.length=" + filteredLinks.length)
+ $scope.filteredLinkFields = filteredLinks;
+ getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
+ // if we have a selected link
+ if ($scope.Link) {
+ // find the selected link in the array of all links
+ var links = $scope.filteredLinkFields.filter(function (link) {
+ return link.name === $scope.Link.data.fields.name;
+ })
+ if (links.length > 0) {
+ // linkInfo() is the function that is called by dynatree when a link is selected
+ // It is passed a dynatree node. We need to simulate that node type to update the link grid
+ $scope.Link.data.info({data: {title: links[0].title, fields: links[0]}})
+ //linkInfo({data: {title: links[0].title, fields: links[0]}})
+ }
+ }
+ }
+
+ // get info for a all links
+ $scope.linkPagingOptions = {
+ pageSizes: [50, 100, 500],
+ pageSize: 50,
+ currentPage: 1
+ };
+ var getLinkPagedData = function (pageSize, page) {
+ $scope.totalLinks = $scope.filteredLinkFields.length
+ $scope.linksGrid.showFooter = $scope.totalLinks > 50
+ $scope.pagedLinkData = $scope.filteredLinkFields.slice((page - 1) * pageSize, page * pageSize);
+ }
+ $scope.$watch('linkPagingOptions', function (newVal, oldVal) {
+ if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
+ getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
+ }
+ }, true);
+
+ $scope.totalLinks = 0;
+ $scope.pagedLinkData = []
+ $scope.selectedLinks = []
+ $scope.linksGrid = {
+ saveKey: 'linksGrid',
+ data: 'pagedLinkData',
+ columnDefs: [
+ {
+ field: 'link',
+ displayName: 'Link',
+ groupable: false,
+ saveKey: 'linksGrid',
+ width: '11%'
+ },
+ {
+ field: 'linkType',
+ displayName: 'Link type',
+ groupable: false,
+ width: '9%'
+ },
+ {
+ field: 'linkDir',
+ displayName: 'Link dir',
+ groupable: false,
+ width: '8%'
+ },
+ {
+ field: 'adminStatus',
+ displayName: 'Admin status',
+ groupable: false,
+ width: '9%'
+ },
+ {
+ field: 'operStatus',
+ displayName: 'Oper status',
+ groupable: false,
+ width: '9%'
+ },
+ {
+ field: 'deliveryCount',
+ displayName: 'Delivery Count',
+ groupable: false,
+ cellClass: 'grid-align-value',
+ width: '11%'
+ },
+ {
+ field: 'rate',
+ displayName: 'Rate',
+ groupable: false,
+ cellClass: 'grid-align-value',
+ width: '8%'
+ },
+ {
+ field: 'uncounts',
+ displayName: 'Outstanding',
+ groupable: false,
+ cellClass: 'grid-align-value',
+ width: '9%'
+ },
+ {
+ field: 'owningAddr',
+ displayName: 'Address',
+ groupable: false,
+ width: '15%'
+ }/*,
+ {
+ displayName: 'Quiesce',
+ cellClass: 'gridCellButton',
+ cellTemplate: '<button title="{{quiesceLinkText(row)}} this link" type="button" ng-class="quiesceLinkClass(row)" class="btn" ng-click="quiesceLink(row, $event)" ng-disabled="quiesceLinkDisabled(row)">{{quiesceLinkText(row)}}</button>',
+ width: '10%'
+ }*/
+ ],
+ enablePaging: true,
+ showFooter: $scope.totalLinks > 50,
+ totalServerItems: 'totalLinks',
+ pagingOptions: $scope.linkPagingOptions,
+ enableColumnResize: true,
+ enableColumnReordering: true,
+ showColumnMenu: true,
+ rowTemplate: 'linkRowTemplate.html',
+ // aggregateTemplate: "linkAggTemplate.html",
+ multiSelect: false,
+ selectedItems: $scope.selectedLinks,
+ plugins: [new ngGridFlexibleHeightPlugin()],
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = data.entity;
+ var nodeId = selItem.uid
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
+
+
+ $scope.$on('ngGridEventColumns', function (e, columns) {
+ var saveInfo = columns.map( function (col) {
+ return [col.width, col.visible]
+ })
+ var saveKey = columns[0].colDef.saveKey
+ if (saveKey)
+ localStorage.setItem(COLUMNSTATEKEY+saveKey, JSON.stringify(saveInfo));
+ })
+
+ var loadColState = function (grid) {
+ if (!grid)
+ return;
+ var columns = localStorage.getItem(COLUMNSTATEKEY+grid.saveKey);
+ if (columns) {
+ var cols = JSON.parse(columns);
+ cols.forEach( function (col, index) {
+ if (grid.columnDefs[index]) {
+ grid.columnDefs[index].width = col[0];
+ grid.columnDefs[index].visible = col[1]
+ }
+ })
+ }
+ }
+ var allLinkInfo = function () {
+ var gridCallback = function (linkFields) {
+ QDRService.ensureAllEntities({entity: ".connection", force: true}, function () {
+ // only update the grid with these fields if the List tree node is selected
+ // this is becuase we are using the link grid in other places and we don't want to overwrite it
+ if ($scope.template.name === "Links")
+ updateLinkGrid(linkFields)
+ updateLinkTree(linkFields)
+ })
+ }
+ getAllLinkFields([gridCallback, scheduleNextUpdate])
+ loadColState($scope.linksGrid);
+ }
+
+ var getAllLinkFields = function (completionCallbacks, selectionCallback) {
+ if (!$scope.filteredLinkFields) {
+ QDR.log.info("$scope.filteredLinkFields was not defined")
+ return;
+ }
+ var nodeIds = QDRService.nodeIdList()
+ var linkFields = []
+ var now = Date.now()
+ var rate = function (linkName, response, result) {
+ if (!$scope.filteredLinkFields)
+ return 0;
+ var oldname = $scope.filteredLinkFields.filter(function (link) {
+ return link.link === linkName
+ })
+ if (oldname.length === 1) {
+ var elapsed = (now - oldname[0].timestamp) / 1000;
+ if (elapsed < 0)
+ return 0
+ var delivered = QDRService.valFor(response.attributeNames, result, "deliveryCount") - oldname[0].rawDeliveryCount
+ //QDR.log.debug("elapsed " + elapsed + " delivered " + delivered)
+ return elapsed > 0 ? parseFloat(Math.round((delivered/elapsed) * 100) / 100).toFixed(2) : 0;
+ } else {
+ //QDR.log.debug("unable to find old linkName")
+ return 0
+ }
+ }
+ var expected = nodeIds.length;
+ var received = 0;
+ var gotLinkInfo = function (nodeName, entity, response) {
+ response.results.forEach( function (result) {
+ var nameIndex = response.attributeNames.indexOf('name')
+ var prettyVal = function (field) {
+ var fieldIndex = response.attributeNames.indexOf(field)
+ if (fieldIndex < 0) {
+ return "-"
+ }
+ var val = result[fieldIndex]
+ return QDRService.pretty(val)
+ }
+ var uncounts = function () {
+ var und = QDRService.valFor(response.attributeNames, result, "undeliveredCount")
+ var uns = QDRService.valFor(response.attributeNames, result, "unsettledCount")
+ return QDRService.pretty(und + uns)
+ }
+ var linkName = function () {
+ var namestr = QDRService.nameFromId(nodeName)
+ return namestr + ':' + QDRService.valFor(response.attributeNames, result, "identity")
+ }
+ var fixAddress = function () {
+ var addresses = []
+ var owningAddr = QDRService.valFor(response.attributeNames, result, "owningAddr") || ""
+ var rawAddress = owningAddr
+ /*
+ - "L*" => "* (local)"
+ - "M0*" => "* (direct)"
+ - "M1*" => "* (dequeue)"
+ - "MX*" => "* (phase X)"
+ */
+ var address = undefined;
+ var starts = {'L': '(local)', 'M0': '(direct)', 'M1': '(dequeue)'}
+ for (var start in starts) {
+ if (owningAddr.startsWith(start)) {
+ var ends = owningAddr.substr(start.length)
+ address = ends + " " + starts[start]
+ rawAddress = ends
+ break;
+ }
+ }
+ if (!address) {
+ // check for MX*
+ if (owningAddr.length > 3) {
+ if (owningAddr[0] === 'M') {
+ var phase = parseInt(owningAddress.substr(1))
+ if (phase && !isNaN(phase)) {
+ var phaseStr = phase + "";
+ var star = owningAddress.substr(2 + phaseStr.length)
+ address = star + " " + "(phase " + phaseStr + ")"
+ }
+ }
+ }
+ }
+ addresses[0] = address || owningAddr
+ addresses[1] = rawAddress
+ return addresses
+ }
+ if (!selectionCallback || selectionCallback(response, result)) {
+ var adminStatus = QDRService.valFor(response.attributeNames, result, "adminStatus")
+ var operStatus = QDRService.valFor(response.attributeNames, result, "operStatus")
+ var linkName = linkName()
+ var linkType = QDRService.valFor(response.attributeNames, result, "linkType")
+ var addresses = fixAddress();
+ var link = QDRService.flatten(response.attributeNames, result)
+ linkFields.push({
+ link: linkName,
+ title: linkName,
+ uncounts: uncounts(),
+ operStatus: operStatus,
+ adminStatus:adminStatus,
+ owningAddr: addresses[0],
+
+ acceptedCount: prettyVal("acceptedCount"),
+ modifiedCount: prettyVal("modifiedCount"),
+ presettledCount: prettyVal("presettledCount"),
+ rejectedCount: prettyVal("rejectedCount"),
+ releasedCount: prettyVal("releasedCount"),
+ deliveryCount:prettyVal("deliveryCount") + " ",
+
+ rate: QDRService.pretty(rate(linkName, response, result)),
+ capacity: link.capacity,
+ undeliveredCount: link.undeliveredCount,
+ unsettledCount: link.unsettledCount,
+
+ rawAddress: addresses[1],
+ rawDeliveryCount: link.deliveryCount,
+ name: link.name,
+ linkName: link.linkName,
+ connectionId: link.connectionId,
+ linkDir: link.linkDir,
+ linkType: linkType,
+ peer: link.peer,
+ type: link.type,
+
+ uid: linkName,
+ timestamp: now,
+ nodeId: nodeName,
+ identity: link.identity,
+ })
+ }
+ })
+ if (expected === ++received) {
+ linkFields.sort ( function (a,b) { return a.link < b.link ? -1 : a.link > b.link ? 1 : 0})
+ completionCallbacks.forEach( function (cb) {
+ cb(linkFields)
+ })
+ }
+ }
+ nodeIds.forEach( function (nodeId) {
+ QDRService.fetchEntity(nodeId, "router.link", [], gotLinkInfo);
+ })
+ }
+
+ $scope.connectionPagingOptions = {
+ pageSizes: [50, 100, 500],
+ pageSize: 50,
+ currentPage: 1
+ };
+ var getConnectionPagedData = function (pageSize, page) {
+ $scope.totalConnections = $scope.allConnectionFields.length
+ $scope.allConnectionGrid.showFooter = $scope.totalConnections > 50
+ $scope.pagedConnectionsData = $scope.allConnectionFields.slice((page - 1) * pageSize, page * pageSize);
+ }
+ $scope.$watch('connectionPagingOptions', function (newVal, oldVal) {
+ if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
+ getConnectionPagedData($scope.connectionPagingOptions.pageSize, $scope.connectionPagingOptions.currentPage);
+ }
+ }, true);
+
+ $scope.totalConnections = 0;
+ $scope.pagedConnectionsData = []
+ $scope.allConnectionFields = []
+ $scope.allConnectionSelections = [];
+ $scope.allConnectionGrid = {
+ saveKey: 'allConnGrid',
+ data: 'pagedConnectionsData',
+ columnDefs: [
+ {
+ field: 'host',
+ saveKey: 'allConnGrid',
+ displayName: 'host'
+ },
+ {
+ field: 'container',
+ displayName: 'container'
+ },
+ {
+ field: 'role',
+ displayName: 'role'
+ },
+ {
+ field: 'dir',
+ displayName: 'dir'
+ },
+ {
+ field: 'security',
+ displayName: 'security'
+ },
+ {
+ field: 'authentication',
+ displayName: 'authentication'
+ },
+ ],
+ enablePaging: true,
+ showFooter: $scope.totalConnections > 50,
+ totalServerItems: 'totalConnections',
+ pagingOptions: $scope.connectionPagingOptions,
+ enableColumnResize: true,
+ multiSelect: false,
+ selectedItems: $scope.allConnectionSelections,
+ plugins: [new ngGridFlexibleHeightPlugin()],
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = $scope.allConnectionSelections[0]
+ var nodeId = selItem.uid
+ // activate Routers->nodeId in the tree
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
+ // get info for a all connections
+ var allConnectionInfo = function () {
+ getAllConnectionFields([updateConnectionGrid, updateConnectionTree, scheduleNextUpdate])
+ loadColState($scope.allConnectionGrid);
+ }
+ // called after conection data is available
+ var updateConnectionGrid = function (connectionFields) {
+ $scope.allConnectionFields = connectionFields;
+ getConnectionPagedData($scope.connectionPagingOptions.pageSize, $scope.connectionPagingOptions.currentPage);
+ }
+
+ // get the connection data for all nodes
+ // called periodically
+ // creates a connectionFields array and calls the callbacks (updateTree and updateGrid)
+ var getAllConnectionFields = function (callbacks) {
+ var nodeIds = QDRService.nodeIdList()
+ var connectionFields = [];
+ var expected = nodeIds.length;
+ var received = 0;
+ var gotConnectionInfo = function (nodeName, entity, response) {
+ response.results.forEach( function (result) {
+
+ var auth = "no_auth"
+ var sasl = QDRService.valFor(response.attributeNames, result, "sasl")
+ if (QDRService.valFor(response.attributeNames, result, "isAuthenticated")) {
+ auth = sasl
+ if (sasl === "ANONYMOUS")
+ auth = "anonymous-user"
+ else {
+ if (sasl === "GSSAPI")
+ sasl = "Kerberos"
+ if (sasl === "EXTERNAL")
+ sasl = "x.509"
+ auth = QDRService.valFor(response.attributeNames, result, "user") + "(" +
+ QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
+ }
+ }
+
+ var sec = "no-security"
+ if (QDRService.valFor(response.attributeNames, result, "isEncrypted")) {
+ if (sasl === "GSSAPI")
+ sec = "Kerberos"
+ else
+ sec = QDRService.valFor(response.attributeNames, result, "sslProto") + "(" +
+ QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
+ }
+
+ var host = QDRService.valFor(response.attributeNames, result, "host")
+ var connField = {
+ host: host,
+ security: sec,
+ authentication: auth,
+ routerId: nodeName,
+ uid: host + QDRService.valFor(response.attributeNames, result, "identity")
+ }
+ response.attributeNames.forEach( function (attribute, i) {
+ connField[attribute] = result[i]
+ })
+ connectionFields.push(connField)
+ })
+ if (expected === ++received) {
+ connectionFields.sort ( function (a,b) { return a.host < b.host ? -1 : a.host > b.host ? 1 : 0})
+ $timeout( function () {
+ callbacks.forEach( function (cb) {
+ cb(connectionFields)
+ })
+ })
+ }
+ }
+ nodeIds.forEach( function (nodeId) {
+ QDRService.fetchEntity(nodeId, ".connection", [], gotConnectionInfo)
+ })
+ }
+
+ var SingleEntityGrid = function (name) {
+ this.saveKey = name
+ this.data = name
+ this.columnDefs = [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: this.saveKey,
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ]
+ this.enableColumnResize = true
+ this.multiSelect = false
+ }
+ $scope.addressFields = []
+ $scope.addressGrid = new SingleEntityGrid('addressFields')
+ $scope.connectionFields = []
+ $scope.connectionGrid = new SingleEntityGrid('connectionFields')
+ $scope.routerFields = []
+ $scope.routerGrid = new SingleEntityGrid('routerFields')
+ $scope.linkFields = []
+ $scope.linkGrid = new SingleEntityGrid('linkFields')
+
+ var SingleEntityInfo = function (entityName) {
+ return function (entity) {
+ if (!entity)
+ return
+ $scope[entityName] = entity
+ var currentEntity = getCurrentLinksEntity()
+ if (currentEntity === entityName && entityModes[currentEntity] && entityModes[currentEntity].currentModeId === 'links') {
+ updateModeLinks()
+ scheduleNextUpdate()
+ return
+ }
+ var filteredFields = []
+ var fields = Object.keys(entity.data.fields)
+ fields.forEach( function (field) {
+ if (field != "title" && field != "uid")
+ filteredFields.push({attribute: field, value: entity.data.fields[field]})
+ })
+ $timeout(() => $scope[entityName.toLowerCase()+'Fields'] = filteredFields)
+ //$scope[entityName.toLowerCase()+'Fields'] = filteredFields
+ console.log("-------------- " + entityName + "Fields -----------")
+ console.dump(filteredFields)
+ scheduleNextUpdate()
+ loadColState($scope[entityName.toLowerCase()+'Grid']);
+ }
+ }
+
+ // get info for a single connection
+ $scope.gridModes = [{
+ content: '<a><i class="icon-list"></i> Attriutes</a>',
+ id: 'attributes',
+ title: "View attributes"
+ },
+ {
+ content: '<a><i class="icon-link"></i> Links</a>',
+ id: 'links',
+ title: "Show links"
+ }
+ ];
+ var saveModeIds = function () {
+ var modeIds = {Address: entityModes.Address.currentModeId, Connection: entityModes.Connection.currentModeId}
+ localStorage[OVERVIEWMODEIDS] = JSON.stringify(modeIds)
+ }
+ var loadModeIds = function () {
+ return angular.fromJson(localStorage[OVERVIEWMODEIDS]) ||
+ {Address: 'attributes', Connection: 'attributes'}
+ }
+ var savedModeIds = loadModeIds()
+ var entityModes = {
+ Address: {
+ currentModeId: savedModeIds.Address,
+ filter: function (response, result) {
+ var owningAddr = QDRService.valFor(response.attributeNames, result, "owningAddr")
+ var id = $scope.Address.data.fields.uid
+ return (owningAddr === $scope.Address.data.fields.uid)
+ }
+ },
+ Connection: {
+ currentModeId: savedModeIds.Connection,
+ filter: function (response, result) {
+ var connectionId = QDRService.valFor(response.attributeNames, result, "connectionId")
+ return (connectionId === $scope.Connection.data.fields.identity)
+ }
+ }
+ }
+ $scope.selectMode = function (mode, entity) {
+ if (!mode || !entity)
+ return;
+ entityModes[entity].currentModeId = mode.id;
+ saveModeIds();
+ if (mode.id === 'links') {
+QDR.log.debug("setting linkFields to [] in selectMode")
+ $scope.filteredLinkFields = [];
+ getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
+ updateModeLinks();
+ }
+ }
+ $scope.isModeSelected = function (mode, entity) {
+ return mode.id === entityModes[entity].currentModeId
+ }
+ $scope.isModeVisible = function (entity, id) {
+ return entityModes[entity].currentModeId === id
+ }
+
+ var updateEntityLinkGrid = function (linkFields) {
+ $timeout(function () {
+ QDR.log.debug("setting linkFields in updateEntityLinkGrid");
+ $scope.filteredLinkFields = linkFields
+ getLinkPagedData($scope.linkPagingOptions.pageSize, $scope.linkPagingOptions.currentPage);
+ })
+ }
+ // based on which entity is selected, get and filter the links
+ var updateModeLinks = function () {
+ var currentEntity = getCurrentLinksEntity()
+ if (!currentEntity)
+ return;
+ var selectionCallback = entityModes[currentEntity].filter;
+ getAllLinkFields([updateEntityLinkGrid], selectionCallback)
+ }
+ var getCurrentLinksEntity = function () {
+ var currentEntity;
+ var active = $("#overtree").dynatree("getActiveNode");
+ if (active) {
+ currentEntity = active.data.type;
+ }
+ return currentEntity;
+ }
+
+ $scope.quiesceLinkClass = function (row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ disabled: 'btn-danger'
+ }
+ return stateClassMap[row.entity.adminStatus]
+ }
+
+ $scope.quiesceLink = function (row, $event) {
+ QDRService.quiesceLink(row.entity.nodeId, row.entity.name);
+ $event.stopPropagation()
+ }
+
+ $scope.quiesceLinkDisabled = function (row) {
+ return (row.entity.operStatus !== 'up' && row.entity.operStatus !== 'down')
+ }
+ $scope.quiesceLinkText = function (row) {
+ return row.entity.adminStatus === 'disabled' ? "Revive" : "Quiesce";
+ }
+
+ $scope.expandAll = function () {
+ $("#overtree").dynatree("getRoot").visit(function(node){
+ node.expand(true);
+ });
+ }
+ $scope.contractAll = function () {
+ $("#overtree").dynatree("getRoot").visit(function(node){
+ node.expand(false);
+ })
+ }
+
+ var logModuleCellTemplate = '<div ng-click="logInfoFor(row, col)" class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text>{{COL_FIELD | pretty}}</span></div>'
+ $scope.logModule = {}
+ $scope.logModuleSelected = []
+ $scope.logModuleData = []
+ $scope.logModuleGrid = {
+ data: 'logModuleData',
+ columnDefs: [
+ {
+ field: 'nodeName',
+ displayName: 'Router',
+ },
+ {
+ field: 'enable',
+ displayName: 'Enable level',
+ },
+ {
+ field: 'noticeCount',
+ displayName: 'Notice',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'infoCount',
+ displayName: 'Info',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'traceCount',
+ displayName: 'Trace',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'debugCount',
+ displayName: 'Debug',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'warningCount',
+ displayName: 'Warning',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'errorCount',
+ displayName: 'Error',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'criticalCount',
+ displayName: 'Critical',
+ cellTemplate: logModuleCellTemplate,
+ cellClass: 'grid-align-value',
+ },
+ ],
+ enableColumnResize: true,
+ multiSelect: false,
+ selectedItems: $scope.logModuleSelected,
+ plugins: [new ngGridFlexibleHeightPlugin()],
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = $scope.logModuleSelected[0]
+ var nodeId = selItem.nodeId
+
+ }
+ }
+ }
+
+ $scope.logInfoFor = function (row, col) {
+ logDialog(row, col)
+ }
+
+ function logDialog(row, col) {
+ var d = $dialog.dialog({
+ backdrop: false,
+ keyboard: true,
+ backdropClick: false,
+ templateUrl: 'viewLogs.html',
+ controller: "QDR.OverviewLogsController",
+ resolve: {
+ nodeName: function () {
+ return row.entity.nodeName
+ },
+ module: function () {
+ return row.entity.name
+ },
+ level: function () {
+ return col.displayName
+ },
+ nodeId: function () {
+ return row.entity.nodeId
+ },
+ }
+ });
+ d.open().then(function(result) { console.log("d.open().then"); });
+ };
+
+ var numberTemplate = '<div class="ngCellText" ng-class="col.colIndex()"><span ng-cell-text>{{COL_FIELD | pretty}}</span></div>'
+ $scope.allLogFields = []
+ $scope.allLogSelections = [];
+ $scope.allLogGrid = {
+ saveKey: 'allLogGrid',
+ data: 'allLogFields',
+ columnDefs: [
+ {
+ field: 'name',
+ saveKey: 'allLogGrid',
+ displayName: 'Module'
+ },
+/* {
+ field: 'enable',
+ displayName: 'Enable'
+ },
+*/
+
+ {
+ field: 'noticeCount',
+ displayName: 'Notice',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'infoCount',
+ displayName: 'Info',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'traceCount',
+ displayName: 'Trace',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'debugCount',
+ displayName: 'Debug',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'warningCount',
+ displayName: 'Warning',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'errorCount',
+ displayName: 'Error',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ {
+ field: 'criticalCount',
+ displayName: 'Critical',
+ cellTemplate: numberTemplate,
+ cellClass: 'grid-align-value',
+ },
+ ],
+ //enableCellSelection: true,
+ enableColumnResize: true,
+ multiSelect: false,
+ selectedItems: $scope.allLogSelections,
+ plugins: [new ngGridFlexibleHeightPlugin()],
+
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = $scope.allLogSelections[0]
+ var nodeId = selItem.name
+ // activate in the tree
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+
+ };
+
+ var allLogEntries = {}
+ var allLogInfo = function () {
+ // update the count of entries for each module
+ $scope.allLogFields = []
+ var logResults = {}
+ var logDetails = {}
+
+ var gotLogStats = function (node, entity, response) {
+ logDetails[node] = []
+ response.results.forEach( function (result) {
+ var oresult = QDRService.flatten(response.attributeNames, result)
+ // make a copy for the details grid since logResults has the same object reference
+ logDetails[node].push(angular.copy(oresult))
+ if (!(oresult.name in logResults)) {
+ logResults[oresult.name] = oresult
+ }
+ else {
+ response.attributeNames.forEach( function (attr, i) {
+ if (attr.substr(attr.length-5) === 'Count') {
+ logResults[oresult.name][attr] += result[i]
+ }
+ })
+ }
+ })
+ }
+ var gotAllLogStats = function () {
+ var sortedModules = Object.keys(logResults)
+ sortedModules.sort(function (a,b) {return a<b?-1:a>b?1:0})
+ sortedModules.forEach( function (module) {
+ $scope.allLogFields.push(logResults[module])
+ })
+ allLogEntries = logDetails
+ updateLogTree($scope.allLogFields)
+ }
+ QDRService.fetchAllEntities({entity: 'logStats'}, gotAllLogStats, gotLogStats)
+/*
+ var q = QDR.queue(1)
+
+ var queuedSendMethod = function (node, callback) {
+ var gotLogInfo = function (nodeId, entity, response, context) {
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ callback("getLog failed with statusCode of " + statusCode)
+ } else {
+ var logFields = response.map( function (result) {
+ return {
+ nodeId: QDRService.nameFromId(nodeId),
+ name: result[0],
+ type: result[1],
+ message: result[2],
+ source: result[3],
+ line: result[4],
+ time: Date(result[5]).toString()
+ }
+ })
+ logResults.push.apply(logResults, logFields) // append new array to existing
+ callback(null)
+ }
+ }
+ QDRService.sendMethod(node, undefined, {}, "GET-LOG", {}, gotLogInfo)
+ }
+ for (var i=0; i<nodeIds.length; ++i) {
+ q.defer(queuedSendMethod, nodeIds[i])
+ }
+ q.await(function (error) {
+ if (!error) {
+ logResults.sort( function (a, b) {return b.name - a.name})
+ var allLogFields = $scope.allLogFields
+ $scope.allLogFields = [];
+ for (var i=0; i<allLogFields.length; ++i) {
+ $scope.allLogFields.push({module: allLogFields[i].module,
+ count: logResults.filter( function (entry) {
+ return entry.name === allLogFields[i].module
+ }).length
+ })
+ }
+ $timeout(function () {allLogEntries = logResults; scheduleNextUpdate()})
+ }
+ })
+ }
+ if ($scope.allLogFields.length == 0) {
+ QDRService.fetchEntity(nodeIds[0], "logStats", [], function (nodeName, entity, response) {
+ var moduleIndex = response.attributeNames.indexOf("name")
+ response.results.sort( function (a,b) {return a[moduleIndex] < b[moduleIndex] ? -1 : a[moduleIndex] > b[moduleIndex] ? 1 : 0})
+ response.results.forEach( function (result) {
+ var log = QDRService.flatten(response.attributeNames, result)
+ $scope.allLogFields.push(log)
+ })
+ updateLogTree($scope.allLogFields)
+ haveLogFields()
+ })
+ } else {
+ haveLogFields()
+ }
+ */
+ }
+
+ $scope.logFields = []
+ // get info for a single log
+ var logInfo = function (node) {
+
+ var gotLogInfo = function (responses) {
+ $timeout(function () {
+ $scope.logModuleData = []
+ $scope.logModule.module = node.data.key
+ for (var n in responses) {
+ var moduleIndex = responses[n]['log'].attributeNames.indexOf("module")
+ var result = responses[n]['log'].results.filter( function (r) {
+ return r[moduleIndex] === node.data.key
+ })[0]
+ var logInfo = QDRService.flatten(responses[n]['log'].attributeNames, result)
+ var entry = allLogEntries[n]
+ entry.forEach( function (module) {
+ if (module.name === node.data.key) {
+ module.nodeName = QDRService.nameFromId(n)
+ module.nodeId = n
+ module.enable = logInfo.enable
+ $scope.logModuleData.push(module)
+ }
+ })
+ }
+ $scope.logModuleData.sort ( function (a,b) { return a.nodeName < b.nodeName? -1 : a.nodeName> b.nodeName? 1 : 0})
+ scheduleNextUpdate()
+ })
+ }
+ QDRService.fetchAllEntities({entity: 'log', attrs: ['module', 'enable']}, gotLogInfo)
+/*
+ $timeout(function () {
+ $scope.log = node
+ $scope.logFields = []
+ for (var n in allLogEntries) {
+ var entry = allLogEntries[n]
+ entry.forEach( function (module) {
+ if (module.name === node.data.key) {
+ module.nodeId = n
+ $scope.logFields.push(module)
+ }
+ })
+ }
+ scheduleNextUpdate()
+ })
+*/
+ }
+
+ var getExpandedList = function () {
+ if (!treeRoot)
+ return;
+ var list = [];
+ if (treeRoot.visit) {
+ treeRoot.visit(function(node){
+ if (node.isExpanded()) {
+ list.push(node.data.parent)
+ }
+ });
+ }
+ return list;
+ }
+
+ // loads the tree node name that was last selected
+ var loadActivatedNode = function () {
+ return localStorage[OVERVIEWACTIVATEDKEY] || 'Routers'
+ }
+ // saved the tree node name that is currently selected
+ var saveActivated = function (key) {
+ localStorage[OVERVIEWACTIVATEDKEY] = key;
+ lastKey = key;
+ }
+ // loads list that was saved
+ var loadExpandedNodeList = function () {
+ try {
+ return angular.fromJson(localStorage[OVERVIEWEXPANDEDKEY]) || [];
+ } catch (e) {
+ QDR.log.debug("localStorage[OVERVIEWEXPANDEDKEY]=" + localStorage[OVERVIEWEXPANDEDKEY])
+ return ["Routers"]
+ }
+ }
+ // called when a node is expanded
+ // here we save the expanded node so it can be restored when the page reloads
+ var saveExpanded = function () {
+ var list = getExpandedList();
+ localStorage[OVERVIEWEXPANDEDKEY] = JSON.stringify(list)
+ expandedNodeList = list
+ }
+
+ var setTemplate = function (node) {
+ var type = node.data.type;
+ var template = $scope.templates.filter( function (tpl) {
+ return tpl.name == type;
+ })
+ $scope.template = template[0];
+ }
+ // activated is called each time a tree node is clicked
+ // based on which node is clicked, load the correct data grid template and start getting the data
+ var activated = function (node) {
+ QDR.log.debug("node activated: " + node.data.title)
+ saveExpanded()
+ saveActivated(node.data.key)
+
+ setTemplate(node)
+ // the nodes info function will fetch the grids data
+ if (node.data.info) {
+ $timeout(function () {
+ if (node.data.key === node.data.parent) {
+ node.data.info()
+ }
+ else {
+ node.data.info(node)
+ }
+ })
+ }
+ }
+
+ var treeNodeExpanded = function (node) {
+ saveExpanded()
+ tick()
+ }
+ $scope.template = {url: ''};
+
+ if (!QDRService.connected) {
+ QDRService.redirectWhenConnected("overview")
+ return;
+ }
+
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ $timeout( () => QDRService.redirectWhenConnected("overview") )
+ })
+
+ /* --------------------------------------------------
+ *
+ * setup the tree on the left
+ *
+ * -------------------------------------------------
+ */
+ // utility function called by each top level tree node when it needs to populate its child nodes
+ var updateLeaves = function (leaves, parentKey, parentFolder, worker) {
+ var scrollTree = $('.qdr-overview.pane.left .pane-viewport')
+ var scrollTop = scrollTree.scrollTop();
+ var tree = $("#overtree").dynatree("getTree")
+ var parentNode = tree.getNodeByKey(parentKey);
+ parentNode.removeChildren();
+
+ leaves.forEach( function (leaf) {
+ parentNode.addChild(worker(leaf))
+ })
+ scrollTree.scrollTop(scrollTop)
+ if (firstTime) {
+ var newActive = tree.getActiveNode();
+ if (newActive &&
+// newActive.data.key === lastKey &&
+ newActive.data.key !== newActive.data.parent && // this is a leaf node
+ newActive.data.parent === parentKey) { // the active node was just created
+ firstTime = false
+QDR.log.debug("newly created node needs to be activated")
+ activated(newActive)
+ }
+ }
+ }
+
+ // get saved tree state
+ var lastKey = loadActivatedNode();
+ var expandedNodeList = loadExpandedNodeList();
+ var firstTime = true;
+
+ // create a routers tree branch
+ var routers = new Folder("Routers")
+ routers.type = "Routers"
+ routers.info = allRouterInfo
+ routers.activate = lastKey === 'Routers'
+ routers.expand = (expandedNodeList.indexOf("Routers") > -1)
+ routers.clickFolderMode = 1
+ routers.key = "Routers"
+ routers.parent = "Routers"
+ routers.addClass = "routers"
+ topLevelChildren.push(routers)
+ // called when the list of routers changes
+ var updateRouterTree = function (nodes) {
+ var worker = function (node) {
+ var name = QDRService.nameFromId(node)
+ var router = new Folder(name)
+ router.type = "Router"
+ router.info = routerInfo
+ router.nodeId = node
+ router.key = node
+ router.addClass = "router"
+ router.parent = "Routers"
+ router.activate = lastKey === node
+ return router;
+ }
+ $timeout(function () {updateLeaves(nodes, "Routers", routers, worker)})
+ }
+
+ // create an addresses tree branch
+ var addresses = new Folder("Addresses")
+ addresses.type = "Addresses"
+ addresses.info = allAddressInfo
+ addresses.activate = lastKey === 'Addresses'
+ addresses.expand = (expandedNodeList.indexOf("Addresses") > -1)
+ addresses.clickFolderMode = 1
+ addresses.key = "Addresses"
+ addresses.parent = "Addresses"
+ addresses.addClass = "addresses"
+ topLevelChildren.push(addresses)
+ var updateAddressTree = function (addressFields) {
+ var info = SingleEntityInfo('Address')
+ var worker = function (address) {
+ var a = new Folder(address.title)
+ a.info = info
+ a.key = address.uid
+ a.fields = address
+ a.type = "Address"
+ a.tooltip = address['class'] + " address"
+ if (address.address === '$management')
+ a.tooltip = "internal " + a.tooltip
+ a.addClass = a.tooltip
+ a.activate = lastKey === address.uid
+ a.parent = "Addresses"
+ return a;
+ }
+ $timeout(function () {updateLeaves(addressFields, "Addresses", addresses, worker)})
+ }
+
+ $scope.$watch("filter", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ $timeout(allLinkInfo);
+ localStorage[FILTERKEY] = JSON.stringify($scope.filter)
+ }
+ }, true)
+
+ $scope.filterToggle = function () {
+ var filter = $('#linkFilter')
+ filter.toggle();
+ }
+
+ $scope.filter = angular.fromJson(localStorage[FILTERKEY]) || {endpointsOnly: "true", hideConsoles: true};
+ var links = new Folder("Links")
+ links.type = "Links"
+ links.info = allLinkInfo
+ links.activate = lastKey === 'Links'
+ links.expand = (expandedNodeList.indexOf("Links") > -1)
+ links.clickFolderMode = 1
+ links.key = "Links"
+ links.parent = "Links"
+ links.addClass = "links"
+ topLevelChildren.push(links)
+
+ // called both before the tree is created and whenever a background update is done
+ var updateLinkTree = function (linkFields) {
+ var info = SingleEntityInfo('Link')
+ var worker = function (link) {
+ var l = new Folder(link.title)
+ var isConsole = QDRService.isConsoleLink(link)
+ l.info = info
+ l.key = link.uid
+ l.fields = link
+ l.type = "Link"
+ l.parent = "Links"
+ l.activate = lastKey === link.uid
+ if (isConsole)
+ l.tooltip = "console link"
+ else
+ l.tooltip = link.linkType + " link"
+ l.addClass = l.tooltip
+ return l;
+ }
+ $timeout(function () {updateLeaves(linkFields, "Links", links, worker)})
+ }
+
+ var connections = new Folder("Connections")
+ connections.type = "Connections"
+ connections.info = allConnectionInfo
+ connections.activate = lastKey === 'Connections'
+ connections.expand = (expandedNodeList.indexOf("Connections") > -1)
+ connections.clickFolderMode = 1
+ connections.key = "Connections"
+ connections.parent = "Connections"
+ connections.addClass = "connections"
+ topLevelChildren.push(connections)
+
+ updateConnectionTree = function (connectionFields) {
+ var info = SingleEntityInfo('Connection')
+ var worker = function (connection) {
+ var c = new Folder(connection.host)
+ var isConsole = QDRService.isAConsole (connection.properties, connection.identity, connection.role, connection.routerId)
+ c.type = "Connection"
+ c.info = info
+ c.key = connection.uid
+ c.fields = connection
+ if (isConsole)
+ c.tooltip = "console connection"
+ else
+ c.tooltip = connection.role === "inter-router" ? "inter-router connection" : "external connection"
+ c.addClass = c.tooltip
+ c.parent = "Connections"
+ c.activate = lastKey === connection.uid
+ return c
+ }
+ $timeout(function () {updateLeaves(connectionFields, "Connections", connections, worker)})
+ }
+
+ var updateLogTree = function (logFields) {
+ var worker = function (log) {
+ var l = new Folder(log.name)
+ l.type = "Log"
+ l.info = logInfo
+ l.key = log.name
+ l.parent = "Logs"
+ l.activate = lastKey === l.key
+ l.addClass = "log"
+ return l
+ }
+ $timeout(function () {updateLeaves(logFields, "Logs", logs, worker)})
+ }
+
+ var htmlReady = false;
+ var dataReady = false;
+ $scope.largeNetwork = QDRService.isLargeNetwork()
+ var logs = new Folder("Logs")
+ logs.type = "Logs"
+ logs.info = allLogInfo
+ logs.activate = lastKey === 'Logs'
+ logs.expand = (expandedNodeList.indexOf("Logs") > -1)
+ logs.clickFolderMode = 1
+ logs.key = "Logs"
+ logs.parent = "Logs"
+ if (QDRService.versionCheck('0.8.0'))
+ topLevelChildren.push(logs)
+ var initTreeAndGrid = function () {
+ if (!htmlReady || !dataReady)
+ return;
+ var div = angular.element("#overtree");
+ if (!div.width()) {
+ setTimeout(initTreeAndGrid, 100);
+ return;
+ }
+ $('#overtree').dynatree({
+ onActivate: activated,
+ onExpand: treeNodeExpanded,
+ autoCollapse: $scope.largeNetwork,
+ activeVisible: !$scope.largeNetwork,
+ selectMode: 1,
+ debugLevel: 0,
+ children: topLevelChildren
+ })
+ treeRoot = $("#overtree").dynatree("getRoot");
+ tick()
+ loadColState($scope.allRouters);
+ loadColState($scope.routerGrid);
+ loadColState($scope.addressesGrid);
+ loadColState($scope.addressGrid);
+ loadColState($scope.linksGrid);
+ loadColState($scope.linkGrid);
+ loadColState($scope.allConnectionGrid);
+ loadColState($scope.connectionGrid);
+ }
+
+ $scope.overviewLoaded = function () {
+ htmlReady = true;
+ initTreeAndGrid();
+ }
+
+ var nodeIds = QDRService.nodeIdList()
+ //updateRouterTree(nodeIds);
+ // add placeholders for the top level tree nodes
+ var topLevelTreeNodes = [routers, addresses, links, connections, logs]
+ topLevelTreeNodes.forEach( function (parent) {
+ var placeHolder = new Folder("loading...")
+ placeHolder.addClass = "loading"
+ parent.children = [placeHolder]
+ })
+
+ var singleQ = null
+ var updateExpanded = function () {
+ if (!treeRoot)
+ return;
+ if (treeRoot.visit) {
+ treeRoot.visit(function(node){
+ if (node.isActive())
+ setTemplate(node)
+ if (node.isActive() || node.isExpanded()) {
+ if (node.data.key === node.data.parent) {
+ node.data.info()
+ }
+ else {
+ node.data.info(node)
+ }
+ }
+ })
+ }
+ }
+
+ var tickTimer;
+ var scheduleNextUpdate = function () {
+ clearTimeout(tickTimer)
+ tickTimer = setTimeout(tick, refreshInterval)
+ }
+ var tick = function () {
+ clearTimeout(tickTimer)
+ updateExpanded();
+ }
+ dataReady = true;
+ initTreeAndGrid();
+ $scope.$on("$destroy", function( event ) {
+ clearTimeout(tickTimer)
+ //QDRService.stopUpdating()
+ //QDRService.delUpdatedAction("overview")
+ });
+
+ }]);
+
+ return QDR;
+
+}(QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js
deleted file mode 120000
index d48ecbb..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/qdrOverviewLogsController.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js
new file mode 100644
index 0000000..fed1e3d
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrOverviewLogsController.js
@@ -0,0 +1,67 @@
+/*
+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) {
+
+ QDR.module.controller('QDR.OverviewLogsController', function ($scope, dialog, QDRService, $timeout, nodeName, nodeId, module, level) {
+
+ var gotLogInfo = function (nodeId, entity, response, context) {
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ } else {
+ var levelLogs = response.filter( function (result) {
+ if (result[1] == null)
+ result[1] = "error"
+ return result[1].toUpperCase() === level.toUpperCase() && result[0] === module
+ })
+ var logFields = levelLogs.map( function (result) {
+ return {
+ nodeId: QDRService.nameFromId(nodeId),
+ name: result[0],
+ type: result[1],
+ message: result[2],
+ source: result[3],
+ line: result[4],
+ time: Date(result[5]).toString()
+ }
+ })
+ $timeout(function () {
+ $scope.loading = false
+ $scope.logFields = logFields
+ })
+ }
+ }
+ QDRService.sendMethod(nodeId, undefined, {}, "GET-LOG", {module: module}, gotLogInfo)
+
+ $scope.loading = true
+ $scope.module = module
+ $scope.level = level
+ $scope.nodeName = nodeName
+ $scope.logFields = []
+ $scope.ok = function () {
+ dialog.close(true);
+ };
+
+ });
+ return QDR;
+
+} (QDR || {}));
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[2/4] qpid-dispatch git commit: DISPATCH-745 Remove symlinks from
hawtio to stand-alone
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
deleted file mode 120000
index 36d5187..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/qdrTopology.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
new file mode 100644
index 0000000..9899393
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
@@ -0,0 +1,2160 @@
+/*
+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) {
+
+ QDR.module.controller('QDR.TopologyFormController', function($scope, QDRService) {
+
+ $scope.attributes = []
+ var nameTemplate = '<div title="{{row.entity.description}}" class="ngCellText {{row.entity.cls}}"><span>{{row.entity.attributeName}}</span></div>';
+ var valueTemplate = '<div title="{{row.entity.attributeValue}}" class="ngCellText {{row.entity.cls}}"><span>{{row.entity.attributeValue}}</span></div>';
+ $scope.topoGridOptions = {
+ data: 'attributes',
+ enableColumnResize: false,
+ multiSelect: false,
+ columnDefs: [{
+ field: 'attributeName',
+ displayName: 'Attribute',
+ cellTemplate: nameTemplate
+ }, {
+ field: 'attributeValue',
+ displayName: 'Value',
+ cellTemplate: valueTemplate
+ }]
+ };
+ $scope.form = ''
+ $scope.$on('showEntityForm', function(event, args) {
+ var attributes = args.attributes;
+ var entityTypes = QDRService.schema.entityTypes[args.entity].attributes;
+ attributes.forEach(function(attr) {
+ attr.cls = ''
+QDR.log.debug("attr.description " + attr.description)
+ if (attr.attributeName === 'Listening on')
+ attr.cls = 'listening-on'
+ if (entityTypes[attr.attributeName] && entityTypes[attr.attributeName].description) {
+ attr.description = entityTypes[attr.attributeName].description
+ }
+ })
+ $scope.attributes = attributes;
+ $scope.form = args.entity;
+ })
+ $scope.$on('showAddForm', function(event) {
+ $scope.form = 'add';
+ })
+ })
+
+ /**
+ * @method TopologyController
+ *
+ * Controller that handles the QDR topology page
+ */
+ QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'QDRService', '$location', '$timeout', '$dialog',
+ function($scope, $rootScope, QDRService, $location, $timeout, $dialog) {
+
+ $scope.panelVisible = true // show/hide the panel on the left
+ $scope.multiData = []
+ $scope.selectedClient = [];
+ $scope.quiesceState = {}
+ var dontHide = false;
+
+ $scope.hideLeftPane = function () {
+ d3.select(".qdr-topology.pane.left")
+ .transition().duration(300).ease("sin-in")
+ .style("left" , "-380px")
+
+ d3.select(".panel-adjacent")
+ .transition().duration(300).ease("sin-in")
+ .style("margin-left", "30px")
+ .each("end", function () {
+ resize()
+ $timeout(function () {QDR.log.debug("done with transition. setting scope ");$scope.panelVisible = false})
+ })
+ }
+ $scope.showLeftPane = function () {
+ d3.select(".qdr-topology.pane.left")
+ .transition().duration(300).ease("sin-out")
+ .style("left" , "0px")
+
+ d3.select(".panel-adjacent")
+ .transition().duration(300).ease("sin-out")
+ .style("margin-left", "430px")
+ .each("end", function () {
+ resize()
+ $timeout(function () {QDR.log.debug("done with transition. setting scope ");$scope.panelVisible = true})
+ })
+ }
+ $scope.quiesceConnection = function(row) {
+ var entity = row.entity;
+ var state = $scope.quiesceState[entity.connectionId].state;
+ if (state === 'enabled') {
+ // start quiescing all links
+ $scope.quiesceState[entity.connectionId].state = 'quiescing';
+ } else if (state === 'quiesced') {
+ // start reviving all links
+ $scope.quiesceState[entity.connectionId].state = 'reviving';
+ }
+ $scope.multiDetails.updateState(entity);
+ dontHide = true;
+ $scope.multiDetails.selectRow(row.rowIndex, true);
+ $scope.multiDetails.showLinksList(row)
+ }
+ $scope.quiesceDisabled = function(row) {
+ return $scope.quiesceState[row.entity.connectionId].buttonDisabled;
+ }
+ $scope.quiesceText = function(row) {
+ return $scope.quiesceState[row.entity.connectionId].buttonText;
+ }
+ $scope.quiesceClass = function(row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ quiescing: 'btn-warning',
+ reviving: 'btn-warning',
+ quiesced: 'btn-danger'
+ }
+ return stateClassMap[$scope.quiesceState[row.entity.connectionId].state];
+ }
+
+ $scope.multiData = []
+ $scope.multiDetails = {
+ data: 'multiData',
+ selectedItems: $scope.selectedClient,
+ multiSelect: false,
+ afterSelectionChange: function(obj) {
+ if (obj.selected && obj.orig) {
+ var detailsDiv = d3.select('#link_details')
+ var isVis = detailsDiv.style('display') === 'block';
+ if (!dontHide && isVis && $scope.connectionId === obj.entity.connectionId) {
+ hideLinkDetails();
+ return;
+ }
+ dontHide = false;
+ $scope.multiDetails.showLinksList(obj)
+ }
+ },
+ showLinksList: function(obj) {
+ $scope.linkData = obj.entity.linkData;
+ $scope.connectionId = obj.entity.connectionId;
+ var visibleLen = Math.min(obj.entity.linkData.length, 10)
+ QDR.log.debug("visibleLen is " + visibleLen)
+ var left = parseInt(d3.select('#multiple_details').style("left"))
+ var detailsDiv = d3.select('#link_details')
+ detailsDiv
+ .style({
+ display: 'block',
+ opacity: 1,
+ left: (left + 20) + "px",
+ top: (mouseY + 20 + $(document).scrollTop()) + "px",
+ height: ((visibleLen + 1) * 30) + 40 + "px", // +1 for the header row
+ 'overflow-y': obj.entity.linkData > 10 ? 'scroll' : 'hidden'
+ })
+ },
+ updateState: function(entity) {
+ var state = $scope.quiesceState[entity.connectionId].state
+
+ // count enabled and disabled links for this connection
+ var enabled = 0,
+ disabled = 0;
+ entity.linkData.forEach(function(link) {
+ if (link.adminStatus === 'enabled')
+ ++enabled;
+ if (link.adminStatus === 'disabled')
+ ++disabled;
+ })
+
+ var linkCount = entity.linkData.length;
+ // if state is quiescing and any links are enabled, button should say 'Quiescing' and be disabled
+ if (state === 'quiescing' && (enabled > 0)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Quiescing';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = true;
+ } else
+ // if state is enabled and all links are disabled, button should say Revive and be enabled. set state to quisced
+ // if state is quiescing and all links are disabled, button should say 'Revive' and be enabled. set state to quiesced
+ if ((state === 'quiescing' || state === 'enabled') && (disabled === linkCount)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Revive';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = false;
+ $scope.quiesceState[entity.connectionId].state = 'quiesced'
+ } else
+ // if state is reviving and any links are disabled, button should say 'Reviving' and be disabled
+ if (state === 'reviving' && (disabled > 0)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Reviving';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = true;
+ } else
+ // if state is reviving or quiesced and all links are enabled, button should say 'Quiesce' and be enabled. set state to enabled
+ if ((state === 'reviving' || state === 'quiesced') && (enabled === linkCount)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Quiesce';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = false;
+ $scope.quiesceState[entity.connectionId].state = 'enabled'
+ }
+ },
+ columnDefs: [{
+ field: 'host',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Connection host'
+ }, {
+ field: 'user',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'User'
+ }, {
+ field: 'properties',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Properties'
+ }
+ /*,
+ {
+ cellClass: 'gridCellButton',
+ cellTemplate: '<button title="{{quiesceText(row)}} the links" type="button" ng-class="quiesceClass(row)" class="btn" ng-click="$event.stopPropagation();quiesceConnection(row)" ng-disabled="quiesceDisabled(row)">{{quiesceText(row)}}</button>'
+ }*/
+ ]
+ };
+ $scope.quiesceLinkClass = function(row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ disabled: 'btn-danger'
+ }
+ return stateClassMap[row.entity.adminStatus]
+ }
+ $scope.quiesceLink = function(row) {
+ QDRService.quiesceLink(row.entity.nodeId, row.entity.name);
+ }
+ $scope.quiesceLinkDisabled = function(row) {
+ return (row.entity.operStatus !== 'up' && row.entity.operStatus !== 'down')
+ }
+ $scope.quiesceLinkText = function(row) {
+ return row.entity.operStatus === 'down' ? "Revive" : "Quiesce";
+ }
+ $scope.linkData = [];
+ $scope.linkDetails = {
+ data: 'linkData',
+ columnDefs: [{
+ field: 'adminStatus',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Admin state'
+ }, {
+ field: 'operStatus',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Oper state'
+ }, {
+ field: 'dir',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'dir'
+ }, {
+ field: 'owningAddr',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Address'
+ }, {
+ field: 'deliveryCount',
+ displayName: 'Delivered',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+
+ }, {
+ field: 'uncounts',
+ displayName: 'Outstanding',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+ }
+ /*,
+ {
+ cellClass: 'gridCellButton',
+ cellTemplate: '<button title="{{quiesceLinkText(row)}} this link" type="button" ng-class="quiesceLinkClass(row)" class="btn" ng-click="quiesceLink(row)" ng-disabled="quiesceLinkDisabled(row)">{{quiesceLinkText(row)}}</button>'
+ }*/
+ ]
+ }
+
+ if (!QDRService.connected) {
+ // we are not connected. we probably got here from a bookmark or manual page reload
+ QDRService.redirectWhenConnected("topology");
+ return;
+ }
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction(function() {
+ QDRService.redirectWhenConnected("topology");
+ $scope.$apply();
+ })
+
+ var urlPrefix = $location.absUrl();
+ urlPrefix = urlPrefix.split("#")[0]
+ QDR.log.debug("started QDR.TopologyController with urlPrefix: " + urlPrefix);
+
+ $scope.addingNode = {
+ step: 0,
+ hasLink: false,
+ trigger: ''
+ };
+
+ $scope.cancel = function() {
+ $scope.addingNode.step = 0;
+ }
+ $scope.editNewRouter = function() {
+ $scope.addingNode.trigger = 'editNode';
+ }
+
+ var NewRouterName = "__NEW__";
+ // mouse event vars
+ var selected_node = null,
+ selected_link = null,
+ mousedown_link = null,
+ mousedown_node = null,
+ mouseover_node = null,
+ mouseup_node = null,
+ initial_mouse_down_position = null;
+
+ $scope.schema = "Not connected";
+
+ $scope.modes = [{
+ title: 'Topology view',
+ name: 'Diagram',
+ right: false
+ },
+ /* {title: 'Add a new router node', name: 'Add Router', right: true} */
+ ];
+ $scope.mode = "Diagram";
+ $scope.contextNode = null; // node that is associated with the current context menu
+
+ $scope.isModeActive = function(name) {
+ if ((name == 'Add Router' || name == 'Diagram') && $scope.addingNode.step > 0)
+ return true;
+ return ($scope.mode == name);
+ }
+ $scope.selectMode = function(name) {
+ if (name == "Add Router") {
+ name = 'Diagram';
+ if ($scope.addingNode.step > 0) {
+ $scope.addingNode.step = 0;
+ } else {
+ // start adding node mode
+ $scope.addingNode.step = 1;
+ }
+ } else {
+ $scope.addingNode.step = 0;
+ }
+
+ $scope.mode = name;
+ }
+ $scope.$watch(function() { return $scope.addingNode.step }, function(newValue, oldValue) {
+ if (newValue == 0 && oldValue != 0) {
+ // we are cancelling the add
+
+ // find the New node
+ nodes.every(function(n, i) {
+ // for the placeholder node, the key will be __internal__
+ if (QDRService.nameFromId(n.key) == '__internal__') {
+ var newLinks = links.filter(function(e, i) {
+ return e.source.id == n.id || e.target.id == n.id;
+ })
+ // newLinks is an array of links to remove
+ newLinks.map(function(e) {
+ links.splice(links.indexOf(e), 1);
+ })
+ // i is the index of the node to remove
+ nodes.splice(i, 1);
+ force.nodes(nodes).links(links).start();
+ restart(false);
+ return false; // stop looping
+ }
+ return true;
+ })
+ updateForm(Object.keys(QDRService.topology.nodeInfo())[0], 'router', 0);
+
+ } else if (newValue > 0) {
+ // we are starting the add mode
+ $scope.$broadcast('showAddForm')
+
+ resetMouseVars();
+ selected_node = null;
+ selected_link = null;
+ // add a new node
+ var id = "amqp:/_topo/0/__internal__/$management";
+ var x = radiusNormal * 4;
+ var y = x;;
+ if (newValue > 1) { // add at current mouse position
+ var offset = jQuery('#topology').offset();
+ x = mouseX - offset.left + $(document).scrollLeft();
+ y = mouseY - offset.top + $(document).scrollTop();;
+ }
+ QDRService.ensureAllEntities({entity: ".router"}, function () {
+ NewRouterName = genNewName();
+ nodes.push(aNode(id, NewRouterName, "inter-router", undefined, nodes.length, x, y, undefined, true));
+ force.nodes(nodes).links(links).start();
+ restart(false);
+ })
+ }
+ })
+ $scope.isRight = function(mode) {
+ return mode.right;
+ }
+
+ // for ng-grid that shows details for multiple consoles/clients
+ // generate unique name for router and containerName
+ var genNewName = function() {
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var nameIndex = 1;
+ var newName = "R." + nameIndex;
+
+ var names = [];
+ for (key in nodeInfo) {
+ var node = nodeInfo[key];
+ var router = node['.router'];
+ var attrNames = router.attributeNames;
+ var name = QDRService.valFor(attrNames, router.results[0], 'routerId')
+ if (!name)
+ name = QDRService.valFor(attrNames, router.results[0], 'name')
+ names.push(name);
+ }
+
+ while (names.indexOf(newName) >= 0) {
+ newName = "R." + nameIndex++;
+ }
+ return newName;
+ }
+
+ $scope.$watch(function() {
+ return $scope.addingNode.trigger
+ }, function(newValue, oldValue) {
+ if (newValue == 'editNode') {
+ $scope.addingNode.trigger = "";
+ editNode();
+ }
+ })
+
+ function editNode() {
+ doAddDialog(NewRouterName);
+ };
+ $scope.reverseLink = function() {
+ if (!mousedown_link)
+ return;
+ var d = mousedown_link;
+ var tmp = d.left;
+ d.left = d.right;;
+ d.right = 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 setNodesFixed = function (name, b) {
+ nodes.some(function (n) {
+ if (n.name === name) {
+ n.fixed = b;
+ return true;
+ }
+ })
+ }
+ $scope.setFixed = function(b) {
+ if ($scope.contextNode) {
+ $scope.contextNode.fixed = b;
+ setNodesFixed($scope.contextNode.name, b)
+ savePositions()
+ }
+ restart();
+ }
+ $scope.isFixed = function() {
+ if (!$scope.contextNode)
+ return false;
+ return ($scope.contextNode.fixed & 0b1);
+ }
+
+ var mouseX, mouseY;
+ // event handlers for popup context menu
+ $(document).mousemove(function(e) {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ });
+ $(document).mousemove();
+ $(document).click(function(e) {
+ $scope.contextNode = null;
+ $(".contextMenu").fadeOut(200);
+ });
+
+ 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 tpformHeight = $('#topologyForm').height()
+ var height = Math.max(window.innerHeight, tpformHeight + 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,
+ resultIndex: resultIndex,
+ fixed: !!+fixed,
+ cls: name == NewRouterName ? 'temp' : ''
+ };
+ };
+
+
+ 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 getLinkDir = function (id, connection, onode) {
+ var links = onode[".router.link"]
+ if (!links) {
+ return "unknown"
+ }
+ var inCount = 0, outCount = 0
+ links.results.forEach( function (linkResult) {
+ var link = QDRService.flatten(links.attributeNames, linkResult)
+ if (link.linkType === "endpoint" && link.connectionId === connection.identity)
+ if (link.linkDir === "in")
+ ++inCount
+ else
+ ++outCount
+ })
+ if (inCount > 0 && outCount > 0)
+ return "both"
+ if (inCount > 0)
+ return "in"
+ if (outCount > 0)
+ return "out"
+ return "unknown"
+ }
+
+ var savePositions = function () {
+ nodes.forEach( function (d) {
+ localStorage[d.name] = angular.toJson({
+ x: Math.round(d.x),
+ y: Math.round(d.y),
+ fixed: d.fixed ? 1 : 0,
+ });
+ })
+ }
+
+ var initializeNodes = function (nodeInfo) {
+ var nodeCount = Object.keys(nodeInfo).length
+ var yInit = 50;
+ nodes = []
+ for (var id in nodeInfo) {
+ var name = QDRService.nameFromId(id);
+ // if we have any new nodes, animate the force graph to position them
+ var position = angular.fromJson(localStorage[name]);
+ if (!angular.isDefined(position)) {
+ animate = true;
+ position = {
+ x: Math.round(width / 4 + ((width / 2) / nodeCount) * nodes.length),
+ y: Math.round(height / 2 + Math.sin(nodes.length / (Math.PI*2.0)) * height / 4),
+ fixed: false,
+ };
+ //QDR.log.debug("new node pos (" + position.x + ", " + position.y + ")")
+ }
+ if (position.y > height) {
+ position.y = 200 - yInit;
+ yInit *= -1
+ }
+ nodes.push(aNode(id, name, "inter-router", nodeInfo, nodes.length, position.x, position.y, undefined, position.fixed));
+ //QDR.log.debug("adding node " + nodes.length-1);
+ }
+ }
+
+ var initializeLinks = function (nodeInfo, unknowns) {
+ links = [];
+ var source = 0;
+ var client = 1.0;
+ for (var id in nodeInfo) {
+ var onode = nodeInfo[id];
+ var conns = onode['.connection'].results;
+ var attrs = onode['.connection'].attributeNames;
+ //QDR.log.debug("external client parent is " + parent);
+ var normalsParent = {}; // 1st normal node for this parent
+
+ for (var j = 0; j < conns.length; j++) {
+ var connection = QDRService.flatten(attrs, conns[j])
+ var role = connection.role
+ var properties = connection.properties || {};
+ var dir = connection.dir
+ if (role == "inter-router") {
+ var connId = connection.container
+ var target = getContainerIndex(connId, nodeInfo);
+ if (target >= 0) {
+ getLink(source, target, dir, "", source + "-" + target);
+ }
+ } else if (role == "normal" || role == "on-demand" || role === "route-container") {
+ // not a router, but an external client
+ var name = QDRService.nameFromId(id) + "." + connection.identity;
+
+ // if we have any new clients, animate the force graph to position them
+ var position = angular.fromJson(localStorage[name]);
+ if (!angular.isDefined(position)) {
+ animate = true;
+ position = {
+ x: Math.round(nodes[source].x + 40 * Math.sin(client / (Math.PI * 2.0))),
+ y: Math.round(nodes[source].y + 40 * Math.cos(client / (Math.PI * 2.0))),
+ fixed: false
+ };
+ //QDR.log.debug("new client pos (" + position.x + ", " + position.y + ")")
+ }// else QDR.log.debug("using previous location")
+ if (position.y > height) {
+ position.y = Math.round(nodes[source].y + 40 + Math.cos(client / (Math.PI * 2.0)))
+ }
+ var node = aNode(id, name, role, nodeInfo, nodes.length, position.x, position.y, j, position.fixed, properties)
+ var nodeType = QDRService.isAConsole(properties, connection.identity, role, node.key) ? "console" : "client"
+ if (role === 'normal') {
+ var cdir = getLinkDir(id, connection, onode)
+ if (cdir !== 'unknown') {
+ node.user = connection.user
+ node.isEncrypted = connection.isEncrypted
+ node.host = connection.host
+ node.connectionId = connection.identity
+ node.cdir = cdir
+ // determine arrow direction by using the link directions
+ if (!normalsParent[nodeType+cdir]) {
+ normalsParent[nodeType+cdir] = node;
+ nodes.push(node);
+ node.normals = [node];
+ // now add a link
+ getLink(source, nodes.length - 1, cdir, "small", connection.name);
+ client++;
+ } else {
+ normalsParent[nodeType+cdir].normals.push(node)
+ }
+ } else {
+ unknowns.push(node)
+ }
+ } else {
+ nodes.push(node)
+ // now add a link
+ getLink(source, nodes.length - 1, dir, "small", connection.name);
+ client++;
+ }
+ }
+ }
+ source++;
+ }
+ }
+
+ // 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 > 80) count = 80
+ var x = d3.scale.linear()
+ .domain([6,80])
+ .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, 70)
+ return forceScale(nodeCount, 75, 40)
+ }
+ var charge = function (d, nodeCount) {
+ if (d.nodeType === 'inter-router')
+ return forceScale(nodeCount, -1800, -900)
+ return -900
+ }
+ var gravity = function (d, nodeCount) {
+ return forceScale(nodeCount, 0.0001, 0.1)
+ }
+
+ // initialize the nodes and links array from the QDRService.topology._nodeInfo object
+ var initForceGraph = function() {
+ nodes = [];
+ links = [];
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var nodeCount = Object.keys(nodeInfo).length
+
+ var oldSelectedNode = selected_node
+ var oldMouseoverNode = mouseover_node
+ mouseover_node = null;
+ selected_node = null;
+ selected_link = null;
+
+ savePositions();
+ 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();
+ d3.select('#svg_context_menu')
+ .style('left', (mouseX + $(document).scrollLeft()) + "px")
+ .style('top', (mouseY + $(document).scrollTop()) + "px")
+ .style('display', 'block');
+ })
+ .on('click', function(d) {
+ removeCrosssection()
+ });
+
+ $(document).keyup(function(e) {
+ if (e.keyCode === 27) {
+ removeCrosssection()
+ }
+ });
+
+ // 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');
+
+ // mouse event vars
+ mousedown_link = null;
+ mousedown_node = null;
+ mouseup_node = null;
+
+ // initialize the list of nodes
+ initializeNodes(nodeInfo)
+ savePositions()
+
+ // initialize the list of links
+ var unknowns = []
+ initializeLinks(nodeInfo, unknowns)
+ $scope.schema = QDRService.schema;
+ // init D3 force layout
+ force = d3.layout.force()
+ .nodes(nodes)
+ .links(links)
+ .size([width, height])
+ .linkDistance(function(d) { return linkDistance(d, nodeCount) })
+ .charge(function(d) { return charge(d, nodeCount) })
+ .friction(.10)
+ .gravity(function(d) { return gravity(d, nodeCount) })
+ .on('tick', tick)
+ .on('end', function () {savePositions()})
+ .start()
+
+ 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');
+
+ var grad = svg.append("svg:defs").append("linearGradient")
+ .attr("id", "half-circle")
+ .attr("x1", "0%")
+ .attr("x2", "0%")
+ .attr("y1", "100%")
+ .attr("y2", "0%");
+ grad.append("stop").attr("offset", "50%").style("stop-color", "#C0F0C0");
+ grad.append("stop").attr("offset", "50%").style("stop-color", "#F0F000");
+
+ // handles to link and node element groups
+ path = svg.append('svg:g').selectAll('path'),
+ circle = svg.append('svg:g').selectAll('g');
+
+ // app starts here
+ restart(false);
+ force.start();
+ if (oldSelectedNode) {
+ d3.selectAll('circle.inter-router').classed("selected", function (d) {
+ if (d.key === oldSelectedNode.key) {
+ selected_node = d;
+ return true
+ }
+ return false
+ })
+ }
+ if (oldMouseoverNode && selected_node) {
+ d3.selectAll('circle.inter-router').each(function (d) {
+ if (d.key === oldMouseoverNode.key) {
+ mouseover_node = d
+ QDRService.ensureAllEntities([{entity: ".router.node", attrs: ["id","nextHop"]}], function () {
+ nextHop(selected_node, d);
+ restart();
+ })
+ }
+ })
+ }
+ setTimeout(function () {
+ updateForm(Object.keys(QDRService.topology.nodeInfo())[0], 'router', 0);
+ })
+
+ // if any clients don't yet have link directions, get the links for those nodes and restart the graph
+ if (unknowns.length > 0)
+ setTimeout(resolveUnknowns, 10, nodeInfo, unknowns)
+
+ var continueForce = function (extra) {
+ if (extra > 0) {
+ --extra
+ force.start()
+ setTimeout(continueForce, 100, extra)
+ }
+ }
+ continueForce(forceScale(nodeCount, 20, 200)) // give graph time to settle down
+ }
+
+ var resolveUnknowns = function (nodeInfo, unknowns) {
+ var unknownNodes = {}
+ // collapse the unknown node.keys using an object
+ for (var i=0; i<unknowns.length; ++i) {
+ unknownNodes[unknowns[i].key] = 1
+ }
+ unknownNodes = Object.keys(unknownNodes)
+ //QDR.log.debug("there were " + unknownNodes.length + " connections with normal links")
+ //console.dump(unknownNodes)
+
+ QDRService.ensureEntities(unknownNodes, {entity: ".router.link", attrs: ["linkType","connectionId","linkDir"], force: true}, function () {
+ initializeLinks(nodeInfo, [])
+ animate = true;
+ force.nodes(nodes).links(links).start();
+ restart(false);
+ })
+ }
+
+ function updateForm(key, entity, resultIndex) {
+ var nodeInfo = QDRService.topology.nodeInfo();
+ if (key in nodeInfo) {
+ QDRService.ensureEntities(key, [
+ {entity: '.'+entity},
+ {entity: '.listener', attrs: ["role", "port"]}], function () {
+ var onode = nodeInfo[key]
+ var nodeResults = onode['.' + entity].results[resultIndex]
+ var nodeAttributes = onode['.' + entity].attributeNames
+ var attributes = nodeResults.map(function(row, i) {
+ return {
+ attributeName: nodeAttributes[i],
+ attributeValue: row
+ }
+ })
+ // sort by attributeName
+ attributes.sort(function(a, b) {
+ return a.attributeName.localeCompare(b.attributeName)
+ })
+
+ // move the Name first
+ var nameIndex = attributes.findIndex(function(attr) {
+ return attr.attributeName === 'name'
+ })
+ if (nameIndex >= 0)
+ attributes.splice(0, 0, attributes.splice(nameIndex, 1)[0]);
+
+ // get the list of ports this router is listening on
+ if (entity === 'router') {
+ var listeners = onode['.listener'].results;
+ var listenerAttributes = onode['.listener'].attributeNames;
+ var normals = listeners.filter(function(listener) {
+ return QDRService.valFor(listenerAttributes, listener, 'role') === 'normal';
+ })
+ var ports = []
+ normals.forEach(function(normalListener) {
+ ports.push(QDRService.valFor(listenerAttributes, normalListener, 'port'))
+ })
+ // add as 2nd row
+ if (ports.length) {
+ attributes.splice(1, 0, {
+ attributeName: 'Listening on',
+ attributeValue: ports,
+ description: 'The port on which this router is listening for connections'
+ });
+ }
+ }
+ $scope.$broadcast('showEntityForm', {
+ entity: entity,
+ attributes: attributes
+ })
+ if (!$scope.$$phase) $scope.$apply()
+ })
+ }
+ }
+
+ 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;
+ }
+ }
+
+ //QDR.log.debug("creating new link (" + (links.length) + ") between " + nodes[_source].name + " and " + nodes[_target].name);
+ 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) {
+ //QDR.log.debug("in tick for d");
+ //console.dump(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();
+ }
+ }
+
+ // highlight the paths between the selected node and the hovered node
+ function findNextHopNode(from, d) {
+ // d is the node that the mouse is over
+ // from is the selected_node ....
+ if (!from)
+ return null;
+
+ if (from == d)
+ return selected_node;
+
+ //QDR.log.debug("finding nextHop from: " + from.name + " to " + d.name);
+ var sInfo = QDRService.topology.nodeInfo()[from.key];
+
+ if (!sInfo) {
+ QDR.log.warn("unable to find topology node info for " + from.key);
+ return null;
+ }
+
+ // find the hovered name in the selected name's .router.node results
+ if (!sInfo['.router.node'])
+ return null;
+ var aAr = sInfo['.router.node'].attributeNames;
+ var vAr = sInfo['.router.node'].results;
+ for (var hIdx = 0; hIdx < vAr.length; ++hIdx) {
+ var addrT = QDRService.valFor(aAr, vAr[hIdx], "id");
+ if (addrT == d.name) {
+ //QDR.log.debug("found " + d.name + " at " + hIdx);
+ var nextHop = QDRService.valFor(aAr, vAr[hIdx], "nextHop");
+ //QDR.log.debug("nextHop was " + nextHop);
+ return (nextHop == null) ? nodeFor(addrT) : nodeFor(nextHop);
+ }
+ }
+ return null;
+ }
+
+ function nodeFor(name) {
+ for (var i = 0; i < nodes.length; ++i) {
+ if (nodes[i].name == name)
+ return nodes[i];
+ }
+ return null;
+ }
+
+ 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];
+ }
+ // the selected node was a client/broker
+ //QDR.log.debug("failed to find a link between ");
+ //console.dump(source);
+ //QDR.log.debug(" and ");
+ //console.dump(target);
+ return null;
+ }
+
+ 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('#node_context_menu').style('display', 'none');
+
+ }
+
+ function removeCrosssection() {
+ setTimeout(function() {
+ d3.select("[id^=tooltipsy]").remove()
+ $('.hastip').empty();
+ }, 1010);
+ d3.select("#crosssection svg g").transition()
+ .duration(1000)
+ .attr("transform", "scale(0)")
+ .style("opacity", 0)
+ .each("end", function (d) {
+ d3.select("#crosssection svg").remove();
+ d3.select("#crosssection").style("display","none");
+ });
+ d3.select("#multiple_details").transition()
+ .duration(500)
+ .style("opacity", 0)
+ .each("end", function(d) {
+ d3.select("#multiple_details").style("display", "none")
+ stopUpdateConnectionsGrid();
+ })
+ hideLinkDetails();
+ }
+
+ 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(' + urlPrefix + '#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(' + urlPrefix + '#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(' + urlPrefix + '#start-arrow' + sel + ')' : '';
+ })
+ .attr('marker-end', function(d) {
+ var sel = d === selected_link ? '-selected' : (d.cls === 'small' ? '-small' : '');
+ return d.right ? 'url(' + urlPrefix + '#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;
+ }
+ //QDR.log.debug("showing connections form");
+ var resultIndex = 0; // the connection to use
+ var left = d.left ? d.target : d.source;
+ // right is the node that the arrow points to, left is the other node
+ var right = d.left ? d.source : d.target;
+ var onode = QDRService.topology.nodeInfo()[left.key];
+ // loop through all the connections for left, and find the one for right
+ if (!onode || !onode['.connection'])
+ return;
+ // update the info dialog for the link the mouse is over
+ if (!selected_node && !selected_link) {
+ for (resultIndex = 0; resultIndex < onode['.connection'].results.length; ++resultIndex) {
+ var conn = onode['.connection'].results[resultIndex];
+ /// find the connection whose container is the right's name
+ var name = QDRService.valFor(onode['.connection'].attributeNames, conn, "container");
+ if (name == right.routerId) {
+ break;
+ }
+ }
+ // did not find connection. this is a connection to a non-interrouter node
+ if (resultIndex === onode['.connection'].results.length) {
+ // use the non-interrouter node's connection info
+ left = d.target;
+ resultIndex = left.resultIndex;
+ }
+ if (resultIndex)
+ updateForm(left.key, 'connection', resultIndex);
+ }
+
+ 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;
+ }
+ //QDR.log.debug("showing connections form");
+ selected_link = null;
+ restart();
+ })
+ .on("contextmenu", function(d) { // right click a path
+ $(document).click();
+ d3.event.preventDefault();
+ if (d.cls !== "temp")
+ return;
+
+ mousedown_link = d;
+ d3.select('#link_context_menu')
+ .style('left', (mouseX + $(document).scrollLeft()) + "px")
+ .style('top', (mouseY + $(document).scrollTop()) + "px")
+ .style('display', 'block');
+ })
+ // left click a path
+ .on("click", function (d) {
+ var clickPos = d3.mouse(this);
+ d3.event.stopPropagation();
+ clearPopups();
+ var showCrossSection = function() {
+ var diameter = 400;
+ var format = d3.format(",d");
+ var pack = d3.layout.pack()
+ .size([diameter - 4, diameter - 4])
+ .padding(-10)
+ .value(function(d) { return d.size; });
+
+ d3.select("#crosssection svg").remove();
+ var svg = d3.select("#crosssection").append("svg")
+ .attr("width", diameter)
+ .attr("height", diameter)
+ var svgg = svg.append("g")
+ .attr("transform", "translate(2,2)");
+
+ var root = {
+ name: " Links between " + d.source.name + " and " + d.target.name,
+ children: []
+ }
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var connections = nodeInfo[d.source.key]['.connection'];
+ var containerIndex = connections.attributeNames.indexOf('container');
+ connections.results.some ( function (connection) {
+ if (connection[containerIndex] == d.target.routerId) {
+ root.attributeNames = connections.attributeNames;
+ root.obj = connection;
+ root.desc = "Connection";
+ return true; // stop looping after 1 match
+ }
+ return false;
+ })
+
+ // find router.links where link.remoteContainer is d.source.name
+ var links = nodeInfo[d.source.key]['.router.link'];
+ var identityIndex = connections.attributeNames.indexOf('identity')
+ var roleIndex = connections.attributeNames.indexOf('role')
+ var connectionIdIndex = links.attributeNames.indexOf('connectionId');
+ var linkTypeIndex = links.attributeNames.indexOf('linkType');
+ var nameIndex = links.attributeNames.indexOf('name');
+ var linkDirIndex = links.attributeNames.indexOf('linkDir');
+
+ if (roleIndex < 0 || identityIndex < 0 || connectionIdIndex < 0
+ || linkTypeIndex < 0 || nameIndex < 0 || linkDirIndex < 0)
+ return;
+ links.results.forEach ( function (link) {
+ if (root.obj && link[connectionIdIndex] == root.obj[identityIndex] && link[linkTypeIndex] == root.obj[roleIndex])
+ root.children.push (
+ { name: " " + link[linkDirIndex] + " ",
+ size: 100,
+ obj: link,
+ desc: "Link",
+ attributeNames: links.attributeNames
+ })
+ })
+ if (root.children.length == 0)
+ return;
+ var node = svgg.datum(root).selectAll(".node")
+ .data(pack.nodes)
+ .enter().append("g")
+ .attr("class", function(d) { return d.children ? "parent node hastip" : "leaf node hastip"; })
+ .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" + (!d.children ? "scale(0.9)" : ""); })
+ .attr("title", function (d) {
+ var title = "<h4>" + d.desc + "</h4><table class='tiptable'><tbody>";
+ if (d.attributeNames)
+ d.attributeNames.forEach( function (n, i) {
+ title += "<tr><td>" + n + "</td><td>";
+ title += d.obj[i] != null ? d.obj[i] : '';
+ title += '</td></tr>';
+ })
+ title += "</tbody></table>"
+ return title
+ })
+ node.append("circle")
+ .attr("r", function(d) { return d.r; });
+
+ // node.filter(function(d) { return !d.children; }).append("text")
+ node.append("text")
+ .attr("dy", function (d) { return d.children ? "-10em" : ".5em"})
+ .style("text-anchor", "middle")
+ .text(function(d) {
+ return d.name.substring(0, d.r / 3);
+ });
+ $('.hastip').tooltipsy({ alignTo: 'cursor'});
+ svgg.attr("transform", "translate(2,2) scale(0.01)")
+
+ var bounds = $("#topology").position()
+ d3.select("#crosssection")
+ .style("display", "block")
+ .style("left", (clickPos[0] + bounds.left) + "px")
+ .style("top", (clickPos[1] + bounds.top) + "px")
+
+ svgg.transition()
+ .attr("transform", "translate(2,2) scale(1)")
+ .each("end", function () {
+ d3.selectAll("#crosssection g.leaf text").attr("dy", ".3em")
+ })
+ }
+ QDRService.ensureEntities(d.source.key, {entity: '.router.link', force: true}, showCrossSection)
+ })
+ // remove old links
+ path.exit().remove();
+
+
+ // circle (node) group
+ // nodes are known by id
+ circle = circle.data(nodes, function(d) {
+ return d.name;
+ });
+
+ // update existing nodes visual states
+ circle.selectAll('circle')
+ .classed('highlighted', function(d) {
+ return d.highlighted;
+ })
+ .classed('selected', function(d) {
+ return (d === selected_node)
+ })
+ .classed('fixed', function(d) {
+ return d.fixed
+ })
+
+ // 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]
+ })
+ .attr('fill', function (d) {
+ if (d.cdir === 'both' && !QDRService.isConsole(d)) {
+ return 'url(' + urlPrefix + '#half-circle)'
+ }
+ return null;
+ })
+ .classed('fixed', function(d) {
+ return d.fixed
+ })
+ .classed('temp', function(d) {
+ return QDRService.nameFromId(d.key) == '__internal__';
+ })
+ .classed('normal', function(d) {
+ return d.nodeType == 'normal'
+ })
+ .classed('in', function(d) {
+ return d.cdir == 'in'
+ })
+ .classed('out', function(d) {
+ return d.cdir == 'out'
+ })
+ .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 == 'on-demand'
+ })
+ .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('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 (!selected_node) {
+ if (d.nodeType === 'inter-router') {
+ //QDR.log.debug("showing general form");
+ updateForm(d.key, 'router', 0);
+ } else if (d.nodeType === 'normal' || d.nodeType === 'on-demand') {
+ //QDR.log.debug("showing connections form");
+ updateForm(d.key, 'connection', d.resultIndex);
+ }
+ }
+
+ if (d === mousedown_node)
+ return;
+ //if (d === selected_node)
+ // return;
+ // enlarge target node
+ d3.select(this).attr('transform', 'scale(1.1)');
+ // highlight the next-hop route from the selected node to this node
+ mousedown_node = null;
+
+ if (!selected_node) {
+ return;
+ }
+ clerAllHighlights()
+ // we need .router.node info to highlight hops
+ QDRService.ensureAllEntities([{entity: ".router.node", attrs: ["id","nextHop"]}], function () {
+ mouseover_node = d // save this node in case the topology changes so we can restore the highlights
+ nextHop(selected_node, d);
+ restart();
+ })
+ })
+ .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, make it fixed
+ var cur_mouse = d3.mouse(mySvg);
+ if (cur_mouse[0] != initial_mouse_down_position[0] ||
+ cur_mouse[1] != initial_mouse_down_position[1]) {
+ console.log("mouse pos changed. making this node fixed")
+ d.fixed = true;
+ setNodesFixed(d.name, true)
+ resetMouseVars();
+ restart();
+ return;
+ }
+
+ // we didn't drag, we just clicked on the node
+ if ($scope.addingNode.step > 0) {
+ if (d.nodeType !== 'inter-router')
+ return;
+ if (QDRService.nameFromId(d.key) == '__internal__')
+ return;
+
+ // add a link from the clicked node to the new node
+ getLink(d.id, nodes.length - 1, "in", "temp", "__internal__");
+ $scope.addingNode.hasLink = true;
+ if (!$scope.$$phase) $scope.$apply()
+ // add new elements to the svg
+ force.links(links).start();
+ restart();
+ return;
+
+ }
+
+ // if this node was selected, unselect it
+ if (mousedown_node === selected_node) {
+ selected_node = null;
+ } else {
+ if (d.nodeType !== 'normal' && d.nodeType !== 'on-demand')
+ selected_node = mousedown_node;
+ }
+ clerAllHighlights()
+ mousedown_node = null;
+ if (!$scope.$$phase) $scope.$apply()
+ restart(false);
+
+ })
+ .on("dblclick", function(d) { // circle
+ if (d.fixed) {
+ d.fixed = false
+ setNodesFixed(d.name, false)
+ restart() // redraw the node without a dashed line
+ force.start(); // let the nodes move to a new position
+ }
+ if (QDRService.nameFromId(d.key) == '__internal__') {
+ editNode();
+ if (!$scope.$$phase) $scope.$apply()
+ }
+ })
+ .on("contextmenu", function(d) { // circle
+ $(document).click();
+ d3.event.preventDefault();
+ $scope.contextNode = d;
+ if (!$scope.$$phase) $scope.$apply() // we just changed a scope valiable during an async event
+ d3.select('#node_context_menu')
+ .style('left', (mouseX + $(document).scrollLeft()) + "px")
+ .style('top', (mouseY + $(document).scrollTop()) + "px")
+ .style('display', 'block');
+
+ })
+ .on("click", function(d) { // circle
+ if (!mouseup_node)
+ return;
+ // clicked on a circle
+ clearPopups();
+ if (!d.normals) {
+ // circle was a router or a broker
+ if (QDRService.isArtemis(d)) {
+ var artemisPath = '/jmx/attributes?tab=artemis&con=Artemis'
+ if (QDR.isStandalone)
+ window.location = $location.protocol() + '://localhost:8161/hawtio' + artemisPath
+ else
+ $location.path(artemisPath)
+ }
+ return;
+ }
+ clickPos = d3.mouse(this);
+ d3.event.stopPropagation();
+ startUpdateConnectionsGrid(d);
+ })
+ //.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
+ }
+ if (QDRService.isArtemis(d)) {
+ return '\ue900'
+ }
+ if (QDRService.isQpid(d)) {
+ return '\ue901';
+ }
+ if (d.nodeType === 'normal')
+ return '\uf109'; // icon-laptop for clients
+ return d.name.length > 7 ? d.name.substr(0, 6) + '...' : d.name;
+ });
+ }
+
+ appendContent(g)
+
+ var appendTitle = function(g) {
+ g.append("svg:title").text(function(d) {
+ var x = '';
+ if (d.normals && d.normals.length > 1)
+ x = " x " + d.normals.length;
+ if (QDRService.isConsole(d)) {
+ return 'Dispatch console' + x
+ }
+ if (d.properties.product == 'qpid-cpp') {
+ return 'Broker - qpid-cpp' + x
+ }
+ if (QDRService.isArtemis(d)) {
+ return 'Broker - Artemis' + x
+ }
+ if (d.cdir === 'in')
+ return 'Sender' + x
+ if (d.cdir === 'out')
+ return 'Receiver' + x
+ if (d.cdir === 'both')
+ return 'Sender/Receiver' + x
+ return d.nodeType == 'normal' ? 'client' + x : (d.nodeType == 'on-demand' ? 'broker' : 'Router ' + d.name)
+ })
+ }
+ appendTitle(g);
+
+ // remove old nodes
+ circle.exit().remove();
+
+ // add subcircles
+ svg.selectAll('.subcircle').remove();
+ var multiples = svg.selectAll('.multiple')
+ multiples.each(function(d) {
+ d.normals.forEach(function(n, i) {
+ if (i < d.normals.length - 1 && i < 3) // only show a few shadow circles
+ this.insert('svg:circle', ":first-child")
+ .attr('class', 'subcircle node')
+ .attr('r', 15 - i)
+ .attr('transform', "translate(" + 4 * (i + 1) + ", 0)")
+ }, d3.select(this))
+ })
+
+ // 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("Sender", "", "normal", undefined, 2, 0, 0, 0, false, {})
+ node.cdir = "in"
+ legendNodes.push(node)
+ }
+ if (!svg.selectAll('circle.client.out').empty()) {
+ var node = aNode("Receiver", "", "normal", undefined, 3, 0, 0, 0, false, {})
+ node.cdir = "out"
+ legendNodes.push(node)
+ }
+ if (!svg.selectAll('circle.client.inout').empty()) {
+ var node = aNode("Sender/Receiver", "", "normal", undefined, 4, 0, 0, 0, false, {})
+ node.cdir = "both"
+ legendNodes.push(node)
+ }
+ if (!svg.selectAll('circle.qpid-cpp').empty()) {
+ legendNodes.push(aNode("Qpid broker", "", "on-demand", undefined, 5, 0, 0, 0, false, {
+ product: 'qpid-cpp'
+ }))
+ }
+ if (!svg.selectAll('circle.artemis').empty()) {
+ legendNodes.push(aNode("Artemis broker", "", "route-container", undefined, 6, 0, 0, 0, false, {product: 'apache-activemq-artemis'}))
+ }
+ 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 || !selected_node)
+ return;
+
+ if (!start)
+ return;
+ // set the graph in motion
+ //QDR.log.debug("mousedown_node is " + mousedown_node);
+ force.start();
+
+ }
+
+ var startUpdateConnectionsGrid = function(d) {
+ // called after each topology update
+ var extendConnections = function() {
+ // force a fetch of the links for this node
+ QDRService.ensureEntities(d.key, {entity: ".router.link", force: true}, function () {
+ // the links for this node are now available
+ $scope.multiData = []
+ var normals = d.normals;
+ // find updated normals for d
+ d3.selectAll('.normal')
+ .each(function(newd) {
+ if (newd.id == d.id && newd.name == d.name) {
+ normals = newd.normals;
+ }
+ });
+ if (normals) {
+ normals.forEach(function(n) {
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var links = nodeInfo[n.key]['.router.link'];
+ var linkTypeIndex = links.attributeNames.indexOf('linkType');
+ var connectionIdIndex = links.attributeNames.indexOf('connectionId');
+ n.linkData = [];
+ links.results.forEach(function(link) {
+ if (link[linkTypeIndex] === 'endpoint' && link[connectionIdIndex] === n.connectionId) {
+ var l = {};
+ l.owningAddr = QDRService.valFor(links.attributeNames, link, 'owningAddr');
+ l.dir = QDRService.valFor(links.attributeNames, link, 'linkDir');
+ if (l.owningAddr && l.owningAddr.length > 2)
+ if (l.owningAddr[0] === 'M')
+ l.owningAddr = l.owningAddr.substr(2)
+ else
+ l.owningAddr = l.owningAddr.substr(1)
+
+ l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
+ l.uncounts = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount') +
+ QDRService.valFor(links.attributeNames, link, 'unsettledCount'))
+ //l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
+ //l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
+ l.adminStatus = QDRService.valFor(links.attributeNames, link, 'adminStatus');
+ l.operStatus = QDRService.valFor(links.attributeNames, link, 'operStatus');
+ l.identity = QDRService.valFor(links.attributeNames, link, 'identity')
+ l.connectionId = QDRService.valFor(links.attributeNames, link, 'connectionId')
+ l.nodeId = n.key
+ l.type = QDRService.valFor(links.attributeNames, link, 'type')
+ l.name = QDRService.valFor(links.attributeNames, link, 'name')
+
+ // TODO: remove this fake quiescing/reviving logic when the routers do the work
+ initConnState(n.connectionId)
+ if ($scope.quiesceState[n.connectionId].linkStates[l.identity])
+ l.adminStatus = $scope.quiesceState[n.connectionId].linkStates[l.identity];
+ if ($scope.quiesceState[n.connectionId].state == 'quiescing') {
+ if (l.adminStatus === 'enabled') {
+ // 25% chance of switching
+ var chance = Math.floor(Math.random() * 2);
+ if (chance == 1) {
+ l.adminStatus = 'disabled';
+ $scope.quiesceState[n.connectionId].linkStates[l.identity] = 'disabled';
+ }
+ }
+ }
+ if ($scope.quiesceState[n.connectionId].state == 'reviving') {
+ if (l.adminStatus === 'disabled') {
+ // 25% chance of switching
+ var chance = Math.floor(Math.random() * 2);
+ if (chance == 1) {
+ l.adminStatus = 'enabled';
+ $scope.quiesceState[n.connectionId].linkStates[l.identity] = 'enabled';
+ }
+ }
+ }
+ QDR.log.debug("pushing link state for " + l.owningAddr + " status: " + l.adminStatus)
+
+ n.linkData.push(l)
+ }
+ })
+ $scope.multiData.push(n)
+ if (n.connectionId == $scope.connectionId)
+ $scope.linkData = n.linkData;
+ initConnState(n.connectionId)
+ $scope.multiDetails.updateState(n)
+ })
+ }
+ $scope.$apply();
+
+ d3.select('#multiple_details')
+ .style({
+ height: ((normals.length + 1) * 30) + 40 + "px",
+ 'overflow-y': normals.length > 10 ? 'scroll' : 'hidden'
+ })
+ })
+ }
+ // register a notification function for when the topology is updated
+ QDRService.addUpdatedAction("normalsStats", extendConnections)
+ // call the function that gets the links right now
+ extendConnections();
+ clearPopups();
+ var display = 'block'
+ var left = mouseX + $(document).scrollLeft()
+ if (d.normals.length === 1) {
+ display = 'none'
+ left = left - 30;
+ mouseY = mouseY - 20
+ }
+ d3.select('#multiple_details')
+ .style({
+ display: display,
+ opacity: 1,
+ left: (mouseX + $(document).scrollLeft()) + "px",
+ top: (mouseY + $(document).scrollTop()) + "px"
+ })
+ if (d.normals.length === 1) {
+ // simulate a click on the connection to popup the link details
+ QDRService.ensureEntities(d.key, {entity: ".router.link", force: true}, function () {
+ $scope.multiDetails.showLinksList({
+ entity: d
+ })
+ })
+ }
+ }
+ var stopUpdateConnectionsGrid = function() {
+ QDRService.delUpdatedAction("normalsStats");
+ }
+
+ var initConnState = function(id) {
+ if (!angular.isDefined($scope.quiesceState[id])) {
+ $scope.quiesceState[id] = {
+ state: 'enabled',
+ buttonText: 'Quiesce',
+ buttonDisabled: false,
+ linkStates: {}
+ }
+ }
+ }
+
+ function nextHop(thisNode, d) {
+ if ((thisNode) && (thisNode != d)) {
+ var target = findNextHopNode(thisNode, d);
+ //QDR.log.debug("highlight link from node ");
+ //console.dump(nodeFor(selected_node.name));
+ //console.dump(target);
+ if (target) {
+ var hnode = nodeFor(thisNode.name)
+ var hlLink = linkFor(hnode, target);
+ //QDR.log.debug("need to highlight");
+ //console.dump(hlLink);
+ if (hlLink) {
+ hlLink['highlighted'] = true;
+ hnode['highlighted'] = true
+ }
+ else
+ target = null;
+ }
+ nextHop(target, d);
+ }
+ if (thisNode == d) {
+ var hnode = nodeFor(thisNode.name)
+ hnode['highlighted'] = true
+ }
+ }
+
+
+ function mousedown() {
+ // prevent I-bar on drag
+ //d3.event.preventDefault();
+
+ // because :active only works in WebKit?
+ svg.classed('active', true);
+ }
+
+ function hasChanged() {
+ // Don't update the underlying topology diagram if we are adding a new node.
+ // Once adding is completed, the topology will update automatically if it has changed
+ if ($scope.addingNode.step > 0)
+ return -2;
+ var nodeInfo = QDRService.topology.nodeInfo();
+ if (Object.keys(nodeInfo).length != Object.keys(savedKeys).length)
+ return Object.keys(nodeInfo).length > Object.keys(savedKeys).length ? 1 : -1;
+ // we may have dropped a node and added a different node in the same update cycle
+ for (var key in nodeInfo) {
+ // if this node isn't in the saved node list
+ if (!savedKeys.hasOwnProperty(key))
+ return 1;
+ // if the number of connections for this node chaanged
+ if (nodeInfo[key]['.connection'].results.length != savedKeys[key]) {
+ return -1;
+ }
+ }
+ return 0;
+ };
+
+ function saveChanged() {
+ savedKeys = {};
+ var nodeInfo = QDRService.topology.nodeInfo();
+ // save the number of connections per node
+ for (var key in nodeInfo) {
+ if (nodeInfo[key]['.connection'])
+ savedKeys[key] = nodeInfo[key]['.connection'].results.length;
+ }
+ //QDR.log.debug("saving current keys");
+ console.dump(savedKeys);
+ };
+ // we are about to leave the page, save the node positions
+ $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
+ //QDR.log.debug("locationChangeStart");
+ savePositions()
+ $scope.addingNode.step = 0;
+ });
+ // When the DOM element is removed from the page,
+ // AngularJS will trigger the $destroy event on
+ // the scope
+ $scope.$on("$destroy", function(event) {
+ //QDR.log.debug("scope on destroy");
+ savePositions();
+ QDRService.setUpdateEntities([])
+ QDRService.stopUpdating();
+ QDRService.delUpdatedAction("normalsStats");
+ QDRService.delUpdatedAction("topology");
+ d3.select("#SVG_ID").remove();
+ window.removeEventListener('resize', resize);
+ });
+
+ function handleInitialUpdate() {
+ // we only need to update connections during steady-state
+ QDRService.setUpdateEntities([".connection"])
+ // we currently have all entities available on all routers
+ saveChanged();
+ animate = true;
+ initForceGraph();
+ // after the graph is displayed fetch all .router.node info. This is done so highlighting between nodes
+ // doesn't incur a delay
+ QDRService.ensureAllEntities([{entity: ".router.node", attrs: ["id","nextHop"]}], function () {})
+ // call this function every time a background update is done
+ QDRService.addUpdatedAction("topology", function() {
+ var changed = hasChanged()
+ // there is a new node, we need to get all of it's entities before drawing the graph
+ if (changed > 0) {
+ QDRService.delUpdatedAction("topology")
+ setupInitialUpdate()
+ } else if (changed === -1) {
+ // we lost a node (or a client), we can draw the new svg immediately
+ saveChanged();
+ var nodeInfo = QDRService.topology.nodeInfo();
+ initializeNodes(nodeInfo)
+
+ var unknowns = []
+ initializeLinks(nodeInfo, unknowns)
+ if (unknowns.length > 0) {
+ resolveUnknowns(nodeInfo, unknowns)
+ }
+ else {
+ force.nodes(nodes).links(links).start();
+ animate = true;
+ restart();
+ }
+
+ //initForceGraph();
+ } else {
+ //QDR.log.debug("topology didn't change")
+ }
+
+ })
+ }
+
+ function setupInitialUpdate() {
+ // make sure all router nodes have .connection info. if not then fetch any missing info
+ QDRService.ensureAllEntities(
+// [{entity: ".connection"}, {entity: ".router.lin.router.link", attrs: ["linkType","connectionId","linkDir"]}],
+ [{entity: ".connection"}],
+ //[{entity: ".connection"}],
+ handleInitialUpdate)
+ }
+ setupInitialUpdate();
+ QDRService.startUpdating();
+
+ function doAddDialog(NewRouterName) {
+ QDRService.ensureAllEntities({entity: ".listener"}, function () {
+ var d = $dialog.dialog({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.NodeDialogController',
+ templateUrl: 'node-config-template.html',
+ resolve: {
+ newname: function() {
+ return NewRouterName;
+ }
+ }
+ });
+ $timeout(function () {
+ d.open().then(function(result) {
+ if (result)
+ doDownloadDialog(result);
+ });
+ })
+ })
+ };
+
+ function doDownloadDialog(result) {
+ d = $dialog.dialog({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ controller: 'QDR.DownloadDialogController',
+ templateUrl: 'download-dialog-template.html',
+ resolve: {
+ results: function() {
+ return result;
+ }
+ }
+ });
+ d.open().then(function(result) {
+ //QDR.log.debug("download dialog done")
+ })
+ if (!$scope.$$phase) $scope.$apply()
+ };
+ }
+ ]);
+
+ return QDR;
+}(QDR || {}));
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[4/4] qpid-dispatch git commit: DISPATCH-745 Remove symlinks from
hawtio to stand-alone
Posted by ea...@apache.org.
DISPATCH-745 Remove symlinks from hawtio to stand-alone
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/6a1e6632
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/6a1e6632
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/6a1e6632
Branch: refs/heads/master
Commit: 6a1e66322cf8b1298acc76bf3ed9d5bfeade2c3f
Parents: 4c14b0a
Author: Ernest Allen <ea...@redhat.com>
Authored: Wed Apr 19 08:16:53 2017 -0400
Committer: Ernest Allen <ea...@redhat.com>
Committed: Wed Apr 19 08:16:53 2017 -0400
----------------------------------------------------------------------
.../hawtio/src/main/webapp/plugin/js/navbar.js | 302 ++-
.../hawtio/src/main/webapp/plugin/js/qdrList.js | 788 ++++++-
.../src/main/webapp/plugin/js/qdrListChart.js | 142 +-
.../src/main/webapp/plugin/js/qdrNewNode.js | 446 +++-
.../src/main/webapp/plugin/js/qdrOverview.js | 1767 +++++++++++++-
.../plugin/js/qdrOverviewLogsController.js | 68 +-
.../src/main/webapp/plugin/js/qdrTopology.js | 2161 +++++++++++++++++-
console/stand-alone/plugin/js/navbar.js | 43 +-
console/stand-alone/plugin/js/qdrList.js | 13 +-
console/stand-alone/plugin/js/qdrListChart.js | 835 ++++++-
console/stand-alone/plugin/js/qdrNewNode.js | 10 +-
console/stand-alone/plugin/js/qdrOverview.js | 309 ++-
.../plugin/js/qdrOverviewLogsController.js | 4 +-
console/stand-alone/plugin/js/qdrTopology.js | 88 +-
14 files changed, 6709 insertions(+), 267 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/navbar.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/navbar.js b/console/hawtio/src/main/webapp/plugin/js/navbar.js
deleted file mode 120000
index e88b618..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/navbar.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/navbar.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/navbar.js b/console/hawtio/src/main/webapp/plugin/js/navbar.js
new file mode 100644
index 0000000..5125748
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/navbar.js
@@ -0,0 +1,301 @@
+/*
+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) {
+
+ /**
+ * @property breadcrumbs
+ * @type {{content: string, title: string, isValid: isValid, href: string}[]}
+ *
+ * Data structure that defines the sub-level tabs for
+ * our plugin, used by the navbar controller to show
+ * or hide tabs based on some criteria
+ */
+ QDR.breadcrumbs = [
+ {
+ content: '<i class="icon-cogs"></i> Connect',
+ title: "Connect to a router",
+ isValid: function () { return true; },
+ href: "#" + QDR.pluginRoot + "/connect"
+ },
+ {
+ content: '<i class="icon-home"></i> Overview',
+ title: "View router overview",
+ isValid: function (QDRService) { return QDRService.isConnected(); },
+ href: "#" + QDR.pluginRoot + "/overview"
+ },
+ {
+ content: '<i class="icon-list "></i> Entities',
+ title: "View the attributes of the router entities",
+ isValid: function (QDRService) { return QDRService.isConnected(); },
+ href: "#" + QDR.pluginRoot + "/list"
+ },
+ {
+ content: '<i class="icon-star-empty"></i> Topology',
+ title: "View router network topology",
+ isValid: function (QDRService) { return QDRService.isConnected(); },
+ href: "#" + QDR.pluginRoot + "/topology"
+ },
+ {
+ content: '<i class="icon-bar-chart"></i> Charts',
+ title: "View charts",
+ isValid: function (QDRService, $location) { return QDRService.isConnected() && QDR.isStandalone; },
+ href: "#/charts"
+ },
+ {
+ content: '<i class="icon-align-left"></i> Schema',
+ title: "View dispatch schema",
+ isValid: function (QDRService) { return QDRService.isConnected(); },
+ href: "#" + QDR.pluginRoot + "/schema",
+ right: true
+ }
+ ];
+ /**
+ * @function NavBarController
+ *
+ * @param $scope
+ * @param workspace
+ *
+ * The controller for this plugin's navigation bar
+ *
+ */
+ QDR.module.controller("QDR.NavBarController", ['$scope', 'QDRService', 'QDRChartService', '$routeParams', '$location', function($scope, QDRService, QDRChartService, $routeParams, $location) {
+ $scope.breadcrumbs = QDR.breadcrumbs;
+ $scope.isValid = function(link) {
+ return link.isValid(QDRService, $location);
+ };
+
+ $scope.isActive = function(href) {
+ // highlight the connect tab if we are on the root page
+ if (($location.path() === QDR.pluginRoot) && (href.split("#")[1] === QDR.pluginRoot + "/connect"))
+ return true
+ return href.split("#")[1] == $location.path();
+ };
+
+ $scope.isRight = function (link) {
+ return angular.isDefined(link.right);
+ };
+
+ $scope.hasChart = function (link) {
+ if (link.href == "#/charts") {
+ return QDRChartService.charts.some(function (c) { return c.dashboard });
+ }
+ }
+
+ $scope.isDashboardable = function () {
+ return ($location.path().indexOf("schema") < 0 && $location.path().indexOf("connect") < 0);
+ }
+
+ $scope.addToDashboardLink = function () {
+ var href = "#" + $location.path();
+ var size = angular.toJson({
+ size_x: 2,
+ size_y: 2
+ });
+
+ var routeParams = angular.toJson($routeParams);
+ var title = "Dispatch Router";
+ return "/hawtio/#/dashboard/add?tab=dashboard" +
+ "&href=" + encodeURIComponent(href) +
+ "&routeParams=" + encodeURIComponent(routeParams) +
+ "&title=" + encodeURIComponent(title) +
+ "&size=" + encodeURIComponent(size);
+ };
+
+ }]);
+
+ // controller for the edit/configure chart dialog
+ QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, dialog, chart, updateTick, dashboard, adding) {
+ var dialogSvgChart = null;
+ $scope.svgDivId = "dialogEditChart"; // the div id for the svg chart
+
+ var updateTimer = null;
+ $scope.chart = chart; // the underlying chart object from the dashboard
+ $scope.dialogChart = $scope.chart.copy(); // the chart object for this dialog
+ $scope.userTitle = $scope.chart.title();
+
+ $scope.$watch('userTitle', function(newValue, oldValue) {
+ if (newValue !== oldValue) {
+ $scope.dialogChart.title(newValue);
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+ $scope.$watch("dialogChart.areaColor", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+ $scope.$watch("dialogChart.lineColor", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+ $scope.$watch("dialogChart.type", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+
+ // the stored rateWindow is in milliseconds, but the slider is in seconds
+ $scope.rateWindow = $scope.chart.rateWindow / 1000;
+
+ $scope.addChartsPage = function () {
+ QDRChartService.addDashboard(dialogSvgChart.chart);
+ };
+
+ $scope.showChartsPage = function () {
+ cleanup();
+ dialog.close(true);
+ $location.path(QDR.pluginRoot + "/charts");
+ };
+
+ var cleanup = function () {
+ if (updateTimer) {
+ clearTimeout(updateTimer);
+ updateTimer = null;
+ }
+ if (!$scope.isOnChartsPage())
+ QDRChartService.unRegisterChart($scope.dialogChart); // remove the chart
+ }
+ $scope.okClick = function () {
+ cleanup();
+ dialog.close(true);
+ };
+
+ var initRateSlider = function () {
+ if (document.getElementById('rateSlider')) {
+ $( "#rateSlider" ).slider({
+ value: $scope.rateWindow,
+ min: 1,
+ max: 10,
+ step: 1,
+ slide: function( event, ui ) {
+ $scope.rateWindow = ui.value;
+ $scope.dialogChart.rateWindow = ui.value * 1000;
+ $scope.$apply();
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ });
+ } else {
+ setTimeout(initRateSlider, 100)
+ }
+ }
+ initRateSlider();
+
+ var initDurationSlider = function () {
+ if (document.getElementById('durationSlider')) {
+ $( "#durationSlider" ).slider({
+ value: $scope.dialogChart.visibleDuration,
+ min: 1,
+ max: 10,
+ step: 1,
+ slide: function( event, ui ) {
+ $scope.visibleDuration = $scope.dialogChart.visibleDuration = ui.value;
+ $scope.$apply();
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ });
+ } else {
+ setTimeout(initDurationSlider, 100)
+ }
+ }
+ initDurationSlider();
+
+ $scope.adding = function () {
+ return adding
+ }
+
+ $scope.isOnChartsPage = function () {
+ if (adding)
+ return dialogSvgChart ? dialogSvgChart.chart.dashboard : false;
+ else
+ return $scope.chart.dashboard
+ }
+
+ // handle the Apply button click
+ // update the dashboard chart's properties
+ $scope.apply = function () {
+ $scope.chart.areaColor = $scope.dialogChart.areaColor;
+ $scope.chart.lineColor = $scope.dialogChart.lineColor;
+ $scope.chart.type = $scope.dialogChart.type;
+ $scope.chart.rateWindow = $scope.rateWindow * 1000;
+ $scope.chart.title($scope.dialogChart.title());
+ $scope.chart.visibleDuration = $scope.dialogChart.visibleDuration;
+ QDRChartService.saveCharts();
+ if (typeof updateTick === "function")
+ updateTick();
+ }
+
+ // add a new chart to the dashboard based on the current dialog settings
+ $scope.copyToDashboard = function () {
+ var chart = $scope.dialogChart.copy();
+ // set the new chart's dashboard state
+ QDRChartService.addDashboard(chart);
+ // notify the chart controller that it needs to display a new chart
+ dashboard.addChart(chart);
+ }
+
+ // update the chart on the popup dialog
+ var updateDialogChart = function () {
+ // draw the chart using the current data
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+
+ // draw the chart again in 1 second
+ var updateRate = localStorage['updateRate'] ? localStorage['updateRate'] : 5000;
+ if (updateTimer)
+ clearTimeout(updateTimer);
+ updateTimer = setTimeout(updateDialogChart, updateRate);
+ }
+
+ var showChart = function () {
+ // ensure the div for our chart is loaded in the dom
+ var div = angular.element("#" + $scope.svgDivId);
+ if (!div.width()) {
+ setTimeout(showChart, 100);
+ return;
+ }
+ dialogSvgChart = new QDRChartService.AreaChart($scope.dialogChart);
+ $('input[name=lineColor]').val($scope.dialogChart.lineColor);
+ $('input[name=areaColor]').val($scope.dialogChart.areaColor);
+ $('input[name=areaColor]').on('input', function (e) {
+ $scope.dialogChart.areaColor = $(this).val();
+ updateDialogChart()
+ })
+ $('input[name=lineColor]').on('input', function (e) {
+ $scope.dialogChart.lineColor = $(this).val();
+ updateDialogChart()
+ })
+ if (updateTimer)
+ clearTimeout(updateTimer);
+ updateDialogChart();
+ }
+ showChart();
+ });
+
+ return QDR;
+
+} (QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/qdrList.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrList.js b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
deleted file mode 120000
index 3955db5..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrList.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/qdrList.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrList.js b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
new file mode 100644
index 0000000..ec2efb2
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
@@ -0,0 +1,787 @@
+/*
+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 ListController
+ * @param $scope
+ * @param QDRService
+ *
+ * Controller for the main interface
+ */
+ QDR.module.controller("QDR.ListController", ['$scope', '$location', '$dialog', '$filter', '$timeout', 'QDRService', 'QDRChartService',
+ function ($scope, $location, $dialog, $filter, $timeout, QDRService, QDRChartService) {
+
+ var updateIntervalHandle = undefined;
+ var updateInterval = 5000;
+ var ListExpandedKey = "QDRListExpanded";
+ $scope.details = {};
+
+ $scope.tmplListTree = QDR.templatePath + 'tmplListTree.html';
+ $scope.selectedEntity = localStorage['QDRSelectedEntity'] || "address";
+ $scope.selectedNode = localStorage['QDRSelectedNode'];
+ $scope.selectedNodeId = localStorage['QDRSelectedNodeId'];
+ $scope.selectedRecordName = localStorage['QDRSelectedRecordName'];
+ $scope.nodes = []
+ $scope.currentNode = undefined;
+ $scope.modes = [
+ {
+ content: '<a><i class="icon-list"></i> Attributes</a>',
+ id: 'attributes',
+ op: 'READ',
+ title: "View router attributes",
+ isValid: function () { return true; }
+ },
+ {
+ content: '<a><i class="icon-edit"></i> Update</a>',
+ id: 'operations',
+ op: 'UPDATE',
+ title: "Update this attribute",
+ isValid: function () {
+ //QDR.log.debug("isValid UPDAATE? " + this.op)
+ //console.dump($scope.operations)
+ return $scope.operations.indexOf(this.op) > -1
+ }
+ },
+ {
+ content: '<a><i class="icon-plus"></i> Create</a>',
+ id: 'operations',
+ op: 'CREATE',
+ title: "Create a new attribute",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-remove"></i> Delete</a>',
+ id: 'delete',
+ op: 'DELETE',
+ title: "Delete",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-eye-open"></i> Fetch</a>',
+ id: 'log',
+ op: 'GET-LOG',
+ title: "Fetch recent log entries",
+ isValid: function () { return ($scope.selectedEntity === 'log') }
+ }
+ ];
+ $scope.operations = []
+ $scope.currentMode = $scope.modes[0];
+ $scope.isModeSelected = function (mode) {
+ return mode === $scope.currentMode;
+ }
+ $scope.fetchingLog = false;
+ $scope.selectMode = function (mode) {
+ $scope.currentMode = mode;
+ if (mode.id === 'log') {
+ $scope.logResults = [];
+ $scope.fetchingLog = true;
+ var entity; // undefined since it is not supported in the GET-LOG call
+ QDRService.sendMethod($scope.currentNode.id, entity, {}, $scope.currentMode.op, {}, function (nodeName, entity, response, context) {
+ $scope.fetchingLog = false;
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ //QDR.log.debug(context.message.application_properties.statusDescription)
+ return;
+ }
+ $scope.logResults = response.filter( function (entry) {
+ return entry[0] === $scope.detailsObject.module
+ }).sort( function (a, b) {
+ return b[5] - a[5]
+ }).map( function (entry) {
+ return {
+ type: entry[1],
+ message: entry[2],
+ source: entry[3],
+ line: entry[4],
+ time: Date(entry[5]).toString()
+ }
+ })
+ $scope.$apply();
+ })
+ }
+ }
+ $scope.isValid = function (mode) {
+ return mode.isValid()
+ }
+
+ $scope.expandAll = function () {
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.expand(true);
+ });
+ }
+ $scope.contractAll = function () {
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.expand(false);
+ });
+ }
+
+ if (!QDRService.connected) {
+ // we are not connected. we probably got here from a bookmark or manual page reload
+ QDRService.redirectWhenConnected("list");
+ return;
+ }
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("list")
+ $scope.$apply();
+ })
+
+ $scope.nodes = []
+ var excludedEntities = ["management", "org.amqp.management", "operationalEntity", "entity", "configurationEntity", "dummy", "console"];
+ var aggregateEntities = ["router.address"];
+ var classOverrides = {
+ "connection": function (row, nodeId) {
+ var isConsole = QDRService.isAConsole (row.properties.value, row.identity.value, row.role.value, nodeId)
+ return isConsole ? "console" : row.role.value === "inter-router" ? "inter-router" : "external";
+ },
+ "router.link": function (row, nodeId) {
+ var link = {nodeId: nodeId, connectionId: row.connectionId.value}
+ var isConsole = QDRService.isConsoleLink(link)
+ return isConsole ? "console" : row.linkType.value;
+ },
+ "router.address": function (row) {
+ var identity = QDRService.identity_clean(row.identity.value)
+ var address = QDRService.addr_text(identity)
+ var cls = QDRService.addr_class(identity)
+ if (address === "$management")
+ cls = "internal " + cls
+ return cls
+ }
+ }
+
+ var lookupOperations = function () {
+ var ops = QDRService.schema.entityTypes[$scope.selectedEntity].operations.filter( function (op) { return op !== 'READ'});
+ $scope.operation = ops.length ? ops[0] : "";
+ return ops;
+ }
+
+ var entityTreeChildren = [];
+ var expandedList = angular.fromJson(localStorage[ListExpandedKey]) || [];
+ var onTreeNodeExpanded = function (expanded, node) {
+ // save the list of entities that are expanded
+ var tree = $("#entityTree").dynatree("getTree");
+ var list = [];
+ tree.visit( function (tnode) {
+ if (tnode.isExpanded()) {
+ list.push(tnode.data.key)
+ }
+ })
+ localStorage[ListExpandedKey] = JSON.stringify(list)
+
+ if (expanded)
+ onTreeSelected(node);
+ }
+ // a tree node was selected
+ var onTreeSelected = function (selectedNode) {
+ $timeout( function () {
+ if ($scope.currentMode.id === 'operations')
+ $scope.currentMode = $scope.modes[0];
+ else if ($scope.currentMode.id === 'log')
+ $scope.selectMode($scope.currentMode)
+ else if ($scope.currentMode.id === 'delete') {
+ // clicked on a tree node while on the delete screen -> switch to attribute screen
+ $scope.currentMode = $scope.modes[0];
+ }
+ if (selectedNode.data.typeName === "entity") {
+ $scope.selectedEntity = selectedNode.data.key;
+ $scope.operations = lookupOperations()
+ } else if (selectedNode.data.typeName === 'attribute') {
+ $scope.selectedEntity = selectedNode.parent.data.key;
+ $scope.operations = lookupOperations()
+ $scope.selectedRecordName = selectedNode.data.key;
+ updateDetails(selectedNode.data.details); // update the table on the right
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.select(false);
+ });
+ selectedNode.select();
+ }
+ })
+ }
+
+ // fill in an empty results recoord based on the entities schema
+ var fromSchema = function (entityName) {
+ var row = {}
+ var schemaEntity = QDRService.schema.entityTypes[entityName]
+ for (attr in schemaEntity.attributes) {
+ var entity = schemaEntity.attributes[attr]
+ var value = ""
+ if (angular.isDefined(entity['default']))
+ value = entity['default']
+ row[attr] = {
+ value: value,
+ type: entity.type,
+ graph: false,
+ title: entity.description,
+ aggregate: false,
+ aggregateTip: '',
+ 'default': entity['default']
+ }
+ }
+ return row;
+ }
+ $scope.hasCreate = function () {
+ var schemaEntity = QDRService.schema.entityTypes[$scope.selectedEntity]
+ return (schemaEntity.operations.indexOf("CREATE") > -1)
+ }
+
+ var stopUpdating = function () {
+ if (angular.isDefined(updateIntervalHandle)) {
+ clearInterval(updateIntervalHandle);
+ }
+ updateIntervalHandle = undefined;
+ }
+
+ // the data for the selected entity is available, populate the tree
+ var updateEntityChildren = function (entity, tableRows, expand) {
+ var tree = $("#entityTree").dynatree("getTree");
+ if (!tree.getNodeByKey) {
+ return stopUpdating()
+ }
+ var node = tree.getNodeByKey(entity)
+ var updatedDetails = false;
+ var scrollTreeDiv = $('.qdr-attributes.pane.left .pane-viewport')
+ var scrollTop = scrollTreeDiv.scrollTop();
+ node.removeChildren();
+ if (tableRows.length == 0) {
+ node.addChild({
+ addClass: "no-data",
+ typeName: "none",
+ title: "no data",
+ key: node.data.key + ".1"
+ })
+ if (expand) {
+ updateDetails(fromSchema(entity));
+ $scope.selectedRecordName = entity;
+ }
+ } else {
+ tableRows.forEach( function (row) {
+ var addClass = entity;
+ if (classOverrides[entity]) {
+ addClass += " " + classOverrides[entity](row, $scope.currentNode.id);
+ }
+ var child = {
+ typeName: "attribute",
+ addClass: addClass,
+ tooltip: addClass,
+ key: row.name.value,
+ title: row.name.value,
+ details: row
+ }
+ if (row.name.value === $scope.selectedRecordName) {
+ if (expand)
+ updateDetails(row); // update the table on the right
+ child.select = true;
+ updatedDetails = true;
+ }
+ node.addChild(child)
+ })
+ }
+ // if the selectedRecordName was not found, select the 1st one
+ if (expand && !updatedDetails && tableRows.length > 0) {
+ var row = tableRows[0];
+ $scope.selectedRecordName = row.name.value;
+ var node = tree.getNodeByKey($scope.selectedRecordName);
+ node.select(true);
+ updateDetails(row) // update the table on the right
+ }
+ scrollTreeDiv.scrollTop(scrollTop)
+ }
+
+ var schemaProps = function (entityName, key, currentNode) {
+ var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean', map: 'textarea'};
+
+ var entity = QDRService.schema.entityTypes[entityName]
+ var value = entity.attributes[key]
+ // skip identity and depricated fields
+ if (!value)
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ var description = value.description || ""
+ var val = value['default'];
+ var disabled = (key == 'identity' || description.startsWith('Deprecated'))
+ // special cases
+ if (entityName == 'log' && key == 'module') {
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ }
+ if (entityName === 'linkRoutePattern' && key === 'connector') {
+ // turn input into a select. the values will be populated later
+ value.type = []
+ // find all the connector names and populate the select
+ QDRService.fetchEntity(currentNode.id, '.connector', ['name'], function (nodeName, dotentity, response) {
+ $scope.detailFields.some( function (field) {
+ if (field.name === 'connector') {
+ field.rawtype = response.results.map (function (result) {return result[0]})
+ return true;
+ }
+ })
+ });
+ }
+ return { name: key,
+ humanName: QDRService.humanify(key),
+ description:value.description,
+ type: disabled ? 'disabled' : typeMap[value.type],
+ rawtype: value.type,
+ input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input'
+ : 'select',
+ selected: val ? val : undefined,
+ 'default': value['default'],
+ value: val,
+ required: value.required,
+ unique: value.unique,
+ disabled: disabled
+ };
+ }
+ $scope.getAttributeValue = function (attribute) {
+ var value = attribute.attributeValue;
+ if ($scope.currentMode.op === "CREATE" && attribute.name === 'identity')
+ value = "<assigned by system>"
+ return value;
+ }
+
+ // update the table on the right
+ var updateDetails = function (row) {
+ var details = [];
+ $scope.detailsObject = {};
+ var attrs = Object.keys(row).sort();
+ attrs.forEach( function (attr) {
+ var changed = $scope.detailFields.filter(function (old) {
+ return (old.name === attr) ? old.graph && old.rawValue != row[attr].value : false;
+ })
+ var schemaEntity = schemaProps($scope.selectedEntity, attr, $scope.currentNode)
+ details.push( {
+ attributeName: QDRService.humanify(attr),
+ attributeValue: attr === 'port' ? row[attr].value : QDRService.pretty(row[attr].value),
+ name: attr,
+ changed: changed.length,
+ rawValue: row[attr].value,
+ graph: row[attr].graph,
+ title: row[attr].title,
+ aggregateValue: QDRService.pretty(row[attr].aggregate),
+ aggregateTip: row[attr].aggregateTip,
+
+ input: schemaEntity.input,
+ type: schemaEntity.type,
+ required: schemaEntity.required,
+ selected: schemaEntity.selected,
+ rawtype: schemaEntity.rawtype,
+ disabled: schemaEntity.disabled,
+ 'default': schemaEntity['default']
+ })
+ $scope.detailsObject[attr] = row[attr].value;
+ })
+ setTimeout(applyDetails, 1, details)
+ }
+
+ var applyDetails = function (details) {
+ $scope.detailFields = details;
+ aggregateColumn();
+ $scope.$apply();
+ // ng-grid bug? the entire table doesn't always draw unless a reflow is triggered;
+ $(window).trigger('resize');
+ }
+
+ var restartUpdate = function () {
+ stopUpdating();
+ updateTableData($scope.selectedEntity, true);
+ updateIntervalHandle = setInterval(updateExpandedEntities, updateInterval);
+ }
+ var updateExpandedEntities = function () {
+ var tree = $("#entityTree").dynatree("getTree");
+ if (tree.visit) {
+ tree.visit( function (node) {
+ if (node.isExpanded()) {
+ updateTableData(node.data.key, node.data.key === $scope.selectedEntity)
+ }
+ })
+ } else {
+ stopUpdating();
+ }
+ }
+
+ $scope.selectNode = function(node) {
+ $scope.selectedNode = node.name;
+ $scope.selectedNodeId = node.id;
+ setCurrentNode();
+ restartUpdate();
+ };
+ $scope.$watch('selectedEntity', function(newValue, oldValue) {
+ if (newValue !== oldValue) {
+ localStorage['QDRSelectedEntity'] = $scope.selectedEntity;
+ restartUpdate();
+ $scope.operations = lookupOperations()
+ }
+ })
+ $scope.$watch('selectedNode', function(newValue, oldValue) {
+ if (newValue !== oldValue) {
+ localStorage['QDRSelectedNode'] = $scope.selectedNode;
+ localStorage['QDRSelectedNodeId'] = $scope.selectedNodeId;
+ }
+ })
+ $scope.$watch('selectedRecordName', function(newValue, oldValue) {
+ if (newValue != oldValue) {
+ localStorage['QDRSelectedRecordName'] = $scope.selectedRecordName;
+ }
+ })
+
+ /* Called periodically to refresh the data on the page */
+ var updateTableData = function (entity, expand) {
+ if (!QDRService.connected) {
+ // we are no longer connected. bail back to the connect page
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', "list");
+ return;
+ }
+ // don't update the data when on the operations tab
+ if ($scope.currentMode.id === 'operations') {
+ return;
+ }
+
+ var gotNodeInfo = function (nodeName, dotentity, response) {
+ var tableRows = [];
+ var records = response.results;
+ var aggregates = response.aggregates;
+ var attributeNames = response.attributeNames;
+ // If !attributeNmes then there was an error getting the records for this entity
+ if (attributeNames) {
+ var nameIndex = attributeNames.indexOf("name");
+ var identityIndex = attributeNames.indexOf("identity");
+ var ent = QDRService.schema.entityTypes[entity];
+ for (var i=0; i<records.length; ++i) {
+ var record = records[i];
+ var aggregate = aggregates ? aggregates[i] : undefined;
+ var row = {};
+ var rowName;
+ if (nameIndex > -1) {
+ rowName = record[nameIndex];
+ if (!rowName && identityIndex > -1) {
+ rowName = record[nameIndex] = (dotentity + '/' + record[identityIndex])
+ }
+ }
+ if (!rowName) {
+ QDR.log.error("response attributeNames did not contain a name field");
+ console.dump(response.attributeNames);
+ return;
+ }
+ for (var j=0; j<attributeNames.length; ++j) {
+ var col = attributeNames[j];
+ row[col] = {value: record[j], type: undefined, graph: false, title: '', aggregate: '', aggregateTip: ''};
+ if (ent) {
+ var att = ent.attributes[col];
+ if (att) {
+ row[col].type = att.type;
+ row[col].graph = att.graph;
+ row[col].title = att.description;
+
+ if (aggregate) {
+ if (att.graph) {
+ row[col].aggregate = att.graph ? aggregate[j].sum : '';
+ var tip = [];
+ aggregate[j].detail.forEach( function (line) {
+ tip.push(line);
+ })
+ row[col].aggregateTip = angular.toJson(tip);
+ }
+ }
+ }
+ }
+ }
+ tableRows.push(row);
+ }
+ }
+
+ tableRows.sort( function (a, b) { return a.name.value.localeCompare(b.name.value) })
+ setTimeout(selectRow, 0, {entity: dotentity, rows: tableRows, expand: expand});
+ }
+ // if this entity should show an aggregate column, send the request to get the info for this entity from all the nedes
+ if (aggregateEntities.indexOf(entity) > -1) {
+ var nodeInfo = QDRService.topology.nodeInfo();
+ QDRService.getMultipleNodeInfo(Object.keys(nodeInfo), entity, [], gotNodeInfo, $scope.selectedNodeId);
+ } else {
+ QDRService.fetchEntity($scope.selectedNodeId, entity, [], gotNodeInfo);
+ }
+ };
+
+ // tableRows are the records that were returned, this populates the left hand table on the page
+ var selectRow = function (info) {
+ updateEntityChildren(info.entity, info.rows, info.expand);
+ fixTooltips();
+ }
+
+ var titleFromAlt = function (alt) {
+ if (alt && alt.length) {
+ var data = angular.fromJson(alt);
+ var table = "<table class='tiptable'><tbody>";
+ data.forEach (function (row) {
+ table += "<tr>";
+ table += "<td>" + row.node + "</td><td align='right'>" + QDRService.pretty(row.val) + "</td>";
+ table += "</tr>"
+ })
+ table += "</tbody></table>"
+ return table;
+ }
+ return '';
+ }
+
+ var fixTooltips = function () {
+ if ($('.hastip').length == 0) {
+ setTimeout(fixTooltips, 100);
+ return;
+ }
+ $('.hastip').each( function (i, tip) {
+ var tipset = tip.getAttribute('tipset')
+ if (!tipset) {
+ $(tip).tipsy({html: true, className: 'subTip', opacity: 1, title: function () {
+ return titleFromAlt(this.getAttribute('alt'))
+ } });
+ tip.setAttribute('tipset', true)
+ } else {
+ var title = titleFromAlt(tip.getAttribute('alt'))
+ tip.setAttribute('original-title', title)
+ }
+ })
+ }
+
+ $scope.detailFields = [];
+
+ $scope.addToGraph = function(rowEntity) {
+ var chart = QDRChartService.registerChart(
+ {nodeId: $scope.selectedNodeId,
+ entity: "." + $scope.selectedEntity,
+ name: $scope.selectedRecordName,
+ attr: rowEntity.name,
+ forceCreate: true});
+ doDialog('tmplListChart.html', chart);
+ }
+
+ $scope.addAllToGraph = function(rowEntity) {
+ var chart = QDRChartService.registerChart({
+ nodeId: $scope.selectedNodeId,
+ entity: $scope.selectedEntity,
+ name: $scope.selectedRecordName,
+ attr: rowEntity.name,
+ type: "rate",
+ rateWindow: updateInterval,
+ visibleDuration: 1,
+ forceCreate: true,
+ aggregate: true});
+ doDialog('tmplListChart.html', chart);
+ }
+
+ $scope.detailCols = [];
+ var aggregateColumn = function () {
+ if ((aggregateEntities.indexOf($scope.selectedEntity) > -1 && $scope.detailCols.length != 3) ||
+ (aggregateEntities.indexOf($scope.selectedEntity) == -1 && $scope.detailCols.length != 2)) {
+ // column defs have to be reassigned and not spliced, so no push/pop
+ $scope.detailCols = [
+ {
+ field: 'attributeName',
+ displayName: 'Attribute',
+ cellTemplate: '<div title="{{row.entity.title}}" class="listAttrName">{{row.entity[col.field]}}<i ng-if="row.entity.graph" ng-click="addToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>'
+ },
+ {
+ field: 'attributeValue',
+ displayName: 'Value',
+ cellTemplate: '<div class="ngCellText" ng-class="{\'changed\': row.entity.changed == 1}"><span>{{row.getProperty(col.field)}}</span></div>'
+ }
+ ]
+ if (aggregateEntities.indexOf($scope.selectedEntity) > -1) {
+ $scope.detailCols.push(
+ {
+ width: '10%',
+ field: 'aggregateValue',
+ displayName: 'Aggregate',
+ cellTemplate: '<div class="hastip" alt="{{row.entity.aggregateTip}}"><span ng-class="{\'changed\': row.entity.changed == 1}">{{row.entity[col.field]}}</span><i ng-if="row.entity.graph" ng-click="addAllToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>',
+ cellClass: 'aggregate'
+ }
+ )
+ }
+ }
+ if ($scope.selectedRecordName === "")
+ $scope.detailCols = [];
+ }
+
+ // the table on the right of the page contains a row for each field in the selected record in the table on the left
+ $scope.details = {
+ data: 'detailFields',
+ columnDefs: "detailCols",
+ enableColumnResize: true,
+ multiSelect: false,
+ beforeSelectionChange: function() {
+ return false;
+ }
+ };
+ $scope.$on("$destroy", function( event ) {
+ //QDR.log.debug("scope destroyed for qdrList");
+ stopUpdating();
+ });
+
+ function gotMethodResponse (nodeName, entity, response, context) {
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ //QDR.log.debug(context.message.application_properties.statusDescription)
+ } else {
+ var note = entity + " " + $filter('Pascalcase')($scope.currentMode.op) + "d"
+ Core.notification('success', note);
+ $scope.selectMode($scope.modes[0]);
+ restartUpdate();
+ }
+ }
+ $scope.ok = function () {
+ var attributes = {}
+ $scope.detailFields.forEach( function (field) {
+ var value = field.rawValue;
+ if (field.input === 'input') {
+ if (field.type === 'text' || field.type === 'disabled')
+ value = field.attributeValue;
+ } else if (field.input === 'select') {
+ value = field.selected;
+ } else if (field.input === 'boolean') {
+ value = field.rawValue
+ }
+ if (value === "")
+ value = undefined;
+
+ if ((value && value != field['default']) || field.required || (field.name === 'role')) {
+ if (field.name !== 'identity')
+ attributes[field.name] = value
+ }
+ })
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, undefined, gotMethodResponse)
+ }
+ $scope.remove = function () {
+ var attributes = {type: $scope.selectedEntity, name: $scope.selectedRecordName}
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, undefined, gotMethodResponse)
+ }
+
+ function doDialog(tmpl, chart) {
+ var d = $dialog.dialog({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ templateUrl: QDR.templatePath + tmpl,
+ controller: "QDR.ListChartController",
+ resolve: {
+ chart: function() {
+ return chart
+ },
+ nodeName: function () {
+ return $scope.selectedNode
+ }
+ }
+ });
+
+ d.open().then(function(result) { console.log("d.open().then"); });
+
+ };
+
+ var setCurrentNode = function () {
+ $scope.nodes.some( function (node, i) {
+ if (node.name === $scope.selectedNode) {
+ $scope.currentNode = $scope.nodes[i]
+ return true;
+ }
+ })
+ }
+
+ var treeReady = false;
+ var serviceReady = false;
+ $scope.largeNetwork = QDRService.isLargeNetwork()
+ // called after we know for sure the schema is fetched and the routers are all ready
+ QDRService.addUpdatedAction("initList", function () {
+ QDRService.stopUpdating();
+ QDRService.delUpdatedAction("initList")
+
+ $scope.nodes = QDRService.nodeList().sort(function (a, b) { return a.name.toLowerCase() > b.name.toLowerCase()});
+ // unable to get node list? Bail.
+ if ($scope.nodes.length == 0) {
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', "list");
+ }
+ if (!angular.isDefined($scope.selectedNode)) {
+ //QDR.log.debug("selectedNode was " + $scope.selectedNode);
+ if ($scope.nodes.length > 0) {
+ $scope.selectedNode = $scope.nodes[0].name;
+ $scope.selectedNodeId = $scope.nodes[0].id;
+ //QDR.log.debug("forcing selectedNode to " + $scope.selectedNode);
+ }
+ }
+ setCurrentNode();
+ if ($scope.currentNode == undefined) {
+ if ($scope.nodes.length > 0) {
+ $scope.selectedNode = $scope.nodes[0].name;
+ $scope.selectedNodeId = $scope.nodes[0].id;
+ $scope.currentNode = $scope.nodes[0];
+ }
+ }
+ var sortedEntities = Object.keys(QDRService.schema.entityTypes).sort();
+ sortedEntities.forEach( function (entity) {
+ if (excludedEntities.indexOf(entity) == -1) {
+ if (!angular.isDefined($scope.selectedEntity)) {
+ $scope.selectedEntity = entity;
+ $scope.operations = lookupOperations()
+ }
+ var e = new Folder(entity)
+ e.typeName = "entity"
+ e.key = entity
+ e.expand = (expandedList.indexOf(entity) > -1)
+ var placeHolder = new Folder("loading...")
+ placeHolder.addClass = "loading"
+ e.children = [placeHolder]
+ entityTreeChildren.push(e)
+ }
+ })
+ serviceReady = true;
+ initTree();
+ })
+ $scope.treeReady = function () {
+ treeReady = true;
+ initTree();
+ }
+
+ var initTree = function () {
+ if (!treeReady || !serviceReady)
+ return;
+ $('#entityTree').dynatree({
+ onActivate: onTreeSelected,
+ onExpand: onTreeNodeExpanded,
+ selectMode: 1,
+ autoCollapse: $scope.largeNetwork,
+ activeVisible: !$scope.largeNetwork,
+ debugLevel: 0,
+ children: entityTreeChildren
+ })
+ restartUpdate()
+ updateExpandedEntities();
+ };
+ QDRService.ensureAllEntities({entity: ".connection"}, function () {
+ QDRService.setUpdateEntities([".connection"])
+ QDRService.startUpdating();
+ })
+
+
+ }]);
+
+ return QDR;
+
+} (QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js b/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
deleted file mode 120000
index d1fcf4a..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/qdrListChart.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js b/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
new file mode 100644
index 0000000..93391f1
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
@@ -0,0 +1,141 @@
+/*
+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) {
+
+ QDR.module.controller('QDR.ListChartController', function ($scope, dialog, $dialog, $location, QDRChartService, chart, nodeName) {
+ $scope.chart = chart;
+ $scope.dialogSvgChart = null;
+ var updateTimer = null;
+ $scope.svgDivId = "dialogChart"; // the div id for the svg chart
+
+ $scope.showChartsPage = function () {
+ cleanup();
+ dialog.close(true);
+ $location.path(QDR.pluginRoot + "/charts");
+ };
+
+ $scope.addHChart = function () {
+ QDRChartService.addHDash($scope.chart);
+ cleanup();
+ dialog.close(true);
+ }
+
+ $scope.addToDashboardLink = function () {
+ var href = "#/" + QDR.pluginName + "/charts";
+ var size = angular.toJson({
+ size_x: 2,
+ size_y: 2
+ });
+
+ var params = angular.toJson({chid: $scope.chart.id()});
+ var title = "Dispatch - " + nodeName;
+ return "/hawtio/#/dashboard/add?tab=dashboard" +
+ "&href=" + encodeURIComponent(href) +
+ "&routeParams=" + encodeURIComponent(params) +
+ "&title=" + encodeURIComponent(title) +
+ "&size=" + encodeURIComponent(size);
+ };
+
+
+ $scope.addChartsPage = function () {
+ QDRChartService.addDashboard($scope.chart);
+ };
+
+ $scope.delChartsPage = function () {
+ QDRChartService.delDashboard($scope.chart);
+ };
+
+ $scope.isOnChartsPage = function () {
+ return $scope.chart.dashboard;
+ }
+
+ var showChart = function () {
+ // the chart divs are generated by angular and aren't available immediately
+ var div = angular.element("#" + $scope.svgDivId);
+ if (!div.width()) {
+ setTimeout(showChart, 100);
+ return;
+ }
+ dialogSvgChart = new QDRChartService.AreaChart($scope.chart);
+ $scope.dialogSvgChart = dialogSvgChart;
+ updateDialogChart();
+ }
+ showChart();
+
+ var updateDialogChart = function () {
+ if ($scope.dialogSvgChart)
+ $scope.dialogSvgChart.tick($scope.svgDivId);
+ if (updateTimer)
+ clearTimeout(updateTimer)
+ updateTimer = setTimeout(updateDialogChart, 1000);
+ }
+
+ var cleanup = function () {
+ if (updateTimer) {
+ clearTimeout(updateTimer);
+ updateTimer = null;
+ }
+ if (!$scope.chart.hdash && !$scope.chart.dashboard)
+ QDRChartService.unRegisterChart($scope.chart); // remove the chart
+
+ }
+ $scope.ok = function () {
+ cleanup();
+ dialog.close(true);
+ };
+
+ $scope.editChart = function () {
+ doDialog('tmplChartConfig.html', chart)
+ }
+
+ function doDialog(template, chart) {
+
+ $dialog.dialog({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ templateUrl: QDR.templatePath + template,
+ controller: "QDR.ChartDialogController",
+ resolve: {
+ chart: function() {
+ return chart;
+ },
+ updateTick: function () {
+ return function () {};
+ },
+ dashboard: function () {
+ return $scope;
+ },
+ adding: function () {
+ return true
+ }
+ }
+ }).open().then(function(result) {
+ $scope.ok()
+ });
+ };
+
+ });
+
+ return QDR;
+
+} (QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6a1e6632/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js b/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js
deleted file mode 120000
index 16b0e42..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../stand-alone/plugin/js/qdrNewNode.js
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js b/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js
new file mode 100644
index 0000000..f6d035a
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrNewNode.js
@@ -0,0 +1,445 @@
+/*
+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) {
+
+ QDR.module.controller("QDR.NodeDialogController", function($scope, QDRService, dialog, newname) {
+ var schema = QDRService.schema;
+ var myEntities = ['router', 'log', 'listener'];
+ var typeMap = {
+ integer: 'number',
+ string: 'text',
+ path: 'text',
+ boolean: 'boolean'
+ };
+ var newLinks = $('path.temp').toArray(); // jquery array of new links for the added router
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var separatedEntities = []; // additional entities required if a link is reversed
+ var myPort = 0,
+ myAddr = '0.0.0.0'; // port and address for new router
+ $scope.entities = [];
+
+ // find max port number that is used in all the listeners
+ var getMaxPort = function(nodeInfo) {
+ var maxPort = 5674;
+ for (var key in nodeInfo) {
+ var node = nodeInfo[key];
+ var listeners = node['.listener'];
+ var attrs = listeners.attributeNames;
+ for (var i = 0; i < listeners.results.length; ++i) {
+ var res = listeners.results[i];
+ var port = QDRService.valFor(attrs, res, 'port');
+ if (parseInt(port, 10) > maxPort)
+ maxPort = parseInt(port, 10);
+ }
+ }
+ return maxPort;
+ }
+ var maxPort = getMaxPort(nodeInfo);
+
+ // construct an object that contains all the info needed for a single tab's fields
+ var entity = function(actualName, tabName, humanName, ent, icon, link) {
+ var nameIndex = -1; // the index into attributes that the name field was placed
+ var index = 0;
+ var info = {
+ actualName: actualName,
+ tabName: tabName,
+ humanName: humanName,
+ description: ent.description,
+ icon: angular.isDefined(icon) ? icon : '',
+ references: ent.references,
+ link: link,
+
+ attributes: $.map(ent.attributes, function(value, key) {
+ // skip identity and depricated fields
+ if (key == 'identity' || value.description.startsWith('Deprecated'))
+ return null;
+ var val = value['default'];
+ if (key == 'name')
+ nameIndex = index;
+ index++;
+ return {
+ name: key,
+ humanName: QDRService.humanify(key),
+ description: value.description,
+ type: typeMap[value.type],
+ rawtype: value.type,
+ input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input' : 'select',
+ selected: val ? val : undefined,
+ 'default': value['default'],
+ value: val,
+ required: value.required,
+ unique: value.unique
+ };
+ })
+ }
+ // move the 'name' attribute to the 1st position
+ if (nameIndex > -1) {
+ var tmp = info.attributes[0];
+ info.attributes[0] = info.attributes[nameIndex];
+ info.attributes[nameIndex] = tmp;
+ }
+ return info;
+ }
+
+ // remove the annotation fields
+ var stripAnnotations = function(entityName, ent, annotations) {
+ if (ent.references) {
+ var newEnt = {
+ attributes: {}
+ };
+ ent.references.forEach(function(annoKey) {
+ if (!annotations[annoKey])
+ annotations[annoKey] = {};
+ annotations[annoKey][entityName] = true; // create the key/consolidate duplicates
+ var keys = Object.keys(schema.annotations[annoKey].attributes);
+ for (var attrib in ent.attributes) {
+ if (keys.indexOf(attrib) == -1) {
+ newEnt.attributes[attrib] = ent.attributes[attrib];
+ }
+ }
+ // add a field for the reference name
+ newEnt.attributes[annoKey] = {
+ type: 'string',
+ description: 'Name of the ' + annoKey + ' section.',
+ 'default': annoKey,
+ required: true
+ };
+ })
+ newEnt.references = ent.references;
+ newEnt.description = ent.description;
+ return newEnt;
+ }
+ return ent;
+ }
+
+ var annotations = {};
+ myEntities.forEach(function(entityName) {
+ var ent = schema.entityTypes[entityName];
+ var hName = QDRService.humanify(entityName);
+ if (entityName == 'listener')
+ hName = "Listener for clients";
+ var noAnnotations = stripAnnotations(entityName, ent, annotations);
+ var ediv = entity(entityName, entityName, hName, noAnnotations, undefined);
+ if (ediv.actualName == 'router') {
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'name'
+ })[0].value = newname;
+ // if we have any new links (connectors), then the router's mode should be interior
+ if (newLinks.length) {
+ var roleAttr = ediv.attributes.filter(function(attr) {
+ return attr.name == 'mode'
+ })[0];
+ roleAttr.value = roleAttr.selected = "interior";
+ }
+ }
+ if (ediv.actualName == 'container') {
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'containerName'
+ })[0].value = newname + "-container";
+ }
+ if (ediv.actualName == 'listener') {
+ // find max port number that is used in all the listeners
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'port'
+ })[0].value = ++maxPort;
+ }
+ // special case for required log.module since it doesn't have a default
+ if (ediv.actualName == 'log') {
+ var moduleAttr = ediv.attributes.filter(function(attr) {
+ return attr.name == 'module'
+ })[0];
+ moduleAttr.value = moduleAttr.selected = "DEFAULT";
+ }
+ $scope.entities.push(ediv);
+ })
+
+ // add a tab for each annotation that was found
+ var annotationEnts = [];
+ for (var key in annotations) {
+ ent = angular.copy(schema.annotations[key]);
+ ent.attributes.name = {
+ type: "string",
+ unique: true,
+ description: "Unique name that is used to refer to this set of attributes."
+ }
+ var ediv = entity(key, key + 'tab', QDRService.humanify(key), ent, undefined);
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'name'
+ })[0].value = key;
+ $scope.entities.push(ediv);
+ annotationEnts.push(ediv);
+ }
+
+ // add an additional listener tab if any links are reversed
+ ent = schema.entityTypes['listener'];
+ newLinks.some(function(link) {
+ if (link.__data__.right) {
+ var noAnnotations = stripAnnotations('listener', ent, annotations);
+ var ediv = entity("listener", "listener0", "Listener (internal)", noAnnotations, undefined);
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'port'
+ })[0].value = ++maxPort;
+ // connectors from other routers need to connect to this addr:port
+ myPort = maxPort;
+ myAddr = ediv.attributes.filter(function(attr) {
+ return attr.name == 'host'
+ })[0].value
+
+ // override the role. 'normal' is the default, but we want inter-router
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'role'
+ })[0].selected = 'inter-router';
+ separatedEntities.push(ediv);
+ return true; // stop looping
+ }
+ return false; // continue looping
+ })
+
+ // Add connector tabs for each new link on the topology graph
+ ent = schema.entityTypes['connector'];
+ newLinks.forEach(function(link, i) {
+ var noAnnotations = stripAnnotations('connector', ent, annotations);
+ var ediv = entity('connector', 'connector' + i, " " + link.__data__.source.name, noAnnotations, link.__data__.right, link)
+
+ // override the connector role. 'normal' is the default, but we want inter-router
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'role'
+ })[0].selected = 'inter-router';
+
+ // find the addr:port of the inter-router listener to use
+ var listener = nodeInfo[link.__data__.source.key]['.listener'];
+ var attrs = listener.attributeNames;
+ for (var i = 0; i < listener.results.length; ++i) {
+ var res = listener.results[i];
+ var role = QDRService.valFor(attrs, res, 'role');
+ if (role == 'inter-router') {
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'host'
+ })[0].value =
+ QDRService.valFor(attrs, res, 'host')
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'port'
+ })[0].value =
+ QDRService.valFor(attrs, res, 'port')
+ break;
+ }
+ }
+ if (link.__data__.right) {
+ // connectors from other nodes need to connect to the new router's listener addr:port
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'port'
+ })[0].value = myPort;
+ ediv.attributes.filter(function(attr) {
+ return attr.name == 'host'
+ })[0].value = myAddr;
+
+ separatedEntities.push(ediv)
+ } else
+ $scope.entities.push(ediv);
+ })
+ Array.prototype.push.apply($scope.entities, separatedEntities);
+
+ // update the description on all the annotation tabs
+ annotationEnts.forEach(function(ent) {
+ var shared = Object.keys(annotations[ent.actualName]);
+ ent.description += " These fields are shared by " + shared.join(" and ") + ".";
+
+ })
+
+ $scope.testPattern = function(attr) {
+ if (attr.rawtype == 'path')
+ return /^(\/)?([^/\0]+(\/)?)+$/;
+ //return /^(.*\/)([^/]*)$/;
+ return /(.*?)/;
+ }
+
+ $scope.attributeDescription = '';
+ $scope.attributeType = '';
+ $scope.attributeRequired = '';
+ $scope.attributeUnique = '';
+ $scope.active = 'router'
+ $scope.fieldsetDivs = "/fieldsetDivs.html"
+ $scope.setActive = function(tabName) {
+ $scope.active = tabName
+ }
+ $scope.isActive = function(tabName) {
+ return $scope.active === tabName
+ }
+ $scope.showDescription = function(attr, e) {
+ $scope.attributeDescription = attr.description;
+ var offset = jQuery(e.currentTarget).offset()
+ jQuery('.attr-description').offset({
+ top: offset.top
+ })
+
+ $scope.attributeType = "Type: " + JSON.stringify(attr.rawtype);
+ $scope.attributeRequired = attr.required ? 'required' : '';
+ $scope.attributeUnique = attr.unique ? 'Must be unique' : '';
+ }
+ // handle the download button click
+ // copy the dialog's values to the original node
+ $scope.download = function() {
+ dialog.close({
+ entities: $scope.entities,
+ annotations: annotations
+ });
+ }
+ $scope.cancel = function() {
+ dialog.close()
+ };
+
+ $scope.selectAnnotationTab = function(tabName) {
+ var tabs = $("#tabs").tabs();
+ tabs.tabs("select", tabName);
+ }
+
+ var initTabs = function() {
+ var div = angular.element("#tabs");
+ if (!div.width()) {
+ setTimeout(initTabs, 100);
+ return;
+ }
+ $("#tabs")
+ .tabs()
+ .addClass('ui-tabs-vertical ui-helper-clearfix');
+ }
+ // start the update loop
+ initTabs();
+
+ });
+
+ QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, dialog, results) {
+ var result = results.entities;
+ var annotations = results.annotations;
+ var annotationKeys = Object.keys(annotations);
+ var annotationSections = {};
+
+ // use the router's name as the file name if present
+ $scope.newRouterName = 'router';
+ result.forEach(function(e) {
+ if (e.actualName == 'router') {
+ e.attributes.forEach(function(a) {
+ if (a.name == 'name') {
+ $scope.newRouterName = a.value;
+ }
+ })
+ }
+ })
+ $scope.newRouterName = $scope.newRouterName + ".conf";
+
+ var template = $templateCache.get('config-file-header.html');
+ $scope.verbose = true;
+ $scope.$watch('verbose', function(newVal) {
+ if (newVal !== undefined) {
+ // recreate output using current verbose setting
+ getOutput();
+ }
+ })
+
+ var getOutput = function() {
+ $scope.output = template + '\n';
+ $scope.parts = [];
+ var commentChar = '#'
+ result.forEach(function(entity) {
+ // don't output a section for annotations, they get flattened into the entities
+ var section = "";
+ if (entity.icon) {
+ section += "##\n## Add to " + entity.link.__data__.source.name + "'s configuration file\n##\n";
+ }
+ section += "##\n## " + QDRService.humanify(entity.actualName) + " - " + entity.description + "\n##\n";
+ section += entity.actualName + " {\n";
+ entity.attributes.forEach(function(attribute) {
+ if (attribute.input == 'select')
+ attribute.value = attribute.selected;
+
+ // treat values with all spaces and empty strings as undefined
+ attribute.value = String(attribute.value).trim();
+ if (attribute.value === 'undefined' || attribute.value === '')
+ attribute.value = undefined;
+
+ if ($scope.verbose) {
+ commentChar = attribute.required || attribute.value != attribute['default'] ? ' ' : '#';
+ if (!attribute.value) {
+ commentChar = '#';
+ attribute.value = '';
+ }
+ section += commentChar + " " + attribute.name + ":" + Array(Math.max(20 - attribute.name.length, 1)).join(" ") + attribute.value + Array(Math.max(20 - ((attribute.value) + "").length, 1)).join(" ") + '# ' + attribute.description + "\n";
+ } else {
+ if (attribute.value) {
+ if (attribute.value != attribute['default'] || attribute.required)
+ section += " " + attribute.name + ":" + Array(20 - attribute.name.length).join(" ") + attribute.value + "\n";
+
+ }
+ }
+ })
+ section += "}\n\n";
+ // if entity.icon is true, this is a connector intended for another router
+ if (entity.icon)
+ $scope.parts.push({
+ output: section,
+ link: entity.link,
+ name: entity.link.__data__.source.name,
+ references: entity.references
+ });
+ else
+ $scope.output += section;
+
+ // if this section is actually an annotation
+ if (annotationKeys.indexOf(entity.actualName) > -1) {
+ annotationSections[entity.actualName] = section;
+ }
+ })
+ // go back and add annotation sections to the parts
+ $scope.parts.forEach(function(part) {
+ for (var section in annotationSections) {
+ if (part.references.indexOf(section) > -1) {
+ part.output += annotationSections[section];
+ }
+ }
+ })
+ QDR.log.debug($scope.output);
+ }
+
+ // handle the download button click
+ $scope.download = function() {
+ var output = $scope.output + "\n\n"
+ var blob = new Blob([output], {
+ type: 'text/plain;charset=utf-16'
+ });
+ saveAs(blob, $scope.newRouterName);
+ }
+
+ $scope.downloadPart = function(part) {
+ var linkName = part.link.__data__.source.name + 'additional.conf';
+ var blob = new Blob([part.output], {
+ type: 'text/plain;charset=utf-16'
+ });
+ saveAs(blob, linkName);
+ }
+
+ $scope.done = function() {
+ dialog.close();
+ }
+ });
+
+ return QDR;
+}(QDR || {}));
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org