You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2016/10/19 12:49:09 UTC

[10/10] qpid-dispatch git commit: DISPATCH-531 Initial version of openstack horizon plugin

DISPATCH-531 Initial version of openstack horizon plugin


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/0c58c381
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/0c58c381
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/0c58c381

Branch: refs/heads/master
Commit: 0c58c3814866cbe60f13ff69ad73c74a4d8692aa
Parents: 9790303
Author: Ernest Allen <ea...@redhat.com>
Authored: Wed Oct 19 08:48:34 2016 -0400
Committer: Ernest Allen <ea...@redhat.com>
Committed: Wed Oct 19 08:48:34 2016 -0400

----------------------------------------------------------------------
 console/dispatch-dashboard/MANIFEST.in          |     3 +
 console/dispatch-dashboard/README.rst           |    41 +
 console/dispatch-dashboard/dispatch/__init__.py |     0
 .../dispatch-dashboard/dispatch/dashboard.py    |    23 +
 .../dispatch/overv/__init__.py                  |     0
 .../dispatch-dashboard/dispatch/overv/panel.py  |    20 +
 .../dispatch/overv/templates/overv/index.html   |    13 +
 .../dispatch-dashboard/dispatch/overv/tests.py  |    19 +
 .../dispatch-dashboard/dispatch/overv/urls.py   |    20 +
 .../dispatch-dashboard/dispatch/overv/views.py  |    22 +
 .../static/dashboard/dispatch/connect.json      |     2 +
 .../dashboard/dispatch/dispatch.comService.js   |   935 +
 .../dashboard/dispatch/dispatch.module.js       |   256 +
 .../static/dashboard/dispatch/dispatch.scss     |  2135 ++
 .../dashboard/dispatch/jquery.dynatree.min.js   |     4 +
 .../static/dashboard/dispatch/lib/d3.v3.min.js  |     5 +
 .../static/dashboard/dispatch/lib/rhea-min.js   |     4 +
 .../static/dashboard/dispatch/lib/slider.js     |   233 +
 .../dashboard/dispatch/lib/tooltipsy.min.js     |    20 +
 .../static/dashboard/dispatch/lib/ui-grid.js    | 28540 +++++++++++++++++
 .../dispatch/overv/overview.controller.js       |  1428 +
 .../dashboard/dispatch/overv/overview.module.js |   178 +
 .../dashboard/dispatch/qdrChartService.js       |  1109 +
 .../dispatch/topology/config-file-header.html   |    17 +
 .../topology/download-dialog-template.html      |    23 +
 .../dispatch/topology/node-config-template.html |    51 +
 .../dispatch/topology/topology.controller.js    |  1703 +
 .../topology/topology.download-controller.js    |   150 +
 .../topology/topology.form-controller.js        |    73 +
 .../dispatch/topology/topology.module.js        |   112 +
 .../topology/topology.node-controller.js        |   294 +
 .../dispatch/templates/dispatch/base.html       |    10 +
 .../dispatch/topology/__init__.py               |     0
 .../dispatch/topology/panel.py                  |    20 +
 .../topology/templates/topology/index.html      |    35 +
 .../dispatch/topology/tests.py                  |    19 +
 .../dispatch/topology/urls.py                   |    20 +
 .../dispatch/topology/views.py                  |    22 +
 .../enabled/_4000_dispatch.py                   |    33 +
 .../enabled/_4030_dispatch_overv_panel.py       |     9 +
 .../enabled/_4050_dispatch_topology_panel.py    |     9 +
 console/dispatch-dashboard/setup.py             |    42 +
 42 files changed, 37652 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/MANIFEST.in
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/MANIFEST.in b/console/dispatch-dashboard/MANIFEST.in
new file mode 100644
index 0000000..1d1b591
--- /dev/null
+++ b/console/dispatch-dashboard/MANIFEST.in
@@ -0,0 +1,3 @@
+include setup.py
+
+recursive-include dispatch *

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/README.rst
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/README.rst b/console/dispatch-dashboard/README.rst
new file mode 100644
index 0000000..ac3b17c
--- /dev/null
+++ b/console/dispatch-dashboard/README.rst
@@ -0,0 +1,41 @@
+=========
+dispatch_dashboard
+=========
+
+Qpid Dispatch Router Horizon plugin
+
+Manual Installation
+-------------------
+
+Copy the contents of this directoty to /opt/stack/dispatch_plugin and setup the plugin::
+
+    cd /opt/stack/dispatch_plugin/
+    python setup.py sdist
+
+If needed, create a virtual environment and install Horizon dependencies::
+
+    cd /opt/stack/horizon
+    python tools/install_venv.py
+
+If needed, set up your ``local_settings.py`` file::
+
+    cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py
+
+
+Install the dispatch dashboard in your horizon virtual environment::
+
+    ./tools/with_venv.sh pip install ../dispatch-plugin/dist/dispatch-0.0.1.tar.gz
+
+And enable it in Horizon::
+
+    cp ../dispatch-plugin/enabled/_4*.py openstack_dashboard/local/enabled
+
+If needed, compress the files::
+
+     ./tools/with-venv.sh python manage.py compress
+
+Run a server in the virtual environment::
+
+    ./tools/with-venv.sh python manage.py runserver 0.0.0.0:8080
+
+The horizon dashboard will be available in your browser at http://localhost:8080/

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/__init__.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/__init__.py b/console/dispatch-dashboard/dispatch/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/dashboard.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/dashboard.py b/console/dispatch-dashboard/dispatch/dashboard.py
new file mode 100644
index 0000000..9fad953
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/dashboard.py
@@ -0,0 +1,23 @@
+# Licensed 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.
+
+from django.utils.translation import ugettext_lazy as _
+
+import horizon
+
+
+class Dispatch(horizon.Dashboard):
+    name = _("Qpid Dispatch")
+    slug = "dispatch"
+    default_panel = 'overv'  # slug of the dashboard's default panel.
+
+horizon.register(Dispatch)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/overv/__init__.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/overv/__init__.py b/console/dispatch-dashboard/dispatch/overv/__init__.py
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/overv/panel.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/overv/panel.py b/console/dispatch-dashboard/dispatch/overv/panel.py
new file mode 100644
index 0000000..315c7e0
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/overv/panel.py
@@ -0,0 +1,20 @@
+# Licensed 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.
+
+from django.utils.translation import ugettext_lazy as _
+
+import horizon
+
+
+class Overv(horizon.Panel):
+    name = _("Overview")
+    slug = "overv"

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/overv/templates/overv/index.html
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/overv/templates/overv/index.html b/console/dispatch-dashboard/dispatch/overv/templates/overv/index.html
new file mode 100644
index 0000000..afe47bd
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/overv/templates/overv/index.html
@@ -0,0 +1,13 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% block title %}{% trans "Overv" %}{% endblock %}
+
+{% block page_header %}
+  {% include "horizon/common/_page_header.html" with title=_("Overview") %}
+{% endblock page_header %}
+
+{% block main %}
+  <ng-include src="'dispatch/overview.html'"></ng-include>
+{% endblock %}
+
+

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/overv/tests.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/overv/tests.py b/console/dispatch-dashboard/dispatch/overv/tests.py
new file mode 100644
index 0000000..47816a3
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/overv/tests.py
@@ -0,0 +1,19 @@
+# Licensed 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.
+
+from horizon.test import helpers as test
+
+
+class OvervTests(test.TestCase):
+    # Unit tests for overv.
+    def test_me(self):
+        self.assertTrue(1 + 1 == 2)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/overv/urls.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/overv/urls.py b/console/dispatch-dashboard/dispatch/overv/urls.py
new file mode 100644
index 0000000..6debf00
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/overv/urls.py
@@ -0,0 +1,20 @@
+# Licensed 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.
+
+from django.conf.urls import url
+
+from dispatch.overv import views
+
+
+urlpatterns = [
+    url(r'^$', views.IndexView.as_view(), name='index'),
+]

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/overv/views.py
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/overv/views.py b/console/dispatch-dashboard/dispatch/overv/views.py
new file mode 100644
index 0000000..235a0d5
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/overv/views.py
@@ -0,0 +1,22 @@
+# Licensed 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.
+
+from horizon import views
+
+
+class IndexView(views.APIView):
+    # A very simple class-based view...
+    template_name = 'dispatch/overv/index.html'
+
+    def get_data(self, request, context, *args, **kwargs):
+        # Add data to the context here...
+        return context

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/connect.json
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/connect.json b/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/connect.json
new file mode 100644
index 0000000..2be876d
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/connect.json
@@ -0,0 +1,2 @@
+)]}',
+{"address": "0.0.0.0", "port": 5673}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.comService.js
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.comService.js b/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.comService.js
new file mode 100644
index 0000000..ace792a
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.comService.js
@@ -0,0 +1,935 @@
+/*
+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.
+*/
+
+(function() {
+    console.dump = function(object) {
+        if (window.JSON && window.JSON.stringify)
+            QDR.log.info(JSON.stringify(object,undefined,2));
+        else
+            console.log(object);
+    };
+})();
+
+var QDR = (function(QDR) {
+  'use strict';
+
+  // The QDR service handles the connection to
+  // the server in the background
+  angular
+    .module('horizon.dashboard.dispatch')
+    .factory('horizon.dashboard.dispatch.comService', QDRService);
+
+  QDRService.$inject = [
+    '$rootScope',
+    '$http',
+    '$timeout',
+    '$location',
+    'horizon.dashboard.dispatch.basePath',
+  ];
+
+  function QDRService($rootScope, $http, $timeout, $location, basePath) {
+    var self = {
+
+	  rhea: require("rhea"),
+
+      timeout: 10,
+      connectActions: [],
+      disconnectActions: [],
+      updatedActions: {},
+      stop: undefined,  // update interval handle
+
+      addConnectAction: function(action) {
+        if (angular.isFunction(action)) {
+          self.connectActions.push(action);
+        }
+      },
+      addDisconnectAction: function(action) {
+        if (angular.isFunction(action)) {
+          self.disconnectActions.push(action);
+        }
+      },
+      addUpdatedAction: function(key, action) {
+        if (angular.isFunction(action)) {
+            self.updatedActions[key] = action;
+        }
+      },
+      delUpdatedAction: function(key) {
+        if (key in self.updatedActions)
+            delete self.updatedActions[key];
+      },
+
+      executeConnectActions: function() {
+        self.connectActions.forEach(function(action) {
+          //QDR.log.debug("executing connect action " + action);
+			try {
+                action.apply();
+            } catch (e) {
+                // in case the page that registered the handler has been unloaded
+            }
+        });
+        self.connectActions = [];
+
+      },
+      executeDisconnectActions: function() {
+        self.disconnectActions.forEach(function(action) {
+			try {
+                action.apply();
+            } catch (e) {
+                // in case the page that registered the handler has been unloaded
+            }
+        });
+        self.disconnectActions = [];
+      },
+      executeUpdatedActions: function() {
+        for (var action in self.updatedActions) {
+			try {
+                self.updatedActions[action].apply();
+            } catch (e) {
+                delete self.updatedActions[action]
+            }
+        }
+      },
+	redirectWhenConnected: function (org) {
+		//$location.path(basePath + "/connect")
+		//$location.search('org', org);
+           window.location.replace("/connect/");
+	},
+
+      notifyTopologyDone: function() {
+        //QDR.log.debug("got Toplogy done notice");
+
+        if (!angular.isDefined(self.schema))
+            return;
+        else if (self.topology._gettingTopo)
+            return;
+        if (!self.gotTopology) {
+            QDR.log.debug("topology was just initialized");
+            self.gotTopology = true;
+            self.executeConnectActions();
+            $rootScope.$apply();
+        } else {
+            //QDR.log.debug("topology model was just updated");
+            self.executeUpdatedActions();
+        }
+
+      },
+      /**
+       * @property options
+       * Holds a reference to the connection options when
+       * a connection is started
+       */
+      options: undefined,
+
+      /*
+       * @property message
+       * The proton message that is used to send commands
+       * and receive responses
+       */
+		sender: undefined,
+		receiver: undefined,
+		sendable: false,
+
+      schema: undefined,
+
+      toAddress: undefined,
+      connected: false,
+      gotTopology: false,
+      errorText: undefined,
+	  connectionError: undefined,
+
+      isConnected: function() {
+        return self.connected;
+      },
+
+    correlator: {
+        _objects: {},
+        _corremationID: 0,
+
+        corr: function () {
+            var id = ++this._corremationID + "";
+			this._objects[id] = {resolver: null}
+            return id;
+        },
+        request: function() {
+            //QDR.log.debug("correlator:request");
+            return this;
+        },
+        then: function(id, resolver, error) {
+            //QDR.log.debug("registered then resolver for correlationID: " + id);
+			if (error) {
+	            delete this._objects[id];
+				return;
+			}
+            this._objects[id].resolver = resolver;
+        },
+        // called by receiver's on('message') handler when a response arrives
+        resolve: function(context) {
+			var correlationID = context.message.properties.correlation_id;
+            this._objects[correlationID].resolver(context.message.body, context);
+            delete this._objects[correlationID];
+        }
+    },
+
+    onSubscription: function() {
+        self.getSchema();
+     },
+
+    startUpdating: function () {
+        self.stopUpdating();
+        QDR.log.info("startUpdating called")
+        self.topology.get();
+        self.stop = setInterval(function() {
+            self.topology.get();
+        }, 2000);
+    },
+    stopUpdating: function () {
+        if (angular.isDefined(self.stop)) {
+            QDR.log.info("stopUpdating called")
+            clearInterval(self.stop);
+            self.stop = undefined;
+        }
+    },
+
+      initProton: function() {
+        //self.loadConnectOptions()
+      },
+      cleanUp: function() {
+      },
+      error: function(line) {
+        if (line.num) {
+          QDR.log.debug("error - num: ", line.num, " message: ", line.message);
+        } else {
+          QDR.log.debug("error - message: ", line.message);
+        }
+      },
+      disconnected: function(line) {
+        QDR.log.debug("Disconnected from QDR server");
+        self.executeDisconnectActions();
+      },
+
+      nameFromId: function (id) {
+		    return id.split('/')[3];
+      },
+
+      humanify: function (s) {
+          if (!s || s.length === 0)
+			return s;
+          var t = s.charAt(0).toUpperCase() + s.substr(1).replace(/[A-Z]/g, ' $&');
+          return t.replace(".", " ");
+      },
+	  pretty: function(v) {
+    	var formatComma = d3.format(",");
+		if (!isNaN(parseFloat(v)) && isFinite(v))
+			return formatComma(v);
+		return v;
+	  },
+
+      nodeNameList: function() {
+        var nl = [];
+        // if we are in the middel of updating the topology
+        // then use the last known node info
+        var ni = self.topology._nodeInfo;
+        if (self.topology._gettingTopo)
+            ni = self.topology._lastNodeInfo;
+		for (var id in ni) {
+            nl.push(self.nameFromId(id));
+        }
+        return nl.sort();
+      },
+
+      nodeIdList: function() {
+        var nl = [];
+        // if we are in the middel of updating the topology
+        // then use the last known node info
+        var ni = self.topology._nodeInfo;
+        if (self.topology._gettingTopo)
+            ni = self.topology._lastNodeInfo;
+		for (var id in ni) {
+            nl.push(id);
+        }
+        return nl.sort();
+      },
+
+      nodeList: function () {
+        var nl = [];
+        var ni = self.topology._nodeInfo;
+        if (self.topology._gettingTopo)
+            ni = self.topology._lastNodeInfo;
+		for (var id in ni) {
+            nl.push({name: self.nameFromId(id), id: id});
+        }
+        return nl;
+      },
+
+      // given an attribute name array, find the value at the same index in the values array
+      valFor: function (aAr, vAr, key) {
+          var idx = aAr.indexOf(key);
+          if ((idx > -1) && (idx < vAr.length)) {
+              return vAr[idx];
+          }
+          return null;
+      },
+
+		isArtemis: function (d) {
+			return d.nodeType ==='on-demand' && !d.properties.product;
+		},
+
+		isQpid: function (d) {
+			return d.nodeType ==='on-demand' && (d.properties && d.properties.product === 'qpid-cpp');
+		},
+
+		isAConsole: function (properties, connectionId, nodeType, key) {
+			return self.isConsole({properties: properties, connectionId: connectionId, nodeType: nodeType, key: key})
+		},
+		isConsole: function (d) {
+			// use connection properties if available
+			if (d && d['properties'] && d['properties']['console_identifier'] == 'Dispatch console')
+				return true;
+			return false;
+		},
+
+		flatten: function (attributes, result) {
+			var flat = {}
+			attributes.forEach( function (attr, i) {
+				if (result && result.length > i)
+					flat[attr] = result[i]
+			})
+			return flat;
+		},
+		isConsoleLink: function (link) {
+			// find the connection for this link
+			var conns = self.topology.nodeInfo()[link.nodeId]['.connection']
+			var connIndex = conns.attributeNames.indexOf("identity")
+			var linkCons = conns.results.filter ( function (conn) {
+				return conn[connIndex] === link.connectionId;
+			})
+			var conn = self.flatten(conns.attributeNames, linkCons[0]);
+
+			return self.isConsole(conn)
+		},
+
+		quiesceLink: function (nodeId, name) {
+			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);
+				}
+			}
+			var attributes = {adminStatus: 'disabled', name: name};
+			self.sendMethod(nodeId, "router.link", attributes, "UPDATE", undefined, gotMethodResponse)
+		},
+
+    connectionOptions: {address: '0.0.0.0', port: 5673},
+    loadConnectOptions: function (callback) {
+      $http.get(basePath + 'connect.json').
+        success(function(data, status, headers, config) {
+        //QDR.log.debug("got connect info from file")
+        //console.dump(data)
+          self.connectionOptions = data;
+          if (callback)
+            callback()
+        }).
+        error(function(data, status, headers, config) {
+        //QDR.log.debug("did not get connect info from file")
+        //console.dump(status)
+          if (callback)
+            callback()
+        });
+    },
+
+		addr_text: function (addr) {
+	        if (!addr)
+	            return "-"
+	        if (addr[0] == 'M')
+	            return addr.substring(2)
+	        else
+	            return addr.substring(1)
+		},
+		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]
+		},
+		identity_clean: function (identity) {
+	        if (!identity)
+	            return "-"
+	        var pos = identity.indexOf('/')
+	        if (pos >= 0)
+	            return identity.substring(pos + 1)
+	        return identity
+		},
+
+      /*
+       * send the management messages that build up the topology
+       *
+       *
+       */
+      topology: {
+        _gettingTopo: false,
+        _nodeInfo: {},
+        _lastNodeInfo: {},
+        _expected: {},
+        _timerHandle: null,
+
+        nodeInfo: function () {
+            return this._gettingTopo ? this._lastNodeInfo : this._nodeInfo;
+        },
+
+        get: function () {
+            if (this._gettingTopo)
+                return;
+            if (!self.connected) {
+				QDR.log.debug("topology get failed because !self.connected")
+                return;
+            }
+            this._lastNodeInfo = angular.copy(this._nodeInfo);
+            this._gettingTopo = true;
+
+            self.errorText = undefined;
+            this.cleanUp(this._nodeInfo);
+            this._nodeInfo = {};
+            this._expected = {};
+
+            // get the list of nodes to query.
+            // once this completes, we will get the info for each node returned
+            self.getRemoteNodeInfo( function (response, context) {
+                //QDR.log.debug("got remote node list of ");
+                //console.dump(response);
+                if( Object.prototype.toString.call( response ) === '[object Array]' ) {
+					if (response.length === 0) {
+						// there is only one router, get its node id from the reeciiver
+						//"amqp:/_topo/0/Router.A/temp.aSO3+WGaoNUgGVx"
+						var address = context.receiver.remote.attach.source.address;
+						var addrParts = address.split('/')
+						addrParts.splice(addrParts.length-1, 1, '$management')
+						response = [addrParts.join('/')]
+					}
+                    // we expect a response for each of these nodes
+                    self.topology.wait(self.timeout);
+                    for (var i=0; i<response.length; ++i) {
+                        self.makeMgmtCalls(response[i]);
+                    }
+                };
+            });
+        },
+
+        cleanUp: function (obj) {
+            //if (obj)
+            //    delete obj;
+        },
+        wait: function (timeout) {
+            this.timerHandle = setTimeout(this.timedOut, timeout * 1000);
+         },
+        timedOut: function () {
+        // a node dropped out. this happens when the get-mgmt-nodex
+        // results contains more nodes than actually respond within
+        // the timeout. However, if the responses we get don't contain
+        // the missing node, assume we are done.
+            QDR.log.info("timed out waiting for management responses");
+            // note: can't use 'this' in a timeout handler
+            self.topology.miniDump("state at timeout");
+            // check if _nodeInfo is consistent
+            if (self.topology.isConsistent()) {
+                //TODO: notify controllers which node was dropped
+                // so they can keep an event log
+                self.topology.ondone();
+                return;
+            }
+            self.topology.onerror(Error("Timed out waiting for management responses"));
+        },
+        isConsistent: function () {
+            // see if the responses we have so far reference any nodes
+            // for which we don't have a response
+            var gotKeys = {};
+            for (var id in this._nodeInfo) {
+                var onode = this._nodeInfo[id];
+                var conn = onode['.connection'];
+                // get list of node names in the connection data
+                if (conn) {
+                    var containerIndex = conn.attributeNames.indexOf('container');
+                    var connectionResults = conn.results;
+                    if (containerIndex >= 0)
+                        for (var j=0; j < connectionResults.length; ++j) {
+                            // inter-router connection to a valid dispatch connection name
+                            gotKeys[connectionResults[j][containerIndex]] = ""; // just add the key
+                        }
+                }
+            }
+            // gotKeys now contains all the container names that we have received
+            // Are any of the keys that are still expected in the gotKeys list?
+            var keys = Object.keys(gotKeys);
+            for (var id in this._expected) {
+                var key = self.nameFromId(id);
+                if (key in keys)
+                    return false;
+            }
+            return true;
+        },
+
+        addNodeInfo: function (id, entity, values) {
+            // save the results in the nodeInfo object
+            if (id) {
+                if (!(id in self.topology._nodeInfo)) {
+                    self.topology._nodeInfo[id] = {};
+                }
+                self.topology._nodeInfo[id][entity] = values;
+            }
+
+            // remove the id / entity from _expected
+            if (id in self.topology._expected) {
+                var entities = self.topology._expected[id];
+                var idx = entities.indexOf(entity);
+                if (idx > -1) {
+                    entities.splice(idx, 1);
+                    if (entities.length == 0)
+                        delete self.topology._expected[id];
+                }
+            }
+            // see if the expected obj is empty
+            if (Object.getOwnPropertyNames(self.topology._expected).length == 0)
+                self.topology.ondone();
+            self.topology.cleanUp(values);
+        },
+        expect: function (id, key) {
+            if (!key || !id)
+                return;
+            if (!(id in this._expected))
+                this._expected[id] = [];
+            if (this._expected[id].indexOf(key) == -1)
+                this._expected[id].push(key);
+        },
+        ondone: function () {
+            clearTimeout(this.timerHandle);
+            this._gettingTopo = false;
+            //this.miniDump();
+            //this.dump();
+            self.notifyTopologyDone();
+         },
+         dump: function (prefix) {
+            if (prefix)
+                QDR.log.info(prefix);
+            QDR.log.info("---");
+            for (var key in this._nodeInfo) {
+                QDR.log.info(key);
+                console.dump(this._nodeInfo[key]);
+                QDR.log.info("---");
+            }
+            QDR.log.debug("was still expecting:");
+            console.dump(this._expected);
+        },
+         miniDump: function (prefix) {
+            if (prefix)
+                QDR.log.info(prefix);
+            QDR.log.info("---");
+            console.dump(Object.keys(this._nodeInfo));
+            QDR.log.info("---");
+        },
+        onerror: function (err) {
+            this._gettingTopo = false;
+            QDR.log.debug("Err:" + err);
+            self.executeDisconnectActions();
+
+        }
+
+      },
+
+      getRemoteNodeInfo: function (callback) {
+	 	//QDR.log.debug("getRemoteNodeInfo called");
+        var ret;
+        // first get the list of remote node names
+	 	self.correlator.request(
+                ret = self.sendMgmtQuery('GET-MGMT-NODES')
+            ).then(ret.id, function(response, context) {
+                callback(response, context);
+                self.topology.cleanUp(response);
+            }, ret.error);
+      },
+
+      makeMgmtCalls: function (id) {
+            var keys = [".router", ".connection", ".container", ".router.node", ".listener", ".router.link"];
+            $.each(keys, function (i, key) {
+                self.topology.expect(id, key);
+                self.getNodeInfo(id, key, [], self.topology.addNodeInfo);
+            });
+      },
+
+      getNodeInfo: function (nodeName, entity, attrs, callback) {
+        //QDR.log.debug("getNodeInfo called with nodeName: " + nodeName + " and entity " + entity);
+        var ret;
+        self.correlator.request(
+            ret = self.sendQuery(nodeName, entity, attrs)
+        ).then(ret.id, function(response) {
+            callback(nodeName, entity, response);
+            //self.topology.addNodeInfo(nodeName, entity, response);
+            //self.topology.cleanUp(response);
+        }, ret.error);
+      },
+
+		getMultipleNodeInfo: function (nodeNames, entity, attrs, callback, selectedNodeId, aggregate) {
+			if (!angular.isDefined(aggregate))
+				aggregate = true;
+			var responses = {};
+			var gotNodesResult = function (nodeName, dotentity, response) {
+				responses[nodeName] = response;
+				if (Object.keys(responses).length == nodeNames.length) {
+					if (aggregate)
+						self.aggregateNodeInfo(nodeNames, entity, selectedNodeId, responses, callback);
+					else {
+						callback(nodeNames, entity, responses)
+					}
+				}
+			}
+
+			nodeNames.forEach( function (id) {
+	            self.getNodeInfo(id, '.'+entity, attrs, gotNodesResult);
+	        })
+			//TODO: implement a timeout in case not all requests complete
+		},
+
+		aggregateNodeInfo: function (nodeNames, entity, selectedNodeId, responses, callback) {
+			//QDR.log.debug("got all results for  " + entity);
+			// aggregate the responses
+			var newResponse = {};
+			var thisNode = responses[selectedNodeId];
+			newResponse['attributeNames'] = thisNode.attributeNames;
+			newResponse['results'] = thisNode.results;
+			newResponse['aggregates'] = [];
+			for (var i=0; i<thisNode.results.length; ++i) {
+				var result = thisNode.results[i];
+				var vals = [];
+				result.forEach( function (val) {
+					vals.push({sum: val, detail: []})
+				})
+				newResponse.aggregates.push(vals);
+			}
+			var nameIndex = thisNode.attributeNames.indexOf("name");
+			var ent = self.schema.entityTypes[entity];
+			var ids = Object.keys(responses);
+			ids.sort();
+			ids.forEach( function (id) {
+				var response = responses[id];
+				var results = response.results;
+				results.forEach( function (result) {
+					// find the matching result in the aggregates
+					var found = newResponse.aggregates.some( function (aggregate, j) {
+						if (aggregate[nameIndex].sum === result[nameIndex]) {
+							// result and aggregate are now the same record, add the graphable values
+							newResponse.attributeNames.forEach( function (key, i) {
+								if (ent.attributes[key] && ent.attributes[key].graph) {
+									if (id != selectedNodeId)
+										aggregate[i].sum += result[i];
+								}
+								aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
+							})
+							return true; // stop looping
+						}
+						return false; // continute looking for the aggregate record
+					})
+					if (!found) {
+						// this attribute was not found in the aggregates yet
+						// because it was not in the selectedNodeId's results
+						var vals = [];
+						result.forEach( function (val) {
+							vals.push({sum: val, detail: [{node: self.nameFromId(id), val: val}]})
+						})
+						newResponse.aggregates.push(vals)
+					}
+				})
+			})
+			callback(nodeNames, entity, newResponse);
+		},
+
+
+      getSchema: function () {
+        //QDR.log.debug("getting schema");
+        var ret;
+        self.correlator.request(
+            ret = self.sendMgmtQuery('GET-SCHEMA')
+        ).then(ret.id, function(response) {
+            //QDR.log.debug("Got schema response");
+			// remove deprecated
+			for (var entityName in response.entityTypes) {
+				var entity = response.entityTypes[entityName]
+				if (entity.deprecated) {
+					// deprecated entity
+				    delete response.entityTypes[entityName]
+				} else {
+					for (var attributeName in entity.attributes) {
+						var attribute = entity.attributes[attributeName]
+						if (attribute.deprecated) {
+							// deprecated attribute
+							delete response.entityTypes[entityName].attributes[attributeName]
+						}
+					}
+				}
+			}
+			self.schema = response;
+	        self.topology.get();
+        }, ret.error);
+      },
+
+      getNodeInfo: function (nodeName, entity, attrs, callback) {
+        //QDR.log.debug("getNodeInfo called with nodeName: " + nodeName + " and entity " + entity);
+        var ret;
+        self.correlator.request(
+            ret = self.sendQuery(nodeName, entity, attrs)
+        ).then(ret.id, function(response) {
+            callback(nodeName, entity, response);
+            //self.topology.addNodeInfo(nodeName, entity, response);
+            //self.topology.cleanUp(response);
+        }, ret.error);
+      },
+
+	sendMethod: function (nodeId, entity, attrs, operation, props, callback) {
+		var ret;
+		self.correlator.request(
+			ret = self._sendMethod(nodeId, entity, attrs, operation, props)
+		).then(ret.id, function (response, context) {
+				callback(nodeId, entity, response, context);
+		}, ret.error);
+	},
+
+	_fullAddr: function (toAddr) {
+        var toAddrParts = toAddr.split('/');
+        if (toAddrParts.shift() != "amqp:") {
+            self.topology.error(Error("unexpected format for router address: " + toAddr));
+            return;
+        }
+        //var fullAddr =  self.toAddress + "/" + toAddrParts.join('/');
+        var fullAddr =  toAddrParts.join('/');
+		return fullAddr;
+	},
+
+	_sendMethod: function (toAddr, entity, attrs, operation, props) {
+		var fullAddr = self._fullAddr(toAddr);
+		var ret = {id: self.correlator.corr()};
+		if (!self.sender || !self.sendable) {
+			ret.error = "no sender"
+			return ret;
+		}
+		try {
+			var application_properties = {
+				operation:  operation
+			}
+			if (entity) {
+				var ent = self.schema.entityTypes[entity];
+				var fullyQualifiedType = ent ? ent.fullyQualifiedType : entity;
+				application_properties.type = fullyQualifiedType || entity;
+			}
+			if (attrs.name)
+				application_properties.name = attrs.name;
+			if (props) {
+				jQuery.extend(application_properties, props);
+			}
+			var msg = {
+	                body: attrs,
+	                properties: {
+	                    to:                     fullAddr,
+                        reply_to:               self.receiver.remote.attach.source.address,
+	                    correlation_id:         ret.id
+	                },
+	                application_properties: application_properties
+            }
+            self.sender.send( msg );
+			console.dump("------- method called -------")
+            console.dump (msg)
+		}
+		catch (e) {
+			error = "error sending: " + e;
+			QDR.log.error(error)
+			ret.error = error;
+		}
+		return ret;
+	},
+
+    sendQuery: function(toAddr, entity, attrs, operation) {
+        operation = operation || "QUERY"
+		var fullAddr = self._fullAddr(toAddr);
+
+		var body;
+        if (attrs)
+            body = {
+                    "attributeNames": attrs,
+            }
+        else
+            body = {
+                "attributeNames": [],
+            }
+		if (entity[0] === '.')
+			entity = entity.substr(1, entity.length-1)
+		var prefix = "org.apache.qpid.dispatch."
+		var configs = ["address", "autoLink", "linkRoute"]
+		if (configs.indexOf(entity) > -1)
+			prefix += "router.config."
+		return self._send(body, fullAddr, operation, prefix + entity);
+    },
+
+    sendMgmtQuery: function (operation) {
+		return self._send([], "/$management", operation);
+    },
+
+	_send: function (body, to, operation, entityType) {
+		var ret = {id: self.correlator.corr()};
+		if (!self.sender || !self.sendable) {
+			ret.error = "no sender"
+			return ret;
+		}
+		try {
+			var application_properties = {
+				operation:  operation,
+                type:       "org.amqp.management",
+                name:       "self"
+            };
+			if (entityType)
+                application_properties.entityType = entityType;
+
+	        self.sender.send({
+	                body: body,
+	                properties: {
+	                    to:                     to,
+                        reply_to:               self.receiver.remote.attach.source.address,
+	                    correlation_id:         ret.id
+	                },
+	                application_properties: application_properties
+            })
+		}
+		catch (e) {
+			error = "error sending: " + e;
+			QDR.log.error(error)
+			ret.error = error;
+		}
+		return ret;
+	},
+
+      disconnect: function() {
+        self.connection.close();
+		self.errorText = "Disconnected."
+      },
+
+      connect: function(overrideConnectOptions) {
+  			QDR.log.debug("****** calling rhea.connect ********")
+        var options = self.connectionOptions;
+        if (overrideConnectOptions)
+          options = overrideConnectOptions;
+        self.topologyInitialized = false;
+		    if (!self.connected) {
+			    var okay = {connection: false, sender: false, receiver: false}
+          var port = options.port || 5673;
+          var baseAddress = options.address + ':' + port;
+			    var ws = self.rhea.websocket_connect(WebSocket);
+			    self.toAddress = "amqp://" + baseAddress;
+			    self.connectionError = undefined;
+
+			var stop = function (context) {
+				//self.stopUpdating();
+				okay.sender = false;
+				okay.receiver = false;
+				okay.connected = false;
+				self.connected = false;
+				self.sender = null;
+				self.receiver = null;
+				self.sendable = false;
+				self.gotTopology = false;
+			}
+			var maybeStart = function () {
+				if (okay.connection && okay.sender && okay.receiver && self.sendable && !self.connected) {
+					QDR.log.info("okay to start")
+					self.connected = true;
+					self.connection = connection;
+					self.sender = sender;
+					self.receiver = receiver;
+					self.onSubscription();
+					self.gotTopology = false;
+				}
+			}
+			var onDisconnect = function () {
+				//QDR.log.warn("Disconnected");
+				self.connectionError = true;
+				stop();
+				self.executeDisconnectActions();
+			}
+
+			var connection;
+			try {
+QDR.log.debug("trying to connect to ws://" + baseAddress)
+                connection = self.rhea.connect({
+                    connection_details:ws('ws://' + baseAddress, ["binary", "base64", "AMQWSB10"]),
+                    reconnect:true,
+                    properties: {console_identifier: 'Dispatch console'}
+	            });
+			}
+			catch (e) {
+				QDR.log.debug("exception caught on connect")
+				self.errorText = "Connection failed"
+				onDisconnect();
+			}
+			if (!self.connectionError) {
+				connection.on('connection_open', function (context) {
+					QDR.log.debug("connection_opened")
+					okay.connection = true;
+					okay.receiver = false;
+					okay.sender = false;
+				})
+				connection.on('disconnected', function (context) {
+					QDR.log.debug("connection disconnected")
+					self.errorText = "Unable to connect"
+					onDisconnect();
+				})
+				connection.on('connection_close', function (context) {
+					QDR.log.debug("connection closed")
+					self.errorText = "Disconnected"
+					onDisconnect();
+				})
+
+				var sender = connection.open_sender();
+				sender.on('sender_open', function (context) {
+					QDR.log.debug("sender_opened")
+					okay.sender = true
+					maybeStart()
+				})
+				sender.on('sendable', function (context) {
+					//QDR.log.debug("sendable")
+					self.sendable = true;
+					maybeStart();
+				})
+
+				var receiver = connection.open_receiver({source: {dynamic: true}});
+				receiver.on('receiver_open', function (context) {
+					QDR.log.debug("receiver_opened")
+					okay.receiver = true;
+					maybeStart()
+				})
+				receiver.on("message", function (context) {
+					self.correlator.resolve(context);
+				});
+			}
+		}
+      }
+    }
+    return self;
+  };
+
+  return QDR;
+}(QDR || {}));

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/0c58c381/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.module.js
----------------------------------------------------------------------
diff --git a/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.module.js b/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.module.js
new file mode 100644
index 0000000..48cc85f
--- /dev/null
+++ b/console/dispatch-dashboard/dispatch/static/dashboard/dispatch/dispatch.module.js
@@ -0,0 +1,256 @@
+/*
+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
+ * @main QDR
+ *
+ * The main entry point for the QDR module
+ *
+ */
+var QDR = (function(QDR) {
+
+  /**
+   * @property pluginName
+   * @type {string}
+   *
+   * The name of this plugin
+   */
+  QDR.pluginName = "QDR";
+  QDR.pluginRoot = "";
+  QDR.isStandalone = true;
+  QDR.isHorizon = true;
+  QDR.offsetParent = ".col-xs-12";
+
+  /**
+   * @property log
+   * @type {Logging.Logger}
+   *
+   * This plugin's logger instance
+   */
+  //HIO QDR.log = Logger.get(QDR.pluginName);
+  /**
+   * @property templatePath
+   * @type {string}
+   *
+   * The top level path to this plugin's partials
+   */
+  QDR.srcBase = "plugin/";
+  QDR.templatePath = QDR.srcBase + "html/";
+  QDR.cssPath = QDR.srcBase + "css/";
+  /**
+   * @property SETTINGS_KEY
+   * @type {string}
+   *
+   * The key used to fetch our settings from local storage
+   */
+  QDR.SETTINGS_KEY = 'QDRSettings';
+  QDR.LAST_LOCATION = "QDRLastLocation";
+
+  /**
+   * @property module
+   * @type {object}
+   *
+   * This plugin's angularjs module instance
+   */
+  QDR.module = angular.module('horizon.dashboard.dispatch',
+    [
+    'ui.grid',
+    'ui.grid.resizeColumns',
+    'ui.grid.selection',
+    'ui.bootstrap',
+    'ui.slider',
+    'horizon.dashboard.dispatch.overv',
+    'horizon.dashboard.dispatch.topology'
+    ])
+
+  Core = {
+	  notification: function (severity, msg) {
+        $.notify(msg, severity);
+    }
+  }
+
+  QDR.module.config(['$provide', '$windowProvider',
+    function ($provide, $windowProvider) {
+      var path = $windowProvider.$get().STATIC_URL + 'dashboard/dispatch/';
+      $provide.constant('horizon.dashboard.dispatch.basePath', path);
+    }
+  ]);
+
+  QDR.module.config(['$compileProvider',
+    function($compileProvider) {
+      $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|blob):/);
+    }
+  ]);
+
+	QDR.module.filter('to_trusted', ['$sce', function($sce){
+          return function(text) {
+              return $sce.trustAsHtml(text);
+          };
+    }]);
+
+	QDR.module.filter('humanify', ['horizon.dashboard.dispatch.comService', function (QDRService) {
+		return function (input) {
+			return QDRService.humanify(input);
+		};
+	}]);
+
+	QDR.module.filter('Pascalcase', function () {
+		return function (str) {
+			if (!str)
+				return "";
+			return str.replace(/(\w)(\w*)/g,
+			function(g0,g1,g2){return g1.toUpperCase() + g2.toLowerCase();});
+		}
+	})
+
+    QDR.module.filter('safePlural', function () {
+	        return function (str) {
+				var es = ['x', 'ch', 'ss', 'sh']
+				for (var i=0; i<es.length; ++i) {
+					if (str.endsWith(es[i]))
+						return str + 'es'
+				}
+				if (str.endsWith('y'))
+					return str.substr(0, str.length-2) + 'ies'
+				if (str.endsWith('s'))
+					return str;
+				return str + 's'
+	        }
+	})
+
+	QDR.logger = function ($log) {
+		var log = $log;
+
+		this.debug = function (msg) { msg = "QDR: " + msg; log.debug(msg)};
+		this.error = function (msg) {msg = "QDR: " + msg; log.error(msg)}
+		this.info = function (msg) {msg = "QDR: " + msg; log.info(msg)}
+		this.warn = function (msg) {msg = "QDR: " + msg; log.warn(msg)}
+
+		return this;
+	}
+    // one-time initialization happens in the run function
+    // of our module
+  QDR.module.run(
+    ["$rootScope",
+    '$route',
+    '$timeout',
+    "$location",
+    "$log",
+    "horizon.dashboard.dispatch.comService",
+    "horizon.dashboard.dispatch.chartService",
+    function (
+      $rootScope,
+      $route,
+      $timeout,
+      $location,
+      $log,
+      QDRService,
+      QDRChartService) {
+        QDR.log = new QDR.logger($log);
+        QDR.log.info("*************creating Dispatch Console************");
+
+        var curPath = $location.path()
+        var org = curPath.substr(1)
+        if (org && org.length > 0 && org !== "connect") {
+        //  $location.search('org', org)
+        } else {
+        //  $location.search('org', null)
+        }
+
+        QDRService.initProton();
+        var settings = angular.fromJson(localStorage[QDR.SETTINGS_KEY]);
+        QDRService.addConnectAction(function() {
+          QDRChartService.init(); // initialize charting service after we are connected
+        });
+
+    if (settings && settings.autostart) {
+      QDRService.addDisconnectAction( function () {
+        $timeout(function () {
+          var lastLocation = localStorage[QDR.LAST_LOCATION] || "/overview";
+          org = lastLocation.substr(1)
+          //$location.path("/connect");
+          //$location.search('org', org)
+debugger;
+          window.location.replace("/dispatch/connect/");
+        })
+      })
+      QDRService.addConnectAction(function() {
+        var searchObject = $location.search();
+        // the redirect will be handled by QDRService when connected
+        if (searchObject.org) {
+          return;
+        }
+        // there was no org= parameter, so redirect to last known location
+        $timeout(function () {
+          var lastLocation = localStorage[QDR.LAST_LOCATION] || "/overview";
+          //$location.path(lastLocation);
+        })
+      });
+      QDRService.connect(settings);
+    } else {
+QDR.log.debug("QDR.module run called with location of " + $location.path());
+      $timeout(function () {
+        //$location.path('/connect')
+        //$location.search('org', org)
+//debugger;
+//        window.location.replace("/dispatch/connect/");
+      })
+    }
+
+    $rootScope.$on('$routeChangeSuccess', function() {
+      var path = $location.path();
+      if (path !== "/connect") {
+        localStorage[QDR.LAST_LOCATION] = path;
+      }
+    });
+  }]);
+
+	QDR.module.controller ("QDR.Core", function ($scope, $rootScope) {
+		$scope.alerts = [];
+		$scope.closeAlert = function(index) {
+            $scope.alerts.splice(index, 1);
+        };
+		$scope.$on('newAlert', function(event, data) {
+			$scope.alerts.push(data);
+			$scope.$apply();
+		});
+		$scope.$on("clearAlerts", function () {
+			$scope.alerts = [];
+			$scope.$apply();
+		})
+
+	})
+
+  return QDR;
+}(QDR || {}));
+
+var Folder = (function () {
+    function Folder(title) {
+        this.title = title;
+	this.children = [];
+	this.folder = true;
+    }
+    return Folder;
+})();
+var Leaf = (function () {
+    function Leaf(title) {
+        this.title = title;
+    }
+    return Leaf;
+})();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org