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-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to