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 <eal...@redhat.com> Authored: Wed Apr 19 08:16:53 2017 -0400 Committer: Ernest Allen <eal...@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-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org