You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2020/10/09 23:09:48 UTC

[activemq-artemis] branch master updated: ARTEMIS-2838 - migrate to HawtIO 2

This is an automated email from the ASF dual-hosted git repository.

clebertsuconic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/master by this push:
     new 0ce173d  ARTEMIS-2838 - migrate to HawtIO 2
     new 950e087  This closes #3257
0ce173d is described below

commit 0ce173dcb50476c87397caacb98d238070873599
Author: Andy Taylor <an...@gmail.com>
AuthorDate: Mon Feb 17 10:20:19 2020 +0000

    ARTEMIS-2838 - migrate to HawtIO 2
    
    https://issues.apache.org/jira/browse/ARTEMIS-2838
---
 .../apache/activemq/artemis/cli/commands/Run.java  |  30 +-
 .../artemis/cli/factory/BrokerFactory.java         |   5 +-
 .../artemis/cli/factory/BrokerHandler.java         |   3 +-
 .../artemis/cli/factory/FileBrokerHandler.java     |   5 +-
 .../activemq/artemis/integration/FileBroker.java   |   7 +-
 .../apache/activemq/cli/test/FileBrokerTest.java   |   8 +-
 .../api/core/management/ActiveMQServerControl.java |   3 +
 .../api/core/management/ObjectNameBuilder.java     |   4 +
 .../artemis/api/core/management/QueueControl.java  |   5 +
 .../artemis/api/core/management/ResourceNames.java |   2 +
 artemis-hawtio/activemq-branding/pom.xml           |  13 +
 .../src/main/webapp/plugin/css/activemq.css        | 378 +++++----
 .../src/main/webapp/plugin/doc/welcome.md          |   0
 .../src/main/webapp/plugin/img/activemq.png        | Bin 25694 -> 22865 bytes
 .../src/main/webapp/plugin/js/brandingPlugin.js    |  93 +++
 .../src/main/webapp/plugin/js/plugin.js            |  97 ---
 artemis-hawtio/artemis-console/pom.xml             |  60 +-
 .../src/main/webapp/app/core/doc/about.md          |  53 --
 .../src/main/webapp/app/jvm/html/connect.html      | 104 ---
 .../src/main/webapp/hawtconfig.json                |  26 +
 .../src/main/webapp/img/img_avatar.svg             |  49 ++
 artemis-hawtio/artemis-plugin/pom.xml              |   4 +
 .../src/main/webapp/index.html}                    |  31 +-
 .../src/main/webapp/plugin/html/addresses.html     |  54 --
 .../src/main/webapp/plugin/html/artemisLayout.html |  42 -
 .../src/main/webapp/plugin/html/brokerDiagram.html | 313 --------
 .../src/main/webapp/plugin/html/browseQueue.html   | 156 ----
 .../src/main/webapp/plugin/html/connections.html   |  72 --
 .../src/main/webapp/plugin/html/consumers.html     |  75 --
 .../src/main/webapp/plugin/html/createAddress.html |  44 --
 .../src/main/webapp/plugin/html/createQueue.html   |  77 --
 .../src/main/webapp/plugin/html/deleteAddress.html |  48 --
 .../src/main/webapp/plugin/html/deleteQueue.html   |  65 --
 .../src/main/webapp/plugin/html/preferences.html   |  87 ++-
 .../src/main/webapp/plugin/html/producers.html     |  54 --
 .../src/main/webapp/plugin/html/queues.html        |  54 --
 .../src/main/webapp/plugin/html/sendMessage.html   | 135 ----
 .../src/main/webapp/plugin/html/sessions.html      |  74 --
 .../src/main/webapp/plugin/html/tree/content.html} |  22 +-
 .../src/main/webapp/plugin/html/tree/header.html   |  41 +
 .../src/main/webapp/plugin/js/address.js           | 120 ---
 .../src/main/webapp/plugin/js/addresses.js         | 234 ------
 .../src/main/webapp/plugin/js/artemisHelpers.js    | 146 +---
 .../src/main/webapp/plugin/js/artemisPlugin.js     | 398 ++--------
 .../src/main/webapp/plugin/js/artemisService.js    |  44 --
 .../src/main/webapp/plugin/js/brokerDiagram.js     | 687 -----------------
 .../src/main/webapp/plugin/js/browse.js            | 593 --------------
 .../main/webapp/plugin/js/components/addresses.js  | 217 ++++++
 .../src/main/webapp/plugin/js/components/browse.js | 849 +++++++++++++++++++++
 .../webapp/plugin/js/components/connections.js     | 229 ++++++
 .../main/webapp/plugin/js/components/consumers.js  | 248 ++++++
 .../webapp/plugin/js/components/createAddress.js   | 139 ++++
 .../webapp/plugin/js/components/createQueue.js     | 206 +++++
 .../webapp/plugin/js/components/deleteAddress.js   | 126 +++
 .../webapp/plugin/js/components/deleteQueue.js     | 172 +++++
 .../main/webapp/plugin/js/components/diagram.js    | 434 +++++++++++
 .../src/main/webapp/plugin/js/components/help.js   |  51 ++
 .../main/webapp/plugin/js/components/navigation.js | 238 ++++++
 .../webapp/plugin/js/components/preferences.js     | 113 +++
 .../main/webapp/plugin/js/components/producers.js  | 194 +++++
 .../src/main/webapp/plugin/js/components/queues.js | 255 +++++++
 .../webapp/plugin/js/components/sendMessage.js     | 246 ++++++
 .../main/webapp/plugin/js/components/sessions.js   | 251 ++++++
 .../src/main/webapp/plugin/js/components/status.js | 160 ++++
 .../src/main/webapp/plugin/js/components/tree.js   | 191 +++++
 .../src/main/webapp/plugin/js/connections.js       | 265 -------
 .../src/main/webapp/plugin/js/consumers.js         | 294 -------
 .../src/main/webapp/plugin/js/jmsHeaderSchema.js   |  62 --
 .../src/main/webapp/plugin/js/preferences.js       |  54 --
 .../src/main/webapp/plugin/js/producers.js         | 254 ------
 .../src/main/webapp/plugin/js/queue.js             | 152 ----
 .../src/main/webapp/plugin/js/queues.js            | 345 ---------
 .../src/main/webapp/plugin/js/send.js              | 210 -----
 .../main/webapp/plugin/js/services/pagination.js   |  97 +++
 .../main/webapp/plugin/js/services/resource.js}    |  49 +-
 .../src/main/webapp/plugin/js/services/toolbar.js  | 116 +++
 .../src/main/webapp/plugin/js/sessions.js          | 284 -------
 .../src/main/webapp/plugin/js/tree.js              |  76 --
 .../src/main/webapp/plugin/lib/artemis-console.js  |  92 ---
 artemis-hawtio/pom.xml                             |   2 +-
 .../artemis/jms/client/ActiveMQMessage.java        |   2 +-
 .../server/config/impl/FileJMSConfiguration.java   |   3 +-
 .../apache/activemq/artemis/osgi/OsgiBroker.java   |   2 +-
 .../artemis/core/config/FileDeploymentManager.java |   5 +-
 .../artemis/core/config/HAPolicyConfiguration.java |  22 +-
 .../core/config/impl/FileConfiguration.java        |   9 +-
 .../core/config/impl/LegacyJMSConfiguration.java   |   3 +-
 .../artemis/core/deployers/Deployable.java         |   3 +-
 .../management/impl/ActiveMQServerControlImpl.java |   7 +-
 .../core/management/impl/QueueControlImpl.java     |   6 +-
 .../artemis/core/server/ActiveMQServerLogger.java  |  10 +
 .../server/management/ArtemisMBeanServerGuard.java |  35 +-
 .../server/management/HawtioSecurityControl.java   |  39 +
 .../core/server/management/ManagementContext.java  |  20 +-
 .../core/server/management/ManagementService.java  |   4 +
 .../management/impl/HawtioSecurityControlImpl.java | 155 ++++
 .../management/impl/ManagementServiceImpl.java     |  17 +
 .../config/impl/FileConfigurationParserTest.java   |   2 +-
 .../server/group/impl/ClusteredResetMockTest.java  |  11 +
 pom.xml                                            |   3 +-
 .../ActiveMQServerControlUsingCoreTest.java        |  10 +
 .../management/QueueControlUsingCoreTest.java      |   9 +
 102 files changed, 5548 insertions(+), 6115 deletions(-)

diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java
index 366f0c0..552f7ef 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/Run.java
@@ -30,6 +30,8 @@ import org.apache.activemq.artemis.cli.factory.BrokerFactory;
 import org.apache.activemq.artemis.cli.factory.jmx.ManagementFactory;
 import org.apache.activemq.artemis.cli.factory.security.SecurityManagerFactory;
 import org.apache.activemq.artemis.components.ExternalComponent;
+import org.apache.activemq.artemis.core.server.ActivateCallback;
+import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
 import org.apache.activemq.artemis.core.server.management.ManagementContext;
 import org.apache.activemq.artemis.dto.BrokerDTO;
 import org.apache.activemq.artemis.dto.ComponentDTO;
@@ -81,7 +83,33 @@ public class Run extends LockAbstract {
 
          ActiveMQSecurityManager security = SecurityManagerFactory.create(broker.security);
 
-         server = BrokerFactory.createServer(broker.server, security);
+         ActivateCallback activateCallback = new ActivateCallback() {
+            @Override
+            public void preActivate() {
+               try {
+                  managementContext.start();
+               } catch (Exception e) {
+                  ActiveMQServerLogger.LOGGER.unableStartManagementContext(e);
+                  return;
+               }
+               try {
+                  server.getServer().getManagementService().registerHawtioSecurity(managementContext.getArtemisMBeanServerGuard());
+               } catch (Exception e) {
+                  ActiveMQServerLogger.LOGGER.unableToDeployHawtioMBean(e);
+               }
+            }
+
+            @Override
+            public void deActivate() {
+               try {
+                  server.getServer().getManagementService().unregisterHawtioSecurity();
+               } catch (Exception e) {
+                  //ok to ignore
+               }
+            }
+         };
+
+         server = BrokerFactory.createServer(broker.server, security, activateCallback);
 
          managementContext.start();
          server.createComponents();
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
index dc9b9e1..5a1a28c 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.net.URI;
 
 import org.apache.activemq.artemis.cli.ConfigurationException;
+import org.apache.activemq.artemis.core.server.ActivateCallback;
 import org.apache.activemq.artemis.dto.BrokerDTO;
 import org.apache.activemq.artemis.dto.ServerDTO;
 import org.apache.activemq.artemis.integration.Broker;
@@ -53,7 +54,7 @@ public class BrokerFactory {
       return createBrokerConfiguration(new URI(configuration), artemisHome, artemisInstance, artemisURIInstance);
    }
 
-   public static Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security) throws Exception {
+   public static Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security, ActivateCallback activateCallback) throws Exception {
       if (brokerDTO.configuration != null) {
          BrokerHandler handler;
          URI configURI = brokerDTO.getConfigurationURI();
@@ -65,7 +66,7 @@ public class BrokerFactory {
             throw new ConfigurationException("Invalid configuration URI, can't find configuration scheme: " + configURI.getScheme());
          }
 
-         return handler.createServer(brokerDTO, security);
+         return handler.createServer(brokerDTO, security, activateCallback);
       }
       return null;
    }
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerHandler.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerHandler.java
index df874a7..513206c 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerHandler.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerHandler.java
@@ -16,11 +16,12 @@
  */
 package org.apache.activemq.artemis.cli.factory;
 
+import org.apache.activemq.artemis.core.server.ActivateCallback;
 import org.apache.activemq.artemis.dto.ServerDTO;
 import org.apache.activemq.artemis.integration.Broker;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 
 public interface BrokerHandler {
 
-   Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security);
+   Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security, ActivateCallback activateCallback);
 }
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/FileBrokerHandler.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/FileBrokerHandler.java
index 74d1eb7..2b5faec 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/FileBrokerHandler.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/FileBrokerHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.activemq.artemis.cli.factory;
 
+import org.apache.activemq.artemis.core.server.ActivateCallback;
 import org.apache.activemq.artemis.dto.ServerDTO;
 import org.apache.activemq.artemis.integration.Broker;
 import org.apache.activemq.artemis.integration.FileBroker;
@@ -24,7 +25,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 public class FileBrokerHandler implements BrokerHandler {
 
    @Override
-   public Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security) {
-      return new FileBroker(brokerDTO, security);
+   public Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security, ActivateCallback activateCallback) {
+      return new FileBroker(brokerDTO, security, activateCallback);
    }
 }
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/integration/FileBroker.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/integration/FileBroker.java
index 9d66778..6d911dd 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/integration/FileBroker.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/integration/FileBroker.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import org.apache.activemq.artemis.core.config.FileDeploymentManager;
 import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
 import org.apache.activemq.artemis.core.config.impl.LegacyJMSConfiguration;
+import org.apache.activemq.artemis.core.server.ActivateCallback;
 import org.apache.activemq.artemis.core.server.ActiveMQComponent;
 import org.apache.activemq.artemis.core.server.ActiveMQServer;
 import org.apache.activemq.artemis.core.server.ServiceComponent;
@@ -33,6 +34,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 public class FileBroker implements Broker {
 
    private final String configurationUrl;
+   private ActivateCallback activateCallback;
 
    private boolean started;
 
@@ -40,9 +42,10 @@ public class FileBroker implements Broker {
 
    private Map<String, ActiveMQComponent> components;
 
-   public FileBroker(ServerDTO broker, ActiveMQSecurityManager security) {
+   public FileBroker(ServerDTO broker, ActiveMQSecurityManager security, ActivateCallback activateCallback) {
       this.securityManager = security;
       this.configurationUrl = broker.configuration;
+      this.activateCallback = activateCallback;
    }
 
    @Override
@@ -116,7 +119,7 @@ public class FileBroker implements Broker {
 
       createDirectories(configuration);
 
-      components = fileDeploymentManager.buildService(securityManager, ManagementFactory.getPlatformMBeanServer());
+      components = fileDeploymentManager.buildService(securityManager, ManagementFactory.getPlatformMBeanServer(), activateCallback);
    }
 
    /*
diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
index e1a2879..59d1e89 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/FileBrokerTest.java
@@ -50,7 +50,7 @@ public class FileBrokerTest {
       serverDTO.configuration = "broker-nojms.xml";
       FileBroker broker = null;
       try {
-         broker = new FileBroker(serverDTO, new ActiveMQJAASSecurityManager());
+         broker = new FileBroker(serverDTO, new ActiveMQJAASSecurityManager(), null);
          broker.start();
          JMSServerManagerImpl jmsServerManager = (JMSServerManagerImpl) broker.getComponents().get("jms");
          Assert.assertNull(jmsServerManager);
@@ -70,8 +70,8 @@ public class FileBrokerTest {
       ServerDTO serverDTO2 = new ServerDTO();
       serverDTO1.configuration = "FileBrokerTest-broker1.xml";
       serverDTO2.configuration = "FileBrokerTest-broker2.xml";
-      FileBroker broker1 = new FileBroker(serverDTO1, new ActiveMQJAASSecurityManager());
-      FileBroker broker2 = new FileBroker(serverDTO2, new ActiveMQJAASSecurityManager());
+      FileBroker broker1 = new FileBroker(serverDTO1, new ActiveMQJAASSecurityManager(), null);
+      FileBroker broker2 = new FileBroker(serverDTO2, new ActiveMQJAASSecurityManager(), null);
       try {
          broker1.start();
          Assert.assertTrue(broker1.isStarted());
@@ -115,7 +115,7 @@ public class FileBrokerTest {
          securityConfiguration.addUser("myUser", "myPass");
          securityConfiguration.addRole("myUser", "guest");
          ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), securityConfiguration);
-         broker = new FileBroker(serverDTO, securityManager);
+         broker = new FileBroker(serverDTO, securityManager, null);
          broker.start();
          ActiveMQServerImpl activeMQServer = (ActiveMQServerImpl) broker.getComponents().get("core");
          Assert.assertNotNull(activeMQServer);
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
index ea739cd..ae8e266 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
@@ -460,6 +460,9 @@ public interface ActiveMQServerControl {
    @Attribute(desc = ADDRESS_MEMORY_USAGE_PERCENTAGE_DESCRIPTION)
    int getAddressMemoryUsagePercentage();
 
+   @Attribute(desc = "Returns the HA Policy of this broker as a String")
+   String getHAPolicy();
+
    /**
     * Returns the runtime size of the authentication cache
     */
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java
index dbebec2..5fe0d73 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ObjectNameBuilder.java
@@ -160,4 +160,8 @@ public final class ObjectNameBuilder {
          return "";
       }
    }
+
+   public ObjectName getManagementContextObjectName() throws Exception {
+      return ObjectName.getInstance(String.format("hawtio:type=security,area=jmx,name=ArtemisJMXSecurity"));
+   }
 }
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/QueueControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/QueueControl.java
index 4b09a5f..b6ba1e1 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/QueueControl.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/QueueControl.java
@@ -627,6 +627,11 @@ public interface QueueControl {
    CompositeData[] browse(@Parameter(name = "page", desc = "Current page") int page,
                           @Parameter(name = "pageSize", desc = "Page size") int pageSize) throws Exception;
 
+   @Operation(desc = "Browse Messages", impact = MBeanOperationInfo.ACTION)
+   CompositeData[] browse(@Parameter(name = "page", desc = "Current page") int page,
+                          @Parameter(name = "pageSize", desc = "Page size") int pageSize,
+                          @Parameter(name = "filter", desc = "filter") String filter) throws Exception;
+
    /**
     * Resets the MessagesAdded property
     */
diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ResourceNames.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ResourceNames.java
index 410ee93..7aaa54d 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ResourceNames.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ResourceNames.java
@@ -28,6 +28,8 @@ import org.apache.activemq.artemis.api.core.SimpleString;
 public final class ResourceNames {
    public static final String BROKER = "broker";
 
+   public static final String MANAGEMENT_SECURITY = "managementsecurity";
+
    public static final String QUEUE = "queue.";
 
    public static final String ADDRESS = "address.";
diff --git a/artemis-hawtio/activemq-branding/pom.xml b/artemis-hawtio/activemq-branding/pom.xml
index 48583a4..b4184b4 100644
--- a/artemis-hawtio/activemq-branding/pom.xml
+++ b/artemis-hawtio/activemq-branding/pom.xml
@@ -153,6 +153,9 @@
                                     <map from="${basedir}/src/main/webapp/" to="" />
                                 </pathconvert>
                                 <echo>Files: ${plugin-scripts}</echo>
+                                <!--<replace file="${webapp-outdir}/plugin/js/brandingPlugin.js">
+                                    <replacefilter token="@artemis.version@" value="${project.version}"/>
+                                </replace>-->
 
                             </target>
                             <!-- this exports plugin-scripts to the maven build, without
@@ -254,6 +257,16 @@
                                 <exclude>log4j.properties</exclude>
                             </excludes>
                         </resource>
+                        <resource>
+                            <filtering>true</filtering>
+                            <directory>src/main/webapp</directory>
+                            <includes>
+                                <include>**/*.*</include>
+                            </includes>
+                            <excludes>
+                                <exclude>log4j.properties</exclude>
+                            </excludes>
+                        </resource>
                     </webResources>
                 </configuration>
             </plugin>
diff --git a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css
index edc1583..ea7b1ab 100644
--- a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css
+++ b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/css/activemq.css
@@ -17,15 +17,208 @@
 
 /* fonts */
 
-@import url("../../../console/app/themes/fonts/Open-Sans/stylesheet.css");
-@import url("../../../console/app/themes/fonts/Droid-Sans-Mono/stylesheet.css");
 
+/* You can customise the styles of your application here. */
+@font-face {
+    font-family: 'PatternFlyIcons-webfont';
+    src: url('../../../console/fonts/PatternFlyIcons-webfont.eot');
+    url('../../../console/fonts/PatternFlyIcons-webfont.woff') format('woff'),
+    url('../../../console/fonts/PatternFlyIcons-webfont.ttf') format('truetype'),
+    url('../../../console/fonts/PatternFlyIcons-webfont.svg') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+@font-face {
+    font-family: 'OpenSans';
+    src: url('../../../console/fonts/OpenSans-Regular-webfont.eot');
+    url('../../../console/fonts/OpenSans-Regular-webfont.woff') format('woff'),
+    url('../../../console/fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
+    url('../../../console/fonts/OpenSans-Regular-webfont.svg') format('svg');
+    font-weight: normal;
+    font-style: normal;
+}
+
+/*Uses ActiveMQ colors in broker diagram*/
+svg text {
+   font-family: PatternFlyIcons-webfont;
+}
+
+.pf-topology-svg g.ThisBroker circle {
+   stroke: #801944;
+   fill: #c12766;
+}
+
+.pf-topology-svg g.MasterBroker circle {
+   stroke: #801944;
+   fill: #c12766;
+}
+
+.pf-topology-svg g.SlaveBroker circle {
+   stroke: #82171b;
+   fill: #cf242a;
+}
+
+.pf-topology-svg g.Address circle {
+   stroke:  #2b326e;
+   fill: #3e489f;
+}
+
+.pf-topology-svg g.Queue circle {
+   stroke:  #50621d;
+   fill: #78932c;
+}
+
+/*Adds a border to top of page*/
+.pf-c-page__header {
+    border-top: 3px solid #B21054;
+}
+
+/* Change the background image for Login page and About modal as well as text color etc*/
+.pf-c-login, .pf-c-about-modal-box__hero {
+  background-image: url("/activemq-branding/plugin/img/login-screen-background.png");
+  background-size: cover;
+  --pf-c-form__label--Color: white;
+}
+
+.pf-c-login__main {
+    grid-area: main;
+    background-color: transparent;
+}
+
+.pf-c-login__footer .pf-c-list a {
+    color: white;
+}
+
+.pf-c-login__footer p {
+    font-size: 150%;
+}
+
+.pf-c-login__main-body label {
+    color: white;
+}
+
+.pf-c-login__main-header {
+    color: white;
+}
+
+/*These change the color of the buttons*/
+.btn-link {
+    color: #B24E78;
+}
+
+.pf-c-button.pf-m-primary {
+    background-color: #B24E78;
+}
+
+.pf-c-button.pf-m-primary.pf-m-hover, .pf-c-button.pf-m-primary:hover {
+    background-color: #B24E78;
+    background-image: linear-gradient(to bottom,#B24E78 0,#B24E78 100%);
+    background: #B21054;
+    border-color: #B24E78;
+}
+
+.pf-c-title.pf-m-3xl {
+    color: white;
+}
+
+.btn-primary {
+    background-color: #B24E78;
+    background-image: linear-gradient(to bottom,#B24E78 0,#B24E78 100%);
+    background-repeat: repeat-x;
+    border-color: #B24E78;
+    color: #fff;
+}
+.btn-primary.active.focus,
+.btn-primary.active:focus,
+.btn-primary.active:hover, .btn-primary:active.focus,
+.btn-primary:active:focus,
+.btn-primary:active:hover,
+.open .dropdown-toggle.btn-primary.focus,
+.open .dropdown-toggle.btn-primary:focus,
+.open .dropdown-toggle.btn-primary:hover {
+    background-color: #B24E78;
+    border-color: #B21054;
+}
+
+/*These change the row ina table when hovered over*/
+.table-hover>tbody>tr:hover {
+    background-color: #B24E78;
+}
+
+.table-hover>tbody>tr:hover td {
+    background-color: #B24E78;
+}
+
+select>option:hover,
+select>option:active {
+    background: #B24E78;
+    background-color: #B24E78;
+}
+
+tbody>tr:hover {
+    background-color: #B24E78;
+}
+
+/*This controls the color of the buttons when clicked, hovered or visited*/
+.btn-primary:hover,
+.btn-primary.hover
+.btn-primary:active,
+.btn-primary.active,
+.btn-primary:focus,
+.btn-primary.focus,
+.btn-primary:visited,
+.btn-primary.visited{
+    background-color: #B24E78;
+    background-image: linear-gradient(to bottom,#B24E78 0,#B24E78 100%);
+    background: #B21054;
+    border-color: #B24E78;
+}
+
+/*This changes the color of the hover item in the JMX Tree*/
+.treeview-pf-hover .list-group-item:hover {
+    background-color: #B24E78!important;
+    border-color: #B24E78!important;
+}
+
+/*This changes the color of the chosen selection in the JMX Tree*/
+.treeview-pf-select .list-group-item.node-selected {
+    background: #B24E78!important;
+    border-color: #B24E78!important;
+    color: #fff!important;
+}
+
+/* This changes the color of the underline in the main left menuLeft hand menu tab underline*/
+.pf-c-nav__list .pf-m-current.pf-c-nav__link::after, .pf-c-nav__list .pf-m-current>.pf-c-nav__link::after {
+    background-color: #B24E78;
+}
+
+.pf-c-nav__list .pf-c-nav__link.pf-m-hover::after, .pf-c-nav__list .pf-c-nav__link:hover::after {
+    background-color: #B24E78;
+}
+
+.card-pf.card-pf-accented {
+    border-top-color: #B24E78;
+}
+
+/*This changes the hover color in all the tables*/
+.table-hover tbody tr:hover td.focus {
+  background-color: #B24E78;
+}
+
+/*This changes the color of the sort column header*/
+table.dataTable thead .sorting_asc, table.dataTable thead .sorting_desc {
+    color: #B24E78!important;
+    position: relative;
+}
+
+/*This is the original css from HawtIO 1,leaving as is as somemay be used*/
 * {
-  font-family: OpenSans;
+  font-family: "Open Sans";
 }
 
 body {
-  font-family: OpenSans;
+  font-family: "Open Sans";
 }
 
 #log-panel-statements li {
@@ -750,25 +943,6 @@ td.adding {
   border-bottom-left-radius: 0px;
 }
 
-.login-wrapper {
-  background-color: rgba(255, 168, 27, 0.3);
-  box-shadow: rgba(255, 168, 27, 0.2) 0 0 30px 10px;
-}
-
-.login-wrapper form {
-  background-color: rgba(255, 255, 255, 0.2);
-  box-shadow: inset rgba(255, 168, 27, 0.2) 0 0 30px 10px;
-}
-
-.login-form form fieldset .control-group label {
-  color: white;
-  font-weight: bolder;
-}
-
-.login-logo {
-  color: white;
-}
-
 /** highlight required fields which have no focus */
 input.ng-invalid,
 textarea.ng-invalid,
@@ -1171,7 +1345,7 @@ i.expandable-indicator.folder {
 
 tr.selected,
 tr.selected .ngCell,
-tr.selected .ngCellText a,
+tr.selected .ngCellText i,
 .table-striped tbody tr.selected:nth-child(odd) td {
   background-color: #c9dde1;
 }
@@ -1421,6 +1595,21 @@ h1, h2, h3, h4, h5, h6 {
   font-family: "Overpass", sans-serif;
 }
 
+.nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover {
+    color: #B21054;
+    cursor: default;
+    background-color: #fff;
+    border: 1px solid #ddd;
+    border-bottom-color: transparent;
+}
+
+table.jmx-attributes-table td {
+    color: #B21054;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}
+
 a {
   color: #B21054;
   text-decoration: none;
@@ -1802,89 +1991,6 @@ select, textarea, input[type="text"], input[type="password"], input[type="dateti
   */
 }
 
-div[ng-controller='Core.LoginController']:after {
-  position: relative;
-  horiz-align: center;
-}
-
-
-.login-wrapper {
-  top: inherit;
-  border-radius: 0;
-  box-shadow: none;
-  left: 0;
-  position: absolute;
-  bottom: 15%;
-  padding-left: 0;
-  width: 100%;
-  min-width: 850px;
-  border-top: 1px rgba(255, 255, 255, 0.05) solid;
-  border-bottom: 1px rgba(255, 255, 255, 0.05) solid;
-  background-color: rgba(255, 255, 255, 0.1);
-
-}
-
-.login-logo>img {
-  height: 150px;
-}
-
-.login-logo {
-  top: -200px;
-  /* with no app title */
-  /* left: 183px; */
-  left: 45px;
-  width: 700px;
-}
-
-.login-logo span {
-  position: relative;
-  top: 2px;
-  text-transform: uppercase;
-  letter-spacing: 0.5px;
-}
-
-.login-wrapper form {
-  background: inherit;
-  border-radius: 0;
-  box-shadow: none;
-  padding: 0;
-  margin: 0;
-}
-
-.login-wrapper form fieldset {
-  padding-top: 40px;
-  padding-bottom: 40px;
-  width: 344px;
-}
-
-.login-wrapper form fieldset input[type="text"],
-.login-wrapper form fieldset input[type="password"] {
-  margin: 4px;
-  padding: 3px 6px;
-  min-width: 200px;
-  height: 26px;
-  border: 1px #b6b6b6 solid;
-  border-radius: 2px;
-  background: url("../img/input-background.png") repeat-x top left;
-}
-
-.login-wrapper form fieldset input[type="text"]:hover,
-.login-wrapper form fieldset input[type="password"]:hover {
-  border-color: #B2577A;
-}
-
-.login-wrapper form fieldset input[type="text"]:focus,
-.login-wrapper form fieldset input[type="password"]:focus {
-  border-color: #B2577A;
-  box-shadow: #B2577A 0 0 5px;
-}
-
-.login-wrapper form fieldset .control-group .controls .checkbox {
-  position: absolute;
-  top: 185px;
-  left: 181px;
-}
-
 .dropdown-menu li > a:hover,
 .dropdown-menu li > a:focus,
 .dropdown-submenu:hover > a {
@@ -1915,62 +2021,6 @@ div[ng-controller='Core.LoginController']:after {
   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#B26182', endColorstr='#B2577A', GradientType=0);
 }
 
-.login-wrapper form fieldset button[type="submit"] {
-  position: relative;
-  left: 39px;
-  padding: 4px 14px;
-  border: 1px #B24E78 solid;
-  border-radius: 2px;
-  background-image: linear-gradient(top, #B26182 0%, #B2577A 100%);
-  background-image: -o-linear-gradient(top, #B26182 0%, #B2577A 100%);
-  background-image: -moz-linear-gradient(top, #B26182 0%, #B2577A 100%);
-  background-image: -webkit-linear-gradient(top, #B26182 0%, #B2577A 100%);
-  background-image: -ms-linear-gradient(top, #B26182 0%, #B2577A 100%);
-  background-image: -webkit-gradient(
-          linear,
-          left top,
-          left bottom,
-          color-stop(0.0, #B26182),
-          color-stop(1,0, #B2577A)
-  );
-  color: #fff;
-  font-weight: bold;
-  font-size: 12px;
-  letter-spacing: 0.6px;
-}
-
-.login-wrapper form fieldset button[type="submit"]:hover,
-.login-wrapper form fieldset button[type="submit"]:focus {
-  background-color: #B26182;
-  background-image: none;
-  cursor: pointer;
-}
-
-.login-wrapper form fieldset button[type="submit"]:active {
-  background-color: #B27497;
-  background-image: none;
-  cursor: pointer;
-  box-shadow: inset 0 0 5px 3px #B2577A;
-}
-
-.login-wrapper form fieldset input[type="checkbox"] {
-  margin-right: 6px;
-}
-
-.login-wrapper form fieldset input[type="text"],
-.login-wrapper form fieldset input[type="password"] {
-  color: #ffffff;
-  background-color: inherit;
-  margin: 4px 0px;
-  margin-bottom: 14px;
-  width: 282px;
-}
-
-.login-wrapper form fieldset button[type="submit"] {
-  float: right;
-  margin-top: 12px;
-}
-
 .logbar {
   width: 100%;
   left: 0;
@@ -2155,7 +2205,7 @@ li.dropdown.open > a.dropdown-toggle {
   border-bottom: 1px solid #d4d4d4;
 }
 
-.ngRow.selected .ngCellText a {
+.ngRow.selected .ngCellText i {
   color: #ffffff !important;
   background-color: #B21054 !important;
 }
diff --git a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/doc/welcome.md b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/doc/welcome.md
deleted file mode 100644
index e69de29..0000000
diff --git a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/img/activemq.png b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/img/activemq.png
index f911a4b..13a7ff6 100644
Binary files a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/img/activemq.png and b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/img/activemq.png differ
diff --git a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/js/brandingPlugin.js b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/js/brandingPlugin.js
new file mode 100644
index 0000000..cc33a84
--- /dev/null
+++ b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/js/brandingPlugin.js
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+ /**
+ * The main entry point for the Branding module
+ */
+var Branding = (function (Branding) {
+
+  /**
+   * The name of this plugin
+   */
+  Branding.pluginName = 'activemq-branding';
+
+  /**
+   * This plugin's logger instance
+   */
+  Branding.log = Logger.get('activemq-branding-plugin');
+
+  /**
+   * The top level path of this plugin on the server
+   */
+  Branding.contextPath = '/activemq-branding';
+
+  /**
+   * This plugin's AngularJS module instance.
+   */
+  Branding.module = angular.module(Branding.pluginName, [])
+    .run(initPlugin);
+
+  /**
+   * Here you can overwrite hawtconfig.json by putting the JSON
+   * data directly to configManager.config property.
+   */
+  function initPlugin(configManager, aboutService) {
+    configManager.config = {
+      "branding": {
+        "appName": "Artemis Console",
+        "appLogoUrl": `${Branding.contextPath}/plugin/img/activemq.png`,
+        "companyLogoUrl": `${Branding.contextPath}/plugin/img/activemq.png`,
+        "css": `${Branding.contextPath}/plugin/css/activemq.css`,
+        "favicon": `${Branding.contextPath}/plugin/img/favicon.png`
+      },
+      "login": {
+        "description": "ActiveMQ Artemis Management Console",
+        "links": [
+          {
+            "url": "/user-manual/index.html",
+            "text": "User Manual"
+          },
+          {
+            "url": "https://activemq.apache.org/",
+            "text": "Website"
+          }
+        ]
+      },
+      "about": {
+        "title": "ActiveMQ Artemis Management Console",
+        "productInfo": [],
+        "additionalInfo": "",
+        "imgSrc": `${Branding.contextPath}/plugin/img/activemq.png`
+      },
+      "disabledRoutes": []
+    };
+
+    aboutService.addProductInfo('Artemis', '${project.version}');
+    // Calling this function is required to apply the custom css and
+    // favicon settings
+    Core.applyBranding(configManager);
+
+    Branding.log.info(Branding.pluginName, "loaded");
+  }
+  initPlugin.$inject = ['configManager', 'aboutService'];
+
+  return Branding;
+
+})(Branding || {});
+
+// tell the Hawtio plugin loader about our plugin so it can be
+// bootstrapped with the rest of AngularJS
+hawtioPluginLoader.addModule(Branding.pluginName);
diff --git a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/js/plugin.js b/artemis-hawtio/activemq-branding/src/main/webapp/plugin/js/plugin.js
deleted file mode 100644
index 7edecac..0000000
--- a/artemis-hawtio/activemq-branding/src/main/webapp/plugin/js/plugin.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- */
-/**
- * The activemq hawtio theme
- *
- * @module activemqBranding
- * @main activemq
- */
-var localStorage = Core.getLocalStorage();
-localStorage['showWelcomePage'] = false;
-var activemqBranding = (function (self) {
-
-    self.log = Logger.get("activemq");
-    self.context = '../activemq-branding/';
-    self.pluginName = 'hawtio-activemq-branding';
-
-    hawtioPluginLoader.registerPreBootstrapTask(function (task) {
-        Themes.definitions['activemq'] = {
-            label: 'activemq',
-            file: self.context + 'plugin/css/activemq.css',
-            loginBg: self.context + 'plugin/img/login-screen-background.png'
-        };
-        if (!('theme' in localStorage)) {
-            localStorage['theme'] = 'activemq';
-        }
-        localStorage['showWelcomePage'] = false;
-        Themes.brandings['activemq'] = {
-            label: 'activemq',
-            setFunc: function(branding) {
-                branding.appName = 'ActiveMQ Management Console';
-                branding.appLogo = self.context + 'plugin/img/activemq.png';
-                branding.logoOnly = true;
-                branding.fullscreenLogin = true;
-                branding.css = self.context + 'plugin/css/branding.css';
-                branding.favicon = self.context + 'plugin/img/favicon.png';
-                branding.welcomePageUrl = self.context + 'plugin/doc/welcome.md';
-                return branding;
-            }
-        }
-        if (!('branding' in localStorage)) {
-            localStorage['branding'] = 'activemq';
-        }
-        task();
-    });
-
-    self.module = angular.module(self.pluginName, ['hawtioCore']);
-    self.module.run(function (branding) {
-        self.log.info("ActiveMQ theme loaded");
-        if (localStorage['theme'] != 'activemq' || localStorage['branding'] != 'activemq') {
-            localStorage['theme'] = 'activemq';
-            localStorage['branding'] = 'activemq';
-            location.reload();
-        }
-
-        /**
-         * By default tabs are pulled from the "container" perspective, here
-         * we can define includes or excludes to customize the available tabs
-         * in hawtio.  Use "href" to match from the start of a URL and "rhref"
-         * to match a URL via regex string.
-         * 
-         * Currently we need to exclude provided diagnostics,
-         * as it exposes proprietary Oracle JVM feature, flight recorder.
-         *
-         */
-        window['Perspective']['metadata'] = {
-            container: {
-                label: "Container",
-                lastPage: "#/help",
-                topLevelTabs: {
-                    excludes: [
-                        {
-                            href: "#/diagnostics"
-                        }
-                    ]
-                }
-            }
-        };
-
-    });
-    return self;
-})(activemqBranding || {});
-
-hawtioPluginLoader.addModule(activemqBranding.pluginName);
diff --git a/artemis-hawtio/artemis-console/pom.xml b/artemis-hawtio/artemis-console/pom.xml
index e310d3e..90f30f4 100644
--- a/artemis-hawtio/artemis-console/pom.xml
+++ b/artemis-hawtio/artemis-console/pom.xml
@@ -45,7 +45,7 @@
 
     <dependency>
       <groupId>io.hawt</groupId>
-      <artifactId>hawtio-web</artifactId>
+      <artifactId>hawtio-war</artifactId>
       <version>${hawtio.version}</version>
       <!--
         NOTE this WAR dependency type which enables this WAR to
@@ -61,12 +61,12 @@
       <version>${hawtio.version}</version>
       <scope>provided</scope>
     </dependency>
-    <dependency>
+    <!--<dependency>
       <groupId>io.hawt</groupId>
       <artifactId>hawtio-git</artifactId>
       <version>${hawtio.version}</version>
       <scope>provided</scope>
-    </dependency>
+    </dependency>-->
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
@@ -97,7 +97,7 @@
               <filtering>true</filtering>
               <directory>src/main/webapp</directory>
               <includes>
-                <include>**/*.md</include>
+                <include>**/*.svg</include>
                 <!-- include any other file types you want to filter -->
               </includes>
             </resource>
@@ -105,54 +105,12 @@
           <overlays>
             <overlay>
               <groupId>io.hawt</groupId>
-              <artifactId>hawtio-web</artifactId>
+              <artifactId>hawtio-war</artifactId>
               <excludes>
-                <exclude>bower_components/bootstrap/docs/build/**/*</exclude>
-                <exclude>bower_components/bootstrap/docs/examples/**/*</exclude>
-                <exclude>bower_components/bootstrap/docs/templates/**/*</exclude>
-                <exclude>bower_components/bootstrap/docs/assets/img/examples/**/*</exclude>
-                <exclude>bower_components/bootstrap/docs/assets/img/example-sites/**/*</exclude>
-                <exclude>bower_components/bootstrap/js/tests/**/*</exclude>
-                <exclude>bower_components/bootstrap/docs/**/*.html</exclude>
-                <exclude>bower_components/Font-Awesome/src/**/*</exclude>
-                <exclude>bower_components/d3/src/**/*</exclude>
-                <exclude>bower_components/d3/test/**/*</exclude>
-                <exclude>bower_components/elastic.js/src/**/*</exclude>
-                <exclude>bower_components/elastic.js/tests/**/*</exclude>
-                <exclude>bower_components/elastic.js/examples/**/*</exclude>
-                <exclude>bower_components/jquery/src/**/*</exclude>
-                <exclude>bower_components/jquery/test/**/*</exclude>
-                <exclude>bower_components/js-logger/src/**/*</exclude>
-                <excluse>WEB-INF/lib/guava*.jar</excluse>
-                <excluse>WEB-INF/lib/slf4j-api*.jar</excluse>
-                <excluse>lib/camelModel.js</excluse>
-                <exclude>app/activemq/**/*</exclude>
-                <exclude>app/api/**/*</exclude>
-                <exclude>app/apm/**/*</exclude>
-                <exclude>app/camel/**/*</exclude>
-                <exclude>app/camin/**/*</exclude>
-                <exclude>app/datatable/**/*</exclude>
-                <exclude>app/dozer/**/*</exclude>
-                <exclude>app/elasticsearch/**/*</exclude>
-                <exclude>app/fabric/**/*</exclude>
-                <exclude>app/fabric-deploy/**/*</exclude>
-                <exclude>app/fabric-requirements/**/*</exclude>
-                <exclude>app/forcegraph/**/*</exclude>
-                <exclude>app/git/**/*</exclude>
-                <exclude>app/health/**/*</exclude>
-                <exclude>app/ide/**/*</exclude>
-                <exclude>app/infinispan/**/*</exclude>
-                <exclude>app/jboss/**/*</exclude>
-                <exclude>app/jclouds/**/*</exclude>
-                <exclude>app/junit/**/*</exclude>
-                <exclude>app/maven/**/*</exclude>
-                <exclude>app/openejb/**/*</exclude>
-                <exclude>app/quartz/**/*</exclude>
-                <exclude>app/site/**/*</exclude>
-                <exclude>app/springbatch/**/*</exclude>
-                <exclude>app/springBoot/**/*</exclude>
-                <exclude>app/tomcat/**/*</exclude>
-                <exclude>app/wiki-drop/**/*</exclude>
+                <exclude>hawtconfig.json</exclude>
+                <exclude>img/icons/**/*</exclude>
+                <exclude>img/**/*</exclude>
+                <exclude>fonts/glyphicons**</exclude>
               </excludes>
             </overlay>
           </overlays>
diff --git a/artemis-hawtio/artemis-console/src/main/webapp/app/core/doc/about.md b/artemis-hawtio/artemis-console/src/main/webapp/app/core/doc/about.md
deleted file mode 100644
index 8d36813..0000000
--- a/artemis-hawtio/artemis-console/src/main/webapp/app/core/doc/about.md
+++ /dev/null
@@ -1,53 +0,0 @@
-<h3 class="about-header">About Apache ActiveMQ Artemis</h3>
-
-<div id="content">
-    <div class="wrapper">
-        <p>Apache ActiveMQ Artemis is an open source project to build a multi-protocol, embeddable, very high performance, clustered, asynchronous messaging system.</p>
-        <p>Apache ActiveMQ Artemis has a proven non blocking architecture. It delivers outstanding performance. </p>
-        <p>A full guide on features and usage can be found in the <a href="#/help">User Manual</a></p>
-        <p/>{{branding.appName}} is powered by <img class='no-shadow' ng-src='img/logo-16px.png'><a href="http://hawt.io/">hawtio</a><p/>
-        <h2 id = "Features">Features</h2>
-        <ul>
-            <li>AMQP protocol support</li>
-            <li>OpenWire support for ActiveMQ 5 clients</li>
-            <li>MQTT support</li>
-            <li>STOMP protocol support</li>
-            <li>HornetQ Core protocol support for HornetQ 2.4,2.5 clients</li>
-            <li>JMS 2.0 and 1.1 support</li>
-            <li>High availability with shared store and non shared store (replication)</li>
-            <li>Flexible Clustering</li>
-            <li>High performance journal for message persistence</li>
-            <li>Queue memory limitation</li>
-            <li>SSL support</li>
-            <li>Management over JMX, JMS and core protocol</li>
-            <li>Large message support</li>
-            <li>Topic hierarchies</li>
-            <li>Producer flow control</li>
-            <li>Consumer flow control</li>
-            <li>Diverts</li>
-            <li>Last value queue</li>
-            <li>Message Groups</li>
-            <li>OSGi support</li>
-        </ul>
-        <h2 id = "Links">Links</h2>
-        <ul>
-            <li><a target="_blank" href="#/help">User Manual</a></li>
-            <li><a href="https://activemq.apache.org/artemis/download.html">Download</a></li>
-            <li><a href="https://activemq.apache.org/artemis/migration.html">Migration</a></li>
-            <li><a href="https://activemq.apache.org/artemis/community.html">Community</a></li>
-        </ul>
-    </div>
-</div>
-
-
-<h4>Versions</h4>
-
-  **artemis** version: ${project.version}
-
-  **hawtio** version: {{hawtioVersion}}
-
-  **jolokia** version: {{jolokiaVersion}}
-
-<div ng-show="serverVendor">
-  <strong>server</strong> version: {{serverVendor}} {{serverProduct}} {{serverVersion}}
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-console/src/main/webapp/app/jvm/html/connect.html b/artemis-hawtio/artemis-console/src/main/webapp/app/jvm/html/connect.html
deleted file mode 100644
index 06f8d8a..0000000
--- a/artemis-hawtio/artemis-console/src/main/webapp/app/jvm/html/connect.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="JVM.ConnectController">
-
-    <div class="row-fluid connect-column-container" hawtio-auto-columns=".connect-column">
-
-        <div class="connect-column">
-            <div class="alert alert-info">
-                <p>
-                    This page allows you to connect to remote processes which <strong>already have a <a
-                        href="http://jolokia.org/">jolokia agent</a> running inside them</strong>. You will need to know the
-                    host name, port and path of the jolokia agent to be able to connect.
-                </p>
-
-                <p>
-                    If the process you wish to connect to does not have a jolokia agent inside, please refer to the <a
-                        href="http://jolokia.org/agent.html">jolokia documentation</a> for how to add a JVM, servlet or OSGi
-                    based agent inside it.
-                </p>
-
-                <p ng-show="hasLocalMBean()">
-                    Use the <strong><a href="#/jvm/local">Local Tab</a></strong> to connect to processes locally on this machine (which will install a jolokia agent automatically if required).
-                </p>
-
-                <p ng-show="!hasLocalMBean()">
-                    The <strong>Local Tab</strong> is not currently enabled because either the server side <strong>hawtio-local-jvm-mbean plugin</strong> is not installed or this
-                    JVM cannot find the <strong>com.sun.tools.attach.VirtualMachine</strong> API usually found in the <strong>tool.jar</strong>.
-                    Please see the <a href="http://hawt.io/faq/index.html">FAQ entry</a> for more details.
-                </p>
-            </div>
-        </div>
-
-        <div class="connect-column">
-
-            <dl>
-                <dt>Saved Connections</dt>
-                <dd>
-                    <form class="form-horizontal no-bottom-margin">
-                        <fieldset>
-                            <div class="control-group">
-                                <label class="control-label">Connections: </label>
-                                <div class="controls">
-                                    <select ng-model="lastConnection"
-                                            ng-options="value.name as key for (key, value) in connectionConfigs">
-                                        <option value=""
-                                                ng-hide="lastConnection">New connection...</option>
-                                    </select>
-                                    <button class="btn btn-success"
-                                            title="Connect to this server"
-                                            ng-disabled="!lastConnection"
-                                            ng-click="gotoServer()"><i class="icon-share"></i></button>
-                                    <button class="btn btn-danger"
-                                            title="Delete this connection"
-                                            ng-disabled="!lastConnection"
-                                            ng-click="deleteConnection()"><i class="icon-remove-sign"></i></button>
-                                    <button class="btn btn-primary"
-                                            title="Create a new connection"
-                                            ng-disabled="!lastConnection"
-                                            ng-click="newConnection()"><i class="icon-plus"></i></button>
-                                </div>
-                            </div>
-                        </fieldset>
-                    </form>
-                </dd>
-            </dl>
-
-            <dl>
-                <dt>Connection Settings</dt>
-                <dd>
-                    <div simple-form name="connectForm" data="formConfig" entity="currentConfig" onSubmit="gotoServer()"></div>
-
-                    <div class="centered">
-                        <button class="btn btn-primary"
-                                ng-disabled="!forms.connectForm.$valid"
-                                hawtio-submit="connectForm"
-                                title="Saves the connection and opens a new browser window connecting to the given JVM process via its Jolokia servlet URL">Connect to remote server</button>
-                        <button class="btn"
-                                title="Save this configuration but don't open a new tab"
-                                ng-disabled="!forms.connectForm.$valid"
-                                ng-click="save()">Save</button>
-                    </div>
-                </dd>
-            </dl>
-
-        </div>
-
-    </div>
-
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-console/src/main/webapp/hawtconfig.json b/artemis-hawtio/artemis-console/src/main/webapp/hawtconfig.json
new file mode 100644
index 0000000..84fe779
--- /dev/null
+++ b/artemis-hawtio/artemis-console/src/main/webapp/hawtconfig.json
@@ -0,0 +1,26 @@
+{
+  "branding": {
+    "appName": "Artemis Console",
+    "appLogoUrl": "/activemq-branding/plugin/img/activemq.png",
+    "companyLogoUrl": "/activemq-branding/plugin/img/activemq.png",
+    "css": "/activemq-branding/plugin/css/activemq.css",
+    "favicon": "/activemq-branding/plugin/img/favicon.png"
+  },
+  "login": {
+    "description": "ActiveMQ Artemis Management Console",
+    "links": [
+      {
+        "url": "/user_manual/index.html",
+        "text": "User Manual"
+      }
+    ]
+  },
+  "about": {
+    "title": "ActiveMQ Artemis Management Console",
+    "productInfo": [],
+    "additionalInfo": "",
+    "copyright": "",
+    "imgSrc": "/activemq-branding/plugin/img/activemq.png"
+  },
+  "disabledRoutes": []
+}
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-console/src/main/webapp/img/img_avatar.svg b/artemis-hawtio/artemis-console/src/main/webapp/img/img_avatar.svg
new file mode 100644
index 0000000..457b95d
--- /dev/null
+++ b/artemis-hawtio/artemis-console/src/main/webapp/img/img_avatar.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<svg enable-background="new 0 0 36 36" version="1.1" viewBox="0 0 36 36" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
+<style type="text/css">
+	/*stylelint-disable*/
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
+	.st1{filter:url(#b);}
+	.st2{mask:url(#a);}
+	.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#BBBBBB;}
+	.st4{opacity:0.1;fill-rule:evenodd;clip-rule:evenodd;enable-background:new    ;}
+	.st5{opacity:8.000000e-02;fill-rule:evenodd;clip-rule:evenodd;fill:#231F20;enable-background:new    ;}
+	/*stylelint-enable*/
+</style>
+			<circle class="st0" cx="18" cy="18.5" r="18"/>
+		<defs>
+			<filter id="b" x="5.2" y="7.2" width="25.6" height="53.6" filterUnits="userSpaceOnUse">
+				<feColorMatrix values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"/>
+			</filter>
+		</defs>
+		<mask id="a" x="5.2" y="7.2" width="25.6" height="53.6" maskUnits="userSpaceOnUse">
+			<g class="st1">
+				<circle class="st0" cx="18" cy="18.5" r="18"/>
+			</g>
+		</mask>
+		<g class="st2">
+			<g transform="translate(5.04 6.88)">
+				<path class="st3" d="m22.6 18.1c-1.1-1.4-2.3-2.2-3.5-2.6s-1.8-0.6-6.3-0.6-6.1 0.7-6.1 0.7 0 0 0 0c-1.2 0.4-2.4 1.2-3.4 2.6-2.3 2.8-3.2 12.3-3.2 14.8 0 3.2 0.4 12.3 0.6 15.4 0 0-0.4 5.5 4 5.5l-0.3-6.3-0.4-3.5 0.2-0.9c0.9 0.4 3.6 1.2 8.6 1.2 5.3 0 8-0.9 8.8-1.3l0.2 1-0.2 3.6-0.3 6.3c3 0.1 3.7-3 3.8-4.4s0.6-12.6 0.6-16.5c0.1-2.6-0.8-12.1-3.1-15z"/>
+				<path class="st4" d="m22.5 26c-0.1-2.1-1.5-2.8-4.8-2.8l2.2 9.6s1.8-1.7 3-1.8c0 0-0.4-4.6-0.4-5z"/>
+				<path class="st3" d="m12.7 13.2c-3.5 0-6.4-2.9-6.4-6.4s2.9-6.4 6.4-6.4 6.4 2.9 6.4 6.4-2.8 6.4-6.4 6.4z"/>
+				<path class="st5" d="m9.4 6.8c0-3 2.1-5.5 4.9-6.3-0.5-0.1-1-0.2-1.6-0.2-3.5 0-6.4 2.9-6.4 6.4s2.9 6.4 6.4 6.4c0.6 0 1.1-0.1 1.6-0.2-2.8-0.6-4.9-3.1-4.9-6.1z"/>
+				<path class="st4" d="m8.3 22.4c-2 0.4-2.9 1.4-3.1 3.5l-0.6 18.6s1.7 0.7 3.6 0.9l0.1-23z"/>
+			</g>
+		</g>
+</svg>
diff --git a/artemis-hawtio/artemis-plugin/pom.xml b/artemis-hawtio/artemis-plugin/pom.xml
index 8e2e062..23d52ea 100644
--- a/artemis-hawtio/artemis-plugin/pom.xml
+++ b/artemis-hawtio/artemis-plugin/pom.xml
@@ -62,6 +62,10 @@
     <schema-outdir>${basedir}/src/main/webapp/lib</schema-outdir>
     <appjs-outfile>${webapp-outdir}/app/app.js</appjs-outfile>
 
+<!--
+    <angular.version>1.7.9</angular.version>
+-->
+
   </properties>
 
   <dependencies>
diff --git a/artemis-hawtio/artemis-console/src/main/webapp/app/core/html/help.html b/artemis-hawtio/artemis-plugin/src/main/webapp/index.html
similarity index 62%
copy from artemis-hawtio/artemis-console/src/main/webapp/app/core/html/help.html
copy to artemis-hawtio/artemis-plugin/src/main/webapp/index.html
index 55ffad8..fe036f6 100644
--- a/artemis-hawtio/artemis-console/src/main/webapp/app/core/html/help.html
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/index.html
@@ -15,24 +15,13 @@
   limitations under the License.
   Architecture
 -->
-<style>
-    #scroll-box {
-        background:#e6e6e6;
-        width:100%;
-        height: 100%;
-        padding:0px;
-        overflow-y: scroll;
-        overflow-x: scroll
-    }
-
-    #help-content
-    {
-        position:absolute; left: 0; right: 0; bottom: 0; top: 106px;
-    }
-</style>
-
-<div  ng-controller="Core.HelpController">
-    <div id="help-content">
-        <iframe id=scroll-box src="../user-manual/index.html" scrolling="yes" height="100%" width="100%" />
-    </div>
-</div>
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Artemis plugin</title>
+  </head>
+  <body>
+    <h1>Hawtio :: Artemis plugin example</h1>
+  </body>
+</html>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/addresses.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/addresses.html
deleted file mode 100644
index f6ca987..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/addresses.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.AddressesController">
-
-    <!-- TODO This should be templated and included -->
-    <div class="row-fluid">
-        <div class="span24">
-            <div class="control-group inline-block">
-                <form class="form-inline no-bottom-margin">
-                    &nbsp;<span class="label label-default">Filter</span>
-                    &nbsp;&nbsp;
-                    <select ng-model="filter.values.field" id="filter.values.field">
-                        <option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <select ng-model="filter.values.operation" id="filter.values.operation">
-                        <option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
-                    <button class="btn" ng-click="refresh()"
-                            title="Filter">
-                        <i class="icon-search">&nbsp;&nbsp;</i>
-                    </button>
-                    &nbsp;&nbsp;
-                    <button class="btn pull-right" ng-click="reset()"
-                            title="Reset">
-                        <i class="icon-refresh">&nbsp;&nbsp;Reset</i>
-                    </button>
-                </form>
-            </div>
-        </div>
-    </div>
-
-    <div class="row-fluid">
-        <div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns></div>
-    </div>
-
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html
deleted file mode 100644
index eb254c9..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<script type="text/ng-template" id="header">
-  <div class="tree-header" ng-controller="ARTEMIS.TreeHeaderController">
-    <div class="left">
-    </div>
-    <div class="right">
-      <i class="icon-chevron-down clickable"
-         title="Expand all nodes"
-         ng-click="expandAll()"></i>
-      <i class="icon-chevron-up clickable"
-         title="Unexpand all nodes"
-         ng-click="contractAll()"></i>
-    </div>
-  </div>
-</script>
-<hawtio-pane position="left" width="300" header="header">
-  <div id="tree-container"
-       ng-controller="Jmx.MBeansController">
-    <div id="artemistree"
-         ng-controller="ARTEMIS.TreeController"></div>
-  </div>
-</hawtio-pane>
-<div class="row-fluid">
-  <ng-include src="'app/jmx/html/subLevelTabs.html'"></ng-include>
-  <div id="properties" ng-view></div>
-</div>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html
deleted file mode 100644
index f97ecdd..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html
+++ /dev/null
@@ -1,313 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<style type="text/css">
-
-.span4.node-panel {
-  margin-top: 10px;
-  margin-left: 10px;
-  width: 33%;
-}
-.node-attributes dl {
-  margin-top: 5px;
-  margin-bottom: 10px;
-}
-.node-attributes dt {
-  width: 150px;
-}
-.node-attributes dd {
-  margin-left: 160px;
-}
-.node-attributes dd a {
-  /** lets make the destination links wrap */
-  -ms-word-break: break-all;
-  word-break: break-all;
-  -webkit-hyphens: auto;
-  -moz-hyphens: auto;
-  hyphens: auto;
-}
-
-ul.viewMenu li {
-  padding-left: 10px;
-  padding-top: 2px;
-  padding-bottom: 2px;
-}
-
-div#pop-up {
-  display: none;
-  position: absolute;
-  color: white;
-  font-size: 14px;
-  background: rgba(0, 0, 0, 0.6);
-  padding: 5px 10px 5px 10px;
-  -moz-border-radius: 8px 8px;
-  border-radius: 8px 8px;
-}
-
-div#pop-up-title {
-  font-size: 15px;
-  margin-bottom: 4px;
-  font-weight: bolder;
-}
-
-div#pop-up-content {
-  font-size: 12px;
-}
-
-rect.graphbox {
-  fill: #FFF;
-}
-
-rect.graphbox.frame {
-  stroke: #222;
-  stroke-width: 2px
-}
-
-/* only things directly related to the network graph should be here */
-
-path.link {
-  fill: none;
-  stroke: #666;
-  stroke-width: 1.5px;
-}
-
-marker.broker {
-  stroke: red;
-  fill: red;
-  stroke-width: 1.5px;
-}
-
-circle.broker {
-  fill: #0c0;
-}
-
-circle.brokerSlave {
-  fill: #c00;
-}
-
-circle.notActive {
-  fill: #c00;
-}
-
-path.link.group {
-  stroke: #ccc;
-}
-
-marker#group {
-  stroke: #ccc;
-  fill: #ccc;
-}
-
-circle.group {
-  fill: #eee;
-  stroke: #ccc;
-}
-
-circle.destination {
-  fill: #bbb;
-  stroke: #ccc;
-}
-
-circle.pinned {
-  stroke-width: 4.5px;
-}
-
-path.link.profile {
-  stroke-dasharray: 0, 2 1;
-  stroke: #888;
-}
-
-marker#container {
-}
-
-circle.container {
-  stroke-dasharray: 0, 2 1;
-  stroke: #888;
-}
-
-path.link.container {
-  stroke-dasharray: 0, 2 1;
-  stroke: #888;
-}
-
-circle {
-  fill: #ccc;
-  stroke: #333;
-  stroke-width: 1.5px;
-  cursor: pointer;
-}
-
-circle.closeMode {
-  cursor: crosshair;
-}
-
-path.link.destination {
-  stroke: #ccc;
-}
-
-circle.topic {
-  fill: #c0c;
-}
-
-circle.queue {
-  fill: #00c;
-}
-
-circle.consumer {
-  fill: #cfc;
-}
-
-circle.producer {
-  fill: #ccf;
-}
-
-path.link.producer {
-  stroke: #ccc;
-}
-
-path.link.consumer {
-  stroke: #ccc;
-}
-
-path.link.network {
-  stroke: #ccc;
-}
-
-circle.selected {
-  stroke-width: 3px;
-}
-
-.selected {
-  stroke-width: 3px;
-}
-
-text {
-  font: 10px sans-serif;
-  pointer-events: none;
-}
-
-text.shadow {
-  stroke: #fff;
-  stroke-width: 3px;
-  stroke-opacity: .8;
-}
-</style>
-
-
-<div class="row-fluid mq-page" ng-controller="ARTEMIS.BrokerDiagramController">
-
-  <div ng-hide="inDashboard" class="span12 page-padded">
-    <div class="section-header">
-
-      <div class="section-filter">
-        <input type="text" class="search-query" placeholder="Filter..." ng-model="searchFilter">
-        <i class="icon-remove clickable" title="Clear filter" ng-click="searchFilter = ''"></i>
-      </div>
-
-      <div class="section-controls">
-        <a href="#"
-           class="dropdown-toggle"
-           data-toggle="dropdown">
-          View &nbsp;<i class="icon-caret-down"></i>
-        </a>
-
-        <ul class="dropdown-menu viewMenu">
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.consumer"> Consumers
-            </label>
-          </li>
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.producer"> Producers
-            </label>
-          </li>
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.address"> Addresses
-            </label>
-          </li>
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.queue"> Queues
-            </label>
-          </li>
-          <li class="divider"></li>
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.broker"> Brokers
-            </label>
-          </li>
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.slave"> Slave brokers
-            </label>
-          </li>
-          <li>
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.network"> Networks
-            </label>
-          </li>
-          <li class="divider"></li>
-          <li title="Should we show the details panel on the left">
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.panel"> Details panel
-            </label>
-          </li>
-          <li title="Show the summary popup as you hover over nodes">
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.popup"> Hover text
-            </label>
-          </li>
-          <li title="Show the labels next to nodes">
-            <label class="checkbox">
-              <input type="checkbox" ng-model="viewSettings.label"> Label
-            </label>
-          </li>
-        </ul>
-
-      </div>
-    </div>
-  </div>
-
-
-  <div id="pop-up">
-    <div id="pop-up-title"></div>
-    <div id="pop-up-content"></div>
-  </div>
-
-  <div class="row-fluid">
-    <div class="{{viewSettings.panel ? 'span8' : 'span12'}} canvas broker-canvas">
-      <div hawtio-force-graph graph="graph" selected-model="selectedNode" link-distance="150" charge="-600" nodesize="10" marker-kind="marker-end"
-           style="min-height: 800px">
-      </div>
-    </div>
-    <div ng-show="viewSettings.panel" class="span4 node-panel">
-      <div ng-show="selectedNode" class="node-attributes">
-        <dl ng-repeat="property in selectedNodeProperties" class="dl-horizontal">
-          <dt title="{{property.key}}">{{property.key}}:</dt>
-          <dd ng-bind-html-unsafe="property.value"></dd>
-        </dl>
-      </div>
-    </div>
-  </div>
-
-  <div ng-include="'app/fabric/html/connectToContainerDialog.html'"></div>
-
-</div>
-
-
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html
deleted file mode 100644
index 650972c..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html
+++ /dev/null
@@ -1,156 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.BrowseQueueController">
-  <div class="row-fluid">
-    <div class="span6">
-      <input class="search-query span12" type="text" ng-model="gridOptions.filterOptions.filterText"
-             placeholder="Filter messages">
-    </div>
-    <div class="span6">
-      <div class="pull-right">
-        <form class="form-inline">
-          <button class="btn" ng-disabled="!gridOptions.selectedItems.length" ng-show="dlq" ng-click="retryMessages()"
-                  title="Moves the dead letter queue message back to its original destination so it can be retried" data-placement="bottom">
-            <i class="icon-reply"></i> Retry
-          </button>
-          <button class="btn" ng-disabled="gridOptions.selectedItems.length !== 1" ng-click="resendMessage()"
-                    title="Edit the message to resend it" data-placement="bottom">
-           <i class="icon-share-alt"></i> Resend
-          </button>
-
-          <button class="btn" ng-disabled="!gridOptions.selectedItems.length" ng-click="moveDialog = true"
-                  title="Move the selected messages to another destination" data-placement="bottom">
-            <i class="icon-share-alt"></i> Move
-          </button>
-          <button class="btn" ng-disabled="!gridOptions.selectedItems.length"
-                  ng-click="deleteDialog = true"
-                  title="Delete the selected messages">
-            <i class="icon-remove"></i> Delete
-          </button>
-          <button class="btn" ng-click="refresh()"
-                  title="Refreshes the list of messages">
-            <i class="icon-refresh"></i>
-          </button>
-        </form>
-      </div>
-    </div>
-  </div>
-
-  <div class="row-fluid">
-    <div class="gridStyle" ng-grid="gridOptions"></div>
-  </div>
-
-  <div hawtio-slideout="showMessageDetails" title="{{row.JMSMessageID}}">
-    <div class="dialog-body">
-
-      <div class="row-fluid">
-        <div class="pull-right">
-          <form class="form-horizontal no-bottom-margin">
-
-            <div class="btn-group"
-                 hawtio-pager="messages"
-                 on-index-change="selectRowIndex"
-                 row-index="rowIndex"></div>
-
-            <button class="btn" ng-disabled="!gridOptions.selectedItems.length" ng-click="moveDialog = true"
-                    title="Move the selected messages to another destination" data-placement="bottom">
-              <i class="icon-share-alt"></i> Move
-            </button>
-
-            <button class="btn btn-danger" ng-disabled="!gridOptions.selectedItems.length"
-                    ng-click="deleteDialog = true"
-                    title="Delete the selected messages">
-              <i class="icon-remove"></i> Delete
-            </button>
-
-            <button class="btn" ng-click="showMessageDetails = !showMessageDetails" title="Close this dialog">
-              <i class="icon-remove"></i> Close
-            </button>
-
-          </form>
-        </div>
-      </div>
-
-      <div class="row-fluid">
-        <div class="expandable closed">
-          <div title="Headers" class="title">
-            <i class="expandable-indicator"></i> Headers & Properties
-          </div>
-          <div class="expandable-body well">
-            <table class="table table-condensed table-striped">
-              <thead>
-              <tr>
-                <th>Header</th>
-                <th>Value</th>
-              </tr>
-              </thead>
-              <tbody ng-bind-html-unsafe="row.headerHtml">
-              </tbody>
-              <!--
-                            <tr ng-repeat="(key, value) in row.headers">
-                              <td class="property-name">{{key}}</td>
-                              <td class="property-value">{{value}}</td>
-                            </tr>
-              -->
-            </table>
-          </div>
-        </div>
-      </div>
-
-      <div class="row-fluid">
-        <div>Displaying body as <span ng-bind="row.textMode"></span></div>
-        <div hawtio-editor="row.bodyText" read-only="true" mode='mode'></div>
-      </div>
-
-    </div>
-  </div>
-
-  <div hawtio-confirm-dialog="deleteDialog"
-       ok-button-text="Delete"
-       on-ok="deleteMessages()">
-    <div class="dialog-body">
-      <p>You are about to delete
-        <ng-pluralize count="gridOptions.selectedItems.length"
-                      when="{'1': 'a message!', 'other': '{} messages!'}">
-        </ng-pluralize>
-      </p>
-      <p>This operation cannot be undone so please be careful.</p>
-    </div>
-  </div>
-
-  <div hawtio-confirm-dialog="moveDialog"
-       ok-button-text="Move"
-       on-ok="moveMessages()">
-    <div class="dialog-body">
-      <p>Move
-        <ng-pluralize count="gridOptions.selectedItems.length"
-                      when="{'1': 'message', 'other': '{} messages'}"></ng-pluralize>
-        to: <input type="text" ng-model="queueName" placeholder="Queue name"
-                   typeahead="title.unescapeHTML() for title in queueNames($viewValue) | filter:$viewValue" typeahead-editable='true'></p>
-      <p>
-        You cannot undo this operation.<br>
-        Though after the move you can always move the
-        <ng-pluralize count="gridOptions.selectedItems.length"
-                      when="{'1': 'message', 'other': 'messages'}"></ng-pluralize>
-        back again.
-      </p>
-    </div>
-  </div>
-
-</div>
-
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html
deleted file mode 100644
index d9539f8..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.ConnectionsController">
-
-    <div class="row-fluid">
-        <div class="span24">
-            <div class="control-group inline-block">
-                <form class="form-inline no-bottom-margin">
-                    &nbsp;<span class="label label-default">Filter</span>
-                    &nbsp;&nbsp;
-                    <select ng-model="filter.values.field" id="filter.values.field">
-                        <option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}</option>
-                    </select>
-                    <select ng-model="filter.values.operation" id="filter.values.operation">
-                        <option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
-                    <button class="btn" ng-click="refresh()"
-                            title="Filter">
-                        <i class="icon-search">&nbsp;&nbsp;</i>
-                    </button>
-                    &nbsp;&nbsp;
-                    <button class="btn pull-right" ng-click="reset()"
-                            title="Reset">
-                        <i class="icon-refresh">&nbsp;&nbsp;Reset</i>
-                    </button>
-                </form>
-            </div>
-
-            <div class="pull-right">
-              <form class="form-inline">
-                <button class="btn-danger" ng-show="showClose"
-                        ng-click="deleteDialog = true"
-                        title="Close the selected Connection">
-                  <i class="icon-remove"></i> Close
-                </button>
-                &nbsp;&nbsp;&nbsp;
-              </form>
-            </div>
-        </div>
-    </div>
-
-    <div hawtio-confirm-dialog="deleteDialog"
-           ok-button-text="Close"
-           on-ok="closeConnection()">
-        <div class="dialog-body">
-          <p>You are about to close the selected connection: {{gridOptions.selectedItems[0].connectionID}}
-          </p>
-          <p>Are you sure you want to continue.</p>
-        </div>
-    </div>
-    <div class="row-fluid">
-        <div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns ng-click="selectGridRow()"></div>
-    </div>
-
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html
deleted file mode 100644
index 64de3b2..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.ConsumersController">
-
-    <!-- TODO This should be templated and included -->
-    <div class="row-fluid">
-        <div class="span24">
-            <div class="control-group inline-block">
-                <form class="form-inline no-bottom-margin">
-                    &nbsp;<span class="label label-default">Filter</span>
-                    &nbsp;&nbsp;
-                    <select ng-model="filter.values.field" id="filter.values.field">
-                        <option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <select ng-model="filter.values.operation" id="filter.values.operation">
-                        <option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
-                    <button class="btn" ng-click="refresh()"
-                            title="Filter">
-                        <i class="icon-search">&nbsp;&nbsp;</i>
-                    </button>
-                    &nbsp;&nbsp;
-                    <button class="btn pull-right" ng-click="reset()"
-                            title="Reset">
-                        <i class="icon-refresh">&nbsp;&nbsp;Reset</i>
-                    </button>
-                </form>
-            </div>
-
-            <div class="pull-right">
-              <form class="form-inline">
-                <button class="btn-danger" ng-show="showClose"
-                        ng-click="deleteDialog = true"
-                        title="Close the selected Consumer">
-                  <i class="icon-remove"></i> Close
-                </button>
-                &nbsp;&nbsp;&nbsp;
-              </form>
-            </div>
-        </div>
-    </div>
-
-    <div hawtio-confirm-dialog="deleteDialog"
-          ok-button-text="Close"
-          on-ok="closeConsumer()">
-       <div class="dialog-body">
-         <p>You are about to close the selected consumer: {{gridOptions.selectedItems[0].id}}
-         </p>
-         <p>Are you sure you want to continue.</p>
-       </div>
-    </div>
-
-    <div class="row-fluid">
-        <div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns ng-click="selectGridRow()"></div>
-    </div>
-
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html
deleted file mode 100644
index 0eb2d0a..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<form class="form-horizontal" ng-controller="ARTEMIS.AddressController">
-    <div class="control-group">
-        <label class="control-label" for="addressName"
-                title="The routing name of this address">Address name</label>
-        <div class="controls">
-            <input id="addressName" type="text" maxlength="300" ng-model="addressName" placeholder="Address Name"/>
-        </div>
-    </div>
-
-    <div class="control-group">
-        <label class="control-label" for="routingType">Routing type</label>
-
-        <div class="controls">
-            <select id="routingType" ng-model="routingType">
-                <option value='0'>Multicast</option>
-                <option value='1'>Anycast</option>
-                <option value='2'>Both</option>
-            </select>
-        </div>
-    </div>
-
-    <div class="control-group">
-        <div class="controls">
-            <button type="submit" class="btn btn-info" ng-click="createAddress(addressName, routingType)" ng-disabled="!addressName">Create Address</button>
-        </div>
-    </div>
-</form>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html
deleted file mode 100644
index 1d294fa..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<form class="form-horizontal" ng-controller="ARTEMIS.QueueController">
-
-    <div class="control-group">
-        <label class="control-label" for="queueName"
-               title="The routing name of this address">Queue name</label>
-        <div class="controls">
-            <input id="queueName" type="text" maxlength="300" ng-model="queueName" placeholder="Queue Name"/>
-        </div>
-    </div>
-
-    <div class="control-group">
-        <label class="control-label" for="routingType">Routing type</label>
-
-        <div class="controls">
-            <select id="routingType" ng-model="routingType">
-                <option value='0'>Multicast</option>
-                <option value='1'>Anycast</option>
-            </select>
-        </div>
-    </div>
-
-
-    <div class="control-group">
-        <label class="control-label" for="durable"
-               title="Whether the queue will be durable">Durable</label>
-        <div class="controls">
-            <input id="durable" type="checkbox" ng-model="durable" value="false">
-        </div>
-    </div>
-
-    <div class="control-group">
-        <label class="control-label" for="filter"
-               title="The user name to be used when connecting to the broker">Filter</label>
-        <div class="controls">
-            <input id="filter" type="text" maxlength="300" ng-model="filter" placeholder="Filter"/>
-        </div>
-    </div>
-
-    <div class="control-group">
-        <label class="control-label" for="maxConsumers"
-               title="The maximum consumers the queue can have">Max Consumers</label>
-        <div class="controls">
-            <input id="maxConsumers" type="number" ng-model="maxConsumers" placeholder="maxConsumers"/>
-        </div>
-    </div>
-
-    <div class="control-group">
-        <label class="control-label" for="purgeWhenNoConsumers"
-               title="Whether or not this queue should be purged (emptied and paused) when there are no consumers">Purge when no consumers</label>
-        <div class="controls">
-            <input id="purgeWhenNoConsumers" type="checkbox" ng-model="purgeWhenNoConsumers" value="false"/>
-        </div>
-    </div>
-
-    <div class="control-group">
-        <div class="controls">
-            <button type="submit" class="btn btn-info" ng-click="createQueue(queueName, routingType, durable, filter, maxConsumers, purgeWhenNoConsumers)" ng-disabled="!queueName">Create Queue</button>
-        </div>
-    </div>
-</form>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html
deleted file mode 100644
index afa3172..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.AddressController">
-  <div class="row-fluid">
-
-    <div class="control-group">
-      <div class="alert">
-        <button type="button" class="close" data-dismiss="alert">×</button>
-        <strong>Warning:</strong> these operations cannot be undone. Please be careful!
-      </div>
-    </div>
-  </div>
-  <div class="row-fluid">
-    <div class="span4">
-      <div class="control-group">
-        <button type="submit" class="btn btn-warning" ng-click="deleteDialog = true">Delete address '{{name().unescapeHTML()}}'</button>
-        <label>This will remove the address completely.</label>
-      </div>
-    </div>
-  </div>
-
-  <div hawtio-confirm-dialog="deleteDialog"
-       ok-button-text="Delete"
-       on-ok="deleteAddress()">
-    <div class="dialog-body">
-      <p>You are about to delete the <b>{{name().unescapeHTML()}}</b> address</p>
-      <p>This operation cannot be undone so please be careful.</p>
-    </div>
-  </div>
-
-
-
-</div>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html
deleted file mode 100644
index 3f881c6..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.QueueController">
-  <div class="row-fluid">
-
-    <div class="control-group">
-      <div class="alert">
-        <button type="button" class="close" data-dismiss="alert">×</button>
-        <strong>Warning:</strong> these operations cannot be undone. Please be careful!
-      </div>
-    </div>
-    <h4>Queue '{{name().unescapeHTML()}}'</h4>
-  </div>
-  <div class="row-fluid">
-    <div class="control-group">
-      <hr>
-      <h5>Purge queue</h5>
-      <p>Purge all the current messages on the queue.</p>
-      <button type="submit" class="btn btn-warning" ng-click="purgeDialog = true">Purge queue</button>
-    </div>
-  </div>
-  <div class="row-fluid">
-    <div class="control-group">
-      <hr>
-      <h5>Delete queue</h5>
-      <p>Remove the queue completely.</p>
-      <button type="submit" class="btn btn-warning" ng-click="deleteDialog = true">Delete queue</button>
-    </div>
-  </div>
-
-  <div hawtio-confirm-dialog="deleteDialog"
-       ok-button-text="Delete"
-       on-ok="deleteDestination(true)">
-    <div class="dialog-body">
-      <p>You are about to delete the <b>{{name().unescapeHTML()}}</b> queue</p>
-      <p>This operation cannot be undone so please be careful.</p>
-    </div>
-  </div>
-
-  <div hawtio-confirm-dialog="purgeDialog"
-       ok-button-text="Purge"
-       on-ok="purgeDestination()">
-    <div class="dialog-body">
-      <p>You are about to purge the <b>{{name().unescapeHTML()}}</b> queue</p>
-      <p>This operation cannot be undone so please be careful.</p>
-    </div>
-  </div>
-
-
-</div>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html
index 10fb619..c619263 100644
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html
@@ -15,55 +15,60 @@
   limitations under the License.
   Architecture
 -->
-<div ng-controller="ARTEMIS.PreferencesController">
-  <form class="form-horizontal">
+<form class="form-horizontal artemis-preferences-form" ng-controller="Artemis.PreferencesController">
 
-    <div class="control-group">
-      <label class="control-label" for="artemisUserName"
-             title="The user name to be used when connecting to the broker">User name</label>
-
-      <div class="controls">
-        <input id="artemisUserName" type="text" placeholder="username" ng-model="artemisUserName" autofill/>
-      </div>
+  <div class="form-group">
+    <label class="col-md-2 control-label" for="artemisUserName">
+      Artemis user name
+      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
+    </label>
+    <div class="col-md-6">
+      <input id="artemisUserName" type="text" class="form-control" ng-model="artemisUserName"/>
     </div>
-    <div class="control-group">
-      <label class="control-label" for="artemisPassword" title="Password to be used when connecting to the broker">Password</label>
+  </div>
 
-      <div class="controls">
-        <input id="artemisPassword" type="password" placeholder="password" ng-model="artemisPassword" autofill/>
-      </div>
+  <div class="form-group">
+    <label class="col-md-2 control-label" for="artemisPassword">
+      Artemis password
+      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
+    </label>
+    <div class="col-md-6">
+      <input id="artemisPassword" type="password" class="form-control" ng-model="artemisPassword"/>
     </div>
+  </div>
 
-    <div class="control-group">
-      <label class="control-label" for="artemisDLQ" title="The DLQ of the Broker">DLQ</label>
-
-      <div class="controls">
-        <input id="artemisDLQ" type="text" placeholder="DLQ" ng-model="artemisDLQ" autofill/>
-      </div>
+  <div class="form-group">
+    <label class="col-md-2 control-label" for="artemisDLQ">
+      The DLQ of the Broker
+      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Dead Letter Queue of the Broker"></span>
+    </label>
+    <div class="col-md-6">
+      <input type="text" id="artemisDLQ" ng-model="artemisDLQ">
     </div>
+  </div>
 
-    <div class="control-group">
-      <label class="control-label" for="artemisExpiryQueue" title="The Expiry Queue of the Broker">Expiry Queue</label>
-
-      <div class="controls">
-        <input id="artemisExpiryQueue" type="text" placeholder="ExpiryQueue" ng-model="artemisExpiryQueue" autofill/>
-      </div>
+  <div class="form-group">
+    <label class="col-md-2 control-label" for="artemisExpiryQueue">
+      The Expiry of the Broker
+      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Expiry Queue of the Broker"></span>
+    </label>
+    <div class="col-md-6">
+      <input type="text" id="artemisExpiryQueue" ng-model="artemisExpiryQueue">
     </div>
+  </div>
 
-    <div class="control-group">
-      <label class="control-label" for="byteMessages">Browse byte messages</label>
-
-      <div class="controls">
-        <select id="byteMessages" ng-model="activemqBrowseBytesMessages">
-          <option value='99'>Off</option>
-          <option value='8'>Decimal</option>
-          <option value='4'>Hex</option>
-          <option value='2'>Decimal and text</option>
-          <option value='1'>Hex and text</option>
-        </select>
-        <span class="help-block">Browsing byte messages should display the message body as</span>
-      </div>
+ <!-- <div class="form-group">
+    <label class="col-md-2 control-label" for="artemisBrowseBytesMessages">
+      Display message body as
+      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="Browsing byte messages should display the message body as"></span>
+    </label>
+    <div class="col-md-6">
+      <select id="artemisBrowseBytesMessages"
+              ng-model="artemisBrowseBytesMessages"
+              ng-options="key for (key, value) in messageBodyDisplayOptions"
+              ng-selected="artemisBrowseBytesMessages === value">
+      </select>
     </div>
+  </div>-->
 
-  </form>
-</div>
+</form>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/producers.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/producers.html
deleted file mode 100644
index 12bfe0c..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/producers.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.ProducersController">
-
-    <!-- TODO This should be templated and included -->
-    <div class="row-fluid">
-        <div class="span24">
-            <div class="control-group inline-block">
-                <form class="form-inline no-bottom-margin">
-                    &nbsp;<span class="label label-default">Filter</span>
-                    &nbsp;&nbsp;
-                    <select ng-model="filter.values.field" id="filter.values.field">
-                        <option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <select ng-model="filter.values.operation" id="filter.values.operation">
-                        <option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
-                    <button class="btn" ng-click="refresh()"
-                            title="Filter">
-                        <i class="icon-search">&nbsp;&nbsp;</i>
-                    </button>
-                    &nbsp;&nbsp;
-                    <button class="btn pull-right" ng-click="reset()"
-                            title="Reset">
-                        <i class="icon-refresh">&nbsp;&nbsp;Reset</i>
-                    </button>
-                </form>
-            </div>
-        </div>
-    </div>
-
-    <div class="row-fluid">
-        <div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns></div>
-    </div>
-
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/queues.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/queues.html
deleted file mode 100644
index d5d03fe..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/queues.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.QueuesController">
-
-    <!-- TODO This should be templated and included -->
-    <div class="row-fluid">
-        <div class="span24">
-            <div class="control-group inline-block">
-                <form class="form-inline no-bottom-margin">
-                    &nbsp;<span class="label label-default">Filter</span>
-                    &nbsp;&nbsp;
-                    <select ng-model="filter.values.field" id="filter.values.field">
-                        <option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <select ng-model="filter.values.operation" id="filter.values.operation">
-                        <option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
-                    <button class="btn" ng-click="refresh()"
-                            title="Filter">
-                        <i class="icon-search">&nbsp;&nbsp;</i>
-                    </button>
-                    &nbsp;&nbsp;
-                    <button class="btn pull-right" ng-click="reset()"
-                            title="Reset">
-                        <i class="icon-refresh">&nbsp;&nbsp;Reset</i>
-                    </button>
-                </form>
-            </div>
-        </div>
-    </div>
-
-    <div class="row-fluid">
-        <div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns></div>
-    </div>
-
-</div>
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html
deleted file mode 100644
index 002b558..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.SendMessageController">
-
-  <div class="tabbable" ng-model="tab">
-
-    <div value="compose" class="tab-pane" title="Compose">
-      <!--
-         title="Compose a new message to send"
-      -->
-
-      <div class="row-fluid">
-        <span ng-show="noCredentials" class="alert">
-          No credentials set for endpoint!  Please set your username and password in the <a
-            href="" ng-click="openPrefs()">Preferences</a> page
-        </span>
-
-        <form class="form-inline pull-right">
-          <div class="row-fluid">
-            <div class="controls">
-              <label class="control-label" for="durable" title="Is this message durable">Durable: </label>
-              <input id="durable" type="checkbox" ng-model="durable" value="true">
-            </div>
-          <button class="btn" ng-click="addHeader()" title="Add a new message header"><i
-              class="icon-plus"></i> Header
-          </button>
-          <button type="submit" class="btn btn-primary" ng-click="sendMessage(durable)">Send message</button>
-        </form>
-      </div>
-
-      <form class="form-inline bottom-margin" ng-submit="addHeader()">
-        <ol class="zebra-list header-list">
-          <div class="row-fluid">
-            <li ng-repeat="header in headers">
-              <div class="span4">
-                <input type="text" style="width: 100%" class="headerName"
-                       ng-model="header.name"
-                       typeahead="completion for completion in defaultHeaderNames() | filter:$viewValue"
-                       typeahead-editable='true'
-                       placeholder="Header name">
-              </div>
-              <div class="span6">
-                <input type="text" style="width: 100%" ng-model="header.value"
-                       placeholder="Value of the message header">
-              </div>
-              <div class="span2">
-                <button type="submit" class="btn" title="Add a new message header">
-                  <i class="icon-plus"></i>
-                </button>
-                <button type="button" ng-click="removeHeader(header)" class="btn" title="Removes this message header">
-                  <i class="icon-remove"></i>
-                </button>
-              </div>
-            </li>
-          </div>
-        </ol>
-      </form>
-
-      <div class="row-fluid">
-        <form class="form-inline">
-          <div class="controls">
-            <label class="control-label" for="sourceFormat" title="The text format to use for the message payload">Payload
-              format: </label>
-            <select ng-model="codeMirrorOptions.mode.name" id="sourceFormat">
-              <option value="javascript">JSON</option>
-              <option value="text" selected>Plain text</option>
-              <option value="properties">Properties</option>
-              <option value="xml">XML</option>
-            </select>
-
-            <button class="btn" ng-click="autoFormat()"
-                    title="Automatically pretty prints the message so its easier to read">Auto format
-            </button>
-          </div>
-        </form>
-      </div>
-
-      <div class="row-fluid">
-        <textarea ui-codemirror="codeMirrorOptions" ng-model="message"></textarea>
-      </div>
-    </div>
-    </tab>
-
-    <div ng-switch="showChoose">
-      <div ng-switch-when="true">
-        <div value="choose" class="tab-pane" title="Choose">
-          <!--
-                   title="Choose messages to send from the available files in the Profile configuration for this container">
-          -->
-          <div class="row-fluid bottom-margin">
-        <span ng-show="noCredentials" class="alert">
-          No credentials set for endpoint!  Please set your username and password in the <a
-            href="#/preferences">Preferences</a> page
-        </span>
-            <button type="submit" ng-disabled="!fileSelection().length" class="btn btn-primary pull-right"
-                    ng-click="sendSelectedFiles()">
-              <ng-pluralize count="fileSelection().length"
-                            when="{'0': 'No files selected', '1': 'Send the file','other': 'Send {} files'}">
-              </ng-pluralize>
-            </button>
-          </div>
-
-          <p>Choose which files to send from the profile configuration:</p>
-
-          <div class="control-group inline-block">
-            <input class="search-query" type="text" ng-model="searchText" placeholder="Filter..." autofocus>
-          </div>
-
-          <ul>
-            <li ng-repeat="fileName in profileFileNames | filter:searchText">
-              <input type="checkbox" ng-model="selectedFiles[fileName]"> {{fileName}}
-            </li>
-          </ul>
-        </div>
-      </div>
-
-    </div>
-
-  </div>
-</div>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html
deleted file mode 100644
index 0144e50..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!--
-  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.
-  Architecture
--->
-<div ng-controller="ARTEMIS.SessionsController">
-
-    <div class="row-fluid">
-        <div class="span24">
-            <div class="control-group inline-block">
-                <form class="form-inline no-bottom-margin">
-                    &nbsp;<span class="label label-default">Filter</span>
-                    &nbsp;&nbsp;
-                    <select ng-model="filter.values.field" id="filter.values.field">
-                        <option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <select ng-model="filter.values.operation" id="filter.values.operation">
-                        <option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
-                        </option>
-                    </select>
-                    <input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
-                    <button class="btn" ng-click="refresh()"
-                            title="Filter">
-                        <i class="icon-search">&nbsp;&nbsp;</i>
-                    </button>
-                    &nbsp;&nbsp;
-                    <button class="btn pull-right" ng-click="reset()"
-                            title="Reset">
-                        <i class="icon-refresh">&nbsp;&nbsp;Reset</i>
-                    </button>
-                </form>
-            </div>
-            <div class="pull-right">
-                <form class="form-inline">
-                    <button class="btn-danger" ng-show="showClose"
-                            ng-click="deleteDialog = true"
-                            title="Close the selected Session">
-                        <i class="icon-remove"></i> Close
-                    </button>
-                    &nbsp;&nbsp;&nbsp;
-                </form>
-            </div>
-        </div>
-    </div>
-    <div hawtio-confirm-dialog="deleteDialog"
-          ok-button-text="Close"
-          on-ok="closeSession()">
-       <div class="dialog-body">
-         <p>You are about to close the selected session: {{gridOptions.selectedItems[0].id}}
-         </p>
-         <p>Are you sure you want to continue.</p>
-       </div>
-    </div>
-    <div class="row-fluid">
-        <div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns ng-click="selectGridRow()"></div>
-    </div>
-
-</div>
-
-
-
diff --git a/artemis-hawtio/artemis-console/src/main/webapp/app/core/html/help.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/tree/content.html
similarity index 62%
rename from artemis-hawtio/artemis-console/src/main/webapp/app/core/html/help.html
rename to artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/tree/content.html
index 55ffad8..be06f47 100644
--- a/artemis-hawtio/artemis-console/src/main/webapp/app/core/html/help.html
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/tree/content.html
@@ -15,24 +15,6 @@
   limitations under the License.
   Architecture
 -->
-<style>
-    #scroll-box {
-        background:#e6e6e6;
-        width:100%;
-        height: 100%;
-        padding:0px;
-        overflow-y: scroll;
-        overflow-x: scroll
-    }
-
-    #help-content
-    {
-        position:absolute; left: 0; right: 0; bottom: 0; top: 106px;
-    }
-</style>
-
-<div  ng-controller="Core.HelpController">
-    <div id="help-content">
-        <iframe id=scroll-box src="../user-manual/index.html" scrolling="yes" height="100%" width="100%" />
-    </div>
+<div class="tree-nav-sidebar-content">
+  <div id="artemistree" class="treeview-pf-hover treeview-pf-select"></div>
 </div>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/tree/header.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/tree/header.html
new file mode 100644
index 0000000..6a9ecf6
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/tree/header.html
@@ -0,0 +1,41 @@
+<!--
+  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.
+  Architecture
+-->
+<div class="tree-nav-sidebar-header">
+  <form role="form" class="search-pf has-button">
+    <div class="form-group has-clear">
+      <div class="search-pf-input-group">
+        <label for="input-search" class="sr-only">Search Tree:</label>
+        <input id="input-search" type="search" class="form-control" placeholder="Search tree:"
+          ng-model="$ctrl.filter">
+        <button type="button" class="clear" aria-hidden="true"
+          ng-hide="$ctrl.filter.length === 0"
+          ng-click="$ctrl.filter = ''">
+          <span class="pficon pficon-close"></span>
+        </button>
+      </div>
+    </div>
+    <div class="form-group tree-nav-buttons">
+      <span class="badge" ng-class="{positive: $ctrl.result.length > 0}"
+        ng-show="$ctrl.filter.length > 0">
+        {{$ctrl.result.length}}
+      </span>
+      <i class="fa fa-plus-square-o" title="Expand All" ng-click="$ctrl.expandAll()"></i>
+      <i class="fa fa-minus-square-o" title="Collapse All" ng-click="$ctrl.contractAll()"></i>
+    </div>
+  </form>
+</div>
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js
deleted file mode 100644
index 5227fc4..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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 ARTEMIS
- */
-var ARTEMIS = (function(ARTEMIS) {
-
-    /**
-     * @method AddressController
-     * @param $scope
-     * @param ARTEMISService
-     *
-     * Controller for the Create interface
-     */
-    ARTEMIS.AddressController = function ($scope, workspace, ARTEMISService, jolokia, localStorage) {
-        Core.initPreferenceScope($scope, localStorage, {
-            'routingType': {
-                'value': 0,
-                'converter': parseInt,
-                'formatter': parseInt
-            }
-        });
-        var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
-        $scope.workspace = workspace;
-        $scope.message = "";
-        $scope.deleteDialog = false;
-        $scope.$watch('workspace.selection', function () {
-            workspace.moveIfViewInvalid();
-        });
-        function operationSuccess() {
-            $scope.addressName = "";
-            $scope.workspace.operationCounter += 1;
-            Core.$apply($scope);
-            Core.notification("success", $scope.message);
-            $scope.workspace.loadTree();
-        }
-        function deleteSuccess() {
-            // lets set the selection to the parent
-            workspace.removeAndSelectParentNode();
-            $scope.workspace.operationCounter += 1;
-            Core.$apply($scope);
-            Core.notification("success", $scope.message);
-            $scope.workspace.loadTree();
-        }
-        $scope.createAddress = function (name, routingType) {
-            var mbean = getBrokerMBean(jolokia);
-            if (mbean) {
-                if (routingType == 0) {
-                    $scope.message = "Created  Multicast Address " + name;
-                    ARTEMIS.log.info($scope.message);
-                    ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "MULTICAST", onSuccess(operationSuccess));
-                }
-                else if (routingType == 1) {
-                    $scope.message = "Created Anycast Address " + name;
-                    ARTEMIS.log.info($scope.message);
-                    ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "ANYCAST", onSuccess(operationSuccess));
-                }
-                else {
-                    $scope.message = "Created Anycast/Multicast Address " + name;
-                    ARTEMIS.log.info($scope.message);
-                    ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "ANYCAST,MULTICAST", onSuccess(operationSuccess));
-                }
-            }
-        };
-        $scope.deleteAddress = function () {
-            var selection = workspace.selection;
-            var entries = selection.entries;
-            var mbean = getBrokerMBean(jolokia);
-            ARTEMIS.log.info(mbean);
-            if (mbean) {
-                if (selection && jolokia && entries) {
-                    var domain = selection.domain;
-                    var name = entries["address"];
-                    name = name.unescapeHTML();
-                    if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"')
-                    {
-                        name = name.substr(1,name.length -2);
-                    }
-                    name = ARTEMISService.artemisConsole.ownUnescape(name);
-                    ARTEMIS.log.info(name);
-                    var operation;
-                    $scope.message = "Deleted address " + name;
-                    ARTEMISService.artemisConsole.deleteAddress(mbean, jolokia, name, onSuccess(deleteSuccess));
-                }
-            }
-        };
-        $scope.name = function () {
-            var selection = workspace.selection;
-            if (selection) {
-                return ARTEMISService.artemisConsole.ownUnescape(selection.title);
-            }
-            return null;
-        };
-
-        function getBrokerMBean(jolokia) {
-            var mbean = null;
-            var selection = workspace.selection;
-            var folderNames = selection.folderNames;
-            mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
-            ARTEMIS.log.info("broker=" + mbean);
-            return mbean;
-        }
-    };
-
-    return ARTEMIS;
-} (ARTEMIS || {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/addresses.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/addresses.js
deleted file mode 100644
index 66070eb..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/addresses.js
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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 ARTEMIS
- */
-var ARTEMIS = (function(ARTEMIS) {
-
-    ARTEMIS.AddressesController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisAddress) {
-
-        var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
-
-        /**
-         *  Required For Each Object Type
-         */
-
-        var objectType = "address";
-        var method = 'listAddresses(java.lang.String, int, int)';
-        var defaultAttributes = [
-            {
-                field: 'manage',
-                displayName: 'manage',
-                width: '*',
-                cellTemplate: '<div class="ngCellText"><a ng-click="navigateToAddressAtts(row)">attributes</a>&nbsp;<a ng-click="navigateToAddressOps(row)">operations</a></div>'
-            },
-            {
-                field: 'id',
-                displayName: 'ID',
-                width: '*'
-            },
-            {
-                field: 'name',
-                displayName: 'Name',
-                width: '*',
-                cellTemplate: '<div class="ngCellText" title="{{row.entity.name}}">{{row.entity.name}}</div>'
-            },
-            {
-                field: 'routingTypes',
-                displayName: 'Routing Types',
-                width: '*',
-                sortable: false
-            },
-            {
-                field: 'queueCount',
-                displayName: 'Queue Count',
-                width: '*',
-                cellTemplate: '<div class="ngCellText"><a ng-click="selectQueues(row)">{{row.entity.queueCount}}</a></div>',
-                sortable: false
-            }
-        ];
-        ARTEMIS.log.debug('sessionStorage: addressesColumnDefs =', sessionStorage.getItem('addressesColumnDefs'));
-        var attributes = defaultAttributes;
-        if (sessionStorage.getItem('addressesColumnDefs')) {
-            attributes = JSON.parse(sessionStorage.getItem('addressesColumnDefs'));
-        }
-        $scope.$on('ngGridEventColumns', function (newColumns) {
-            ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
-            var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
-                visibles[column.field] = column.visible;
-                return visibles;
-            }, {});
-            ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
-            attributes.forEach(function (attribute) {
-                attribute.visible = visibles[attribute.field];
-            });
-            sessionStorage.setItem('addressesColumnDefs', JSON.stringify(attributes));
-        });
-        $scope.filter = {
-            fieldOptions: [
-                {id: 'ID', name: 'ID'},
-                {id: 'NAME', name: 'Name'},
-                {id: 'ROUTING_TYPES', name: 'Routing Types'},
-                {id: 'QUEUE_COUNT', name: 'Queue Count'},
-            ],
-            operationOptions: [
-                {id: 'EQUALS', name: 'Equals'},
-                {id: 'CONTAINS', name: 'Contains'},
-                {id: 'GREATER_THAN', name: 'Greater Than'},
-                {id: 'LESS_THAN', name: 'Less Than'}
-            ],
-            values: {
-                field: "",
-                operation: "",
-                value: "",
-                sortOrder: "asc",
-                sortBy: "ID"
-            }
-        };
-
-        /**
-         *  Below here is utility.
-         *
-         *  TODO Refactor into new separate files
-         */
-
-
-        if (artemisAddress.address) {
-            $scope.filter.values.field = $scope.filter.fieldOptions[1].id;
-            $scope.filter.values.operation = $scope.filter.operationOptions[0].id;
-            $scope.filter.values.value = artemisAddress.address.address;
-            artemisAddress.address = null;
-        }
-
-        $scope.navigateToAddressAtts = function (row) {
-            $location.path("jmx/attributes").search({"tab": "artemis", "nid": ARTEMIS.getAddressNid(row.entity, $location)});
-        };
-        $scope.navigateToAddressOps = function (row) {
-            $location.path("jmx/operations").search({"tab": "artemis", "nid": ARTEMIS.getAddressNid(row.entity, $location)});
-        };
-        $scope.selectQueues = function (row) {
-            artemisAddress.address = row.entity;
-            $location.path("artemis/queues");
-        };
-        $scope.workspace = workspace;
-        $scope.objects = [];
-        $scope.totalServerItems = 0;
-        $scope.pagingOptions = {
-            pageSizes: [50, 100, 200],
-            pageSize: 100,
-            currentPage: 1
-        };
-        $scope.sortOptions = {
-            fields: ["id"],
-            columns: ["id"],
-            directions: ["asc"]
-        };
-        var refreshed = false;
-
-        $scope.gridOptions = {
-            selectedItems: [],
-            data: 'objects',
-            showFooter: true,
-            showFilter: true,
-            showColumnMenu: true,
-            enableCellSelection: false,
-            enableHighlighting: true,
-            enableColumnResize: true,
-            enableColumnReordering: true,
-            selectWithCheckboxOnly: false,
-            showSelectionCheckbox: false,
-            multiSelect: false,
-            displaySelectionCheckbox: false,
-            pagingOptions: $scope.pagingOptions,
-            enablePaging: true,
-            totalServerItems: 'totalServerItems',
-            maintainColumnRatios: false,
-            columnDefs: attributes,
-            enableFiltering: true,
-            useExternalFiltering: true,
-            sortInfo: $scope.sortOptions,
-            useExternalSorting: true,
-        };
-        $scope.refresh = function () {
-            refreshed = true;
-            $scope.loadTable();
-        };
-        $scope.reset = function () {
-            $scope.filter.values.field = "";
-            $scope.filter.values.operation = "";
-            $scope.filter.values.value = "";
-            $scope.loadTable();
-        };
-        $scope.loadTable = function () {
-            $scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
-            $scope.filter.values.sortBy = $scope.sortOptions.directions[0];
-            $scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
-            var mbean = getBrokerMBean(jolokia);
-            if (mbean.includes("undefined")) {
-                onBadMBean();
-            } else if (mbean) {
-                var filter = JSON.stringify($scope.filter.values);
-                console.log("Filter string: " + filter);
-                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
-            }
-        };
-        function onError() {
-            Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
-        }
-        function onBadMBean() {
-            Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
-        }
-        function populateTable(response) {
-            var data = JSON.parse(response.value);
-            $scope.objects = [];
-            angular.forEach(data["data"], function (value, idx) {
-                $scope.objects.push(value);
-            });
-            $scope.totalServerItems = data["count"];
-            if (refreshed == true) {
-                $scope.gridOptions.pagingOptions.currentPage = 1;
-                refreshed = false;
-            }
-            Core.$apply($scope);
-        }
-        $scope.$watch('sortOptions', function (newVal, oldVal) {
-            if (newVal !== oldVal) {
-                $scope.loadTable();
-            }
-        }, true);
-        $scope.$watch('pagingOptions', function (newVal, oldVal) {
-            if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
-                $scope.loadTable();
-            }
-            if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
-                $scope.pagingOptions.currentPage = 1;
-                $scope.loadTable();
-            }
-        }, true);
-
-        function getBrokerMBean(jolokia) {
-            var mbean = null;
-            var selection = workspace.selection;
-            var folderNames = selection.folderNames;
-            mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
-            ARTEMIS.log.info("broker=" + mbean);
-            return mbean;
-        };
-        $scope.refresh();
-    };
-    return ARTEMIS;
-} (ARTEMIS || {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js
index 354f093..488bbed 100644
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js
@@ -14,136 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-var ARTEMIS;
-(function (ARTEMIS) {
-    ARTEMIS.log = Logger.get("ARTEMIS");
-    ARTEMIS.jmxDomain = 'org.apache.ARTEMIS';
-    function getSelectionQueuesFolder(workspace) {
-        function findQueuesFolder(node) {
-            if (node) {
-                if (node.title === "Queues" || node.title === "Queue") {
-                    return node;
-                }
-                var parent = node.parent;
-                if (parent) {
-                    return findQueuesFolder(parent);
-                }
-            }
-            return null;
-        }
-        var selection = workspace.selection;
-        if (selection) {
-            return findQueuesFolder(selection);
-        }
-        return null;
-    }
-    ARTEMIS.getSelectionQueuesFolder = getSelectionQueuesFolder;
-    function getSelectionTopicsFolder(workspace) {
-        function findTopicsFolder(node) {
-            var answer = null;
-            if (node) {
-                if (node.title === "Topics" || node.title === "Topic") {
-                    answer = node;
-                }
-                if (answer === null) {
-                    angular.forEach(node.children, function (child) {
-                        if (child.title === "Topics" || child.title === "Topic") {
-                            answer = child;
-                        }
-                    });
-                }
-            }
-            return answer;
-        }
-        var selection = workspace.selection;
-        if (selection) {
-            return findTopicsFolder(selection);
-        }
-        return null;
-    }
-    ARTEMIS.getSelectionTopicsFolder = getSelectionTopicsFolder;
-    /**
-     * Sets $scope.row to currently selected JMS message.
-     * Used in:
-     *  - ARTEMIS/js/browse.ts
-     *  - camel/js/browseEndpoint.ts
-     *
-     * TODO: remove $scope argument and operate directly on other variables. but it's too much side effects here...
-     *
-     * @param message
-     * @param key unique key inside message that distinguishes between values
-     * @param $scope
-     */
-    function selectCurrentMessage(message, key, $scope) {
-        // clicking on message's link would interfere with messages selected with checkboxes
-        $scope.gridOptions.selectAll(false);
-        var idx = Core.pathGet(message, ["rowIndex"]);
-        var jmsMessageID = Core.pathGet(message, ["entity", key]);
-        $scope.rowIndex = idx;
-        var selected = $scope.gridOptions.selectedItems;
-        selected.splice(0, selected.length);
-        if (idx >= 0 && idx < $scope.messages.length) {
-            $scope.row = $scope.messages.find(function (msg) { return msg[key] === jmsMessageID; });
-            if ($scope.row) {
-                selected.push($scope.row);
-            }
-        }
-        else {
-            $scope.row = null;
-        }
+var Artemis;
+(function (Artemis) {
+    function artemisJmxDomain() {
+        return localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
     }
-    ARTEMIS.selectCurrentMessage = selectCurrentMessage;
-    /**
-     * - Adds functions needed for message browsing with details
-     * - Adds a watch to deselect all rows after closing the slideout with message details
-     * TODO: export these functions too?
-     *
-     * @param $scope
-     */
-    function decorate($scope) {
-        $scope.selectRowIndex = function (idx) {
-            $scope.rowIndex = idx;
-            var selected = $scope.gridOptions.selectedItems;
-            selected.splice(0, selected.length);
-            if (idx >= 0 && idx < $scope.messages.length) {
-                $scope.row = $scope.messages[idx];
-                if ($scope.row) {
-                    selected.push($scope.row);
-                }
-            }
-            else {
-                $scope.row = null;
-            }
-        };
-        $scope.$watch("showMessageDetails", function () {
-            if (!$scope.showMessageDetails) {
-                $scope.row = null;
-                $scope.gridOptions.selectedItems.splice(0, $scope.gridOptions.selectedItems.length);
-            }
-        });
-    }
-    ARTEMIS.decorate = decorate;
+    Artemis.artemisJmxDomain = artemisJmxDomain;;
 
-    function getAddressNid(address, $location) {
-       var rootNID = getRootNid($location);
-       var targetNID = rootNID + "-addresses-\"" + address.name + "\"";
-       ARTEMIS.log.info("targetNID=" + targetNID);
-       return targetNID;
-    }
-    ARTEMIS.getAddressNid = getAddressNid;
+    function ownUnescape(name) {
+        //simple return unescape(name); does not work for this :(
+        return name.replace(/\\\\/g, "\\").replace(/\\\*/g, "*").replace(/\\\?/g, "?");
+    };
+    Artemis.ownUnescape = ownUnescape;
 
-    function getQueueNid(queue, $location) {
-       var rootNID = getRootNid($location);
-       var targetNID = rootNID + "-addresses-\"" + queue.address + "\"-queues-\"" + queue.routingType.toLowerCase() + "\"-\"" + queue.name + "\"";
-         return targetNID;
+    function getBrokerMBean(workspace, jolokia) {
+        var mbean = null;
+        var selection = workspace.selection;
+        var folderNames = selection.folderNames;
+        mbean = "" + folderNames[0] + ":broker=\"" + folderNames[1] + "\"";
+        return mbean;
     }
-    ARTEMIS.getQueueNid = getQueueNid;
+    Artemis.getBrokerMBean = getBrokerMBean;
 
-    function getRootNid($location) {
-       var currentNid = $location.search()['nid'];
-       var firstQoute = currentNid.indexOf('"');
-       var secondQuote = currentNid.indexOf('"', firstQoute + 1);
-       var rootNID = currentNid.substring(0, secondQuote + 1);
-    return rootNID;
-}
-})(ARTEMIS || (ARTEMIS = {}));
\ No newline at end of file
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js
index 1dcff17..1cec98f 100644
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js
@@ -15,355 +15,67 @@
  * limitations under the License.
  */
 /**
- * @module ARTEMIS
- * @main ARTEMIS
- *
- * The main entrypoint for the ARTEMIS module
- *
+ * The main entry point for the Simple module
  */
-var ARTEMIS = (function(ARTEMIS) {
+var Artemis = (function (Artemis) {
 
-   /**
-    * @property pluginName
-    * @type {string}
-    *
+    /**
     * The name of this plugin
     */
-   ARTEMIS.pluginName = "ARTEMIS";
+    Artemis.pluginName = 'artemis-plugin';
 
-   /**
-    * @property log
-    * @type {Logging.Logger}
-    *
+    /**
     * This plugin's logger instance
     */
-   ARTEMIS.log = Logger.get(ARTEMIS.pluginName);
-
-   /**
-    * @property templatePath
-    * @type {string}
-    *
-    * The top level path to this plugin's partials
-    */
-   ARTEMIS.templatePath = "../artemis-plugin/plugin/html/";
-
-   /**
-    * @property jmxDomain
-    * @type {string}
-    *
-    * The JMX domain this plugin mostly works with
-    */
-   ARTEMIS.jmxDomain = "hawtio"
-
-   /**
-    * @property mbeanType
-    * @type {string}
-    *
-    * The mbean type this plugin will work with
-    */
-   ARTEMIS.mbeanType = "ARTEMISHandler";
-
-   /**
-    * @property mbean
-    * @type {string}
-    *
-    * The mbean's full object name
-    */
-   ARTEMIS.mbean = ARTEMIS.jmxDomain + ":type=" + ARTEMIS.mbeanType;
-
-   /**
-    * @property SETTINGS_KEY
-    * @type {string}
-    *
-    * The key used to fetch our settings from local storage
-    */
-   ARTEMIS.SETTINGS_KEY = 'ARTEMISSettings';
+    Artemis.log = Logger.get('artemis-plugin');
 
-   /**
-    * @property module
-    * @type {object}
-    *
-    * This plugin's angularjs module instance
+    /**
+    * The top level path of this plugin on the server
     */
-   ARTEMIS.module = angular.module(ARTEMIS.pluginName, ['bootstrap', 'ngResource', 'ui.bootstrap.dialog', 'hawtioCore', 'camel', 'hawtio-ui']);
-
-   // set up the routing for this plugin, these are referenced by the subleveltabs added below
-   ARTEMIS.module.config(function($routeProvider) {
-      $routeProvider
-         .when('/artemis/createAddress', {
-            templateUrl: ARTEMIS.templatePath + 'createAddress.html'
-         })
-         .when('/artemis/deleteAddress', {
-           templateUrl: ARTEMIS.templatePath + 'deleteAddress.html'
-         })
-         .when('/artemis/deleteQueue', {
-            templateUrl: ARTEMIS.templatePath + 'deleteQueue.html'
-         })
-         .when('/artemis/createQueue', {
-            templateUrl: ARTEMIS.templatePath + 'createQueue.html'
-         })
-         .when('/artemis/browseQueue', {
-            templateUrl: ARTEMIS.templatePath + 'browseQueue.html'
-         })
-         .when('/jmx/browseQueue', {
-            templateUrl: ARTEMIS.templatePath + 'browseQueue.html'
-         })
-         .when('/artemis/diagram', {
-            templateUrl: ARTEMIS.templatePath + 'brokerDiagram.html'
-         })
-         .when('/jmx/diagram', {
-            templateUrl: ARTEMIS.templatePath + 'brokerDiagram.html'
-         })
-         .when('/artemis/sendMessage', {
-            templateUrl: ARTEMIS.templatePath + 'sendMessage.html'
-         })
-         .when('/jmx/sendMessage', {
-            templateUrl: ARTEMIS.templatePath + 'sendMessage.html'
-         })
-         .when('/artemis/connections', {
-            templateUrl: ARTEMIS.templatePath + 'connections.html'
-         })
-         .when('/jmx/connections', {
-            templateUrl: ARTEMIS.templatePath + 'connections.html'
-         })
-         .when('/artemis/sessions', {
-            templateUrl: ARTEMIS.templatePath + 'sessions.html'
-         })
-         .when('/jmx/sessions', {
-            templateUrl: ARTEMIS.templatePath + 'sessions.html'
-         })
-         .when('/artemis/consumers', {
-            templateUrl: ARTEMIS.templatePath + 'consumers.html'
-         })
-         .when('/jmx/consumers', {
-            templateUrl: ARTEMIS.templatePath + 'consumers.html'
-         })
-         .when('/artemis/producers', {
-            templateUrl: ARTEMIS.templatePath + 'producers.html'
-         })
-         .when('/jmx/producers', {
-            templateUrl: ARTEMIS.templatePath + 'producers.html'
-         })
-         .when('/artemis/addresses', {
-            templateUrl: ARTEMIS.templatePath + 'addresses.html'
-         })
-         .when('/jmx/addresses', {
-            templateUrl: ARTEMIS.templatePath + 'addresses.html'
-         })
-         .when('/artemis/queues', {
-            templateUrl: ARTEMIS.templatePath + 'queues.html'
-         })
-         .when('/jmx/queues', {
-            templateUrl: ARTEMIS.templatePath + 'queues.html'
-      });
-   });
-
-   ARTEMIS.module.factory('artemisMessage', function () {
-        return { 'message': null };
-   });
-   ARTEMIS.module.factory('artemisConnection', function () {
-        return { 'connection': null };
-   });
-   ARTEMIS.module.factory('artemisSession', function () {
-        return { 'session': null };
-   });
-   ARTEMIS.module.factory('artemisConsumer', function () {
-        return { 'consumer': null };
-   });
-   ARTEMIS.module.factory('artemisProducer', function () {
-        return { 'producer': null };
-   });
-   ARTEMIS.module.factory('artemisQueue', function () {
-        return { 'queue': null };
-   });
-   ARTEMIS.module.factory('artemisAddress', function () {
-        return { 'address': null };
-   });
-
-   // one-time initialization happens in the run function
-   // of our module
-   ARTEMIS.module.run(function(workspace, viewRegistry, helpRegistry, preferencesRegistry, localStorage, jolokia, ARTEMISService, $rootScope, preLogoutTasks) {
-      // let folks know we're actually running
-      ARTEMIS.log.info("plugin running " + jolokia);
-
-      var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
-
-      ARTEMISService.initArtemis();
-
-      // tell hawtio that we have our own custom layout for
-      // our view
-      viewRegistry["artemis"] = ARTEMIS.templatePath + "artemisLayout.html";
-
-      helpRegistry.addUserDoc("artemis", "../artemis-plugin/plugin/doc/help.md", function () {
-         return workspace.treeContainsDomainAndProperties(artemisJmxDomain);
-     });
-
-      preferencesRegistry.addTab("Artemis", ARTEMIS.templatePath + "preferences.html", function () {
-         return workspace.treeContainsDomainAndProperties(artemisJmxDomain);
-      });
-
-      // Add a top level tab to hawtio's navigation bar
-      workspace.topLevelTabs.push({
-         id: "artemis",
-         content: "Artemis",
-         title: "Artemis Broker",
-         isValid: function (workspace) {
-            return workspace.treeContainsDomainAndProperties(artemisJmxDomain);
-         },
-         href: function () {
-            return "#/jmx/attributes?tab=artemis";
-         },
-         isActive: function () {
-            return workspace.isLinkActive("artemis");
-         }
-      });
-
-      subLevelTabs = workspace.subLevelTabs;
-
-      subLevelTabs.push({
-         content: '<i class="icon-plus"></i> Create',
-         title: "Create a new address",
-         isValid: function (workspace) {
-            return isBroker(workspace, artemisJmxDomain) || isAddressFolder(workspace, artemisJmxDomain);
-         },
-         href: function () {
-         return "#/artemis/createAddress";
-         }
-      });
-
-      subLevelTabs.push({
-         content: '<i class="icon-remove"></i> Delete',
-         title: "Delete an address",
-         index: 4,
-         isValid: function (workspace) {
-            return isAddress(workspace, artemisJmxDomain);
-         },
-         href: function () {
-            return "#/artemis/deleteAddress";
-         }
-      });
-
-      subLevelTabs.push({
-         content: '<i class="icon-plus"></i> Create',
-         title: "Create a new queue",
-         isValid: function (workspace) {
-            return isAddress(workspace, artemisJmxDomain)
-         },
-         href: function () {
-            return "#/artemis/createQueue"
-         }
-      });
-
-      subLevelTabs.push({
-         content: '<i class="icon-remove"></i> Delete',
-         title: "Delete or purge this queue",
-         isValid: function (workspace) {
-            return isQueue(workspace, artemisJmxDomain);
-         },
-         href: function () {
-            return "#/artemis/deleteQueue"
-         }
-      });
-
-      subLevelTabs.push({
-         content: '<i class="icon-envelope"></i> Browse',
-         title: "Browse the messages on the queue",
-         isValid: function (workspace) {
-            return isQueue(workspace, artemisJmxDomain);
-         },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/browseQueue"; else return  "#/jmx/browseQueue";}
-      });
-
-      subLevelTabs.push({
-         content: '<i class="icon-pencil"></i> Send',
-         title: "Send a message to this address",
-         isValid: function (workspace) {
-            return isAddress(workspace, artemisJmxDomain) || isQueue(workspace, artemisJmxDomain);
-         },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/sendMessage"; else return  "#/jmx/sendMessage";}
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-picture"></i> Diagram&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|',
-         title: "View a diagram of the producers, destinations and consumers",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis"))return "#/artemis/diagram"; else return  "#/jmx/diagram";}
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-th-list"></i> Queues',
-         title: "Manage Queues",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/queues"; else return  "#/jmx/queues"; }
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-book"></i> Addresses',
-         title: "Manage Addresses",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/addresses"; else return  "#/jmx/addresses"; }
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-upload-alt"></i> Producers',
-         title: "Manage Producers",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/producers"; else return  "#/jmx/producers"; }
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-download-alt"></i> Consumers',
-         title: "Manage Consumers",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/consumers"; else return  "#/jmx/consumers"; }
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-tasks"></i> Sessions',
-         title: "Manage Sessions",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/sessions"; else return  "#/jmx/sessions"; }
-      });
-
-      subLevelTabs.unshift({
-         content: '<i class="icon-signal"></i> Connections',
-         title: "Manage Connections",
-         isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
-         href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/connections"; else return  "#/jmx/connections"; }
-      });
-
-      workspace.subLevelTabs = subLevelTabs;
-
-      preLogoutTasks.addTask("clearArtemisCredentials", function () {
-          localStorage.removeItem('artemisUserName');
-          localStorage.removeItem('artemisPassword');
-      });
-});
-
-
-   function isBroker(workspace, domain) {
-      return workspace.hasDomainAndProperties(domain, {'broker': 'Broker'}, 3);
-   }
-
-   function isAddressFolder(workspace, domain) {
-      return workspace.selectionHasDomainAndLastFolderName(domain, 'addresses');
-   }
-
-   function isAddress(workspace, domain) {
-      return workspace.hasDomainAndProperties(domain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(domain, {'subcomponent': 'queues'}) && !workspace.hasDomainAndProperties(domain, {'subcomponent': 'diverts'});
-   }
-
-   function isDivert(workspace, domain) {
-      return workspace.hasDomainAndProperties(domain, {'subcomponent': 'diverts'});
-   }
-
-   function isQueue(workspace, domain) {
-      return workspace.hasDomainAndProperties(domain, {'subcomponent': 'queues'});
-   }
-
-   return ARTEMIS;
-}(ARTEMIS || {}));
-
-// Very important!  Add our module to hawtioPluginLoader so it
-// bootstraps our module
-hawtioPluginLoader.addModule(ARTEMIS.pluginName);
\ No newline at end of file
+    Artemis.contextPath = "/artemis-plugin/";
+
+    Artemis.log.info("loading artemis plugin")
+    Artemis._module = angular.module(Artemis.pluginName, [
+        'angularResizable'
+    ])
+    .component('artemis', {
+        template:
+           `<div class="tree-nav-layout">
+                <div class="sidebar-pf sidebar-pf-left" resizable r-directions="['right']">
+                  <artemis-tree-header></artemis-tree-header>
+                  <artemis-tree></artemis-tree>
+                </div>
+                <div class="tree-nav-main">
+                  <artemis-navigation></artemis-navigation>
+                  <div class="contents" ng-view></div>
+                </div>
+           </div>
+          `
+          })
+    .run(configurePlugin);
+
+  function configurePlugin(mainNavService, workspace, helpRegistry, preferencesRegistry, localStorage, preLogoutTasks, documentBase, $templateCache) {
+        var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
+        mainNavService.addItem({
+            title: 'Artemis',
+            basePath: '/artemis',
+            template: '<artemis></artemis>',
+            isValid: function () { return workspace.treeContainsDomainAndProperties(artemisJmxDomain); }
+        });
+
+        // clean up local storage upon logout
+        preLogoutTasks.addTask('CleanupArtemisCredentials', function () {
+            Artemis.log.debug("Clean up Artemis credentials in local storage");
+            localStorage.removeItem('artemisUserName');
+            localStorage.removeItem('artemisPassword');
+        });
+    }
+    configurePlugin.$inject = ['mainNavService', 'workspace', 'helpRegistry', 'preferencesRegistry', 'localStorage', 'preLogoutTasks', 'documentBase', '$templateCache'];
+
+  return Artemis;
+
+})(Artemis || {});
+
+// tell the Hawtio plugin loader about our plugin so it can be
+// bootstrapped with the rest of AngularJS
+hawtioPluginLoader.addModule(Artemis.pluginName);
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js
deleted file mode 100644
index 3d7aa55..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 ARTEMIS
- */
-var ARTEMIS = (function(ARTEMIS) {
-
-  ARTEMIS.SERVER = 'Server Messages';
-
-
-  // The ARTEMIS service handles the connection to
-  // the Artemis Jolokia server in the background
-  ARTEMIS.module.factory("ARTEMISService", function(jolokia, $rootScope) {
-    var self = {
-      artemisConsole: undefined,
-
-      getVersion: function(jolokia) {
-        ARTEMIS.log.info("Connecting to ARTEMIS service: " + self.artemisConsole.getServerAttributes(jolokia));
-      } ,
-      initArtemis: function(broker) {
-        ARTEMIS.log.info("*************creating Artemis Console************");
-        self.artemisConsole = new ArtemisConsole();
-      }
-    };
-
-    return self;
-  });
-
-  return ARTEMIS;
-}(ARTEMIS || {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js
deleted file mode 100644
index 539b90e..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * 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 ARTEMIS
- */
-var ARTEMIS = (function(ARTEMIS) {
-   ARTEMIS.BrokerDiagramController = function ($scope, $compile, $location, localStorage, ARTEMISService, jolokia, workspace, $routeParams) {
-
-      Fabric.initScope($scope, $location, jolokia, workspace);
-      var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
-
-      $scope.selectedNode = null;
-      var defaultFlags = {
-         panel: true,
-         popup: false,
-         label: true,
-         group: false,
-         profile: false,
-         slave: false,
-         broker: true,
-         network: true,
-         container: false,
-         address: true,
-         queue: true,
-         consumer: true,
-         producer: true
-      };
-      $scope.viewSettings = {};
-      $scope.shapeSize = {
-         broker: 20,
-         queue: 14,
-         address: 14
-      };
-      var redrawGraph = Core.throttled(doRedrawGraph, 1000);
-      var graphBuilder = new ForceGraph.GraphBuilder();
-      Core.bindModelToSearchParam($scope, $location, "searchFilter", "q", "");
-      angular.forEach(defaultFlags, function (defaultValue, key) {
-         var modelName = "viewSettings." + key;
-         // bind model values to search params...
-         function currentValue() {
-            var answer = $location.search()[paramName] || defaultValue;
-            return answer === "false" ? false : answer;
-         }
-
-         var paramName = key;
-         var value = currentValue();
-         Core.pathSet($scope, modelName, value);
-         $scope.$watch(modelName, function () {
-            var current = Core.pathGet($scope, modelName);
-            var old = currentValue();
-            if (current !== old) {
-               var defaultValue = defaultFlags[key];
-               if (current !== defaultValue) {
-                  if (!current) {
-                     current = "false";
-                  }
-                  $location.search(paramName, current);
-               }
-               else {
-                  $location.search(paramName, null);
-               }
-            }
-            redrawGraph();
-         });
-      });
-      $scope.connectToBroker = function () {
-         var selectedNode = $scope.selectedNode;
-         if (selectedNode) {
-            var container = selectedNode["brokerContainer"] || selectedNode;
-            connectToBroker(container, selectedNode["brokerName"]);
-         }
-      };
-      function connectToBroker(container, brokerName, postfix) {
-         if (postfix === void 0) {
-            postfix = null;
-         }
-
-         var view = "/jmx/attributes?tab=artemis";
-         if (!postfix) {
-            if (brokerName) {
-               // lets default to the broker view
-               postfix = "nid=root-" + artemisJmxDomain + "-Broker-" + brokerName;
-            }
-         }
-         if (postfix) {
-            view += "&" + postfix;
-         }
-         var path = Core.url("/#" + view);
-         window.open(path, '_destination');
-         window.focus();
-      }
-
-      $scope.$on('$destroy', function (event) {
-         stopOldJolokia();
-      });
-      function stopOldJolokia() {
-         var oldJolokia = $scope.selectedNodeJolokia;
-         if (oldJolokia && oldJolokia !== jolokia) {
-            oldJolokia.stop();
-         }
-      }
-
-      $scope.$watch("selectedNode", function (newValue, oldValue) {
-         // lets cancel any previously registered thingy
-         if ($scope.unregisterFn) {
-            $scope.unregisterFn();
-            $scope.unregisterFn = null;
-         }
-         var node = $scope.selectedNode;
-         if (node) {
-            var mbean = node.objectName;
-            var brokerContainer = node.brokerContainer || {};
-            var nodeJolokia = node.jolokia || brokerContainer.jolokia || jolokia;
-            if (nodeJolokia !== $scope.selectedNodeJolokia) {
-               stopOldJolokia();
-               $scope.selectedNodeJolokia = nodeJolokia;
-               if (nodeJolokia !== jolokia) {
-                  var rate = Core.parseIntValue(localStorage['updateRate'] || "2000", "update rate");
-                  if (rate) {
-                     nodeJolokia.start(rate);
-                  }
-               }
-            }
-            var dummyResponse = {value: node.panelProperties || {}};
-            if (mbean && nodeJolokia) {
-               ARTEMIS.log.debug("reading ", mbean, " on remote container");
-               $scope.unregisterFn = Core.register(nodeJolokia, $scope, {
-                  type: 'read',
-                  mbean: mbean
-               }, onSuccess(renderNodeAttributes, {
-                  error: function (response) {
-                     // probably we've got a wrong mbean name?
-                     // so lets render at least
-                     renderNodeAttributes(dummyResponse);
-                     Core.defaultJolokiaErrorHandler(response);
-                  }
-               }));
-            }
-            else {
-               ARTEMIS.log.debug("no mbean or jolokia available, using dummy response");
-               renderNodeAttributes(dummyResponse);
-            }
-         }
-      });
-      function getDestinationTypeName(attributes) {
-         var prefix = attributes["DestinationTemporary"] ? "Temporary " : "";
-         return prefix + (attributes["DestinationTopic"] ? "Topic" : "Queue");
-      }
-
-      var ignoreNodeAttributes = ["Broker", "BrokerId", "BrokerName", "Connection", "DestinationName", "DestinationQueue", "DestinationTemporary", "DestinationTopic",];
-      var ignoreNodeAttributesByType = {
-         producer: ["Producer", "ProducerId"],
-         queue: ["Name", "MessageGroups", "MessageGroupType", "Subscriptions"],
-         topic: ["Name", "Subscriptions"],
-         broker: ["DataDirectory", "DurableTopicSubscriptions", "DynamicDestinationProducers", "InactiveDurableToppicSubscribers"]
-      };
-      var brokerShowProperties = ["Version", "Started"];
-      var onlyShowAttributesByType = {
-         broker: brokerShowProperties,
-         brokerSlave: brokerShowProperties
-      };
-
-      function renderNodeAttributes(response) {
-         var properties = [];
-         if (response) {
-            var value = response.value || {};
-            $scope.selectedNodeAttributes = value;
-            var selectedNode = $scope.selectedNode || {};
-            var brokerContainer = selectedNode['brokerContainer'] || {};
-            var nodeType = selectedNode["type"];
-            var brokerName = selectedNode["brokerName"];
-            var containerId = selectedNode["container"] || brokerContainer["container"];
-            var group = selectedNode["group"] || brokerContainer["group"];
-            var jolokiaUrl = selectedNode["jolokiaUrl"] || brokerContainer["jolokiaUrl"];
-            var profile = selectedNode["profile"] || brokerContainer["profile"];
-            var version = selectedNode["version"] || brokerContainer["version"];
-            var isBroker = nodeType && nodeType.startsWith("broker");
-            var ignoreKeys = ignoreNodeAttributes.concat(ignoreNodeAttributesByType[nodeType] || []);
-            var onlyShowKeys = onlyShowAttributesByType[nodeType];
-            angular.forEach(value, function (v, k) {
-               if (onlyShowKeys ? onlyShowKeys.indexOf(k) >= 0 : ignoreKeys.indexOf(k) < 0) {
-                  var formattedValue = Core.humanizeValueHtml(v);
-                  properties.push({key: Core.humanizeValue(k), value: formattedValue});
-               }
-            });
-            properties = properties.sortBy("key");
-            var brokerProperty = null;
-            if (brokerName) {
-               var brokerHtml = '<a target="broker" ng-click="connectToBroker()">' + '<img title="Apache Artemis" src="img/icons/messagebroker.svg"> ' + brokerName + '</a>';
-               if (version && profile) {
-                  var brokerLink = Fabric.brokerConfigLink(workspace, jolokia, localStorage, version, profile, brokerName);
-                  if (brokerLink) {
-                     brokerHtml += ' <a title="configuration settings" target="brokerConfig" href="' + brokerLink + '"><i class="icon-tasks"></i></a>';
-                  }
-               }
-               var html = $compile(brokerHtml)($scope);
-               brokerProperty = {key: "Broker", value: html};
-               if (!isBroker) {
-                  properties.splice(0, 0, brokerProperty);
-               }
-            }
-            if (containerId) {
-               properties.splice(0, 0, {
-                  key: "Container",
-                  value: $compile('<div fabric-container-link="' + selectedNode['container'] + '"></div>')($scope)
-               });
-            }
-            var destinationName = value["DestinationName"] || selectedNode["destinationName"];
-            if (destinationName && (nodeType !== "queue" && nodeType !== "topic")) {
-               var destinationTypeName = getDestinationTypeName(value);
-               var html = createDestinationLink(destinationName, destinationTypeName);
-               properties.splice(0, 0, {key: destinationTypeName, value: html});
-            }
-            var typeLabel = selectedNode["typeLabel"];
-            var name = selectedNode["name"] || selectedNode["id"] || selectedNode['objectName'];
-            if (typeLabel) {
-               var html = name;
-               if (nodeType === "queue" || nodeType === "topic") {
-                  html = createDestinationLink(name, nodeType);
-               }
-               var typeProperty = {key: typeLabel, value: html};
-               if (isBroker && brokerProperty) {
-                  typeProperty = brokerProperty;
-               }
-               properties.splice(0, 0, typeProperty);
-            }
-         }
-         $scope.selectedNodeProperties = properties;
-         Core.$apply($scope);
-      }
-
-      function createDestinationLink(destinationName, destinationType) {
-         return Core.escapeHtml(destinationName);
-      }
-
-      $scope.$watch("searchFilter", function (newValue, oldValue) {
-         redrawGraph();
-      });
-      // lets just use the current stuff from the workspace
-      $scope.$watch('workspace.tree', function () {
-         redrawGraph();
-      });
-      $scope.$on('jmxTreeUpdated', function () {
-         redrawGraph();
-      });
-
-      function onBrokerData(response) {
-         if (response) {
-            var responseJson = angular.toJson(response.value);
-            if ($scope.responseJson === responseJson) {
-               return;
-            }
-            $scope.responseJson = responseJson;
-            $scope.brokers = response.value;
-            doRedrawGraph();
-         }
-      }
-
-      function redrawLocalBroker() {
-         var container = {
-            jolokia: jolokia
-         };
-         var containerId = "local";
-         $scope.activeContainers = {
-            containerId: container
-         };
-         var brokers = [];
-         jolokia.search(artemisJmxDomain + ":broker=*", onSuccess(function (response) {
-            angular.forEach(response, function (objectName) {
-               var atts = ARTEMISService.artemisConsole.getServerAttributes(jolokia, objectName);
-               var val = atts.value;
-               var details = Core.parseMBean(objectName);
-               if (details) {
-                  var properties = details['attributes'];
-                  ARTEMIS.log.info("Got broker: " + objectName + " on container: " + containerId + " properties: " + angular.toJson(properties, true));
-                  if (properties) {
-                     var brokerId = properties["broker"] || "unknown";
-                     var brokerName = artemisJmxDomain + ":broker=" + brokerId;
-                     var backupRes = ARTEMISService.artemisConsole.isBackup(jolokia, brokerName);
-                     var isBackup = backupRes.value;
-                     var nodeId = val["NodeID"];
-                     var theBroker = {
-                        brokerId: brokerId,
-                        nodeId: nodeId
-                     };
-                     brokers.push(theBroker);
-                     if ($scope.viewSettings.broker) {
-                        var broker = getOrAddBroker(!isBackup, brokerId, nodeId, containerId, container, properties);
-                     }
-                  }
-               }
-            });
-
-            redrawActiveContainers(brokers);
-         }));
-      }
-
-      function redrawActiveContainers(brokers) {
-         // TODO delete any nodes from dead containers in containersToDelete
-         angular.forEach($scope.activeContainers, function (container, id) {
-            var containerJolokia = container.jolokia;
-            if (containerJolokia) {
-               onContainerJolokia(containerJolokia, container, id, brokers);
-            }
-            else {
-               Fabric.containerJolokia(jolokia, id, function (containerJolokia) {
-                  return onContainerJolokia(containerJolokia, container, id, brokers);
-               });
-            }
-         });
-         $scope.graph = graphBuilder.buildGraph();
-         Core.$apply($scope);
-      }
-
-      function doRedrawGraph() {
-         graphBuilder = new ForceGraph.GraphBuilder();
-         redrawLocalBroker();
-      }
-
-      function brokerNameMarkup(brokerName) {
-         return brokerName ? "<p></p>broker: " + brokerName + "</p>" : "";
-      }
-
-      function onContainerJolokia(containerJolokia, container, id, brokers) {
-         function createQueues(brokers) {
-            if ($scope.viewSettings.queue) {
-               containerJolokia.search(artemisJmxDomain + ":*,subcomponent=queues", onSuccess(function (response) {
-                  angular.forEach(response, function (objectName) {
-                     var details = Core.parseMBean(objectName);
-                     if (details) {
-                        var properties = details['attributes'];
-                        if (properties) {
-                           configureDestinationProperties(properties);
-                           var brokerName = properties.broker;
-                           var addressName = properties.address;
-                           var typeName = "queue";
-                           var queueName = properties.queue;
-                           var routingType = properties["routing-type"];
-                           var destination = getOrAddQueue(properties, typeName, routingType, queueName, addressName, brokerName);
-                        }
-                     }
-                  });
-                  graphModelUpdated();
-                  createConsumersAndNetwork(brokers);
-               }));
-            } else {
-               createConsumersAndNetwork(brokers);
-            }
-         }
-
-         function createAddresses(brokers) {
-            if ($scope.viewSettings.address) {
-               containerJolokia.search(artemisJmxDomain + ":*,component=addresses", onSuccess(function (response) {
-                  angular.forEach(response, function (objectName) {
-                     var details = Core.parseMBean(objectName);
-                     if (details) {
-                        var properties = details['attributes'];
-                        if (properties) {
-                           var brokerName = properties.broker;
-                           var typeName = "address";
-                           var addressName = properties.address;
-                           var destination = getOrAddAddress(properties, typeName, addressName, brokerName);
-                        }
-                     }
-                  });
-                  createQueues(brokers);
-                  graphModelUpdated();
-               }));
-            } else {
-               createQueues(brokers);
-            }
-         }
-
-         function createConsumersAndNetwork(brokers) {
-            angular.forEach(brokers, function (broker) {
-               mBean = artemisJmxDomain + ":broker=" + broker.brokerId;
-               // find consumers
-               if ($scope.viewSettings.consumer) {
-                  ARTEMISService.artemisConsole.getConsumers(mBean, containerJolokia, onSuccess(function (properties) {
-                     consumers = properties.value;
-                     angular.forEach(angular.fromJson(consumers), function (consumer) {
-                        if (consumer) {
-
-                           configureDestinationProperties(consumer);
-                           var consumerId = consumer.sessionID + "-" + consumer.consumerID;
-                           if (consumerId) {
-                              var queueName = consumer.queueName;
-                              var consumerNode = getOrAddNode("consumer", consumerId, consumer, function () {
-                                 return {
-                                    typeLabel: "Consumer",
-                                    brokerContainer: container,
-                                    jolokia: containerJolokia,
-                                    popup: {
-                                       title: "Consumer: " + Core.escapeHtml(consumerId),
-                                       content: "<p>client: " + Core.escapeHtml(consumer.connectionID || "") + "</p> " + brokerNameMarkup(broker.brokerId)
-                                    }
-                                 };
-                              });
-                              addLinkIds("queue:\"" + queueName + "\"", consumerNode["id"], "consumer");
-                           }
-                        }
-                     });
-                     graphModelUpdated();
-                  }));
-               }
-
-
-               // find networks of brokers
-               if ($scope.viewSettings.network && $scope.viewSettings.broker) {
-
-                  ARTEMISService.artemisConsole.getRemoteBrokers(mBean, containerJolokia, onSuccess(function (properties) {
-                     remoteBrokers = properties.value;
-
-                     var remoteBrokersObj = angular.fromJson(remoteBrokers);
-
-                     var newBackReq = ARTEMISService.artemisConsole.isBackup(jolokia, mBean);
-                     var newBackup = newBackReq.value;
-
-                     angular.forEach(remoteBrokersObj, function (remoteBroker) {
-                        if (broker.nodeId != remoteBroker.nodeID) {
-                           if (remoteBroker.live) {
-                              getOrAddBroker(true, "\"" + remoteBroker.live + "\"", remoteBroker.nodeID, "remote", null, properties);
-                           }
-                           if (remoteBroker.backup) {
-                              getOrAddBroker(false, "\"" + remoteBroker.backup + "\"", remoteBroker.nodeID, "remote", null, properties);
-                           }
-                        } else {
-                           if (!newBackup) {
-                              getOrAddBroker(false, "\"" + remoteBroker.backup + "\"", remoteBroker.nodeID, "remote", null, properties);
-                           } else {
-                              getOrAddBroker(true, "\"" + remoteBroker.live + "\"", remoteBroker.nodeID, "remote", null, properties);
-                           }
-                        }
-                     });
-
-                     var processedLiveBrokers = [];
-                     angular.forEach(remoteBrokersObj, function (remoteBroker) {
-                        if (remoteBroker) {
-                           if (remoteBroker.live) {
-                              angular.forEach(processedLiveBrokers, function(livebroker) {
-                                 //because the local broker has a different id format we need to identify it
-                                 if (broker.nodeId == livebroker.nodeID) {
-                                    if (!newBackup) {
-                                       addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.live + "\"", "network");
-                                    } else {
-                                       //I am backup
-                                       addLinkIds("broker:" + "\"" + livebroker.live + "\"", "broker:" + "\"" + remoteBroker.live + "\"", "network");
-                                    }
-                                 } else if (broker.nodeId == remoteBroker.nodeID) {
-                                    if (!newBackup) {
-                                       addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + livebroker.live + "\"", "network");
-                                    } else {
-                                       //I am backup
-                                       addLinkIds("broker:" + "\"" + livebroker.live + "\"", "broker:" + "\"" + remoteBroker.live + "\"", "network");
-                                    }
-                                 } else {
-                                    addLinkIds("broker:" + "\"" + livebroker.live + "\"", "broker:" + "\"" + remoteBroker.live + "\"", "network");
-                                 }
-                              });
-                              processedLiveBrokers.push(remoteBroker);
-                           }
-
-                           //now backups
-                           if (broker.nodeId != remoteBroker.nodeID) {
-                              if (remoteBroker.backup) {
-                                 addLinkIds("broker:" + "\"" + remoteBroker.live + "\"", "broker:" + "\"" + remoteBroker.backup + "\"", "network");
-                              }
-                           }
-                           else {
-                              if (!newBackup) {
-                                 if (remoteBroker.backup) {
-                                    addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.backup + "\"", "network");
-                                 }
-                              }
-                              else {
-                                 //I am backup
-                                 addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.live + "\"", "network");
-                              }
-                           }
-                        }
-                     });
-                     graphModelUpdated();
-                  }));
-               }
-            });
-         }
-
-         if (containerJolokia) {
-            container.jolokia = containerJolokia;
-            function getOrAddQueue(properties, typeName, routingType, queueName, addressName, brokerName) {
-               var queue = getOrAddNode(typeName.toLowerCase(), queueName, properties, function () {
-                  var objectName = "";
-                  if (addressName) {
-                     objectName = artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + addressName + ",subcomponent=queues,routing-type=" + routingType + ",queue=" + queueName;
-                     
-                  }
-                  var answer = {
-                     typeLabel: typeName,
-                     brokerContainer: container,
-                     objectName: objectName,
-                     jolokia: containerJolokia,
-                     popup: {
-                        title: "queue: " + Core.escapeHtml(queueName),
-                        content: "address:" + Core.escapeHtml(addressName)
-                     }
-                  };
-                  if (!addressName) {
-                     containerJolokia.search(artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + addressName + ",subcomponent=queues,routing-type=" + routingType + ",queue=" + queueName + ",*", onSuccess(function (response) {
-                        if (response && response.length) {
-                           answer.objectName = response[0];
-                        }
-                     }));
-                  }
-                  return answer;
-               });
-               if (queue && $scope.viewSettings.broker && addressName) {
-                  addLinkIds("address:" + addressName, queue["id"], "queue");
-               }
-               return queue;
-            }
-
-            function getOrAddAddress(properties, typeName, destinationName, brokerName) {
-               var destination = getOrAddNode(typeName.toLowerCase(), destinationName, properties, function () {
-                  var objectName = "";
-                  if (brokerName) {
-                     objectName = artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + destinationName;
-                  }
-                  var answer = {
-                     typeLabel: typeName,
-                     brokerContainer: container,
-                     objectName: objectName,
-                     jolokia: containerJolokia,
-                     popup: {
-                        title: typeName + ": " + destinationName,
-                        content: brokerNameMarkup(brokerName)
-                     }
-                  };
-                  if (!brokerName) {
-                     containerJolokia.search(artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + destinationName + ",*", onSuccess(function (response) {
-                        if (response && response.length) {
-                           answer.objectName = response[0];
-                        }
-                     }));
-                  }
-                  return answer;
-               });
-               if (destination && $scope.viewSettings.broker && brokerName) {
-                  addLinkIds(brokerNodeId(brokerName), destination["id"], "address");
-               }
-               return destination;
-            }
-
-            createAddresses(brokers);
-         }
-      }
-
-      function graphModelUpdated() {
-         $scope.graph = graphBuilder.buildGraph();
-         Core.$apply($scope);
-      }
-
-      function getOrAddBroker(master, brokerId, nodeId, containerId, container, brokerStatus) {
-         var broker = null;
-         var brokerFlag = master ? $scope.viewSettings.broker : $scope.viewSettings.slave;
-         if (brokerFlag) {
-            broker = getOrAddNode("broker", brokerId, brokerStatus, function () {
-               return {
-                  type: master ? "broker" : "brokerSlave",
-                  typeLabel: master ? "Broker" : "Slave Broker",
-                  popup: {
-                     title: (master ? "Master" : "Slave") + " Broker: " + brokerId,
-                     content: "<p>Container: " + containerId + "</p> Node ID: " + nodeId
-                  }
-               };
-            });
-            if (!broker['objectName']) {
-               // lets try guess the mbean name
-               broker['objectName'] = artemisJmxDomain + ":broker=" + brokerId;
-               ARTEMIS.log.debug("Guessed broker mbean: " + broker['objectName']);
-            }
-            if (!broker['brokerContainer'] && container) {
-               broker['brokerContainer'] = container;
-            }
-            if (!broker['nodeID']) {
-               broker['nodeID'] = nodeId;
-            }
-         }
-         return broker;
-      }
-
-      function getOrAddNode(typeName, id, properties, createFn) {
-         var node = null;
-         if (id) {
-            var nodeId = typeName + ":" + id;
-            node = graphBuilder.getNode(nodeId);
-            if (!node) {
-               var nodeValues = createFn();
-               node = angular.copy(properties);
-
-               angular.forEach(nodeValues, function (value, key) {
-                  return node[key] = value;
-               });
-               node['id'] = nodeId;
-               if (!node['type']) {
-                  node['type'] = typeName;
-               }
-               if (!node['name']) {
-                  node['name'] = id;
-               }
-               if (node) {
-                  var size = $scope.shapeSize[typeName];
-                  if (size && !node['size']) {
-                     node['size'] = size;
-                  }
-                  if (!node['summary']) {
-                     node['summary'] = node['popup'] || "";
-                  }
-                  if (!$scope.viewSettings.popup) {
-                     delete node['popup'];
-                  }
-                  if (!$scope.viewSettings.label) {
-                     delete node['name'];
-                  }
-                  // lets not add nodes which are defined as being disabled
-                  var enabled = $scope.viewSettings[typeName];
-                  if (enabled || !angular.isDefined(enabled)) {
-                     graphBuilder.addNode(node);
-                  }
-                  else {
-                  }
-               }
-            }
-         }
-         return node;
-      }
-
-      function addLink(object1, object2, linkType) {
-         if (object1 && object2) {
-            addLinkIds(object1.id, object2.id, linkType);
-         }
-      }
-
-      function addLinkIds(id1, id2, linkType) {
-         if (id1 && id2) {
-            graphBuilder.addLink(id1, id2, linkType);
-         }
-      }
-
-      function brokerNodeId(brokerId) {
-         return brokerId ? "broker:" + brokerId : null;
-      }
-
-      /**
-       * Avoid the JMX type property clashing with the ForceGraph type property; used for associating css classes with nodes on the graph
-       *
-       * @param properties
-       */
-      function renameTypeProperty(properties) {
-         properties.mbeanType = properties['type'];
-         delete properties['type'];
-      }
-
-      function configureDestinationProperties(properties) {
-         renameTypeProperty(properties);
-         var destinationType = properties.destinationType || "Queue";
-         var typeName = destinationType.toLowerCase();
-         properties.isQueue = !typeName.startsWith("t");
-         properties['destType'] = typeName;
-      }
-   };
-
-   return ARTEMIS;
-} (ARTEMIS || {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js
deleted file mode 100644
index 5dd07b2..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * 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 ARTEMIS
- */
-var ARTEMIS = (function(ARTEMIS) {
-
-   ARTEMIS.BrowseQueueController = function($scope, workspace, ARTEMISService, jolokia, localStorage, artemisMessage, $location, $timeout) {
-
-      var defaultAttributes = [{
-         field: 'messageID',
-         displayName: 'Message ID',
-         cellTemplate: '<div class="ngCellText"><a ng-click="openMessageDialog(row)">{{row.entity.messageID}}</a></div>',
-         // for ng-grid
-         width: '100px'
-      }, {
-         field: 'type',
-         displayName: 'Type',
-         cellTemplate: '<div class="ngCellText" title="{{row.entity.type}}">{{formatType(row.entity.type)}}</div>',
-         width: '90px'
-      }, {
-         field: 'durable',
-         displayName: 'Durable',
-         width: '70px'
-      }, {
-         field: 'priority',
-         displayName: 'Priority',
-         width: '70px'
-      }, {
-         field: 'timestamp',
-         displayName: 'Timestamp',
-         cellTemplate: '<div class="ngCellText" title="{{row.entity.timestamp}}">{{formatTimestamp(row.entity.timestamp)}}</div>',
-         width: '160px'
-      }, {
-         field: 'expiration',
-         displayName: 'Expires',
-         cellTemplate: '<div class="ngCellText" title="{{row.entity.expiration}}">{{formatExpires(row.entity.expiration)}}</div>',
-         width: '160px'
-      }, {
-         field: 'redelivered',
-         displayName: 'Redelivered',
-         width: '100px'
-      }, {
-         field: 'largeMessage',
-         displayName: 'Large',
-         width: '50px'
-      }, {
-         field: 'persistentSize',
-         displayName: 'Persistent Size',
-         cellTemplate: '<div class="ngCellText" title="{{row.entity.persistentSize.toLocaleString()}} bytes">{{formatPersistentSize(row.entity.persistentSize)}}</div>',
-         width: '120px'
-      }, {
-         field: 'userID',
-         displayName: 'User ID',
-         width: '15%'
-      }, {
-         displayName: 'Validated User',
-         cellTemplate: '<div class="ngCellText">{{row.entity.StringProperties._AMQ_VALIDATED_USER}}</div>',
-         width: '*'
-      }];
-
-      var attributes = defaultAttributes;
-      if (sessionStorage.getItem('browseColumnDefs')) {
-         attributes = JSON.parse(sessionStorage.getItem('browseColumnDefs'));
-      }
-
-      $scope.$on('ngGridEventColumns', function(newColumns) {
-         ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
-         var visibles = newColumns.targetScope.columns.reduce(function(visibles, column) {
-            visibles[column.field] = column.visible;
-            return visibles;
-         }, {});
-         ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
-         attributes.forEach(function(attribute) {
-            attribute.visible = visibles[attribute.field];
-         });
-         sessionStorage.setItem('browseColumnDefs', JSON.stringify(attributes));
-      });
-
-      $scope.pagingOptions = {
-         pageSizes: [50, 100, 200],
-         pageSize: 100,
-         currentPage: 1
-      };
-      $scope.totalServerItems = 0;
-      $scope.searchText = '';
-      $scope.allMessages = [];
-      $scope.messages = [];
-      $scope.headers = {};
-      $scope.mode = 'text';
-      $scope.deleteDialog = false;
-      $scope.moveDialog = false;
-      $scope.gridOptions = {
-         pagingOptions: $scope.pagingOptions,
-         enablePaging: true,
-         totalServerItems: 'totalServerItems',
-         showFooter: true,
-         selectedItems: [],
-         data: 'messages',
-         displayFooter: false,
-         showFilter: false,
-         showColumnMenu: true,
-         enableColumnResize: true,
-         enableColumnReordering: true,
-         enableHighlighting: true,
-         filterOptions: {
-            filterText: '',
-            useExternalFilter: true
-         },
-         selectWithCheckboxOnly: true,
-         showSelectionCheckbox: true,
-         maintainColumnRatios: false,
-         columnDefs: attributes,
-         afterSelectionChange: afterSelectionChange
-      };
-      $scope.showMessageDetails = false;
-
-      var ignoreColumns = ["PropertiesText", "BodyPreview", "text"];
-      var flattenColumns = ["BooleanProperties", "ByteProperties", "ShortProperties", "IntProperties", "LongProperties", "FloatProperties", "DoubleProperties", "StringProperties"];
-
-      $scope.$watch('workspace.selection', function() {
-         if (workspace.moveIfViewInvalid()) {
-            return;
-         }
-         // lets defer execution as we may not have the selection just yet
-         setTimeout(loadTable, 50);
-      });
-      $scope.$watch('gridOptions.filterOptions.filterText', function(filterText) {
-         filterMessages(filterText);
-      });
-      $scope.$watch('pagingOptions', function(newVal, oldVal) {
-         if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
-            loadTable();
-         }
-         if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
-            $scope.pagingOptions.currentPage = 1;
-            loadTable();
-         }
-      }, true);
-      $scope.openMessageDialog = function(message) {
-         ARTEMIS.selectCurrentMessage(message, "messageID", $scope);
-         if ($scope.row) {
-            $scope.mode = CodeEditor.detectTextFormat($scope.row.Text);
-            $scope.showMessageDetails = true;
-         }
-      };
-      $scope.refresh = loadTable;
-      ARTEMIS.decorate($scope);
-
-      var MS_PER_SEC  = 1000;
-      var MS_PER_MIN  = 60 * MS_PER_SEC;
-      var MS_PER_HOUR = 60 * MS_PER_MIN;
-      var MS_PER_DAY  = 24 * MS_PER_HOUR;
-
-      function pad2(value) {
-         return (value < 10 ? '0' : '') + value;
-      }
-
-      $scope.formatExpires = function(timestamp) {
-         if (isNaN(timestamp)) {
-            return timestamp;
-         }
-         var expiresIn = timestamp - Date.now();
-         if (Math.abs(expiresIn) < MS_PER_DAY) {
-            var duration = expiresIn < 0 ? -expiresIn : expiresIn;
-            var hours = pad2(Math.floor((duration / MS_PER_HOUR) % 24));
-            var mins  = pad2(Math.floor((duration / MS_PER_MIN) % 60));
-            var secs  = pad2(Math.floor((duration / MS_PER_SEC) % 60));
-            if (expiresIn < 0) {
-               // "HH:mm:ss ago"
-               return hours + ":" + mins + ":" + secs + " ago";
-            }
-            // "in HH:mm:ss ago"
-            return "in " + hours + ":" + mins + ":" + secs;
-         }
-         return $scope.formatTimestamp(timestamp);
-      }
-
-      $scope.formatTimestamp = function(timestamp) {
-         if (isNaN(timestamp)) {
-            return timestamp;
-         }
-         var d = new Date(timestamp);
-         // "yyyy-MM-dd HH:mm:ss"
-         //add 1 to month as getmonth returns the position not the actual month
-         return d.getFullYear() + "-" + pad2(d.getMonth() + 1) + "-" + pad2(d.getDate()) + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
-      }
-
-      var typeLabels = ["default", "1", "object", "text", "bytes", "map", "stream", "embedded"];
-      $scope.formatType = function(type) {
-         if (isNaN(type)) {
-            return type;
-         }
-         return type > -1 && type < 8 ? typeLabels[type] : type
-      }
-
-      $scope.formatPersistentSize = function(bytes) {
-         if(isNaN(bytes) || bytes < 0) return "n/a";
-         if(bytes < 10240) return bytes.toLocaleString() + " Bytes";
-         if(bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";
-         if(bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";
-         return (bytes / 1073741824).toFixed(2) + " GB";
-      }
-
-      $scope.moveMessages = function() {
-         var selection = workspace.selection;
-         var mbean = selection.objectName;
-         if (mbean && selection) {
-            var selectedItems = $scope.gridOptions.selectedItems;
-            $scope.message = "Moved " + Core.maybePlural(selectedItems.length, "message" + " to " + $scope.queueName);
-            angular.forEach(selectedItems, function(item, idx) {
-               var id = item.messageID;
-               if (id) {
-                  var callback = (idx + 1 < selectedItems.length) ? intermediateResult : moveSuccess;
-                  ARTEMISService.artemisConsole.moveMessage(mbean, jolokia, id, $scope.queueName, onSuccess(callback));
-               }
-            });
-         }
-      };
-      $scope.resendMessage = function() {
-         var selection = workspace.selection;
-         var mbean = selection.objectName;
-         if (mbean && selection) {
-            var selectedItems = $scope.gridOptions.selectedItems;
-            // always assume a single message
-            artemisMessage.message = selectedItems[0];
-            $location.path('artemis/sendMessage');
-         }
-      };
-      $scope.deleteMessages = function() {
-         var selection = workspace.selection;
-         var mbean = selection.objectName;
-         if (mbean && selection) {
-            var selectedItems = $scope.gridOptions.selectedItems;
-            $scope.message = "Deleted " + Core.maybePlural(selectedItems.length, "message");
-            angular.forEach(selectedItems, function(item, idx) {
-               var id = item.messageID;
-               if (id) {
-                  var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
-                  ARTEMISService.artemisConsole.deleteMessage(mbean, jolokia, id, onSuccess(callback));
-               }
-            });
-         }
-      };
-      $scope.retryMessages = function() {
-         var selection = workspace.selection;
-         var mbean = selection.objectName;
-         if (mbean && selection) {
-            var selectedItems = $scope.gridOptions.selectedItems;
-            $scope.message = "Retry " + Core.maybePlural(selectedItems.length, "message");
-            angular.forEach(selectedItems, function(item, idx) {
-               var id = item.messageID;
-               if (id) {
-                  var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
-                  ARTEMISService.artemisConsole.retryMessage(mbean, jolokia, id, onSuccess(callback));
-               }
-            });
-         }
-      };
-      $scope.queueNames = function(completionText) {
-         var queuesFolder = ARTEMIS.getSelectionQueuesFolder(workspace);
-         if (queuesFolder) {
-            var selectedQueue = workspace.selection.key;
-            var otherQueues = queuesFolder.children.exclude(function(child) {
-               return child.key == selectedQueue;
-            });
-            return (otherQueues) ? otherQueues.map(function(n) {
-               return n.title;
-            }) : [];
-         } else {
-            return [];
-         }
-      };
-
-      function populateTable(response) {
-         var data = response.value;
-         ARTEMIS.log.info("loading data:" + data);
-
-         if (!angular.isArray(data)) {
-            $scope.allMessages = [];
-            angular.forEach(data, function(value, idx) {
-               $scope.allMessages.push(value);
-            });
-         } else {
-            $scope.allMessages = data;
-         }
-         angular.forEach($scope.allMessages, function(message) {
-            message.headerHtml = createHeaderHtml(message);
-            message.bodyText = createBodyText(message);
-         });
-         filterMessages($scope.gridOptions.filterOptions.filterText);
-         Core.$apply($scope);
-      }
-
-      /*
-       * For some reason using ng-repeat in the modal dialog doesn't work so lets
-       * just create the HTML in code :)
-       */
-      function createBodyText(message) {
-         ARTEMIS.log.info("loading message:" + message);
-         if (message.text) {
-            var body = message.text;
-            var lenTxt = "" + body.length;
-            message.textMode = "text (" + lenTxt + " chars)";
-            return body;
-         } else if (message.BodyPreview) {
-            var code = Core.parseIntValue(localStorage["ARTEMISBrowseBytesMessages"] || "1", "browse bytes messages");
-            var body;
-            message.textMode = "bytes (turned off)";
-            if (code != 99) {
-               var bytesArr = [];
-               var textArr = [];
-               message.BodyPreview.forEach(function(b) {
-                  if (code === 1 || code === 2) {
-                     // text
-                     textArr.push(String.fromCharCode(b));
-                  }
-                  if (code === 1 || code === 4) {
-                     // hex and must be 2 digit so they space out evenly
-                     var s = b.toString(16);
-                     if (s.length === 1) {
-                        s = "0" + s;
-                     }
-                     bytesArr.push(s);
-                  } else {
-                     // just show as is without spacing out, as that is usually more used for hex than decimal
-                     var s = b.toString(10);
-                     bytesArr.push(s);
-                  }
-               });
-               var bytesData = bytesArr.join(" ");
-               var textData = textArr.join("");
-               if (code === 1 || code === 2) {
-                  // bytes and text
-                  var len = message.BodyPreview.length;
-                  var lenTxt = "" + textArr.length;
-                  body = "bytes:\n" + bytesData + "\n\ntext:\n" + textData;
-                  message.textMode = "bytes (" + len + " bytes) and text (" + lenTxt + " chars)";
-               } else {
-                  // bytes only
-                  var len = message.BodyPreview.length;
-                  body = bytesData;
-                  message.textMode = "bytes (" + len + " bytes)";
-               }
-            }
-            return body;
-         } else {
-            message.textMode = "unsupported";
-            return "Unsupported message body type which cannot be displayed by hawtio";
-         }
-      }
-
-      /*
-       * For some reason using ng-repeat in the modal dialog doesn't work so lets
-       * just create the HTML in code :)
-       */
-      function createHeaderHtml(message) {
-         var headers = createHeaders(message);
-         var properties = createProperties(message);
-         var headerKeys = Object.extended(headers).keys();
-
-         function sort(a, b) {
-            if (a > b)
-               return 1;
-            if (a < b)
-               return -1;
-            return 0;
-         }
-
-         var propertiesKeys = Object.extended(properties).keys().sort(sort);
-         var jmsHeaders = headerKeys.filter(function(key) {
-            return key.startsWith("JMS");
-         }).sort(sort);
-         var remaining = headerKeys.subtract(jmsHeaders, propertiesKeys).sort(sort);
-         var buffer = [];
-
-         function appendHeader(key) {
-            var value = headers[key];
-            if (value === null) {
-               value = '';
-            }
-            if (key == "expiration" || key == "timestamp") {
-               value = $scope.formatTimestamp(value) + " (" + value + ")";
-            } else if (key == "type") {
-               value = $scope.formatType(value) + " (" + value + ")";
-            }
-            buffer.push('<tr><td class="propertyName"><span class="green">Header</span> - ' + key + '</td><td class="property-value">' + value + '</td></tr>');
-         }
-
-         function appendProperty(key) {
-            var value = properties[key];
-            if (value === null) {
-               value = '';
-            }
-            buffer.push('<tr><td class="propertyName">' + key + '</td><td class="property-value">' + value + '</td></tr>');
-         }
-
-         jmsHeaders.forEach(appendHeader);
-         remaining.forEach(appendHeader);
-         propertiesKeys.forEach(appendProperty);
-         return buffer.join("\n");
-      }
-
-      function createHeaders(row) {
-         var answer = {};
-         angular.forEach(row, function(value, key) {
-            if (!ignoreColumns.any(key) && !flattenColumns.any(key)) {
-               answer[Core.escapeHtml(key)] = Core.escapeHtml(value);
-            }
-         });
-         return answer;
-      }
-
-      function createProperties(row) {
-         ARTEMIS.log.debug("properties: ", row);
-         var answer = {};
-         angular.forEach(row, function(value, key) {
-            if (!ignoreColumns.any(key) && flattenColumns.any(key)) {
-               angular.forEach(value, function(v2, k2) {
-                  answer['<span class="green">' + key.replace('Properties', ' Property') + '</span> - ' + Core.escapeHtml(k2)] = Core.escapeHtml(v2);
-               });
-            }
-         });
-         return answer;
-      }
-
-      function loadTable() {
-         ARTEMIS.log.info("loading table")
-         var objName;
-         $scope.gridOptions.selectedItems.length = 0;
-         if (workspace.selection) {
-            objName = workspace.selection.objectName;
-         } else {
-            // in case of refresh
-            var key = location.search()['nid'];
-            var node = workspace.keyToNodeMap[key];
-            objName = node.objectName;
-         }
-         if (objName) {
-            $scope.dlq = false;
-            var queueName = jolokia.getAttribute(objName, "Name");
-
-            var artemisDLQ = localStorage['artemisDLQ'] || "DLQ";
-            var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue";
-            ARTEMIS.log.info("loading table" + artemisExpiryQueue);
-            if (queueName == artemisDLQ || queueName == artemisExpiryQueue) {
-               onDlq(true);
-            } else {
-               onDlq(false);
-            }
-            jolokia.request({ type: 'exec', mbean: objName, operation: 'countMessages()'}, onSuccess(function(response) { $scope.totalServerItems = response.value; }));
-            jolokia.request({ type: 'exec', mbean: objName, operation: 'browse(int, int)', arguments: [$scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable));
-         }
-      }
-
-      function onDlq(response) {
-         ARTEMIS.log.info("onDLQ=" + response);
-         $scope.dlq = response;
-         Core.$apply($scope);
-      }
-
-      function intermediateResult() {
-      }
-
-      function operationSuccess() {
-         $scope.messageDialog = false;
-         deselectAll();
-         Core.notification("success", $scope.message);
-         loadTable();
-         setTimeout(loadTable, 50);
-      }
-
-      function moveSuccess() {
-         operationSuccess();
-         workspace.loadTree();
-      }
-
-      function filterMessages(filter) {
-         var searchConditions = buildSearchConditions(filter);
-         evalFilter(searchConditions);
-      }
-
-      function evalFilter(searchConditions) {
-         if (!searchConditions || searchConditions.length === 0) {
-            $scope.messages = $scope.allMessages;
-         } else {
-            ARTEMIS.log.debug("Filtering conditions:", searchConditions);
-            $scope.messages = $scope.allMessages.filter(function(message) {
-               ARTEMIS.log.debug("Message:", message);
-               var matched = true;
-               $.each(searchConditions, function(index, condition) {
-                  if (!condition.column) {
-                     matched = matched && evalMessage(message, condition.regex);
-                  } else {
-                     matched = matched && (message[condition.column] && condition.regex.test(message[condition.column])) || (message.StringProperties && message.StringProperties[condition.column] && condition.regex.test(message.StringProperties[condition.column]));
-                  }
-               });
-               return matched;
-            });
-         }
-      }
-
-      function evalMessage(message, regex) {
-         var jmsHeaders = ['JMSDestination', 'JMSDeliveryMode', 'JMSExpiration', 'JMSPriority', 'JMSmessageID', 'JMSTimestamp', 'JMSCorrelationID', 'JMSReplyTo', 'JMSType', 'JMSRedelivered'];
-         for (var i = 0; i < jmsHeaders.length; i++) {
-            var header = jmsHeaders[i];
-            if (message[header] && regex.test(message[header])) {
-               return true;
-            }
-         }
-         if (message.StringProperties) {
-            for ( var property in message.StringProperties) {
-               if (regex.test(message.StringProperties[property])) {
-                  return true;
-               }
-            }
-         }
-         if (message.bodyText && regex.test(message.bodyText)) {
-            return true;
-         }
-         return false;
-      }
-
-      function getRegExp(str, modifiers) {
-         try {
-            return new RegExp(str, modifiers);
-         } catch (err) {
-            return new RegExp(str.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\\|\||\.|\*|\+|\?)/g, '\\$1'));
-         }
-      }
-
-      function buildSearchConditions(filterText) {
-         var searchConditions = [];
-         var qStr;
-         if (!(qStr = $.trim(filterText))) {
-            return;
-         }
-         var columnFilters = qStr.split(";");
-         for (var i = 0; i < columnFilters.length; i++) {
-            var args = columnFilters[i].split(':');
-            if (args.length > 1) {
-               var columnName = $.trim(args[0]);
-               var columnValue = $.trim(args[1]);
-               if (columnName && columnValue) {
-                  searchConditions.push({
-                     column: columnName,
-                     columnDisplay: columnName.replace(/\s+/g, '').toLowerCase(),
-                     regex: getRegExp(columnValue, 'i')
-                  });
-               }
-            } else {
-               var val = $.trim(args[0]);
-               if (val) {
-                  searchConditions.push({
-                     column: '',
-                     regex: getRegExp(val, 'i')
-                  });
-               }
-            }
-         }
-         return searchConditions;
-      }
-
-      function afterSelectionChange(rowItem, checkAll) {
-         if (checkAll === void 0) {
-            // then row was clicked, not select-all checkbox
-            $scope.gridOptions['$gridScope'].allSelected = rowItem.config.selectedItems.length == $scope.messages.length;
-         } else {
-            $scope.gridOptions['$gridScope'].allSelected = checkAll;
-         }
-      }
-
-      function deselectAll() {
-         $scope.gridOptions['$gridScope'].allSelected = false;
-      }
-   }
-
-   return ARTEMIS;
-}(ARTEMIS || {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/addresses.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/addresses.js
new file mode 100644
index 0000000..f579cd8
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/addresses.js
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    //Artemis.log.info("loading addresses");
+    Artemis._module.component('artemisAddresses', {
+        template:
+            `<h1>Browse Addresses
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'addresses-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+             <div ng-include="'plugin/artemistoolbar.html'"></div>
+             <pf-table-view config="$ctrl.tableConfig"
+                            columns="$ctrl.tableColumns"
+                            action-buttons="$ctrl.tableActionButtons"
+                            items="$ctrl.addresses">
+             </pf-table-view>
+             <div ng-include="'plugin/artemispagination.html'"></div>
+             <script type="text/ng-template" id="addresses-instructions.html">
+             <div>
+                <p>
+                    This page allows you to browse all address on the broker. These can be narrowed down
+                    by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
+                    click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    You can also navigate directly to the JMX attributes and operations tabs by using the  <code>attributes</code>
+                    and <code>operations</code> button under the <code>Actions</code> column.You can navigate to the
+                    addresses queues by clicking on the <code>Queue Count</code> field.
+                  </p>
+                  <p>
+                    Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
+                  </p>
+                </div>
+             </script>
+             `,
+              controller: AddressesController
+    })
+    .name;
+
+
+    function AddressesController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisAddress) {
+        var ctrl = this;
+        ctrl.pagination = pagination;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+        ctrl.allAddresses = [];
+        ctrl.addresses = [];
+        ctrl.workspace = workspace;
+        ctrl.refreshed = false;
+        ctrl.filter = {
+            fieldOptions: [
+                {id: 'ID', name: 'ID'},
+                {id: 'NAME', name: 'Name'},
+                {id: 'ROUTING_TYPES', name: 'Queue Count'},
+                {id: 'QUEUE_COUNT', name: 'User'}
+            ],
+            operationOptions: [
+                {id: 'EQUALS', name: 'Equals'},
+                {id: 'CONTAINS', name: 'Contains'},
+                {id: 'GREATER_THAN', name: 'Greater Than'},
+                {id: 'LESS_THAN', name: 'Less Than'}
+            ],
+            sortOptions: [
+                {id: 'asc', name: 'ascending'},
+                {id: 'desc', name: 'descending'}
+            ],
+            values: {
+                field: "",
+                operation: "",
+                value: "",
+                sortOrder: "asc",
+                sortColumn: "id"
+            },
+            text: {
+                fieldText: "Filter Field..",
+                operationText: "Operation..",
+                sortOrderText: "ascending",
+                sortByText: "ID"
+            }
+        };
+
+        ctrl.tableActionButtons = [
+            {
+                name: 'attributes',
+                title: 'Navigate to attributes',
+                actionFn: navigateToAddressAtts
+            },
+            {
+               name: 'operations',
+               title: 'navigate to operations',
+               actionFn: navigateToAddressOps
+            }
+        ];
+        ctrl.tableConfig = {
+            selectionMatchProp: 'id',
+            showCheckboxes: false
+        };
+        ctrl.tableColumns = [
+            { header: 'ID', itemField: 'id' },
+            { header: 'Name', itemField: 'name' },
+            { header: 'Routing Types', itemField: 'routingTypes' },
+            { header: 'Queue Count', itemField: 'queueCount' , templateFn: function(value, item) { return '<a href="#" onclick="selectQueues(\'' + item.name + '\')">' + value + '</a>' }}
+        ];
+
+        ctrl.refresh = function () {
+            ctrl.refreshed = true;
+            ctrl.pagination.load();
+        };
+        ctrl.reset = function () {
+            ctrl.filter.values.field = "";
+            ctrl.filter.values.operation = "";
+            ctrl.filter.values.value = "";
+            ctrl.filter.sortOrder = "asc";
+            ctrl.filter.sortColumn = "id";
+            ctrl.refreshed = true;
+            artemisAddress.address = null;
+            ctrl.pagination.load();
+        };
+
+        if (artemisAddress.address) {
+            Artemis.log.info("navigating to address = " + artemisAddress.address.address);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisAddress.address.address;
+        }
+
+        selectQueues = function (address) {
+            Artemis.log.info("navigating to queues:" + address)
+            artemisAddress.address = { address: address };
+            $location.path("artemis/artemisQueues");
+        };
+
+        function navigateToAddressAtts(action, item) {
+            $location.path("artemis/attributes").search({"tab": "artemis", "nid": getAddressNid(item.name, $location)});
+        };
+        function navigateToAddressOps(action, item) {
+            $location.path("artemis/operations").search({"tab": "artemis", "nid": getAddressNid(item.name, $location)});
+        };
+        function getAddressNid(address, $location) {
+            var rootNID = getRootNid($location);
+            var targetNID = rootNID + "addresses-" + address;
+            Artemis.log.info("targetNID=" + targetNID);
+            return targetNID;
+        }
+        function getRootNid($location) {
+            var currentNid = $location.search()['nid'];
+            Artemis.log.info("current nid=" + currentNid);
+            var firstDash = currentNid.indexOf('-');
+            var secondDash = currentNid.indexOf('-', firstDash + 1);
+            var thirdDash = currentNid.indexOf('-', secondDash + 1);
+            if (thirdDash < 0) {
+                return currentNid + "-";
+            }
+            var rootNID = currentNid.substring(0, thirdDash + 1);
+            return rootNID;
+        }
+        ctrl.loadOperation = function () {
+            if (mbean) {
+                var method = 'listAddresses(java.lang.String, int, int)';
+                var addressFilter = {
+                    field: ctrl.filter.values.field,
+                    operation: ctrl.filter.values.operation,
+                    value: ctrl.filter.values.value,
+                    sortOrder: ctrl.filter.values.sortOrder,
+                    sortColumn: ctrl.filter.values.sortColumn
+                };
+
+                if (ctrl.refreshed == true) {
+                    ctrl.pagination.reset();
+                    ctrl.refreshed = false;
+                }
+                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(addressFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
+            }
+        };
+
+        ctrl.pagination.setOperation(ctrl.loadOperation);
+
+        function onError(response) {
+            Core.notification("error", "could not invoke list sessions" + response.error);
+            $scope.workspace.selectParentNode();
+        };
+
+        function populateTable(response) {
+            var data = JSON.parse(response.value);
+            ctrl.addresses = [];
+            angular.forEach(data["data"], function (value, idx) {
+                ctrl.addresses.push(value);
+            });
+            ctrl.pagination.page(data["count"]);
+            allAddresses = ctrl.addresses;
+            ctrl.addresses = allAddresses;
+            Core.$apply($scope);
+        }
+
+        ctrl.pagination.load();
+    }
+    AddressesController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisAddress'];
+
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/browse.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/browse.js
new file mode 100644
index 0000000..2fb9c5d
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/browse.js
@@ -0,0 +1,849 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisBrowseQueue', {
+        template:
+            `<h1>Browse Queue
+            <button type="button" class="btn btn-link jvm-title-popover"
+                      uib-popover-template="'browse-instructions.html'" popover-placement="bottom-left"
+                      popover-title="Instructions" popover-trigger="'outsideClick'">
+                <span class="pficon pficon-help"></span>
+            </button>
+            </h1>
+
+
+            <div class="table-view artemis-browse-main" ng-show="!$ctrl.showMessageDetails">
+                <div class="row toolbar-pf table-view-pf-toolbar" id="toolbar1">
+                    <div class="col-sm-20">
+                        <form class="toolbar-pf-actions">
+                            <div class="form-group toolbar-pf-filter">
+                                <div class="input-group">
+                                    <input type="text" class="form-control" ng-model="$ctrl.filter.values.value" placeholder="Filter..." autocomplete="off" id="filterInput">
+                                    <div class="input-group-btn">
+                                        <button class="btn btn-link btn-find" ng-click="$ctrl.refresh()" type="button">
+                                            &nbsp;&nbsp;<span class="fa fa-search"></span>&nbsp;&nbsp;
+                                        </button>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="form-group">
+                                    <button class="btn btn-default primary-action ng-binding ng-scope"
+                                        type="button"
+                                        title=""
+                                        ng-click="$ctrl.reset()">Reset
+                                    </button>
+                                    <button class="btn btn-default primary-action ng-binding ng-scope"
+                                        type="button"
+                                        title=""
+                                        ng-disabled="$ctrl.deleteDisabled"
+                                        ng-click="$ctrl.openDeleteDialog()">Delete Messages
+                                    </button>
+                                    <button class="btn btn-default primary-action ng-binding ng-scope"
+                                        type="button"
+                                        title=""
+                                        ng-disabled="$ctrl.moveDisabled"
+                                        ng-click="$ctrl.openMoveDialog()">Move Messages
+                                    </button>
+                                    <button ng-show="$ctrl.dlq" class="btn btn-default primary-action ng-binding ng-scope"
+                                        type="button"
+                                        title=""
+                                        ng-disabled="$ctrl.retryDisabled"
+                                        ng-click="$ctrl.openRetryDialog()">Retry Messages
+                                    </button>
+                            </div>
+                        </form>
+                    </div>
+                </div>
+                <pf-table-view config="$ctrl.tableConfig"
+                    columns="$ctrl.tableColumns"
+                    items="$ctrl.messages"
+                    dt-options="$ctrl.tableDtOptions"
+                    action-buttons="$ctrl.tableMenuActions">
+                </pf-table-view>
+                <div ng-include="'plugin/artemispagination.html'"></div>
+
+            </div>
+            <div class="form-group" ng-show="$ctrl.showMessageDetails">
+                <button class="btn btn-primary" ng-click="$ctrl.showMessageDetails = false">Back</button>
+                <h2>MessageID: {{$ctrl.currentMessage.messageID}}</h2>
+                <h2>Headers</h2>
+                <pf-toolbar config="$ctrl.messageToolbarConfig"></pf-toolbar>
+                <pf-table-view config="$ctrl.messageTableConfig"
+                    columns="$ctrl.messageTableColumns"
+                    items="$ctrl.currentMessage.headers">
+                </pf-table-view>
+
+                <h2>Properties</h2>
+                <div ng-show="$ctrl.showMessageDetails">
+                    <pf-toolbar config="$ctrl.messagePToolbarConfig"></pf-toolbar>
+                    <pf-table-view config="$ctrl.messagePTableConfig"
+                        columns="$ctrl.messageTableColumns"
+                        items="$ctrl.currentMessage.properties">
+                    </pf-table-view>
+                </div>
+
+                <h3>Displaying body as <span ng-bind="$ctrl.currentMessage.textMode"></span></h3>
+                <div hawtio-editor="$ctrl.currentMessage.bodyText" read-only="true" mode='mode'></div>
+            </div>
+
+            <div hawtio-confirm-dialog="$ctrl.deleteDialog" title="Delete messages?"
+               ok-button-text="Delete"
+               cancel-button-text="Cancel"
+               on-ok="$ctrl.deleteMessages()">
+                <div class="dialog-body">
+                    <p class="alert alert-warning">
+                    <span class="pficon pficon-warning-triangle-o"></span>
+                    This operation cannot be undone so please be careful.
+                    </p>
+                    <p>{{$ctrl.actionText}}</p>
+                </div>
+            </div>
+
+            <div hawtio-confirm-dialog="$ctrl.moveDialog" title="Move messages?"
+               ok-button-text="Move"
+               cancel-button-text="Cancel"
+               on-ok="$ctrl.moveMessages()">
+                <div class="dialog-body">
+                    <p class="alert alert-warning">
+                    <span class="pficon pficon-warning-triangle-o"></span>
+                    You cannot undo this operation.<br/>
+                    Though after the move you can always move them back again.
+                    </p>
+                    <p>{{$ctrl.actionText}}</p>
+                    <p>Move
+                    <ng-pluralize count="$filter('filter')(ctrl.messages, {selected: true}).length"
+                                  when="{'1': 'message', 'other': '{} messages'}"></ng-pluralize>
+                    to: <select ng-model="$ctrl.queueName" ng-options="qn for qn in $ctrl.queueNames" ng-init="queueName=$ctrl.queueNames[0]"></select>
+                   </p>
+                </div>
+            </div>
+
+            <div hawtio-confirm-dialog="$ctrl.retryDialog" title="Retry messages?"
+               ok-button-text="Retry"
+               cancel-button-text="Cancel"
+               on-ok="$ctrl.retryMessages()">
+                <div class="dialog-body">
+                    <p class="alert alert-warning">
+                    <span class="pficon pficon-warning-triangle-o"></span>
+                    You cannot undo this operation.<br/>
+                    Though after the move you can always move them back again.
+                    </p>
+                    <p>{{$ctrl.actionText}}</p>
+                </div>
+            </div>
+            <script type="text/ng-template" id="browse-instructions.html">
+              <div>
+                <p>
+                  This page allows you to browse messages on a queue in Artemis. Messages are loaded in from the broker
+                  a page at a time and can be filtered at the broker using the <code>filter</code>: see <a href="https://activemq.apache.org/components/artemis/documentation/latest/filter-expressions.html" target="_blank">Filter Expressions</a>
+                  . To execute a query click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    Clicking on the <code>show</code> buton will show the messages details in more detail including, headers, properties
+                    and the body if viewable. Clicking on the <code>resend</code> button will navigate to the <code>Send Message</code>
+                    tab and copy the message details so a copy of the message can be resent.
+                </p>
+              </div>
+            </script>
+        `,
+        controller: BrowseQueueController
+    })
+    .name;
+
+
+    function BrowseQueueController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination) {
+        var ctrl = this;
+        ctrl.dlq = false;
+        ctrl.deleteDisabled = true;
+        ctrl.moveDisabled = true;
+        ctrl.retryDisabled = true;
+        ctrl.pagination = pagination;
+        ctrl.filter = '';
+        ctrl.actionText = '';
+
+        ctrl.allMessages = [];
+        ctrl.messages = [];
+
+        var objName;
+        if (workspace.selection) {
+            objName = workspace.selection.objectName;
+        } else {
+        // in case of refresh
+            var key = location.search()['nid'];
+            var node = workspace.keyToNodeMap[key];
+            objName = node.objectName;
+        }
+        var artemisDLQ = localStorage['artemisDLQ'] || "DLQ";
+        var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue";
+        Artemis.log.debug("loading table" + artemisExpiryQueue);
+        if (objName) {
+            ctrl.dlq = false;
+            var queueName = jolokia.getAttribute(objName, "Name");
+            if (queueName == artemisDLQ || queueName == artemisExpiryQueue) {
+                ctrl.dlq = true;
+            }
+        }
+
+        ctrl.tableConfig = {
+            onCheckBoxChange: handleCheckBoxChange,
+            selectionMatchProp: 'messageID',
+            showCheckboxes: true
+        };
+        ctrl.tableColumns = [
+            {
+                itemField: 'messageID',
+                header: 'messageID'
+            },
+            {
+                itemField: 'type',
+                header: 'Type',
+                templateFn: function(value) {
+                    return formatType(value);
+                }
+            },
+            {
+                itemField: 'durable',
+                header: 'Durable'
+            },
+            {
+                itemField: 'priority',
+                header: 'Priority'
+            },
+            {
+                itemField: 'timestamp',
+                header: 'Timestamp',
+                templateFn: function(value) {
+                   return formatTimestamp(value);
+                }
+            },
+            {
+                itemField: 'expiration',
+                header: 'Expires',
+                templateFn: function(value) {
+                    return formatExpires(value);
+                }
+            },
+            {
+                header: 'Redelivered',
+                itemField: 'redelivered'
+            },
+            {
+                itemField: 'largeMessage',
+                header: 'Large'
+            },
+            {
+                itemField: 'persistentSize',
+                header: 'Persistent Size',
+                templateFn: function(value) {
+                    return formatPersistentSize(value);
+                }
+            },
+            {
+                itemField: 'userID',
+                header: 'User ID'
+            },
+            {
+                itemField: 'StringProperties',
+                header: 'Validated User',
+                templateFn: function(value) {
+                    return value._AMQ_VALIDATED_USER;
+                }
+            }
+
+        ];
+
+        var resendConfig = {
+            name: 'Resend',
+            title: 'Resend message',
+            actionFn: resendMessage
+        };
+
+        var showConfig = {
+            name: 'Show',
+            title: 'Show message',
+            actionFn: openMessageDialog
+        };
+
+        ctrl.messageTableConfig = { selectionMatchProp: 'key', itemsAvailable: true, showCheckboxes: false };
+        ctrl.messagePTableConfig = { selectionMatchProp: 'key', itemsAvailable: true, showCheckboxes: false };
+        ctrl.messageToolbarConfig = {
+            isTableView: true
+        };
+        ctrl.messagePToolbarConfig = {
+            isTableView: true
+        };
+
+        ctrl.messageTableColumns = [
+        {
+            itemField: 'key',
+            header: 'key'
+        },
+        {
+            itemField: 'value',
+            header: 'value'
+        }];
+
+        ctrl.tableMenuActions = [ showConfig, resendConfig ];
+
+        ctrl.tableDtOptions = {
+          order: [[0, "asc"]]
+        };
+        ctrl.sysprops = [];
+
+        Artemis.log.debug("loaded browse 5" + Artemis.browseQueueModule);
+        ctrl.currentMessage;
+
+        ctrl.queueNames = [];
+        ctrl.queueName = '';
+        ctrl.resultSizeDialog = false;
+        //success message
+        ctrl.message = '';
+        //error message
+        ctrl.errorMessage = '';
+        $scope.mode = 'text';
+        ctrl.deleteDialog = false;
+        ctrl.moveDialog = false;
+        ctrl.retryDialog = false;
+        ctrl.showMessageDetails = false;
+
+        var ignoreColumns = ["PropertiesText", "bodyText", "BodyPreview", "text", "headers", "properties", "textMode"];
+        var flattenColumns = ["BooleanProperties", "ByteProperties", "ShortProperties", "IntProperties", "LongProperties", "FloatProperties", "DoubleProperties", "StringProperties"];
+
+        function openMessageDialog(action, item) {
+            ctrl.currentMessage = item;
+            ctrl.currentMessage.headers = createHeaders(ctrl.currentMessage)
+            ctrl.currentMessage.properties = createProperties(ctrl.currentMessage);
+            ctrl.currentMessage.bodyText = createBodyText(ctrl.currentMessage);
+            ctrl.showMessageDetails = true;
+        };
+
+        var MS_PER_SEC  = 1000;
+        var MS_PER_MIN  = 60 * MS_PER_SEC;
+        var MS_PER_HOUR = 60 * MS_PER_MIN;
+        var MS_PER_DAY  = 24 * MS_PER_HOUR;
+
+        function pad2(value) {
+            return (value < 10 ? '0' : '') + value;
+        }
+
+        function formatExpires(timestamp) {
+            if (isNaN(timestamp)) {
+                return timestamp;
+            }
+            var expiresIn = timestamp - Date.now();
+            if (Math.abs(expiresIn) < MS_PER_DAY) {
+                var duration = expiresIn < 0 ? -expiresIn : expiresIn;
+                var hours = pad2(Math.floor((duration / MS_PER_HOUR) % 24));
+                var mins  = pad2(Math.floor((duration / MS_PER_MIN) % 60));
+                var secs  = pad2(Math.floor((duration / MS_PER_SEC) % 60));
+                if (expiresIn < 0) {
+                // "HH:mm:ss ago"
+                    return hours + ":" + mins + ":" + secs + " ago";
+                }
+                // "in HH:mm:ss ago"
+                return "in " + hours + ":" + mins + ":" + secs;
+            }
+            return formatTimestamp(timestamp);
+        }
+
+        function formatTimestamp(timestamp) {
+            if (isNaN(timestamp)) {
+                return timestamp;
+            }
+            var d = new Date(timestamp);
+            // "yyyy-MM-dd HH:mm:ss"
+            return d.getFullYear() + "-" + pad2(d.getMonth()) + "-" + pad2(d.getDay()) + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
+        }
+
+        var typeLabels = ["default", "1", "object", "text", "bytes", "map", "stream", "embedded"];
+        function formatType(type) {
+            if (isNaN(type)) {
+                return type;
+            }
+            return type > -1 && type < 8 ? typeLabels[type] : type
+        }
+
+        ctrl.refresh = function() {
+            Artemis.log.info(ctrl.filter)
+            ctrl.pagination.load();
+        }
+
+        ctrl.reset = function() {
+            ctrl.filter = '';
+            ctrl.pagination.load();
+        }
+
+        function formatPersistentSize(bytes) {
+            if(isNaN(bytes) || bytes < 0) return "n/a";
+            if(bytes < 10240) return bytes.toLocaleString() + " Bytes";
+            if(bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";
+            if(bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";
+            return (bytes / 1073741824).toFixed(2) + " GB";
+        }
+
+        ctrl.openMoveDialog = function () {
+            var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
+            if(!selectedItems) {
+                return;
+            }
+            ctrl.actionText = "You are about to move " + Core.maybePlural(selectedItems.length, "message");
+            Artemis.log.debug(ctrl.actionText);
+            ctrl.moveDialog = true;
+        };
+
+        ctrl.moveMessages = function (action, item) {
+            var selection = workspace.selection;
+            var mbean = selection.objectName;
+            if (mbean && selection) {
+                var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
+                if(!selectedItems) {
+                    selectedItems = [];
+                    return;
+                }
+                ctrl.message = "Moved " + Core.maybePlural(selectedItems.length, "message" + " to " + ctrl.queueName);
+                ctrl.errorMessage = "failed to move message";
+                angular.forEach(selectedItems, function(item, idx) {
+                    var id = item.messageID;
+                    if (id) {
+                        var callback = (idx + 1 < selectedItems.length) ? intermediateResult : moveSuccess;
+                        jolokia.execute(mbean, "moveMessage(long,java.lang.String)", id,  ctrl.queueName, Core.onSuccess(callback, { error: onError }));
+                    }
+                });
+            }
+        };
+
+        function resendMessage(action, item) {
+            // always assume a single message
+            artemisMessage.message = item;
+            $location.path('artemis/artemisSendMessage');
+        };
+
+        function onError(response) {
+            Core.notification("error", ctrl.errorMessage + response.error);
+        }
+
+        function handleCheckBoxChange (item) {
+            var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
+            Artemis.log.debug("sel " + selectedItems.length);
+            if (selectedItems.length == 0) {
+                ctrl.deleteDisabled = true;
+                ctrl.moveDisabled = true;
+                ctrl.retryDisabled = true;
+                return;
+            }
+            ctrl.deleteDisabled = false;
+            ctrl.moveDisabled = false;
+            ctrl.retryDisabled = false;
+        }
+
+        ctrl.openDeleteDialog = function () {
+            var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
+            if(!selectedItems) {
+                selectedItems = [];
+                return;
+            }
+            ctrl.actionText = "You are about to delete " + Core.maybePlural(selectedItems.length, "message");
+            Artemis.log.debug(ctrl.actionText);
+            ctrl.deleteDialog = true;
+        }
+
+        ctrl.deleteMessages = function () {
+            var selection = workspace.selection;
+            var mbean = selection.objectName;
+            if (mbean && selection) {
+                var selectedItems = $filter('filter')(ctrl.allMessages, {selected: true});
+                if(!selectedItems) {
+                    selectedItems = [];
+                    return;
+                }
+                ctrl.message = "Deleted " + Core.maybePlural(selectedItems.length, "message");
+                ctrl.errorMessage = "failed to delete message";
+                angular.forEach(selectedItems, function(item, idx) {
+                    var id = item.messageID;
+                    if (id) {
+                    var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
+                        jolokia.execute(mbean, "removeMessage(long)", id, Core.onSuccess(callback, { error: onError }));
+                    }
+                });
+            }
+        };
+
+        ctrl.openRetryDialog = function () {
+            var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
+            if(!selectedItems) {
+                return;
+            }
+            ctrl.actionText = "You are about to retry " + Core.maybePlural(selectedItems.length, "message");
+            Artemis.log.debug(ctrl.actionText);
+            ctrl.retryDialog = true;
+        };
+
+        ctrl.retryMessages = function() {
+            var selection = workspace.selection;
+            var mbean = selection.objectName;
+            if (mbean && selection) {
+                var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
+                ctrl.message = "Retry " + Core.maybePlural(selectedItems.length, "message");
+                ctrl.errorMessage = "failed to retry message";
+                angular.forEach(selectedItems, function(item, idx) {
+                    var id = item.messageID;
+                    if (id) {
+                        var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
+                        jolokia.execute(mbean, "retryMessage(long)", id,  Core.onSuccess(callback, { error: onError }));
+                    }
+                });
+            }
+        };
+
+        function populateTable(response) {
+            Artemis.log.debug("loading data:" + data);
+            if (ctrl.queueNames.length === 0) {
+                var queueNames = getSelectionQueuesFolder(workspace);
+                var selectedQueue = workspace.selection.text;
+                ctrl.queueNames = queueNames.filter(function (name) { return name !== selectedQueue; });
+            }
+            var data = response.value;
+
+            if (!angular.isArray(data)) {
+                ctrl.allMessages = [];
+                angular.forEach(data, function(value, idx) {
+                    ctrl.allMessages.push(value);
+                })
+            } else {
+                ctrl.allMessages = data;
+            }
+            angular.forEach(ctrl.allMessages, function(message) {
+                message.bodyText = createBodyText(message);
+            });
+            ctrl.messages = ctrl.allMessages;
+            ctrl.isLoading = false;
+            Core.$apply($scope);
+        }
+
+        function findFolder(node) {
+            if (!node) {
+                return null;
+            }
+            var answer = [];
+
+            var addresses = node.children;
+
+            angular.forEach(addresses, function (address) {
+                var subQueues = address.children;
+                angular.forEach(subQueues, function (subQueue) {
+                    var routingTypes = subQueue.children;
+                    angular.forEach(routingTypes, function (routingType) {
+                        var queues = routingType.children;
+                        angular.forEach(queues, function (queue) {
+                            answer.push(queue.title);
+                        });
+                    });
+                });
+            });
+            return answer;
+        }
+
+        function findAddressesNode(node) {
+            if (!node) {
+                return null;
+            }
+            if (node.title === "addresses") {
+                return node;
+            }
+            if (node.title == Artemis.jmxDomain) {
+                return null;
+            }
+            return findAddressesNode(node.parent);
+        }
+
+        function getSelectionQueuesFolder(workspace) {
+            var selection = workspace.selection;
+            var addressesNode = findAddressesNode(selection);
+            var queueFolder = selection ? findFolder(addressesNode) : null;
+            return queueFolder;
+        }
+
+        /*
+        * For some reason using ng-repeat in the modal dialog doesn't work so lets
+        * just create the HTML in code :)
+        */
+        function createBodyText(message) {
+            Artemis.log.debug("loading message:" + message);
+            if (message.text) {
+                var body = message.text;
+                var lenTxt = "" + body.length;
+                message.textMode = "text (" + lenTxt + " chars)";
+                return body;
+            } else if (message.BodyPreview) {
+                var code = Core.parseIntValue(localStorage["ArtemisBrowseBytesMessages"] || "1", "browse bytes messages");
+                var body;
+                message.textMode = "bytes (turned off)";
+                if (code != 99) {
+                    var bytesArr = [];
+                    var textArr = [];
+                    message.BodyPreview.forEach(function(b) {
+                        if (code === 1 || code === 2) {
+                            // text
+                            textArr.push(String.fromCharCode(b));
+                        }
+                        if (code === 1 || code === 4) {
+                        // hex and must be 2 digit so they space out evenly
+                        var s = b.toString(16);
+                        if (s.length === 1) {
+                            s = "0" + s;
+                        }
+                        bytesArr.push(s);
+                        } else {
+                            // just show as is without spacing out, as that is usually more used for hex than decimal
+                            var s = b.toString(10);
+                            bytesArr.push(s);
+                        }
+                    });
+                    var bytesData = bytesArr.join(" ");
+                    var textData = textArr.join("");
+                    if (code === 1 || code === 2) {
+                        // bytes and text
+                        var len = message.BodyPreview.length;
+                        var lenTxt = "" + textArr.length;
+                        body = "bytes:\n" + bytesData + "\n\ntext:\n" + textData;
+                        message.textMode = "bytes (" + len + " bytes) and text (" + lenTxt + " chars)";
+                    } else {
+                        // bytes only
+                        var len = message.BodyPreview.length;
+                        body = bytesData;
+                        message.textMode = "bytes (" + len + " bytes)";
+                    }
+                }
+            return body;
+            } else {
+                message.textMode = "unsupported";
+                return "Unsupported message body type which cannot be displayed by hawtio";
+            }
+        }
+
+        function createHeaders(message) {
+        var headers = [];
+            angular.forEach(message, function (value, key) {
+                if (!_.some(ignoreColumns, function (k) { return k === key; }) && !_.some(flattenColumns, function (k) { return k === key; })) {
+                    headers.push({key: key, value: value});
+                }
+            });
+            return headers;
+        }
+
+
+        function createProperties(message) {
+            var properties = [];
+            angular.forEach(message, function (value, key) {
+                if (!_.some(ignoreColumns, function (k) { return k === key; }) && _.some(flattenColumns, function (k) { return k === key; })) {
+                    Artemis.log.debug("key=" + key + " value=" + value);
+                    angular.forEach(value, function (v2, k2) {
+                    Artemis.log.debug("key=" + k2 + " value=" + v2);
+                        properties.push({key: k2, value: v2});
+                    });
+                }
+            });
+            return properties;
+        }
+
+        ctrl.loadTable = function() {
+            Artemis.log.debug("loading table")
+            ctrl.isLoading = true;
+            var objName;
+            if (workspace.selection) {
+                objName = workspace.selection.objectName;
+            } else {
+                // in case of refresh
+                var key = location.search()['nid'];
+                var node = workspace.keyToNodeMap[key];
+                objName = node.objectName;
+            }
+            if (objName) {
+                ctrl.dlq = false;
+                var queueName = jolokia.getAttribute(objName, "Name");
+                var artemisDLQ = localStorage['artemisDLQ'] || "DLQ";
+                var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue";
+                Artemis.log.debug("loading table" + artemisExpiryQueue);
+                if (queueName == artemisDLQ || queueName == artemisExpiryQueue) {
+                    onDlq(true);
+                } else {
+                    onDlq(false);
+                }
+                jolokia.request({ type: 'exec', mbean: objName, operation: 'countMessages()'}, Core.onSuccess(function(response) { ctrl.pagination.page(response.value); }));
+                jolokia.request({ type: 'exec', mbean: objName, operation: 'browse(int, int, java.lang.String)', arguments: [ctrl.pagination.pageNumber, ctrl.pagination.pageSize, ctrl.filter] }, Core.onSuccess(populateTable));
+            }
+        }
+
+        function onDlq(response) {
+            Artemis.log.debug("onDLQ=" + response);
+            ctrl.dlq = response;
+            Core.$apply($scope);
+        }
+
+        function operationSuccess() {
+            ctrl.messageDialog = false;
+            Core.notification("success", ctrl.message);
+            ctrl.pagination.load();
+        }
+
+        function intermediateResult() {
+        }
+
+
+        function moveSuccess() {
+            operationSuccess();
+            workspace.loadTree();
+        }
+
+        function filterMessages(filter) {
+            var searchConditions = buildSearchConditions(filter);
+            evalFilter(searchConditions);
+        }
+
+        function applyFilters(filters) {
+            Artemis.log.debug("filters " + filters);
+            ctrl.messages = [];
+            if (filters && filters.length > 0) {
+                ctrl.allMessages.forEach(function (message) {
+                    if (matchesFilters(message, filters)) {
+                        ctrl.messages.push(message);
+                    }
+                });
+            } else {
+                ctrl.messages = ctrl.allMessages;
+            }
+        };
+
+        var matchesFilter = function (message, filter) {
+            var match = true;
+
+            if (filter.id === 'messageID') {
+                match = message.messageID.match(filter.value) !== null;
+            } else if (filter.id === 'body') {
+                match = message.bodyText.match(filter.value) !== null;
+            }  else if (filter.id === 'properties') {
+                match = message.PropertiesText.match(filter.value) !== null;
+            } else if (filter.id === 'priority') {
+                match = message.priority == filter.value;
+            } else if (filter.id === 'redelivered') {
+                var filterTrue = filter.value == 'true';
+                match = (message.redelivered == filterTrue);
+            }
+            return match;
+        };
+
+        var matchesFilters = function (message, filters) {
+            var matches = true;
+
+            filters.forEach(function(filter) {
+
+                Artemis.log.debug("filter " + filter.id);
+                if (!matchesFilter(message, filter)) {
+                    matches = false;
+                    return false;
+                }
+            });
+            return matches;
+        };
+
+      function evalFilter(searchConditions) {
+         if (!searchConditions || searchConditions.length === 0) {
+            $scope.messages = ctrl.allMessages;
+         } else {
+            Artemis.log.debug("Filtering conditions:", searchConditions);
+            $scope.messages = ctrl.allMessages.filter(function(message) {
+               Artemis.log.debug("Message:", message);
+               var matched = true;
+               $.each(searchConditions, function(index, condition) {
+                  if (!condition.column) {
+                     matched = matched && evalMessage(message, condition.regex);
+                  } else {
+                     matched = matched && (message[condition.column] && condition.regex.test(message[condition.column])) || (message.StringProperties && message.StringProperties[condition.column] && condition.regex.test(message.StringProperties[condition.column]));
+                  }
+               });
+               return matched;
+            });
+         }
+      }
+
+      function evalMessage(message, regex) {
+         var jmsHeaders = ['JMSDestination', 'JMSDeliveryMode', 'JMSExpiration', 'JMSPriority', 'JMSmessageID', 'JMSTimestamp', 'JMSCorrelationID', 'JMSReplyTo', 'JMSType', 'JMSRedelivered'];
+         for (var i = 0; i < jmsHeaders.length; i++) {
+            var header = jmsHeaders[i];
+            if (message[header] && regex.test(message[header])) {
+               return true;
+            }
+         }
+         if (message.StringProperties) {
+            for ( var property in message.StringProperties) {
+               if (regex.test(message.StringProperties[property])) {
+                  return true;
+               }
+            }
+         }
+         if (message.bodyText && regex.test(message.bodyText)) {
+            return true;
+         }
+         return false;
+      }
+
+      function getRegExp(str, modifiers) {
+         try {
+            return new RegExp(str, modifiers);
+         } catch (err) {
+            return new RegExp(str.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\\|\||\.|\*|\+|\?)/g, '\\$1'));
+         }
+      }
+
+      function buildSearchConditions(filterText) {
+         var searchConditions = [];
+         var qStr;
+         if (!(qStr = $.trim(filterText))) {
+            return;
+         }
+         var columnFilters = qStr.split(";");
+         for (var i = 0; i < columnFilters.length; i++) {
+            var args = columnFilters[i].split(':');
+            if (args.length > 1) {
+               var columnName = $.trim(args[0]);
+               var columnValue = $.trim(args[1]);
+               if (columnName && columnValue) {
+                  searchConditions.push({
+                     column: columnName,
+                     columnDisplay: columnName.replace(/\s+/g, '').toLowerCase(),
+                     regex: getRegExp(columnValue, 'i')
+                  });
+               }
+            } else {
+               var val = $.trim(args[0]);
+               if (val) {
+                  searchConditions.push({
+                     column: '',
+                     regex: getRegExp(val, 'i')
+                  });
+               }
+            }
+         }
+         return searchConditions;
+      }
+      ctrl.pagination.setOperation(ctrl.loadTable);
+      ctrl.pagination.load();
+   }
+    BrowseQueueController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/connections.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/connections.js
new file mode 100644
index 0000000..f6f2a8e
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/connections.js
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis.log.info("loading connections");
+    Artemis._module.component('artemisConnections', {
+        template:
+            `
+            <h1>Browse Connections
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'connections-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+            <div ng-include="'plugin/artemistoolbar.html'"></div>
+            <pf-table-view config="$ctrl.tableConfig"
+                            columns="$ctrl.tableColumns"
+                            action-buttons="$ctrl.tableActionButtons"
+                            items="$ctrl.connections">
+            </pf-table-view>
+            <div ng-include="'plugin/artemispagination.html'"></div>
+            <div hawtio-confirm-dialog="$ctrl.closeDialog" title="Close Connection?"
+                ok-button-text="Close"
+                cancel-button-text="Cancel"
+                on-ok="$ctrl.closeConnection()">
+                 <div class="dialog-body">
+                    <p class="alert alert-warning">
+                        <span class="pficon pficon-warning-triangle-o"></span>
+                        You are about to close the selected connection: {{$ctrl.connectionToDelete}}
+                        <p>Are you sure you want to continue.</p>
+                    </p>
+                 </div>
+              </div>
+            <script type="text/ng-template" id="connections-instructions.html">
+            <div>
+                <p>
+                    This page allows you to browse all connections currently connected to the broker, including client, cluster
+                    and bridge connections. These can be narrowed down by specifying a filter and also sorted using the sort
+                    function in the toolbar. To execute a query click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    Connections can be closed by using the <code>close</code> button under the <code>Actions</code> column and you can
+                    navigate to the connections sessions open by clicking on the <code>Session Count</code> field.
+                  </p>
+                  <p>
+                    Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
+                  </p>
+                </div>
+            </script>
+            `,
+              controller: ConnectionsController
+    })
+    .name;
+
+
+    function ConnectionsController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisConnection, artemisSession) {
+        var ctrl = this;
+        ctrl.pagination = pagination;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+        ctrl.allConnections = [];
+        ctrl.connections = [];
+        ctrl.pageNumber = 1;
+        ctrl.workspace = workspace;
+        ctrl.refreshed = false;
+        ctrl.connectionToDelete = '';
+        ctrl.closeDialog = false;
+        ctrl.filter = {
+            fieldOptions: [
+                {id: 'CONNECTION_ID', name: 'ID'},
+                {id: 'CLIENT_ID', name: 'Client ID'},
+                {id: 'USERS', name: 'Users'},
+                {id: 'PROTOCOL', name: 'Protocol'},
+                {id: 'SESSION_COUNT', name: 'Session Count'},
+                {id: 'REMOTE_ADDRESS', name: 'Remote Address'},
+                {id: 'LOCAL_ADDRESS', name: 'Local Address'},
+                {id: 'SESSION_ID', name: 'Session ID'}
+            ],
+            operationOptions: [
+                {id: 'EQUALS', name: 'Equals'},
+                {id: 'CONTAINS', name: 'Contains'},
+                {id: 'GREATER_THAN', name: 'Greater Than'},
+                {id: 'LESS_THAN', name: 'Less Than'}
+            ],
+            sortOptions: [
+                {id: 'asc', name: 'ascending'},
+                {id: 'desc', name: 'descending'}
+            ],
+            values: {
+                field: "",
+                operation: "",
+                value: "",
+                sortOrder: "asc",
+                sortColumn: "connectionID"
+            }
+        };
+
+        ctrl.tableActionButtons = [
+          {
+            name: 'Close',
+            title: 'Close the Connection',
+            actionFn: openCloseDialog
+          }
+        ];
+
+        ctrl.tableConfig = {
+            selectionMatchProp: 'connectionID',
+            showCheckboxes: false
+        };
+        ctrl.tableColumns = [
+            { header: 'ID', itemField: 'connectionID' },
+            { header: 'Client ID', itemField: 'clientID' },
+            { header: 'Users', itemField: 'users' },
+            { header: 'protocol', itemField: 'protocol' },
+            { header: 'Session Count', itemField: 'sessionCount', templateFn: function(value, item) { return '<a href="#" onclick="selectSessions(\'' + item.connectionID + '\')">' + value + '</a>' }},
+            { header: 'Remote Address', itemField: 'remoteAddress' },
+            { header: 'Local Address', itemField: 'localAddress' },
+            { header: 'Creation Time', itemField: 'creationTime' }
+        ];
+
+        selectSessions = function (connection) {
+            Artemis.log.info("navigating to connection:" + connection)
+            artemisConnection.connection = { connectionID: connection };
+            $location.path("artemis/artemisSessions");
+        };
+
+        if (artemisSession.session) {
+            Artemis.log.info("navigating to session = " + artemisSession.session.connectionID);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[0].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisSession.session.connectionID;
+        }
+
+        ctrl.refresh = function () {
+            ctrl.refreshed = true;
+            ctrl.pagination.load();
+        };
+        ctrl.reset = function () {
+            ctrl.filter.values.field = "";
+            ctrl.filter.values.operation = "";
+            ctrl.filter.values.value = "";
+            ctrl.filter.sortOrder = "asc";
+            ctrl.filter.sortColumn = "connectionID";
+            ctrl.filter.text.fieldText = "Filter Field..";
+            ctrl.filter.text.operationText = "Operation..";
+            ctrl.filter.text.sortOrderText = "ascending";
+            ctrl.filter.text.sortByText = "ID";
+            ctrl.refreshed = true;
+            artemisSession.session = null;
+            ctrl.pagination.load();
+        };
+
+        ctrl.loadOperation = function () {
+            if (mbean) {
+                var method = 'listConnections(java.lang.String, int, int)';
+                var connectionsFilter = {
+                    field: ctrl.filter.values.field,
+                    operation: ctrl.filter.values.operation,
+                    value: ctrl.filter.values.value,
+                    sortOrder: ctrl.filter.values.sortOrder,
+                    sortColumn: ctrl.filter.values.sortColumn
+                };
+
+                if (ctrl.refreshed == true) {
+                    ctrl.pagination.reset();
+                    ctrl.refreshed = false;
+                }
+                Artemis.log.info(JSON.stringify(connectionsFilter));
+                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(connectionsFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
+            }
+        };
+
+        function openCloseDialog(action, item) {
+            ctrl.connectionToDelete = item.connectionID;
+            ctrl.closeDialog = true;
+        }
+
+        ctrl.closeConnection = function () {
+           Artemis.log.info("closing connection: " + ctrl.connectionToDelete);
+              if (mbean) {
+                  jolokia.request({ type: 'exec',
+                     mbean: mbean,
+                     operation: 'closeConnectionWithID(java.lang.String)',
+                     arguments: [ctrl.connectionToDelete] },
+                     Core.onSuccess(ctrl.pagination.load(), { error: function (response) {
+                        Core.defaultJolokiaErrorHandler("Could not close connection: " + response);
+                 }}));
+           }
+        };
+
+        pagination.setOperation(ctrl.loadOperation);
+
+        function onError(response) {
+            Core.notification("error", "could not invoke list connections" + response.error);
+            $scope.workspace.selectParentNode();
+        };
+
+        function populateTable(response) {
+            var data = JSON.parse(response.value);
+            ctrl.connections = [];
+            angular.forEach(data["data"], function (value, idx) {
+                ctrl.connections.push(value);
+            });
+            ctrl.pagination.page(data["count"]);
+            allConnections = ctrl.connections;
+            ctrl.connections = allConnections;
+            Core.$apply($scope);
+        }
+
+        ctrl.pagination.load();
+    }
+    ConnectionsController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisConnection', 'artemisSession'];
+
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js
new file mode 100644
index 0000000..0a199de
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/consumers.js
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisConsumers', {
+        template:
+            `<h1>Browse Consumers
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'consumers-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+             <div ng-include="'plugin/artemistoolbar.html'"></div>
+             <pf-table-view config="$ctrl.tableConfig"
+                            columns="$ctrl.tableColumns"
+                            action-buttons="$ctrl.tableActionButtons"
+                            items="$ctrl.consumers">
+             </pf-table-view>
+             <div ng-include="'plugin/artemispagination.html'"></div>
+             <div hawtio-confirm-dialog="$ctrl.closeDialog" title="Close Consumer?"
+                  ok-button-text="Close"
+                  cancel-button-text="Cancel"
+                  on-ok="$ctrl.closeConsumer()">
+                  <div class="dialog-body">
+                      <p class="alert alert-warning">
+                          <span class="pficon pficon-warning-triangle-o"></span>
+                          You are about to close the selected consumer: {{$ctrl.consumerToDelete}}
+                          <p>Are you sure you want to continue.</p>
+                      </p>
+                  </div>
+             </div>
+             <script type="text/ng-template" id="consumers-instructions.html">
+             <div>
+                <p>
+                    This page allows you to browse all consumers currently open on the broker. These can be narrowed down
+                    by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
+                    click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    Consumers can be closed by using the <code>close</code> button under the <code>Actions</code> column and you can
+                    navigate to the consumers  session, address and queue by clicking on the appropriate field.
+                  </p>
+                  <p>
+                    Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
+                  </p>
+                </div>
+             </script>
+             `,
+              controller: ConsumersController
+    })
+    .name;
+
+
+    function ConsumersController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisConsumer, artemisQueue, artemisAddress, artemisSession) {
+        var ctrl = this;
+        ctrl.pagination = pagination;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+        ctrl.allConsumers = [];
+        ctrl.consumers = [];
+        ctrl.pageNumber = 1;
+        ctrl.workspace = workspace;
+        ctrl.refreshed = false;
+        ctrl.consumerToDeletesSession = '';
+        ctrl.consumerToDelete = '';
+        ctrl.closeDialog = false;
+        ctrl.filter = {
+            fieldOptions: [
+                {id: 'ID', name: 'ID'},
+                {id: 'SESSION_ID', name: 'Session ID'},
+                {id: 'CLIENT_ID', name: 'Client ID'},
+                {id: 'USER', name: 'User'},
+                {id: 'ADDRESS', name: 'Address'},
+                {id: 'QUEUE', name: 'Queue'},
+                {id: 'PROTOCOL', name: 'Protocol'},
+                {id: 'LOCAL_ADDRESS', name: 'Local Address'},
+                {id: 'REMOTE_ADDRESS', name: 'Remote Address'}
+            ],
+            operationOptions: [
+                {id: 'EQUALS', name: 'Equals'},
+                {id: 'CONTAINS', name: 'Contains'},
+                {id: 'GREATER_THAN', name: 'Greater Than'},
+                {id: 'LESS_THAN', name: 'Less Than'}
+            ],
+            sortOptions: [
+                {id: 'asc', name: 'ascending'},
+                {id: 'desc', name: 'descending'}
+            ],
+            values: {
+                field: "",
+                operation: "",
+                value: "",
+                sortOrder: "asc",
+                sortColumn: "id"
+            },
+            text: {
+                fieldText: "Filter Field..",
+                operationText: "Operation..",
+                sortOrderText: "ascending",
+                sortByText: "ID"
+            }
+        };
+
+        ctrl.tableActionButtons = [
+           {
+            name: 'Close',
+            title: 'Close the Consumer',
+            actionFn: openCloseDialog
+           }
+        ];
+        ctrl.tableConfig = {
+            selectionMatchProp: 'id',
+            showCheckboxes: false
+        };
+        ctrl.tableColumns = [
+            { header: 'ID', itemField: 'id' },
+            { header: 'Session', itemField: 'session' , templateFn: function(value, item) { return '<a href="#" onclick="selectSession(\'' + item.session + '\')">' + value + '</a>' }},
+            { header: 'Client ID', itemField: 'clientID' },
+            { header: 'Protocol', itemField: 'protocol' },
+            { header: 'Queue', itemField: 'queue', templateFn: function(value, item) { return '<a href="#" onclick="selectQueue(\'' + item.queue + '\')">' + value + '</a>' }},
+            { header: 'queueType', itemField: 'queueType' },
+            { header: 'Filter', itemField: 'filter' },
+            { header: 'Address', itemField: 'address' , templateFn: function(value, item) { return '<a href="#" onclick="selectAddress(\'' + item.address + '\')">' + value + '</a>' }},
+            { header: 'Remote Address', itemField: 'remoteAddress' },
+            { header: 'Local Address', itemField: 'localAddress' },
+            { header: 'Creation Time', itemField: 'creationTime' }
+        ];
+
+        ctrl.refresh = function () {
+            ctrl.refreshed = true;
+            ctrl.pagination.load();
+        };
+        ctrl.reset = function () {
+            ctrl.filter.values.field = "";
+            ctrl.filter.values.operation = "";
+            ctrl.filter.values.value = "";
+            ctrl.filter.sortOrder = "asc";
+            ctrl.filter.sortColumn = "id";
+            ctrl.filter.text.fieldText = "Filter Field..";
+            ctrl.filter.text.operationText = "Operation..";
+            ctrl.filter.text.sortOrderText = "ascending";
+            ctrl.filter.text.sortByText = "ID";
+            ctrl.refreshed = true;
+            artemisConsumer.consumer = null;
+            ctrl.pagination.load();
+        };
+
+        if (artemisConsumer.consumer) {
+            Artemis.log.info("navigating to consumer = " + artemisConsumer.consumer.sessionID);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisConsumer.consumer.sessionID;
+        }
+
+        selectQueue = function (queue) {
+            Artemis.log.info("navigating to queue:" + queue)
+            artemisQueue.queue = { queue: queue };
+            $location.path("artemis/artemisQueues");
+        };
+
+        selectAddress = function (address) {
+            Artemis.log.info("navigating to address:" + address)
+            artemisAddress.address = { address: address };
+            $location.path("artemis/artemisAddresses");
+        };
+
+        selectSession = function (session) {
+            Artemis.log.info("navigating to session:" + session)
+            artemisSession.session = { session: session };
+            $location.path("artemis/artemisSessions");
+        };
+
+        function openCloseDialog(action, item) {
+            ctrl.consumerToDelete = item.id;
+            ctrl.consumerToDeletesSession = item.session;
+            ctrl.closeDialog = true;
+        }
+
+        ctrl.closeConsumer = function () {
+           Artemis.log.info("closing session: " + ctrl.consumerToDelete);
+              if (mbean) {
+                  jolokia.request({ type: 'exec',
+                     mbean: mbean,
+                     operation: 'closeConsumerWithID(java.lang.String,java.lang.String)',
+                     arguments: [ctrl.consumerToDeletesSession, ctrl.consumerToDelete] },
+                     Core.onSuccess(ctrl.pagination.load(), { error: function (response) {
+                        Core.defaultJolokiaErrorHandler("Could not close session: " + response);
+                 }}));
+           }
+        };
+        ctrl.loadOperation = function () {
+            if (mbean) {
+                var method = 'listConsumers(java.lang.String, int, int)';
+                var sessionsFilter = {
+                    field: ctrl.filter.values.field,
+                    operation: ctrl.filter.values.operation,
+                    value: ctrl.filter.values.value,
+                    sortOrder: ctrl.filter.values.sortOrder,
+                    sortColumn: ctrl.filter.values.sortColumn
+                };
+
+                if (ctrl.refreshed == true) {
+                    ctrl.pagination.reset();
+                    ctrl.refreshed = false;
+                }
+                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(sessionsFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
+            }
+        };
+
+        ctrl.pagination.setOperation(ctrl.loadOperation);
+
+        function onError(response) {
+            Core.notification("error", "could not invoke list sessions" + response.error);
+            $scope.workspace.selectParentNode();
+        };
+
+        function populateTable(response) {
+            var data = JSON.parse(response.value);
+            ctrl.consumers = [];
+            angular.forEach(data["data"], function (value, idx) {
+                ctrl.consumers.push(value);
+            });
+            ctrl.pagination.page(data["count"]);
+            allConsumers = ctrl.consumers;
+            ctrl.consumers = allConsumers;
+            Core.$apply($scope);
+        }
+
+        ctrl.pagination.load();
+    }
+    ConsumersController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisConsumer', 'artemisQueue', 'artemisAddress', 'artemisSession'];
+
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/createAddress.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/createAddress.js
new file mode 100644
index 0000000..5e06f15
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/createAddress.js
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisCreateAddress', {
+        template:
+            `
+             <h1>Create Address
+                 <button type="button" class="btn btn-link jvm-title-popover"
+                           uib-popover-template="'create-address-instructions.html'" popover-placement="bottom-left"
+                           popover-title="Instructions" popover-trigger="'outsideClick'">
+                     <span class="pficon pficon-help"></span>
+                 </button>
+             </h1>
+             <form class="form-horizontal">
+
+                 <div class="form-group">
+                     <label class="col-sm-2 control-label" for="name-markup">Address name</label>
+
+                     <div class="col-sm-10">
+                         <input id="name-markup" class="form-control" type="text" maxlength="300"
+                                name="addressName" ng-model="$ctrl.addressName" placeholder="Address name"/>
+                     </div>
+                 </div>
+                 <div class="form-group">
+                     <label class="col-sm-2 control-label">Routing type</label>
+
+                     <div class="col-sm-10">
+                         <label class="checkbox">
+                             <input type="radio" ng-model="$ctrl.routingType" value="Multicast"> Multicast
+                         </label>
+                         <label class="checkbox">
+                             <input type="radio" ng-model="$ctrl.routingType" value="Anycast"> Anycast
+                         </label>
+                         <label class="checkbox">
+                             <input type="radio" ng-model="$ctrl.routingType" value="Both"> Both
+                         </label>
+                     </div>
+                 </div>
+
+                 <div class="form-group">
+                     <div class="col-sm-offset-2 col-sm-10">
+                         <button type="submit" class="btn btn-primary"
+                                 ng-click="$ctrl.createAddress($ctrl.addressName, $ctrl.routingType)"
+                                 ng-disabled="!$ctrl.addressName">Create Address
+                         </button>
+                     </div>
+                 </div>
+
+                 <div hawtio-confirm-dialog="$ctrl.createDialog"
+                      ok-button-text="Create"
+                      cancel-button-text="Cancel"
+                      on-ok="$ctrl.createAddress($ctrl.addressName, $ctrl.routingType)">
+                     <div class="dialog-body">
+                         <p>Address name <b>{{$ctrl.addressName}}</b> contains unrecommended characters: <code>:</code></p>
+                         <p>This may cause unexpected problems. Are you really sure to create this {{$ctrl.uncapitalisedDestinationType()}}?</p>
+                     </div>
+                 </div>
+
+             </form>
+             <script type="text/ng-template" id="create-address-instructions.html">
+             <div>
+                <p>
+                    This page allows you to create a new address on the broker, if you want the address to support JMS like
+                    queues, i.e. point to point, then choose anycast. If you want your address to support JMS like topic
+                    subscriptions, publish/subscribe, then choose multicast.
+                </p>
+                </div>
+             </script>
+        `,
+        controller: CreateAddressController
+    })
+    .name;
+    Artemis.log.info("loaded address " + Artemis.addressModule);
+
+    function CreateAddressController($scope, workspace, jolokia, localStorage) {
+        Artemis.log.info("loaded address controller");
+        var ctrl = this;
+        ctrl.addressName = "";
+        ctrl.routingType = "Anycast";
+        ctrl.workspace = workspace;
+        ctrl.message = "";
+
+        $scope.$watch('workspace.selection', function () {
+            workspace.moveIfViewInvalid();
+        });
+
+        function operationSuccess() {
+            ctrl.addressName = "";
+            ctrl.workspace.operationCounter += 1;
+            Core.$apply($scope);
+            Core.notification("success", $scope.message);
+            ctrl.workspace.loadTree();
+        }
+
+        function onError(response) {
+            Core.notification("error", "Could not create address: " + response.error);
+        }
+
+        ctrl.createAddress = function (name, routingType) {
+            Artemis.log.info("creating " + routingType);
+            var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+            if (mbean) {
+                if (routingType == "Multicast") {
+                    $scope.message = "Created  Multicast Address " + name;
+                    Artemis.log.info(ctrl.message);
+                    jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, "MULTICAST",  Core.onSuccess(operationSuccess, { error: onError }));
+                }
+                else if (routingType == "Anycast") {
+                    $scope.message = "Created Anycast Address " + name;
+                    Artemis.log.info(ctrl.message);
+                    jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, "ANYCAST",  Core.onSuccess(operationSuccess, { error: onError }));
+                }
+                else {
+                    $scope.message = "Created Anycast/Multicast Address " + name;
+                    Artemis.log.info(ctrl.message);
+                    jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, "ANYCAST,MULTICAST",  Core.onSuccess(operationSuccess, { error: onError }));
+                }
+            }
+        };
+    }
+    CreateAddressController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/createQueue.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/createQueue.js
new file mode 100644
index 0000000..cb19cd8
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/createQueue.js
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisCreateQueue', {
+        template:
+            `
+             <h1>Create Queue
+                 <button type="button" class="btn btn-link jvm-title-popover"
+                           uib-popover-template="'create-queue-instructions.html'" popover-placement="bottom-left"
+                           popover-title="Instructions" popover-trigger="'outsideClick'">
+                     <span class="pficon pficon-help"></span>
+                 </button>
+             </h1>
+             <form class="form-horizontal">
+
+                 <div class="form-group">
+                     <label class="col-sm-2 control-label" for="name-markup">Queue name</label>
+
+                     <div class="col-sm-10">
+                         <input id="name-markup" class="form-control" type="text" maxlength="300"
+                                name="queueName" ng-model="$ctrl.queueName" placeholder="Queue name"/>
+                     </div>
+                 </div>
+                 <div class="form-group">
+                     <label class="col-sm-2 control-label">Routing type</label>
+
+                     <div class="col-sm-10">
+                         <label class="checkbox">
+                             <input type="radio" ng-model="$ctrl.routingType" value="Anycast"> Anycast
+                         </label>
+                         <label class="checkbox">
+                             <input type="radio" ng-model="$ctrl.routingType" value="Multicast"> Multicast
+                         </label>
+                     </div>
+                 </div>
+
+                 <div class="form-group">
+                     <label class="col-sm-2 control-label">Durable</label>
+
+                     <div class="col-sm-10">
+                         <label class="checkbox">
+                             <input type="checkbox" ng-model="$ctrl.durable">
+                         </label>
+                     </div>
+                 </div>
+
+                 <div class="form-group">
+                    <label class="col-sm-2 control-label" for="filter-markup">Filter</label>
+
+                    <div class="col-sm-10">
+                        <input id="filter-markup" class="form-control" type="text" maxlength="300"
+                         name="filter" ng-model="$ctrl.filter" placeholder="Filter"/>
+                    </div>
+                 </div>
+
+                 <div class="form-group">
+                    <label class="col-sm-2 control-label" for="maxConsumers-markup">Max consumers</label>
+
+                    <div class="col-sm-10">
+                        <input id="maxConsumers-markup" class="form-control" type="integer" maxlength="300"
+                         name="filter" ng-model="$ctrl.maxConsumers" placeholder="Max consumers"/>
+                    </div>
+                 </div>
+
+                 <div class="form-group">
+                    <label class="col-sm-2 control-label">Purge when no consumers</label>
+
+                    <div class="col-sm-10">
+                         <label class="checkbox">
+                         <input type="checkbox" ng-model="$ctrl.purgeWhenNoConsumers">
+                    </label>
+                 </div>
+
+                 <div class="form-group">
+                     <div class="col-sm-offset-2 col-sm-10">
+                         <button type="submit" class="btn btn-primary"
+                                 ng-click="$ctrl.createQueue($ctrl.queueName, $ctrl.routingType, $ctrl.durable, $ctrl.filter, $ctrl.maxConsumers, $ctrl.purgeWhenNoConsumers)"
+                                 ng-disabled="!$ctrl.queueName">Create Queue
+                         </button>
+                     </div>
+                 </div>
+
+                 <div hawtio-confirm-dialog="$ctrl.createDialog"
+                      ok-button-text="Create"
+                      cancel-button-text="Cancel"
+                      on-ok="$ctrl.createQueue($ctrl.queueName, $ctrl.routingType, $ctrl.durable, $ctrl.filter, $ctrl.maxConsumers, $ctrl.purgeWhenNoConsumers)">
+                     <div class="dialog-body">
+                         <p>Queue name <b>{{$ctrl.queueName}}</b> contains unrecommended characters: <code>:</code></p>
+                         <p>This may cause unexpected problems. Are you really sure to create this {{$ctrl.uncapitalisedDestinationType()}}?</p>
+                     </div>
+                 </div>
+
+             </form>
+             <script type="text/ng-template" id="create-queue-instructions.html">
+             <div>
+                <p>
+                    This page allows you to create a queue bound to the chosen address.
+                </p>
+                <p>
+                    if you want the queue to support JMS like queues, i.e. point to point, then choose anycast. If you
+                    want your address to support JMS like topic subscriptions, publish/subscribe, then choose multicast.
+                  </p>
+                  <p>
+                    Selecting durable means that the queue will survive a restart of the broker.
+                  </p>
+                  <p>
+                    Adding a filter expression will mean that only messages that match that filter will be routed to this queue:
+                    see <a href="https://activemq.apache.org/components/artemis/documentation/latest/filter-expressions.html" target="_blank">Filter Expressions</a>
+                  </p>
+                  <p>
+                    Max consumers will limit how many consumers can consume from a queue at any one time, -1 means no limit.
+                  </p>
+                  <p>
+                    Purge on no consumers means the queue will not start receiving messages until a consumer is attached.
+                    When the last consumer is detached from the queue.  The queue is purged (its messages are removed)
+                    and will not receive any more messages until a new consumer is attached.
+                  </p>
+                </div>
+             </script>
+        `,
+        controller: CreateQueueController
+    })
+    .name;
+    Artemis.log.debug("loaded queue " + Artemis.createQueueModule);
+
+    function CreateQueueController($scope, workspace, jolokia, localStorage) {
+        Artemis.log.debug("loaded queue controller");
+        var ctrl = this;
+        Core.initPreferenceScope($scope, localStorage, {
+            'durable': {
+                'value': true,
+                'converter': Core.parseBooleanValue
+            },
+            'maxConsumers': {
+                'value': -1,
+                'converter': parseInt,
+                'formatter': parseInt
+            },
+            'purgeWhenNoConsumers': {
+                'value': false,
+                'converter': Core.parseBooleanValue
+            }
+        });
+        var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
+        ctrl.workspace = workspace;
+        ctrl.maxConsumers = -1;
+        ctrl.routingType = "Anycast";
+        ctrl.filter = "";
+        ctrl.purgeWhenNoConsumers = false;
+        ctrl.durable = true;
+        ctrl.queueName = '';
+
+        $scope.$watch('workspace.selection', function () {
+            workspace.moveIfViewInvalid();
+        });
+
+        function operationSuccess() {
+            ctrl.queueName = "";
+            ctrl.workspace.operationCounter += 1;
+            Core.$apply($scope);
+            Core.notification("success", $scope.message);
+            ctrl.workspace.loadTree();
+        }
+        function onError(response) {
+            Core.notification("error", "Could not create queue: " + response.error);
+        }
+        this.createQueue = function (queueName, routingType, durable, filter, maxConsumers, purgeWhenNoConsumers) {
+            var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+            if (mbean) {
+                var selection = workspace.selection;
+                var entries = selection.entries;
+                var address = entries["address"];
+                if (address.charAt(0) === '"' && address.charAt(address.length -1) === '"')
+                {
+                    address = address.substr(1,address.length -2);
+                }
+                $scope.message = "Created queue " + queueName + " durable=" + durable + " filter=" + filter + " routing type=" + routingType + " max consumers=" + maxConsumers + " purge..=" + purgeWhenNoConsumers + " on address " + address;
+                if (routingType == "Multicast") {
+                    Artemis.log.debug($scope.message);
+                    jolokia.execute(mbean, "createQueue(java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,int,boolean,boolean)", address, "MULTICAST", queueName, filter, durable, maxConsumers, purgeWhenNoConsumers, true, Core.onSuccess(operationSuccess, { error: onError }));
+                } else {
+                   Artemis.log.debug($scope.message);
+                   jolokia.execute(mbean, "createQueue(java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,int,boolean,boolean)", address, "ANYCAST", queueName, filter, durable, maxConsumers, purgeWhenNoConsumers, true, Core.onSuccess(operationSuccess, { error: onError }));
+                }
+            }
+        };
+    }
+    CreateQueueController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/deleteAddress.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/deleteAddress.js
new file mode 100644
index 0000000..1c382b7
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/deleteAddress.js
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisDeleteAddress', {
+        template:
+            `
+             <h1>Delete Address
+                 <button type="button" class="btn btn-link jvm-title-popover"
+                           uib-popover-template="'delete-address-instructions.html'" popover-placement="bottom-left"
+                           popover-title="Instructions" popover-trigger="'outsideClick'">
+                     <span class="pficon pficon-help"></span>
+                 </button>
+             </h1>
+             <p>
+               <div class="alert alert-warning">
+                 <span class="pficon pficon-warning-triangle-o"></span>
+                 This operation cannot be undone. Please be careful!
+               </div>
+             </p>
+
+             <h2>Delete address</h2>
+             <p>Remove the address completely.</p>
+             <button type="submit" class="btn btn-danger" ng-click="$ctrl.deleteDialog = true">
+               Delete address
+             </button>
+
+             <div hawtio-confirm-dialog="$ctrl.deleteDialog"
+                  title="Confirm delete address"
+                  ok-button-text="Delete"
+                  cancel-button-text="Cancel"
+                  on-ok="$ctrl.deleteAddress()">
+               <div class="dialog-body">
+                 <p>You are about to delete address <b>{{ $ctrl.selectedName() }}</b>.</p>
+                 <p>This operation cannot be undone so please be careful.</p>
+               </div>
+             </div>
+             <script type="text/ng-template" id="delete-address-instructions.html">
+             <div>
+                <p>
+                    This page allows you to delete the chosen address on the broker.
+                </p>
+                <p>
+                    Note that this will only succeed if the address has no queues bound to it.
+                </p>
+                </div>
+             </script>
+        `,
+        controller: DeleteAddressController
+    })
+    .name;
+    Artemis.log.debug("loaded address " + Artemis.addressModule);
+
+    function DeleteAddressController($scope, workspace, jolokia, localStorage) {
+        var ctrl = this;
+        ctrl.workspace = workspace;
+        ctrl.deleteDialog = false;
+
+        $onInit = function () {
+            Artemis.log.debug("loaded address controller");
+        }
+
+        $scope.$watch('workspace.selection', function () {
+            workspace.moveIfViewInvalid();
+        });
+
+        function operationSuccess() {
+            // lets set the selection to the parent
+            workspace.removeAndSelectParentNode();
+            ctrl.workspace.operationCounter += 1;
+            Core.$apply($scope);
+            Core.notification("success", $scope.message);
+            ctrl.workspace.loadTree();
+        }
+
+        function onError(response) {
+            Core.notification("error", "Could not delete address: " + response.error);
+        }
+
+        ctrl.deleteAddress = function () {
+            var selection = workspace.selection;
+            var entries = selection.entries;
+            var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+            Artemis.log.debug(mbean);
+            if (mbean) {
+                if (selection && jolokia && entries) {
+                    var domain = selection.domain;
+                    var name = entries["address"];
+                    Artemis.log.debug("name = " + name)
+                    name = Core.unescapeHTML(name);
+                    if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"')
+                    {
+                        name = name.substr(1,name.length -2);
+                    }
+                    name = Artemis.ownUnescape(name);
+                    Artemis.log.debug(name);
+                    var operation;
+                    $scope.message = "Deleted address " + name;
+                    jolokia.execute(mbean, "deleteAddress(java.lang.String)", name,  Core.onSuccess(operationSuccess, { error: onError }));
+                }
+            }
+        };
+
+        ctrl.selectedName = function () {
+            var selection = ctrl.workspace.selection;
+            return selection ? _.unescape(selection.text) : null;
+        };
+    }
+    DeleteAddressController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/deleteQueue.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/deleteQueue.js
new file mode 100644
index 0000000..6b1143c
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/deleteQueue.js
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisDeleteQueue', {
+        template:
+            `<p>
+               <div class="alert alert-warning">
+                 <span class="pficon pficon-warning-triangle-o"></span>
+                 These operations cannot be undone. Please be careful!
+               </div>
+             </p>
+
+             <h2>Delete queue
+                 <button type="button" class="btn btn-link jvm-title-popover"
+                           uib-popover-template="'delete-queue-instructions.html'" popover-placement="bottom-left"
+                           popover-title="Instructions" popover-trigger="'outsideClick'">
+                     <span class="pficon pficon-help"></span>
+                 </button>
+             </h2>
+             <p>Remove the queue completely.</p>
+             <button type="submit" class="btn btn-danger" ng-click="$ctrl.deleteDialog = true">
+               Delete Queue
+             </button>
+
+             <div hawtio-confirm-dialog="$ctrl.deleteDialog"
+                  title="Confirm delete address"
+                  ok-button-text="Delete"
+                  cancel-button-text="Cancel"
+                  on-ok="$ctrl.deleteQueue()">
+               <div class="dialog-body">
+                 <p>You are about to delete queue <b>{{$ctrl.selectedName()}}</b>.</p>
+                 <p>This operation cannot be undone so please be careful.</p>
+               </div>
+             </div>
+
+             <h2>Purge queue
+                 <button type="button" class="btn btn-link jvm-title-popover"
+                           uib-popover-template="'purge-queue-instructions.html'" popover-placement="bottom-left"
+                           popover-title="Instructions" popover-trigger="'outsideClick'">
+                     <span class="pficon pficon-help"></span>
+                 </button>
+             </h2>
+            <p>Remove all messages from queue.</p>
+            <button type="submit" class="btn btn-danger" ng-click="$ctrl.purgeDialog = true">
+            Purge Queue
+            </button>
+
+            <div hawtio-confirm-dialog="$ctrl.purgeDialog"
+               title="Confirm purge address"
+               ok-button-text="Purge"
+               cancel-button-text="Cancel"
+               on-ok="$ctrl.purgeQueue()">
+            <div class="dialog-body">
+              <p>You are about to purge queue <b>{{$ctrl.selectedName()}}</b>.</p>
+              <p>This operation cannot be undone so please be careful.</p>
+            </div>
+            </div>
+             <script type="text/ng-template" id="delete-queue-instructions.html">
+             <div>
+                <p>
+                    This will delete the queue and all of the messages it holds
+                </p>
+                </div>
+             </script>
+             <script type="text/ng-template" id="purge-queue-instructions.html">
+             <div>
+                <p>
+                    This will delete all of the messages held within the queue but will not delete the queue
+                </p>
+                </div>
+             </script>
+        `,
+        controller: DeleteQueueController
+    })
+    .name;
+    Artemis.log.info("loaded delete queue " + Artemis.createQueueModule);
+
+    function DeleteQueueController($scope, workspace, jolokia, localStorage) {
+        Artemis.log.info("loaded queue controller");
+        var ctrl = this;
+        ctrl.workspace = workspace;
+        ctrl.deleteDialog = false;
+        ctrl.purgeDialog = false;
+
+        $scope.$watch('workspace.selection', function () {
+            ctrl.workspace.moveIfViewInvalid();
+        });
+
+        function operationSuccess() {
+           // lets set the selection to the parent
+           ctrl.workspace.removeAndSelectParentNode();
+           ctrl.workspace.operationCounter += 1;
+           Core.$apply($scope);
+           Core.notification("success", $scope.message);
+           ctrl.workspace.loadTree();
+        }
+
+        function onError(response) {
+           Core.notification("error", "Could not delete address: " + response.error);
+        }
+
+       function operationPurgeSuccess() {
+           // lets set the selection to the parent
+           /*$scope.workspace.operationCounter += 1;
+           Core.$apply($scope);*/
+           Core.notification("success", $scope.message);
+       }
+
+      function onPurgeError(response) {
+          Core.notification("error", "Could not purge address: " + response.error);
+      }
+
+       this.deleteQueue = function () {
+           var selection = ctrl.workspace.selection;
+           var entries = selection.entries;
+           var mbean = Artemis.getBrokerMBean(ctrl.workspace, jolokia);
+           Artemis.log.info(mbean);
+           if (mbean) {
+               if (selection && jolokia && entries) {
+                   var domain = selection.domain;
+                   var name = entries["queue"];
+                   Artemis.log.info("name = " + name)
+                   name = Core.unescapeHTML(name);
+                   if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"')
+                   {
+                       name = name.substr(1,name.length -2);
+                   }
+                   name = Artemis.ownUnescape(name);
+                   Artemis.log.info(name);
+                   var operation;
+                   $scope.message = "Deleted queue " + name;
+                   jolokia.execute(mbean, "destroyQueue(java.lang.String)", name,  Core.onSuccess(operationPurgeSuccess, { error: onError }));
+               }
+           }
+       };
+
+        this.purgeQueue = function () {
+            var selection = ctrl.workspace.selection;
+            var entries = selection.entries;
+            var mbean = selection.objectName;
+            if (selection && jolokia && entries) {
+                var name = entries["Destination"] || entries["destinationName"] || selection.title;
+                name = Core.unescapeHTML(name);
+                $scope.message = "Purged queue " + name;
+                jolokia.execute(mbean, "removeAllMessages()", Core.onSuccess(operationSuccess, { error: onPurgeError }));
+            }
+        };
+
+        ctrl.selectedName = function () {
+            var selection = ctrl.workspace.selection;
+            return selection ? _.unescape(selection.text) : null;
+        };
+    }
+    DeleteQueueController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/diagram.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/diagram.js
new file mode 100644
index 0000000..0284f88
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/diagram.js
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisBrokerDiagram', {
+        template:
+            `<div class="container-topology">
+                <h1>Broker Diagram
+                    <button type="button" class="btn btn-link jvm-title-popover"
+                              uib-popover-template="'diagram-instructions.html'" popover-placement="bottom-left"
+                              popover-title="Instructions" popover-trigger="'outsideClick'">
+                        <span class="pficon pficon-help"></span>
+                    </button>
+                </h1>
+                <pf-topology items="$ctrl.data.items" relations="$ctrl.data.relations" kinds="$ctrl.kinds" icons="$ctrl.data.icons" nodes="$ctrl.nodes" item-selected="$ctrl.itemSelected(item)" search-text="searchText" show-labels="$ctrl.showLabels" tooltip-function="$ctrl.tooltip(node)">
+
+                <label>Show labels:
+                    <input type="checkbox" ng-model="$ctrl.showLabels">
+                </label>
+                 <label>Show addresses:
+                    <input type="checkbox" ng-model="$ctrl.showAddresses">
+                </label>
+                <label>Show queues:
+                    <input type="checkbox" ng-model="$ctrl.showQueues">
+                </label>
+                <label>Show internal addresses:
+                    <input type="checkbox" ng-model="$ctrl.showInternalAddresses">
+                </label>
+                <label>Show internal queues:
+                    <input type="checkbox" ng-model="$ctrl.showInternalQueues">
+                </label>
+                <button type="submit" class="btn btn-primary"
+                    ng-click="$ctrl.refresh()">Refresh
+                </button>
+            </div>
+            <div ng-show="$ctrl.showAttributes">
+                <pf-table-view
+                    config="$ctrl.config"
+                    columns="$ctrl.tableColumns"
+                    items="$ctrl.attributes">
+            </div>
+            <script type="text/ng-template" id="diagram-instructions.html">
+            <div>
+                <p>
+                    This page is a graphical representation of the cluster topology. It will show all the brokers in the cluster
+                    as well as well as any Adresses and Queues on the broker the console is connected to.
+                </p>
+                <p>
+                    It is possible to view the attributes of the addresses, queues and connected broker by left clicking
+                    on each node.
+                </p>
+                </div>
+            </script>
+        `,
+        controller: BrokerDiagramController
+    })
+    .name;
+
+
+    function BrokerDiagramController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter) {
+        Artemis.log.debug("loaded browse " + Artemis.browseQueueModule);
+        var ctrl = this;
+        ctrl.index = 0;
+        ctrl.showLabels = false;
+        ctrl.showAddresses = true;
+        ctrl.showQueues = true;
+        ctrl.showInternalAddresses = false;
+        ctrl.showInternalQueues = false;
+        $scope.$watch('$ctrl.showAddresses', function () {
+            if(ctrl.kinds.Address && !ctrl.showAddresses) {
+               delete ctrl.kinds.Address;
+            } else if (!ctrl.kinds.Address && ctrl.showAddresses) {
+                ctrl.kinds.Address = true;
+            }
+        });
+        $scope.$watch('$ctrl.showQueues', function () {
+            if(ctrl.kinds.Queue && !ctrl.showQueues) {
+               delete ctrl.kinds.Queue;
+            } else if (!ctrl.kinds.Queues && ctrl.showQueues) {
+                ctrl.kinds.Queue = true;
+            }
+        });
+        $scope.$watch('$ctrl.showInternalAddresses', function () {
+            if(ctrl.kinds.InternalAddress && !ctrl.showInternalAddresses) {
+               delete ctrl.kinds.InternalAddress;
+            } else if (!ctrl.kinds.InternalAddress && ctrl.showInternalAddresses) {
+                ctrl.kinds.InternalAddress = true;
+            }
+        });
+        $scope.$watch('$ctrl.showInternalQueues', function () {
+            if(ctrl.kinds.InternalQueue && !ctrl.showInternalQueues) {
+               delete ctrl.kinds.InternalQueue;
+            } else if (!ctrl.kinds.InternalQueues && ctrl.showInternalQueues) {
+                ctrl.kinds.InternalQueue = true;
+            }
+        });
+        ctrl.datasets = [];
+        //icons can be found at https://www.patternfly.org/v3/styles/icons/index.html
+        ctrl.serverIcon = "\ue90d";
+        Artemis.log.debug(ctrl.serverIcon);
+        ctrl.addressIcon = "";//\ue91a";
+        ctrl.queueIcon = "";//\ue90a";
+        ctrl.icons = {
+            "ThisBroker": {
+              "type": "glyph",
+              "icon": ctrl.serverIcon,
+              "background": "#456BD9",
+              "fontfamily": "PatternFlyIcons-webfont"
+            },
+            "MasterBroker": {
+              "type": "glyph",
+              "icon": ctrl.serverIcon,
+              "fontfamily": "PatternFlyIcons-webfont"
+            },
+            "SlaveBroker": {
+              "type": "glyph",
+              "icon": ctrl.serverIcon,
+              "fontfamily": "PatternFlyIcons-webfont"
+            },
+            "Address": {
+                "type": "glyph",
+                "icon": ctrl.addressIcon,
+                "fontfamily": "PatternFlyIcons-webfont"
+            },
+            "InternalAddress": {
+                "type": "glyph",
+                "icon": ctrl.addressIcon,
+                "fontfamily": "PatternFlyIcons-webfont"
+            },
+            "Queue": {
+                "type": "glyph",
+                "background": "#456BD9",
+                "icon": ctrl.queueIcon,
+                "fontfamily": "PatternFlyIcons-webfont"
+            },
+            "InternalQueue": {
+                "type": "glyph",
+                "background": "#456BD9",
+                "icon": ctrl.queueIcon,
+                "fontfamily": "PatternFlyIcons-webfont"
+            }
+        };
+
+        load();
+
+        function load() {
+            ctrl.items = {};
+
+            ctrl.relations = [];
+
+            ctrl.datasets.push({
+                "items": ctrl.items,
+                "relations": ctrl.relations,
+                "icons": ctrl.icons
+            });
+
+            Artemis.log.debug("index " + ctrl.index);
+
+            ctrl.data = ctrl.datasets[ctrl.index];
+
+            ctrl.data.url = "fooBar";
+
+            ctrl.kinds = {
+                "ThisBroker": true,
+                "MasterBroker": true,
+                "SlaveBroker": true,
+                "Address": true,
+                "Queue": true
+            };
+
+            ctrl.icons = ctrl.data.icons;
+
+            ctrl.nodes = {
+                "ThisBroker": {
+                     "name": "ThisBroker",
+                     "title": "hello",
+                     "enabled": true,
+                     "radius": 28,
+                     "textX": 0,
+                     "textY": 5,
+                     "height": 30,
+                     "width": 30,
+                     "icon": ctrl.icons["ThisBroker"].icon,
+                     "fontFamily": ctrl.icons["ThisBroker"].fontfamily
+                   },
+                "MasterBroker": {
+                    "name": "MasterBroker",
+                    "enabled": true,
+                    "radius": 28,
+                    "textX": 0,
+                    "textY": 5,
+                    "height": 30,
+                    "width": 30,
+                    "icon": ctrl.icons["MasterBroker"].icon,
+                    "fontFamily": ctrl.icons["MasterBroker"].fontfamily
+                },
+                "SlaveBroker": {
+                    "name": "SlaveBroker",
+                    "enabled": true,
+                    "radius": 28,
+                    "textX": 0,
+                    "textY": 5,
+                    "height": 30,
+                    "icon": ctrl.icons["SlaveBroker"].icon,
+                    "fontFamily": ctrl.icons["SlaveBroker"].fontfamily
+                },
+                "Address": {
+                    "name": "Address",
+                    "enabled": ctrl.showDestinations,
+                    "radius": 16,
+                    "textX": 0,
+                    "textY": 5,
+                    "height": 18,
+                    "width": 18,
+                    "icon": ctrl.icons["Address"].icon,
+                    "fontFamily": ctrl.icons["Address"].fontfamily
+                },
+                "Queue": {
+                    "name": "Queue",
+                    "enabled": ctrl.showDestinations,
+                    "radius": 16,
+                    "textX": 0,
+                    "textY": 5,
+                    "height": 18,
+                    "width": 18,
+                    "icon": ctrl.icons["Queue"].icon,
+                    "fontFamily": ctrl.icons["Queue"].fontfamily
+                }
+            };
+
+            ctrl.tableColumns = [
+                { header: 'attribute', itemField: 'attribute' },
+                { header: 'value', itemField: 'value' }
+            ];
+            ctrl.attributes = [];
+            ctrl.config = {
+                selectionMatchProp: 'attribute',
+                showCheckboxes: false
+            };
+            ctrl.showAttributes = false;
+            loadThisBroker();
+            Core.$apply($scope);
+        }
+        ctrl.itemSelected = function(item) {
+            ctrl.showAttributes = false;
+            ctrl.attributes = [];
+            if (!item || !item.mbean) {
+                Core.$apply($scope);
+                return;
+            }
+            var atts = jolokia.request({ type: "read", mbean: item.mbean}, {method: "post"});
+            var val = atts.value;
+            if (val) {
+                angular.forEach(val, function (value, key) {
+                    attribute = {
+                        "attribute": key,
+                        "value": value
+                    }
+                   ctrl.attributes.push(attribute);
+                });
+            }
+            ctrl.showAttributes = true;
+            Core.$apply($scope);
+        }
+        ctrl.tooltip = function (node) {
+            var status = [
+                'Name: ' + node.item.name,
+                'Type: ' + node.item.brokerKind
+            ];
+            return status;
+        }
+        ctrl.refresh = function () {
+            ctrl.datasets = [];
+            load();
+        }
+
+        function loadThisBroker() {
+            var mBean = Artemis.getBrokerMBean(workspace, jolokia);
+            var atts = jolokia.request({ type: "read", mbean: mBean}, {method: "post"});
+            var val = atts.value;
+            var details = Core.parseMBean(mBean);
+
+            if (details) {
+                var properties = details['attributes'];
+                Artemis.log.debug("Got broker: " + mBean + " properties: " + angular.toJson(properties, true));
+                if (properties) {
+                    var brokerAddress = properties["broker"] || "unknown";
+                    var brokerName = artemisJmxDomain + ":broker=" + brokerAddress;
+                    var backupRes = jolokia.request({ type: "read", mbean: mBean, attribute: "Backup"}, {method: "get"});
+
+                    var isBackup = backupRes.value;
+                    var nodeId = val["NodeID"];
+                    var response = jolokia.request({ type: 'exec', mbean: mBean, operation: 'listNetworkTopology()' }, Core.onSuccess(null));
+                    var responseValue = response.value;
+                    var remoteBrokers = angular.fromJson(responseValue);
+                    var thisBroker = remoteBrokers.find(broker => broker.nodeID == nodeId);
+                    if(!thisBroker) {
+                        if(isBackup) {
+                            thisBroker = {
+                                backup: "broker"
+                            };
+                        } else {
+                            thisBroker = {
+                                live: "broker"
+                            };
+                        }
+                    }
+                    if (thisBroker.live) {
+                        ctrl.items[thisBroker.live] = {
+                            "name": thisBroker.live,
+                            "kind": "ThisBroker",
+                            "brokerKind": "master",
+                            "status": "broker",
+                            "display_kind": "Server",
+                            "mbean": mBean
+                        }
+                    }
+                    if (thisBroker.backup) {
+                        ctrl.items[thisBroker.backup] = {
+                            "name": thisBroker.backup,
+                            "kind": "SlaveBroker",
+                            "brokerKind": "slave",
+                            "status": "broker",
+                            "display_kind": "Server"
+                        };
+                        if (thisBroker.live) {
+                            ctrl.relations.push({
+                                "source": thisBroker.live,
+                                "target": thisBroker.backup
+                            });
+                        }
+                    }
+                    createAddresses(mBean, thisBroker.live)
+                }
+
+                angular.forEach(remoteBrokers, function (remoteBroker) {
+                    if (nodeId != remoteBroker.nodeID) {
+                       if (remoteBroker.live) {
+                          ctrl.items[remoteBroker.live] = {
+                              "name": remoteBroker.live,
+                              "kind": "MasterBroker",
+                              "brokerKind": "master",
+                              "status": "broker",
+                              "display_kind": "Server"
+                          };
+                          //if we arent a backup then connect to it as we are in the cluster
+                          if(!isBackup) {}
+                              ctrl.relations.push({
+                                  "source": thisBroker.live,
+                                  "target": remoteBroker.live
+                              });
+                          }
+                          if (remoteBroker.backup) {
+                              ctrl.items[remoteBroker.backup] = {
+                                  "name": remoteBroker.backup,
+                                  "kind": "SlaveBroker",
+                                  "brokerKind": "slave",
+                                  "status": "broker",
+                                  "display_kind": "Server"
+                              };
+                              ctrl.relations.push({
+                                 "source": remoteBroker.backup,
+                                 "target": remoteBroker.live
+                              });
+                          }
+                    }
+                });
+            }
+        }
+
+        function createAddresses(brokerMBean, brokerId) {
+           jolokia.search(brokerMBean + ",component=addresses,*", Core.onSuccess(function (response) {
+              angular.forEach(response, function (objectName) {
+                 var details = Core.parseMBean(objectName);
+                 if (details) {
+                    var properties = details['attributes'];
+                    if (properties) {
+                        if (!properties.subcomponent) {
+
+                           Artemis.log.debug("Got Address: " + objectName + " properties: " + angular.toJson(properties, true));
+                           addressKind = properties.address.startsWith("$", 1) || properties.address.startsWith("notif", 1) ? "InternalAddress" : "Address";
+                           ctrl.items[properties.address] = {
+                               "name": properties.address,
+                               "kind": addressKind,
+                               "brokerKind": "address",
+                               "status": "Valid",
+                               "display_kind": "Server",
+                               "mbean": objectName
+                           }
+                           ctrl.relations.push({
+                               "source": brokerId,
+                               "target": properties.address
+                           });
+                        }
+                        if (properties.queue) {
+                            Artemis.log.debug("Got Queue: " + objectName + " properties: " + angular.toJson(properties, true));
+                            queueKind = properties.queue.startsWith("$", 1) || properties.queue.startsWith("notif", 1) ? "InternalQueue" : "Queue";
+                            ctrl.items["queue." + properties.queue] = {
+                               "name": properties.queue,
+                               "kind": queueKind,
+                               "brokerKind": "queue",
+                               "status": "Valid",
+                               "display_kind": "Service",
+                               "mbean": objectName
+                           }
+                           ctrl.relations.push({
+                               "source": properties.address,
+                               "target": "queue." + properties.queue
+                           });
+                        }
+                    }
+                 }
+              });
+           }));
+        }
+    }
+    BrokerDiagramController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/help.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/help.js
new file mode 100644
index 0000000..ff5ca68
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/help.js
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis._module
+   .run(configureHelp)
+   .name;
+
+    function configureHelp(helpRegistry, $templateCache) {
+        var path = 'plugin/help.md';
+        helpRegistry.addUserDoc('artemis', path);
+        //this is indented to render correctly as it is markdown
+        $templateCache.put(path, `
+ ### Artemis
+
+ Click [Artemis](#/jmx/attributes?tab=artemis) in the top navigation bar to see the Artemis specific plugin. (The Artemis tab won't appear if there is no broker in this JVM).  The Artemis plugin works very much the same as the JMX plugin however with a focus on interacting with an Artemis broker.
+
+ The tree view on the left-hand side shows the top level JMX tree of each broker instance running in the JVM.  Expanding the tree will show the various MBeans registered by Artemis that you can inspect via the **Attributes** tab.
+
+ #### Creating a new Address
+
+ To create a new address simply click on the broker or the address folder in the jmx tree and click on the create tab.
+
+ Once you have created an address you should be able to **Send** to it by clicking on it in the jmx tree and clicking on the send tab.
+
+ #### Creating a new Queue
+
+ To create a new queue click on the address you want to bind the queue to and click on the create tab.
+
+ Once you have created a queue you should be able to **Send** a message to it or **Browse** it or view the  **Attributes** or **Charts**. Simply click on the queue in th ejmx tree and click on the appropriate tab.
+
+ You can also see a graphical view of all brokers, addresses, queues and their consumers using the **Diagram** tab.
+             `);
+    }
+    configureHelp.$inject = ['helpRegistry', '$templateCache'];
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/navigation.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/navigation.js
new file mode 100644
index 0000000..3036e6f
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/navigation.js
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis.log.info("loading navigation");
+    var TAB_CONFIG = {
+        attributes: {
+            title: 'Attributes',
+            route: '/artemis/attributes'
+        },
+        operations: {
+            title: 'Operations',
+            route: '/artemis/operations'
+        },
+        chart: {
+            title: 'Chart',
+            route: '/artemis/charts'
+        },
+        createAddress: {
+            title: 'Create address',
+            route: '/artemis/artemisCreateAddress'
+        },
+        deleteAddress: {
+            title: 'Delete address',
+            route: '/artemis/artemisDeleteAddress'
+        },
+        createQueue: {
+            title: 'Create queue',
+            route: '/artemis/artemisCreateQueue'
+        },
+        deleteQueue: {
+            title: 'Delete queue',
+            route: '/artemis/artemisDeleteQueue'
+        },
+        sendMessage: {
+            title: 'Send message',
+            route: '/artemis/artemisSendMessage'
+        },
+        browseQueue: {
+            title: 'Browse queue',
+            route: '/artemis/artemisBrowseQueue'
+        },
+        brokerDiagram: {
+            title: 'Broker diagram',
+            route: '/artemis/artemisBrokerDiagram'
+        },
+        artemisStatus: {
+            title: 'Status',
+            route: '/artemis/artemisStatus'
+        },
+        artemisConnections: {
+            title: 'Connections',
+            route: '/artemis/artemisConnections'
+        },
+        artemisSessions: {
+            title: 'Sessions',
+            route: '/artemis/artemisSessions'
+        },
+        artemisConsumers: {
+            title: 'Consumers',
+            route: '/artemis/artemisConsumers'
+        },
+        artemisProducers: {
+            title: 'Producers',
+            route: '/artemis/artemisProducers'
+        },
+        artemisAddresses: {
+            title: 'Addresses',
+            route: '/artemis/artemisAddresses'
+        },
+        artemisQueues: {
+            title: 'Queues',
+            route: '/artemis/artemisQueues'
+        }
+    };
+    Artemis._module
+    .config(configureRoutes)
+    .component('artemisNavigation', {
+        template: `<hawtio-tabs tabs="$ctrl.tabs" on-change="$ctrl.goto(tab)"></hawtio-tabs>`,
+        controller: ArtemisNavigationController
+    })
+    .name;
+    Artemis.log.info("loaded navigation " + Artemis.navigationModule);
+
+    function ArtemisNavigationController($scope, $location, workspace, localStorage, jolokia) {
+        'ngInject';
+        var ctrl = this;
+        this.$location = $location;
+        artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
+
+        $scope.$on('jmxTreeClicked', function () {
+            ctrl.tabs = getTabs();
+            var tab = _.find(ctrl.tabs, { path: ctrl.$location.path() });
+            if (!tab) {
+                tab = ctrl.tabs[0];
+            }
+            ctrl.$location.path(tab.path);
+        });
+
+        ArtemisNavigationController.prototype.$onInit = function () {
+            this.tabs = getTabs();
+        };
+
+        ArtemisNavigationController.prototype.goto = function (tab) {
+            this.$location.path(tab.path);
+        };
+
+        ctrl.showCreateAddress = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'createAddress');
+        ctrl.showDeleteAddress = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'deleteAddress');
+        ctrl.showCreateQueue = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'createQueue');
+        ctrl.showDeleteQueue = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'destroyQueue');
+
+        function getTabs() {
+
+            var tabs = [];
+            var enabledRoutes = Object.keys(TAB_CONFIG)
+                .map(function (config) { return TAB_CONFIG[config].route; })
+                .filter(function (route) { return _.startsWith(route, '/artemis'); });
+            if (enabledRoutes.length > 0) {
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisStatus.title, TAB_CONFIG.artemisStatus.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisConnections.title, TAB_CONFIG.artemisConnections.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisSessions.title, TAB_CONFIG.artemisSessions.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisConsumers.title, TAB_CONFIG.artemisConsumers.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisProducers.title, TAB_CONFIG.artemisProducers.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisAddresses.title, TAB_CONFIG.artemisAddresses.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisQueues.title, TAB_CONFIG.artemisQueues.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.attributes.title, TAB_CONFIG.attributes.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.operations.title, TAB_CONFIG.operations.route));
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.chart.title, TAB_CONFIG.chart.route));
+                if (shouldShowCreateAddressTab()) {
+                    tabs.push(new Nav.HawtioTab(TAB_CONFIG.createAddress.title, TAB_CONFIG.createAddress.route));
+                }
+                if (shouldShowDeleteAddressTab()) {
+                    tabs.push(new Nav.HawtioTab(TAB_CONFIG.deleteAddress.title, TAB_CONFIG.deleteAddress.route));
+                }
+                if (shouldShowCreateQueueTab()) {
+                    tabs.push(new Nav.HawtioTab(TAB_CONFIG.createQueue.title, TAB_CONFIG.createQueue.route));
+                }
+                if (shouldShowDeleteQueueTab()) {
+                    tabs.push(new Nav.HawtioTab(TAB_CONFIG.deleteQueue.title, TAB_CONFIG.deleteQueue.route));
+                }
+                if (shouldShowSendMessageTab(workspace)) {
+                    tabs.push(new Nav.HawtioTab(TAB_CONFIG.sendMessage.title, TAB_CONFIG.sendMessage.route));
+                }
+                if (shouldShowBrowseMessageTab(workspace)) {
+                    tabs.push(new Nav.HawtioTab(TAB_CONFIG.browseQueue.title, TAB_CONFIG.browseQueue.route));
+                }
+                tabs.push(new Nav.HawtioTab(TAB_CONFIG.brokerDiagram.title, TAB_CONFIG.brokerDiagram.route));
+            }
+            return tabs;
+        }
+
+        function shouldShowCreateAddressTab() {
+            return workspace.selectionHasDomainAndLastFolderName(artemisJmxDomain, 'addresses') && ctrl.showCreateAddress;
+        }
+
+        function shouldShowDeleteAddressTab() {
+            return workspace.hasDomainAndProperties(artemisJmxDomain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'diverts'}) && ctrl.showDeleteAddress;
+        }
+
+        function shouldShowCreateQueueTab() {
+            return workspace.hasDomainAndProperties(artemisJmxDomain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'diverts'}) && ctrl.showCreateQueue;
+        }
+
+        function shouldShowDeleteQueueTab() {
+            return workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && ctrl.showDeleteQueue;
+        }
+
+        function shouldShowSendMessageTab(workspace) {
+            return workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && hasQueueinvokeRights(workspace, "sendMessage");
+        }
+
+        function shouldShowBrowseMessageTab(workspace) {
+            return workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && hasQueueinvokeRights(workspace, "browse") && hasQueueinvokeRights(workspace, "countMessages");
+        }
+
+        function hasInvokeRights(jolokia, mbean, operation) {
+            var response = jolokia.request({
+                type: 'exec',
+                mbean: 'hawtio:type=security,area=jmx,name=ArtemisJMXSecurity',
+                operation: 'canInvoke(java.lang.String, java.lang.String)',
+                arguments: [mbean, operation] },
+                Core.onSuccess(null));
+
+            Artemis.log.info(operation + "=" + response.value);
+            return response.value;
+        }
+        function hasQueueinvokeRights(workspace, operation) {
+            var selection = workspace.selection;
+            if (!selection)
+                return false;
+            var mbean = selection.objectName;
+            if (!mbean)
+                return false;
+            return hasInvokeRights(jolokia, mbean, operation)
+        }
+    }
+    ArtemisNavigationController.$inject = ['$scope', '$location', 'workspace', 'localStorage', 'jolokia']
+
+    function configureRoutes($routeProvider) {
+       $routeProvider.
+        when('/artemis/attributes', { templateUrl: 'plugins/jmx/html/attributes/attributes.html' }).
+        when('/artemis/operations', { template: '<operations></operations>' }).
+        when('/artemis/charts', { templateUrl: 'plugins/jmx/html/charts.html' }).
+        when('/artemis/charts/edit', { templateUrl: 'plugins/jmx/html/chartEdit.html' }).
+        when('/artemis/artemisCreateAddress', { template: '<artemis-create-address></artemis-create-address>'}).
+        when('/artemis/artemisDeleteAddress', { template: '<artemis-delete-address></artemis-delete-address>'}).
+        when('/artemis/artemisCreateQueue', { template: '<artemis-create-queue></artemis-create-queue>'}).
+        when('/artemis/artemisDeleteQueue', { template: '<artemis-delete-queue></artemis-delete-queue>'}).
+        when('/artemis/artemisSendMessage', { template: '<artemis-send-message></artemis-send-message>'}).
+        when('/artemis/artemisBrowseQueue', { template: '<artemis-browse-queue></artemis-browse-queue>'}).
+        when('/artemis/artemisBrokerDiagram', { template: '<artemis-broker-diagram></artemis-broker-diagram>'}).
+        when('/artemis/artemisStatus', { template: '<artemis-status></artemis-status>'}).
+        when('/artemis/artemisConnections', { template: '<artemis-connections></artemis-connections>'}).
+        when('/artemis/artemisSessions', { template: '<artemis-sessions></artemis-sessions>'}).
+        when('/artemis/artemisConsumers', { template: '<artemis-consumers></artemis-consumers>'}).
+        when('/artemis/artemisProducers', { template: '<artemis-producers></artemis-producers>'}).
+        when('/artemis/artemisAddresses', { template: '<artemis-addresses></artemis-addresses>'}).
+        when('/artemis/artemisQueues', { template: '<artemis-queues></artemis-queues>'});
+    }
+    configureRoutes.$inject = ['$routeProvider'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/preferences.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/preferences.js
new file mode 100644
index 0000000..20f54ad
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/preferences.js
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis._module
+    .controller("Artemis.PreferencesController", ["$scope", "localStorage", "userDetails", "$rootScope", function ($scope, localStorage, userDetails, $rootScope) {
+          Core.initPreferenceScope($scope, localStorage, {
+             'artemisUserName': {
+                 'value': userDetails.username ? userDetails.username : ""
+             },
+             'artemisPassword': {
+                'value': userDetails.password ? userDetails.password : ""
+             },
+             'artemisDLQ': {
+                'value': "DLQ"
+             },
+             'artemisExpiryQueue': {
+                'value': "ExpiryQueue"
+             },
+             'ArtemisBrowseBytesMessages': {
+                 'value': 99,
+                 'post': function (newValue) {
+                     $scope.$emit('ArtemisBrowseBytesMessages', newValue);
+                 }
+             }
+         })}])
+   .run(configurePreferences)
+   .name;
+
+   function configurePreferences(preferencesRegistry, $templateCache, workspace) {
+
+        Artemis.log.info("£££££££££££££££££££££££££rwerewrwerwerwe£££££££££££££££");
+        var path = 'plugin/preferences.html';
+        preferencesRegistry.addTab("Artemis", path, function () {
+            return workspace.treeContainsDomainAndProperties("org.apache.activemq.artemis");
+        });
+        $templateCache.put(path,
+            `<form class="form-horizontal artemis-preferences-form" ng-controller="Artemis.PreferencesController">
+                  <div class="form-group">
+                    <label class="col-md-2 control-label" for="artemisUserName">
+                      Artemis user name
+                      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
+                    </label>
+                    <div class="col-md-6">
+                      <input id="artemisUserName" type="text" class="form-control" ng-model="artemisUserName"/>
+                    </div>
+                  </div>
+
+                  <div class="form-group">
+                    <label class="col-md-2 control-label" for="artemisPassword">
+                      Artemis password
+                      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
+                    </label>
+                    <div class="col-md-6">
+                      <input id="artemisPassword" type="password" class="form-control" ng-model="artemisPassword"/>
+                    </div>
+                  </div>
+
+                  <div class="form-group">
+                    <label class="col-md-2 control-label" for="artemisDLQ">
+                      The DLQ of the Broker
+                      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Dead Letter Queue of the Broker"></span>
+                    </label>
+                    <div class="col-md-6">
+                      <input type="text" id="artemisDLQ" ng-model="artemisDLQ">
+                    </div>
+                  </div>
+
+                  <div class="form-group">
+                    <label class="col-md-2 control-label" for="artemisExpiryQueue">
+                      The Expiry of the Broker
+                      <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Expiry Queue of the Broker"></span>
+                    </label>
+                    <div class="col-md-6">
+                      <input type="text" id="artemisExpiryQueue" ng-model="artemisExpiryQueue">
+                    </div>
+                  </div>
+
+                  <div class="form-group">
+                      <label class="col-md-2 control-label" for="Browse Byte Messages">
+                        Browse Bytes Messages
+                        <span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="Browsing byte messages should display the message body as this"></span>
+                      </label>
+                      <div class="col-md-6">
+                        <select id="ArtemisBrowseBytesMessages" class="form-control" ng-model="ArtemisBrowseBytesMessages">
+                            <option value="99">Off</option>
+                            <option value="8">Decimal</option>
+                            <option value="4">Hex</option>
+                            <option value="2">Decimal and Text</option>
+                            <option value="1">Hex and Text</option>
+                        </select>
+                      </div>
+                  </div>
+            </form>`
+        );
+   }
+   configurePreferences.$inject = ['preferencesRegistry', '$templateCache', 'workspace'];
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js
new file mode 100644
index 0000000..3a4be61
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/producers.js
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis.log.info("loading producers");
+    Artemis._module.component('artemisProducers', {
+        template:
+            `<h1>Browse Consumers
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'producers-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+             <div ng-include="'plugin/artemistoolbar.html'"></div>
+             <pf-table-view config="$ctrl.tableConfig"
+                            columns="$ctrl.tableColumns"
+                            items="$ctrl.producers">
+             </pf-table-view>
+             <div ng-include="'plugin/artemispagination.html'"></div>
+             <script type="text/ng-template" id="producers-instructions.html">
+             <div>
+                <p>
+                    This page allows you to browse all producers currently open on the broker. These can be narrowed down
+                    by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
+                    click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    You can navigate to the producers  session by clicking on the <code>Session</code> field.
+                  </p>
+                  <p>
+                    Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
+                  </p>
+                </div>
+             </script>
+             `,
+              controller: ProducersController
+    })
+    .name;
+
+
+    function ProducersController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisProducer, artemisAddress, artemisSession) {
+        var ctrl = this;
+        ctrl.pagination = pagination;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+        ctrl.allProducers = [];
+        ctrl.producers = [];
+        ctrl.pageNumber = 1;
+        ctrl.workspace = workspace;
+        ctrl.refreshed = false;
+        ctrl.filter = {
+            fieldOptions: [
+                {id: 'ID', name: 'ID'},
+                {id: 'SESSION_ID', name: 'Session ID'},
+                {id: 'CLIENT_ID', name: 'Client ID'},
+                {id: 'USER', name: 'User'},
+                {id: 'ADDRESS', name: 'Address'},
+                {id: 'PROTOCOL', name: 'Protocol'},
+                {id: 'LOCAL_ADDRESS', name: 'Local Address'},
+                {id: 'REMOTE_ADDRESS', name: 'Remote Address'}
+            ],
+            operationOptions: [
+                {id: 'EQUALS', name: 'Equals'},
+                {id: 'CONTAINS', name: 'Contains'}
+            ],
+            sortOptions: [
+                {id: 'asc', name: 'ascending'},
+                {id: 'desc', name: 'descending'}
+            ],
+            values: {
+                field: "",
+                operation: "",
+                value: "",
+                sortOrder: "asc",
+                sortColumn: "id"
+            },
+            text: {
+                fieldText: "Filter Field..",
+                operationText: "Operation..",
+                sortOrderText: "ascending",
+                sortByText: "ID"
+            }
+        };
+        ctrl.tableConfig = {
+            selectionMatchProp: 'id',
+            showCheckboxes: false
+        };
+        ctrl.tableColumns = [
+            { header: 'ID', itemField: 'id' },
+            { header: 'Session', itemField: 'session' , templateFn: function(value, item) { return '<a href="#" onclick="selectSession(\'' + item.session + '\')">' + value + '</a>' }},
+            { header: 'Client ID', itemField: 'clientID' },
+            { header: 'Protocol', itemField: 'protocol' },
+            { header: 'User', itemField: 'user' },
+            { header: 'Address', itemField: 'address', templateFn: function(value, item) { return '<a href="#" onclick="selectAddress(\'' + item.address + '\')">' + value + '</a>' }},
+            { header: 'Remote Address', itemField: 'remoteAddress' },
+            { header: 'Local Address', itemField: 'localAddress' }
+        ];
+
+        ctrl.refresh = function () {
+            ctrl.refreshed = true;
+            ctrl.pagination.load();
+        };
+        ctrl.reset = function () {
+            ctrl.filter.values.field = "";
+            ctrl.filter.values.operation = "";
+            ctrl.filter.values.value = "";
+            ctrl.filter.sortOrder = "asc";
+            ctrl.filter.sortColumn = "id";
+            ctrl.filter.text.fieldText = "Filter Field..";
+            ctrl.filter.text.operationText = "Operation..";
+            ctrl.filter.text.sortOrderText = "ascending";
+            ctrl.filter.text.sortByText = "ID";
+            ctrl.refreshed = true;
+            artemisProducer.producer = null;
+            ctrl.pagination.load();
+        };
+
+        selectAddress = function (address) {
+            Artemis.log.info("navigating to address:" + address)
+            artemisAddress.address = { address: address };
+            $location.path("artemis/artemisAddresses");
+        };
+
+        selectSession = function (session) {
+            Artemis.log.info("navigating to session:" + session)
+            artemisSession.session = { session: session };
+            $location.path("artemis/artemisSessions");
+        };
+
+        if (artemisProducer.producer) {
+            Artemis.log.info("navigating to producer = " + artemisProducer.producer.sessionID);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisProducer.producer.sessionID;
+        }
+
+        ctrl.loadOperation = function () {
+            if (mbean) {
+                var method = 'listProducers(java.lang.String, int, int)';
+                var producerFilter = {
+                    field: ctrl.filter.values.field,
+                    operation: ctrl.filter.values.operation,
+                    value: ctrl.filter.values.value,
+                    sortOrder: ctrl.filter.values.sortOrder,
+                    sortColumn: ctrl.filter.values.sortColumn
+                };
+
+                if (ctrl.refreshed == true) {
+                    ctrl.pagination.reset();
+                    ctrl.refreshed = false;
+                }
+                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(producerFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
+            }
+        };
+
+        ctrl.pagination.setOperation(ctrl.loadOperation);
+
+        function onError(response) {
+            Core.notification("error", "could not invoke list sessions" + response.error);
+            $scope.workspace.selectParentNode();
+        };
+
+        function populateTable(response) {
+            var data = JSON.parse(response.value);
+            ctrl.producers = [];
+            angular.forEach(data["data"], function (value, idx) {
+                ctrl.producers.push(value);
+            });
+            ctrl.pagination.page(data["count"]);
+            allProducers = ctrl.producers;
+            ctrl.producers = allProducers;
+            Core.$apply($scope);
+        }
+
+        ctrl.pagination.load();
+    }
+    ProducersController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisProducer', 'artemisAddress', 'artemisSession'];
+
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/queues.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/queues.js
new file mode 100644
index 0000000..5d55693
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/queues.js
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    //Artemis.log.info("loading addresses");
+    Artemis._module.component('artemisQueues', {
+        template:
+            `<h1>Browse Queues
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'queues-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+             <div ng-include="'plugin/artemistoolbar.html'"></div>
+             <pf-table-view config="$ctrl.tableConfig"
+                            columns="$ctrl.tableColumns"
+                            action-buttons="$ctrl.tableActionButtons"
+                            items="$ctrl.queues">
+             </pf-table-view>
+             <div ng-include="'plugin/artemispagination.html'"></div>
+             <script type="text/ng-template" id="queues-instructions.html">
+             <div>
+                <p>
+                    This page allows you to browse all queues on the broker. These can be narrowed down
+                    by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
+                    click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    You can also navigate directly to the JMX attributes and operations tabs by using the  <code>attributes</code>
+                    and <code>operations</code> button under the <code>Actions</code> column.You can navigate to the
+                    queues address by clicking on the <code>Address</code> field.
+                  </p>
+                  <p>
+                    Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
+                  </p>
+                </div>
+             </script>
+             `,
+              controller: QueuesController
+    })
+    .name;
+
+
+    function QueuesController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisQueue, artemisAddress) {
+        var ctrl = this;
+        ctrl.pagination = pagination;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+        ctrl.allAddresses = [];
+        ctrl.queues = [];
+        ctrl.workspace = workspace;
+        ctrl.refreshed = false;
+        ctrl.filter = {
+            fieldOptions: [
+                {id: 'ID', name: 'ID'},
+                {id: 'NAME', name: 'Name'},
+                {id: 'CONSUMER_ID', name: 'Consumer ID'},
+                {id: 'ADDRESS', name: 'Address'},
+                {id: 'FILTER', name: 'Filter'},
+                {id: 'MAX_CONSUMERS', name: 'maxConsumers'},
+                {id: 'ROUTING_TYPE', name: 'Routing Type'},
+                {id: 'PURGE_ON_NO_CONSUMERS', name: 'Purge On No Consumers'},
+                {id: 'USER', name: 'User'},
+                {id: 'MESSAGE_COUNT', name: 'Message Count'},
+                {id: 'DELIVERING_COUNT', name: 'Delivering Count'},
+                {id: 'PAUSED', name: 'Paused'},
+                {id: 'TEMPORARY', name: 'Temporary'},
+                {id: 'AUTO_CREATED', name: 'Auto Created'},
+                {id: 'RATE', name: 'Rate'}
+            ],
+            operationOptions: [
+                {id: 'EQUALS', name: 'Equals'},
+                {id: 'CONTAINS', name: 'Contains'},
+                {id: 'GREATER_THAN', name: 'Greater Than'},
+                {id: 'LESS_THAN', name: 'Less Than'}
+            ],
+            sortOptions: [
+                {id: 'asc', name: 'ascending'},
+                {id: 'desc', name: 'descending'}
+            ],
+            values: {
+                field: "",
+                operation: "",
+                value: "",
+                sortOrder: "asc",
+                sortColumn: "id"
+            },
+            text: {
+                fieldText: "Filter Field..",
+                operationText: "Operation..",
+                sortOrderText: "ascending",
+                sortByText: "ID"
+            }
+        };
+
+        ctrl.tableActionButtons = [
+            {
+                name: 'attributes',
+                title: 'Navigate to attributes',
+                actionFn: navigateToQueuesAtts
+            },
+            {
+               name: 'operations',
+               title: 'navigate to operations',
+               actionFn: navigateToQueuesOps
+            }
+        ];
+        ctrl.tableConfig = {
+            selectionMatchProp: 'id',
+            showCheckboxes: false
+        };
+        ctrl.tableColumns = [
+            { header: 'ID', itemField: 'id' },
+            { header: 'Name', itemField: 'name' },
+            { header: 'Routing Types', itemField: 'routingTypes' },
+            { header: 'Queue Count', itemField: 'queueCount' },
+            { header: 'Address', itemField: 'address' , templateFn: function(value, item) { return '<a href="#" onclick="selectAddress(\'' + item.address + '\')">' + value + '</a>' }},
+            { header: 'Routing Type', itemField: 'routingType' },
+            { header: 'Filter', itemField: 'filter' },
+            { header: 'Durable', itemField: 'durable' },
+            { header: 'Max Consumers', itemField: 'maxConsumers' },
+            { header: 'Purge On No Consumers', itemField: 'purgeOnNoConsumers' },
+            { header: 'Consumer Count', itemField: 'consumerCount' },
+            { header: 'Rate', itemField: 'rate' },
+            { header: 'Message Count', itemField: 'messageCount' },
+            { header: 'Paused', itemField: 'paused' },
+            { header: 'Temporary', itemField: 'temporary' },
+            { header: 'Auto Created', itemField: 'autoCreated' },
+            { header: 'User', itemField: 'user' },
+            { header: 'Total Messages Added', itemField: 'messagesAdded' },
+            { header: 'Total Messages Acked', itemField: 'messagesAcked' },
+            { header: 'Delivering Count', itemField: 'deliveringCount' },
+            { header: 'Messages Killed', itemField: 'messagesKilled' },
+            { header: 'Direct Deliver', itemField: 'directDeliver' }
+        ];
+
+        ctrl.refresh = function () {
+            ctrl.refreshed = true;
+            loadTable();
+        };
+        ctrl.reset = function () {
+            ctrl.filter.values.field = "";
+            ctrl.filter.values.operation = "";
+            ctrl.filter.values.value = "";
+            ctrl.filter.sortOrder = "asc";
+            ctrl.filter.sortColumn = "id";
+            ctrl.filter.text.fieldText = "Filter Field..";
+            ctrl.filter.text.operationText = "Operation..";
+            ctrl.filter.text.sortOrderText = "ascending";
+            ctrl.filter.text.sortByText = "ID";
+            ctrl.refreshed = true;
+            ctrl.pagination.load();
+        };
+
+        if (artemisQueue.queue) {
+            Artemis.log.info("navigating to queue = " + artemisQueue.queue.queue);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisQueue.queue.queue;
+        }
+
+        if (artemisAddress.address) {
+            Artemis.log.info("navigating to queue = " + artemisAddress.address.address);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[3].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisAddress.address.address;
+        }
+
+        function navigateToQueuesAtts(action, item) {
+            $location.path("artemis/attributes").search({"tab": "artemis", "nid": getQueuesNid(item, $location)});
+        };
+        function navigateToQueuesOps(action, item) {
+            $location.path("artemis/operations").search({"tab": "artemis", "nid": getQueuesNid(item, $location)});
+        };
+        selectAddress = function (address) {
+            Artemis.log.info("navigating to address:" + address)
+            artemisAddress.address = { address: address };
+            $location.path("artemis/artemisAddresses");
+        };
+        function getQueuesNid(item, $location) {
+            var rootNID = getRootNid($location);
+            var targetNID = rootNID + "addresses-" + item.address + "-queues-" + item.routingType.toLowerCase() + "-" + item.name;
+            Artemis.log.info("targetNID=" + targetNID);
+            return targetNID;
+        }
+        function getRootNid($location) {
+            var currentNid = $location.search()['nid'];
+            Artemis.log.info("current nid=" + currentNid);
+            var firstDash = currentNid.indexOf('-');
+            var secondDash = currentNid.indexOf('-', firstDash + 1);
+            var thirdDash = currentNid.indexOf('-', secondDash + 1);
+            if (thirdDash < 0) {
+                return currentNid + "-";
+            }
+            var rootNID = currentNid.substring(0, thirdDash + 1);
+            return rootNID;
+        }
+        ctrl.loadOperation = function () {
+            if (mbean) {
+                var method = 'listQueues(java.lang.String, int, int)';
+                var queuesFilter = {
+                    field: ctrl.filter.values.field,
+                    operation: ctrl.filter.values.operation,
+                    value: ctrl.filter.values.value,
+                    sortOrder: ctrl.filter.values.sortOrder,
+                    sortColumn: ctrl.filter.values.sortColumn
+                };
+
+                if (ctrl.refreshed == true) {
+                    ctrl.pagination.reset();
+                    ctrl.refreshed = false;
+                }
+                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(queuesFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
+            }
+        };
+
+        ctrl.pagination.setOperation(ctrl.loadOperation);
+
+        function onError(response) {
+            Core.notification("error", "could not invoke list sessions" + response.error);
+            $scope.workspace.selectParentNode();
+        };
+
+        function populateTable(response) {
+            var data = JSON.parse(response.value);
+            ctrl.queues = [];
+            angular.forEach(data["data"], function (value, idx) {
+                ctrl.queues.push(value);
+            });
+            ctrl.pagination.page(data["count"]);
+            allQueues = ctrl.queues;
+            ctrl.queues = allQueues;
+            Core.$apply($scope);
+        }
+
+        ctrl.pagination.load();
+    }
+    QueuesController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisQueue', 'artemisAddress'];
+
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/sendMessage.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/sendMessage.js
new file mode 100644
index 0000000..66ba20c
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/sendMessage.js
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis.log.info("loading send message");
+    Artemis._module.component('artemisSendMessage', {
+        template:
+            `<h1>Send Message
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'send-message-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+
+            <div class="alert alert-warning" ng-show="$ctrl.noCredentials">
+                <span class="pficon pficon-warning-triangle-o"></span>
+                <strong>No credentials set for endpoint!</strong>
+                Please set your username and password in the
+                <a href="#" class="alert-link" ng-click="$ctrl.openPrefs()">Preferences</a> page.
+            </div>
+
+            <div class="row artemis-message-configuration">
+
+                <div class="col-sm-12">
+                    <form>
+                        <div class="form-group">
+                            <label>Durable </label>
+                            <input id="durable" type="checkbox" ng-model="$ctrl.durable" value="true">
+                        </div>
+                    </form>
+                </div>
+            </div>
+
+            <h3>Headers</h3>
+
+            <div class="form-group"  ng-if="$ctrl.headers.length > 0">
+                <table class="scr-component-references-table table">
+                    <tbody>
+                        <tr class="input-group"  ng-repeat="header in $ctrl.headers">
+                            <td><input type="text" class="form-control" ng-model="header.name" placeholder="Name" autocomplete="off" id="name"></td>
+                            <td><input type="text" class="form-control" ng-model="header.value" placeholder="Value" autocomplete="off" id="value"></td>
+                            <td><div class="input-group-prepend">
+                                <button type="button" class="btn btn-default" title="Delete" ng-click="$ctrl.removeHeader(header)">
+                                    <span class="pficon pficon-delete"></span>
+                                </button>
+                            </div></td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+
+            <p>
+                <button type="button" class="btn btn-primary artemis-add-message-button" ng-click="$ctrl.addHeader()">Add Header</button>
+            </p>
+
+            <h3>Body</h3>
+
+            <form>
+                <div class="form-group">
+                    <div hawtio-editor="$ctrl.message" mode="codeMirrorOptions.mode.name"></div>
+                </div>
+                <div class="form-group">
+                    <select class="form-control artemis-send-message-format" ng-model="codeMirrorOptions.mode.name">
+                        <option value="javascript">JSON</option>
+                        <option value="xml">XML</option>
+                    </select>
+                    <button class="btn btn-default" ng-click="$ctrl.formatMessage()"
+                       title="Automatically pretty prints the message so its easier to read">Format
+                    </button>
+                </div>
+            </form>
+
+            <p>
+                <button type="button" class="btn btn-primary artemis-send-message-button" ng-click="$ctrl.sendMessage($ctrl.durable)">Send message</button>
+            </p>
+            <script type="text/ng-template" id="send-message-instructions.html">
+            <div>
+                <p>
+                    This page allows you to send a message to the chosen queue. The message will be of type <code>text</code>
+                    message and it will be possible to add headers to the message. The sending of the message will be authenticated
+                    using the username and password set ion <code>preferences</code>, if this is not set then these will
+                    be null.
+                </p>
+            </div>
+        </script>
+        `,
+        controller: SendMessageController
+    })
+    .name;
+    Artemis.log.info("loaded queue " + Artemis.createQueueModule);
+
+    function SendMessageController($route, $scope, $element, $timeout, workspace,  jolokia, localStorage, $location, artemisMessage) {
+        Core.initPreferenceScope($scope, localStorage, {
+            'durable': {
+                'value': true,
+                'converter': Core.parseBooleanValue
+            }
+        });
+        var ctrl = this;
+        ctrl.noCredentials = false;
+        ctrl.durable = true;
+        ctrl.message = "";
+        ctrl.headers = [];
+        // bind model values to search params...
+        Core.bindModelToSearchParam($scope, $location, "tab", "subtab", "compose");
+        Core.bindModelToSearchParam($scope, $location, "searchText", "q", "");
+        // only reload the page if certain search parameters change
+        Core.reloadWhenParametersChange($route, $scope, $location);
+        ctrl.checkCredentials = function () {
+            ctrl.noCredentials = (Core.isBlank(localStorage['artemisUserName']) || Core.isBlank(localStorage['artemisPassword']));
+        };
+        if ($location.path().indexOf('artemis') > -1) {
+            ctrl.localStorage = localStorage;
+            $scope.$watch('localStorage.artemisUserName', ctrl.checkCredentials);
+            $scope.$watch('localStorage.artemisPassword', ctrl.checkCredentials);
+            //prefill if it's a resent
+            if (artemisMessage.message !== null) {
+                ctrl.message = artemisMessage.message.bodyText;
+                if (artemisMessage.message.PropertiesText !== null) {
+                    for (var p in artemisMessage.message.StringProperties) {
+                        ctrl.headers.push({name: p, value: artemisMessage.message.StringProperties[p]});
+                    }
+                }
+            }
+            // always reset at the end
+            artemisMessage.message = null;
+        }
+
+        this.openPrefs = function () {
+            Artemis.log.info("opening prefs");
+            $location.path('/preferences').search({'pref': 'Artemis'});
+        }
+
+        var LANGUAGE_FORMAT_PREFERENCE = "defaultLanguageFormat";
+        var sourceFormat = workspace.getLocalStorage(LANGUAGE_FORMAT_PREFERENCE) || "javascript";
+
+        $scope.codeMirrorOptions = CodeEditor.createEditorSettings({
+            mode: {
+                name: sourceFormat
+            }
+        });
+
+        $scope.$on('hawtioEditor_default_instance', function (event, codeMirror) {
+            $scope.codeMirror = codeMirror;
+        });
+
+        ctrl.addHeader = function  () {
+            ctrl.headers.push({name: "", value: ""});
+            // lets set the focus to the last header
+            if ($element) {
+                $timeout(function () {
+                    var lastHeader = $element.find("input.headerName").last();
+                    lastHeader.focus();
+                }, 100);
+            }
+        }
+
+        this.removeHeader = function (header) {
+            var index = ctrl.headers.indexOf(header);
+            ctrl.headers.splice(index, 1);
+        };
+
+        ctrl.defaultHeaderNames = function () {
+            var answer = [];
+
+            function addHeaderSchema(schema) {
+                angular.forEach(schema.definitions.headers.properties, function (value, name) {
+                    answer.push(name);
+                });
+            }
+
+            addHeaderSchema(Artemis.jmsHeaderSchema);
+            return answer;
+        };
+
+        function operationSuccess() {
+            Core.notification("success", "Message sent!");
+            ctrl.headers = [];
+            ctrl.message = "";
+        };
+
+        function onError(response) {
+           Core.notification("error", "Could not send message: " + response.error);
+        }
+
+        ctrl.formatMessage = function () {
+            CodeEditor.autoFormatEditor($scope.codeMirror);
+        };
+        ctrl.sendMessage = function (durable) {
+            var body = ctrl.message;
+            Artemis.log.info(body);
+            doSendMessage(ctrl.durable, body);
+        };
+
+        function doSendMessage(durable, body) {
+            var selection = workspace.selection;
+            if (selection) {
+                var mbean = selection.objectName;
+                if (mbean) {
+                    var headers = null;
+                    if (ctrl.headers.length) {
+                        headers = {};
+                        angular.forEach(ctrl.headers, function (object) {
+                            var key = object.name;
+                            if (key) {
+                                headers[key] = object.value;
+                            }
+                        });
+                        Artemis.log.debug("About to send headers: " + JSON.stringify(headers));
+                    }
+
+                    var user = ctrl.localStorage["artemisUserName"];
+                    var pwd = ctrl.localStorage["artemisPassword"];
+
+                    if (!headers) {
+                        headers = {};
+                    }
+                    var type = 3;
+                    Artemis.log.debug(headers);
+                    Artemis.log.debug(type);
+                    Artemis.log.debug(body);
+                    Artemis.log.debug(durable);
+                    jolokia.execute(mbean, "sendMessage(java.util.Map, int, java.lang.String, boolean, java.lang.String, java.lang.String)", headers, type, body, durable, user, pwd,  Core.onSuccess(operationSuccess, { error: onError }));
+                }
+            }
+        }
+    }
+    SendMessageController.$inject = ['$route', '$scope', '$element', '$timeout', 'workspace', 'jolokia', 'localStorage', '$location', 'artemisMessage'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/sessions.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/sessions.js
new file mode 100644
index 0000000..eab7be6
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/sessions.js
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ */
+var Artemis;
+(function (Artemis) {
+    Artemis.log.info("loading sessions");
+    Artemis._module.component('artemisSessions', {
+        template:
+            `<h1>Browse Sessions
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'sessions-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+            </h1>
+             <div ng-include="'plugin/artemistoolbar.html'"></div>
+             <pf-table-view config="$ctrl.tableConfig"
+                            columns="$ctrl.tableColumns"
+                            action-buttons="$ctrl.tableActionButtons"
+                            items="$ctrl.sessions">
+             </pf-table-view>
+             <div ng-include="'plugin/artemispagination.html'"></div>
+             <div hawtio-confirm-dialog="$ctrl.closeDialog" title="Close Session?"
+                 ok-button-text="Close"
+                 cancel-button-text="Cancel"
+                 on-ok="$ctrl.closeSession()">
+                 <div class="dialog-body">
+                     <p class="alert alert-warning">
+                         <span class="pficon pficon-warning-triangle-o"></span>
+                         You are about to close the selected session: {{$ctrl.sessionToDelete}}
+                         <p>Are you sure you want to continue.</p>
+                     </p>
+                 </div>
+             </div>
+             <script type="text/ng-template" id="sessions-instructions.html">
+             <div>
+                <p>
+                    This page allows you to browse all session currently open on the broker. These can be narrowed down
+                    by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
+                    click on the <span class="fa fa-search"></span> button.
+                </p>
+                <p>
+                    Sessions can be closed by using the <code>close</code> button under the <code>Actions</code> column and you can
+                    navigate to the connection, consumers and producers by clicking on the appropriate field.
+                  </p>
+                  <p>
+                    Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
+                  </p>
+                </div>
+             </script>
+             `,
+              controller: SessionsController
+    })
+    .name;
+
+
+    function SessionsController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisConnection, artemisSession, artemisConsumer, artemisProducer) {
+        var ctrl = this;
+        ctrl.pagination = pagination;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+        ctrl.allSessions = [];
+        ctrl.sessions = [];
+        ctrl.pageNumber = 1;
+        ctrl.workspace = workspace;
+        ctrl.refreshed = false;
+        ctrl.sessionToDeletesConnection = '';
+        ctrl.sessionToDelete = '';
+        ctrl.closeDialog = false;
+        ctrl.filter = {
+            fieldOptions: [
+                {id: 'ID', name: 'ID'},
+                {id: 'CONNECTION_ID', name: 'Connection ID'},
+                {id: 'CONSUMER_COUNT', name: 'Consumer Count'},
+                {id: 'USER', name: 'User'},
+                {id: 'PROTOCOL', name: 'Protocol'},
+                {id: 'CLIENT_ID', name: 'Client ID'},
+                {id: 'LOCAL_ADDRESS', name: 'Local Address'},
+                {id: 'REMOTE_ADDRESS', name: 'Remote Address'}
+            ],
+            operationOptions: [
+                {id: 'EQUALS', name: 'Equals'},
+                {id: 'CONTAINS', name: 'Contains'},
+                {id: 'GREATER_THAN', name: 'Greater Than'},
+                {id: 'LESS_THAN', name: 'Less Than'}
+            ],
+            sortOptions: [
+                {id: 'asc', name: 'ascending'},
+                {id: 'desc', name: 'descending'}
+            ],
+            values: {
+                field: "",
+                operation: "",
+                value: "",
+                sortOrder: "asc",
+                sortColumn: "id"
+            },
+            text: {
+                fieldText: "Filter Field..",
+                operationText: "Operation..",
+                sortOrderText: "ascending",
+                sortByText: "ID"
+            }
+        };
+        ctrl.tableActionButtons = [
+           {
+            name: 'Close',
+            title: 'Close the Session',
+            actionFn: openCloseDialog
+           }
+        ];
+        ctrl.tableConfig = {
+            selectionMatchProp: 'id',
+            showCheckboxes: false
+        };
+        ctrl.tableColumns = [
+            { header: 'ID', itemField: 'id' },
+            { header: 'Connection', itemField: 'connectionID', templateFn: function(value, item) { return '<a href="#" onclick="selectConnection(\'' + item.connectionID + '\')">' + value + '</a>' }},
+            { header: 'User', itemField: 'user' },
+            { header: 'Consumer Count', itemField: 'consumerCount', templateFn: function(value, item) { return '<a href="#" onclick="selectConsumers(\'' + item.id + '\')">' + value + '</a>' }},
+            { header: 'Producer Count', itemField: 'producerCount', templateFn: function(value, item) { return '<a href="#" onclick="selectProducers(\'' + item.id + '\')">' + value + '</a>' }},
+            { header: 'Creation Time', itemField: 'creationTime' }
+        ];
+
+        ctrl.refresh = function () {
+            ctrl.refreshed = true;
+            ctrl.pagination.load();
+        };
+        ctrl.reset = function () {
+            ctrl.filter.values.field = "";
+            ctrl.filter.values.operation = "";
+            ctrl.filter.values.value = "";
+            ctrl.filter.sortOrder = "asc";
+            ctrl.filter.sortColumn = "id";
+            ctrl.filter.text.fieldText = "Filter Field..";
+            ctrl.filter.text.operationText = "Operation..";
+            ctrl.filter.text.sortOrderText = "ascending";
+            ctrl.filter.text.sortByText = "ID";
+            ctrl.refreshed = true;
+            artemisConnection.connection = null;
+            artemisSession.session = null;
+            artemisConsumer.consumer = null;
+            ctrl.pagination.load();
+        };
+
+        selectConnection = function (connection) {
+            Artemis.log.info("navigating to connection:" + connection)
+            artemisSession.session = { connectionID: connection };
+            $location.path("artemis/artemisConnections");
+        };
+
+        selectConsumers = function (session) {
+            Artemis.log.info("navigating to consumers:" + session)
+            artemisConsumer.consumer = { sessionID: session };
+            $location.path("artemis/artemisConsumers");
+        };
+
+        selectProducers = function (session) {
+            Artemis.log.info("navigating to producers:" + session)
+            artemisProducer.producer = { sessionID: session };
+            $location.path("artemis/artemisProducers");
+        };
+
+        if (artemisConnection.connection) {
+            Artemis.log.info("navigating to connection = " + artemisConnection.connection.connectionID);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisConnection.connection.connectionID;
+        }
+
+        if (artemisSession.session) {
+            Artemis.log.info("navigating to session = " + artemisSession.session.session);
+            ctrl.filter.values.field = ctrl.filter.fieldOptions[0].id;
+            ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
+            ctrl.filter.values.value = artemisSession.session.session;
+        }
+
+        function openCloseDialog(action, item) {
+            ctrl.sessionToDelete = item.id;
+            ctrl.sessionToDeletesConnection = item.connectionID;
+            ctrl.closeDialog = true;
+        }
+
+        ctrl.closeSession = function () {
+           Artemis.log.info("closing session: " + ctrl.sessionToDelete);
+              if (mbean) {
+                  jolokia.request({ type: 'exec',
+                     mbean: mbean,
+                     operation: 'closeSessionWithID(java.lang.String,java.lang.String)',
+                     arguments: [ctrl.sessionToDeletesConnection, ctrl.sessionToDelete] },
+                     Core.onSuccess(ctrl.pagination.load(), { error: function (response) {
+                        Core.defaultJolokiaErrorHandler("Could not close session: " + response);
+                 }}));
+           }
+        };
+        ctrl.loadOperation = function () {
+            if (mbean) {
+                var method = 'listSessions(java.lang.String, int, int)';
+                var sessionsFilter = {
+                    field: ctrl.filter.values.field,
+                    operation: ctrl.filter.values.operation,
+                    value: ctrl.filter.values.value,
+                    sortOrder: ctrl.filter.values.sortOrder,
+                    sortColumn: ctrl.filter.values.sortColumn
+                };
+
+                if (ctrl.refreshed == true) {
+                    ctrl.pagination.reset();
+                    ctrl.refreshed = false;
+                }
+                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(sessionsFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
+            }
+        };
+
+        ctrl.pagination.setOperation(ctrl.loadOperation);
+
+        function onError(response) {
+            Core.notification("error", "could not invoke list sessions" + response.error);
+            $scope.workspace.selectParentNode();
+        };
+
+        function populateTable(response) {
+            var data = JSON.parse(response.value);
+            ctrl.sessions = [];
+            angular.forEach(data["data"], function (value, idx) {
+                ctrl.sessions.push(value);
+            });
+            ctrl.pagination.page(data["count"]);
+            allSessions = ctrl.sessions;
+            ctrl.sessions = allSessions;
+            Core.$apply($scope);
+        }
+
+        ctrl.pagination.load();
+    }
+    SessionsController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisConnection', 'artemisSession', 'artemisConsumer', 'artemisProducer'];
+
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/status.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/status.js
new file mode 100644
index 0000000..48a71ae
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/status.js
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis.log.info("loading status");
+    Artemis._module.component('artemisStatus', {
+        template:
+               `<h1>Current Status
+                <button type="button" class="btn btn-link jvm-title-popover"
+                          uib-popover-template="'status-instructions.html'" popover-placement="bottom-left"
+                          popover-title="Instructions" popover-trigger="'outsideClick'">
+                    <span class="pficon pficon-help"></span>
+                </button>
+                </h1>
+                <div class="container-fluid">
+                     <div class="row">
+                        <div class="col-md-3 text-center">
+                            <label>'Address Memory Used'</label>
+                            <p class="text-left">
+                            <pf-donut-pct-chart config="$ctrl.addressMemoryConfig" data="$ctrl.addressMemoryData" center-label="$ctrl.addressMemoryLabel"></pf-donut-pct-chart>
+                            </p>
+                        </div>
+                     </div>
+                     <div class="row">
+                         <div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
+                               <pf-info-status-card status="$ctrl.infoStatus" show-top-border="true"></pf-info-status-card>
+                         </div>
+                     </div>
+                     <div class="row">
+                         <div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
+                               <pf-info-status-card status="$ctrl.clusterInfoStatus" show-top-border="true"></pf-info-status-card>
+                         </div>
+                     </div>
+                </div>
+                <script type="text/ng-template" id="status-instructions.html">
+                  <div>
+                    <p>
+                      This page allows you to view the current status of the broker as well as the status of the cluster it belongs to.
+                    </p>
+                    <p>
+                    It also shows the current address memory usage in relationship to the <code>global-max-size</code>
+                    </p>
+                    <p>Note these metrics update every 5 seconds</p>
+                  </div>
+                </script>
+        `,
+        controller: StatusController
+    })
+    .name;
+    Artemis.log.info("loaded address " + Artemis.addressModule);
+
+    function StatusController($scope, workspace, jolokia, localStorage, $interval) {
+        var ctrl = this;
+        var mbean = Artemis.getBrokerMBean(workspace, jolokia);
+
+        StatusController.prototype.$onInit = function () {
+            jolokia.request({ type: 'read', mbean: mbean, attribute: 'Version'}, Core.onSuccess(function(response) {
+                ctrl.infoStatus.info[0] = "version: " + response.value;
+            }));
+            jolokia.request({ type: 'read', mbean: mbean, attribute: 'HAPolicy'}, Core.onSuccess(function(response) {
+                ctrl.clusterInfoStatus.info[2] = "HA Policy: " + response.value;
+            }));
+            loadStatus();
+            ctrl.promise = $interval(function () { return loadStatus(); }, 5000);
+        };
+        StatusController.prototype.$onDestroy = function () {
+            $interval.cancel(this.promise);
+        };
+
+        ctrl.infoStatus = {
+          "title":"Broker Info",
+          "href":"#",
+          "iconClass": "pficon pficon-ok",
+          "info":[
+            "version",
+            "uptime:",
+            "started:"
+          ]
+        };
+        ctrl.clusterInfoStatus = {
+          "title":"Cluster Info",
+          "href":"#",
+          "iconClass": "pficon pficon-ok",
+          "info":[
+            "Lives:",
+            "Backups:",
+            "HA Policy: :"
+          ]
+        };
+        ctrl.addressMemoryConfig = {
+            'chartId': 'addressMemoryChart',
+            'units': 'MB',
+            'thresholds':{'warning':'75','error':'90'}
+        };
+
+        ctrl.addressMemoryData = {
+            'used': '0',
+            'total': '1000'
+        };
+        ctrl.addressMemoryLabel = "used";
+
+        function loadStatus() {
+            jolokia.request({ type: 'read', mbean: mbean, attribute: 'GlobalMaxSize'}, Core.onSuccess(function(response) { ctrl.addressMemoryData.total = (response.value / 1048576).toFixed(2); }));
+            jolokia.request({ type: 'read', mbean: mbean, attribute: 'AddressMemoryUsage'}, Core.onSuccess(function(response) { ctrl.addressMemoryData.used = (response.value / 1048576).toFixed(2); }));
+            jolokia.request({ type: 'read', mbean: mbean, attribute: 'Uptime'}, Core.onSuccess(function(response) {
+                ctrl.infoStatus.info[1] = "uptime: " + response.value;
+            }));
+            jolokia.request({ type: 'read', mbean: mbean, attribute: 'Started'}, Core.onSuccess(function(response) {
+                ctrl.infoStatus.info[2] = "started: " + response.value;
+                if(response.value == false) {
+                    ctrl.infoStatus.iconClass = "pficon pficon-error-circle-o";
+                } else {
+                    ctrl.infoStatus.iconClass = "pficon pficon-ok";
+                }
+            }));
+            var lives = 0;
+            var backups = 0;
+            var response = jolokia.request({ type: 'exec', mbean: mbean, operation: 'listNetworkTopology()' }, Core.onSuccess(null));
+            var responseValue = response.value;
+            var brokers = angular.fromJson(responseValue);
+            angular.forEach(brokers, function (broker) {
+                if (broker.live) {
+                    lives++;
+                }
+                if (broker.backup) {
+                    backups++;
+                }
+            })
+            ctrl.clusterInfoStatus.info[0] = "Lives: " + lives;
+            ctrl.clusterInfoStatus.info[1] = "Backups: " + backups;
+            if (ctrl.clusterInfoStatus.info[2] == "HA Policy: Replicated") {
+                jolokia.request({ type: 'read', mbean: mbean, attribute: 'ReplicaSync'}, Core.onSuccess(function(response) {
+                    ctrl.clusterInfoStatus.info[3] = "replicating: " + response.value;
+                    if (response.value == false) {
+                        ctrl.clusterInfoStatus.iconClass = "pficon pficon-error-circle-o";
+                    } else {
+                        ctrl.clusterInfoStatus.iconClass = "pficon pficon-ok";
+                    }
+                }));
+            }
+        }
+    }
+    StatusController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', '$interval'];
+
+})(Artemis || (Artemis = {}));
\ No newline at end of file
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/tree.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/tree.js
new file mode 100644
index 0000000..5d6fbf9
--- /dev/null
+++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/components/tree.js
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+ /// <reference path="tree.component.ts"/>
+var Artemis;
+(function (Artemis) {
+    Artemis._module.component('artemisTreeHeader', {
+            template:
+                `<div class="tree-nav-sidebar-header">
+                  <form role="form" class="search-pf has-button">
+                    <div class="form-group has-clear">
+                      <div class="search-pf-input-group">
+                        <label for="input-search" class="sr-only">Search Tree:</label>
+                        <input id="input-search" type="search" class="form-control" placeholder="Search tree:"
+                          ng-model="$ctrl.filter">
+                        <button type="button" class="clear" aria-hidden="true"
+                          ng-hide="$ctrl.filter.length === 0"
+                          ng-click="$ctrl.filter = ''">
+                          <span class="pficon pficon-close"></span>
+                        </button>
+                      </div>
+                    </div>
+                    <div class="form-group tree-nav-buttons">
+                      <span class="badge" ng-class="{positive: $ctrl.result.length > 0}"
+                        ng-show="$ctrl.filter.length > 0">
+                        {{$ctrl.result.length}}
+                      </span>
+                      <i class="fa fa-plus-square-o" title="Expand All" ng-click="$ctrl.expandAll()"></i>
+                      <i class="fa fa-minus-square-o" title="Collapse All" ng-click="$ctrl.contractAll()"></i>
+                    </div>
+                  </form>
+                </div>
+            `,
+            controller: TreeHeaderController
+        })
+        .component('artemisTree', {
+              template:
+              `<div class="tree-nav-sidebar-content">
+                  <div id="artemistree" class="treeview-pf-hover treeview-pf-select"></div>
+              </div>
+              `,
+              controller: TreeController
+        })
+        .name;
+    treeElementId = '#artemistree';
+    Artemis.log.debug("loaded tree" + Artemis.treeModule);
+
+
+    function TreeHeaderController($scope, $element) {
+        'ngInject';
+        Artemis.log.debug("TreeHeaderController ");
+        this.$scope = $scope;
+        this.$element = $element;
+        this.filter = '';
+        this.result = [];
+        // it's not possible to declare classes to the component host tag in AngularJS
+        $element.addClass('tree-nav-sidebar-header');
+
+        TreeHeaderController.prototype.$onInit = function () {
+        Artemis.log.debug("TreeHeaderController init");
+            var _this = this;
+            this.$scope.$watch(angular.bind(this, function () { return _this.filter; }), function (filter, previous) {
+                if (filter !== previous) {
+                    _this.search(filter);
+                }
+            });
+        };
+
+        TreeHeaderController.prototype.search = function (filter) {
+                Artemis.log.debug("TreeHeaderController search");
+            var _this = this;
+            var doSearch = function (filter) {
+                var result = _this.tree().search(filter, {
+                    ignoreCase: true,
+                    exactMatch: false,
+                    revealResults: true
+                });
+                _this.result.length = 0;
+                (_a = _this.result).push.apply(_a, result);
+                Core.$apply(_this.$scope);
+                var _a;
+            };
+            _.debounce(doSearch, 300, { leading: false, trailing: true })(filter);
+        };
+
+        TreeHeaderController.prototype.tree = function () {
+                Artemis.log.debug("TreeHeaderController tree");
+            return $(treeElementId).treeview(true);
+        };
+
+        TreeHeaderController.prototype.expandAll = function () {
+                Artemis.log.debug("TreeHeaderController expand");
+            return this.tree()
+                .expandNode(this.tree().getNodes(), { levels: HawtioTree.getMaxTreeLevel(this.tree()), silent: true });
+        };
+
+        TreeHeaderController.prototype.contractAll = function () {
+                Artemis.log.debug("TreeHeaderController contract");
+            return this.tree()
+                .collapseNode(this.tree().getNodes(), { ignoreChildren: true, silent: true });
+        };
+    }
+    TreeHeaderController.$inject = ['$scope', '$element'];
+
+    function TreeController($scope, $location, workspace, $element) {
+        'ngInject';
+        this.$scope = $scope;
+        this.$location = $location;
+        this.workspace = workspace;
+        this.$element = $element;
+        // it's not possible to declare classes to the component host tag in AngularJS
+        $element.addClass('tree-nav-sidebar-content');
+        Artemis.log.debug("TreeController ");
+        var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
+        TreeController.prototype.$onInit = function () {
+        Artemis.log.debug("TreeController onInit");
+            var _this = this;
+            this.$scope.$on('$destroy', function () { return _this.removeTree(); });
+            this.$scope.$on('$routeChangeStart', function () { return Jmx.updateTreeSelectionFromURL(_this.$location, $(treeElementId)); });
+            this.$scope.$on('jmxTreeUpdated', function () { return _this.populateTree(); });
+            this.populateTree();
+        };
+        TreeController.prototype.updateSelectionFromURL = function () {
+            Jmx.updateTreeSelectionFromURLAndAutoSelect(this.$location, $(treeElementId), function (first) {
+                if (first.children == null) {
+                    return null;
+                }
+                // use function to auto select the queue folder on the 1st broker
+                var queues = first.children[0];
+                if (queues && queues.text === 'Queue') {
+                    return queues;
+                }
+                return null;
+            }, true);
+        };
+        TreeController.prototype.populateTree = function () {
+            var _this = this;
+            var children = [];
+            var tree = this.workspace.tree;
+            Artemis.log.debug("tree= "+tree);
+            if (tree) {
+                var domainName = artemisJmxDomain;
+                var folder = tree.get(domainName);
+
+                if (folder) {
+                    children = folder.children;
+                }
+                angular.forEach(children,  function(child) {
+                    Artemis.log.debug("child=" + child.text + " " + child.id);
+                });
+                var treeElement = $("#artemistree");
+                this.removeTree();
+                Jmx.enableTree(this.$scope, this.$location, this.workspace, $(treeElementId), children);
+                this.updateSelectionFromURL();
+            }
+        };
+        TreeController.prototype.removeTree = function () {
+            var tree = $(treeElementId).treeview(true);
+            // There is no exposed API to check whether the tree has already been initialized,
+            // so let's just check if the methods are presents
+            if (tree.clearSearch) {
+                tree.clearSearch();
+                // Bootstrap tree view leaks the node elements into the data structure
+                // so let's clean this up when the user leaves the view
+                var cleanTreeFolder_1 = function (node) {
+                    delete node['$el'];
+                    if (node.nodes)
+                        node.nodes.forEach(cleanTreeFolder_1);
+                };
+                cleanTreeFolder_1(this.workspace.tree);
+                // Then call the tree clean-up method
+                tree.remove();
+            }
+        }
+    }
+    TreeController.$inject = ['$scope', '$location', 'workspace', '$element'];
+
+})(Artemis || (Artemis = {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js
deleted file mode 100644
index bab70c6..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * 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 ARTEMIS
- */
-var ARTEMIS = (function(ARTEMIS) {
-
-    ARTEMIS.ConnectionsController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisConnection, artemisSession) {
-
-        var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
-
-        /**
-         *  Required For Each Object Type
-         */
-
-        var objectType = "connection"
-        var method = 'listConnections(java.lang.String, int, int)';
-        var defaultAttributes = [
-            {
-                field: 'connectionID',
-                displayName: 'ID',
-                width: '*'
-            },
-            {
-                field: 'clientID',
-                displayName: 'Client ID',
-                width: '*'
-            },
-            {
-                field: 'users',
-                displayName: 'Users',
-                width: '*'
-            },
-            {
-                field: 'protocol',
-                displayName: 'Protocol',
-                width: '*'
-            },
-            {
-                field: 'sessionCount',
-                displayName: 'Session Count',
-                width: '*',
-                cellTemplate: '<div class="ngCellText"><a ng-click="selectSessions(row)">{{row.entity.sessionCount}}</a></div>',
-                sortable: false
-            },
-            {
-                field: 'remoteAddress',
-                displayName: 'Remote Address',
-                width: '*'
-            },
-            {
-                field: 'localAddress',
-                displayName: 'Local Address',
-                width: '*'
-            },
-            {
-                field: 'creationTime',
-                displayName: 'Creation Time',
-                width: '*'
-            }
-        ];
-        ARTEMIS.log.debug('sessionStorage: connectionsColumnDefs =', sessionStorage.getItem('connectionsColumnDefs'));
-        var attributes = defaultAttributes;
-        if (sessionStorage.getItem('connectionsColumnDefs')) {
-            attributes = JSON.parse(sessionStorage.getItem('connectionsColumnDefs'));
-        }
-        $scope.$on('ngGridEventColumns', function (newColumns) {
-            ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
-            var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
-                visibles[column.field] = column.visible;
-                return visibles;
-            }, {});
-            ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
-            attributes.forEach(function (attribute) {
-                attribute.visible = visibles[attribute.field];
-            });
-            sessionStorage.setItem('connectionsColumnDefs', JSON.stringify(attributes));
-        });
-        $scope.filter = {
-            fieldOptions: [
-                {id: 'CONNECTION_ID', name: 'Connection ID'},
-                {id: 'CLIENT_ID', name: 'Client ID'},
-                {id: 'USERS', name: 'Users'},
-                {id: 'PROTOCOL', name: 'Protocol'},
-                {id: 'SESSION_COUNT', name: 'Session Count'},
-                {id: 'REMOTE_ADDRESS', name: 'Remote Address'},
-                {id: 'LOCAL_ADDRESS', name: 'Local Address'},
-                {id: 'SESSION_ID', name: 'Session ID'}
-            ],
-            operationOptions: [
-                {id: 'EQUALS', name: 'Equals'},
-                {id: 'CONTAINS', name: 'Contains'},
-                {id: 'GREATER_THAN', name: 'Greater Than'},
-                {id: 'LESS_THAN', name: 'Less Than'}
-            ],
-            values: {
-                field: "",
-                operation: "",
-                value: "",
-                sortOrder: "asc",
-                sortBy: "connectionID"
-            }
-        };
-
-        // Configure Parent/Child click through relationships
-        if (artemisSession.session) {
-            $scope.filter.values.field = $scope.filter.fieldOptions[0].id;
-            $scope.filter.values.operation = $scope.filter.operationOptions[0].id;
-            $scope.filter.values.value = artemisSession.session.connectionID;
-            artemisSession.session = null;
-        }
-
-        $scope.selectSessions = function (connection) {
-            artemisConnection.connection = connection.entity;
-            $location.path("artemis/sessions");
-        };
-        $scope.closeConnection = function () {
-            var connectionID = $scope.gridOptions.selectedItems[0].connectionID
-           ARTEMIS.log.info("closing connection: " + connectionID);
-           if (workspace.selection) {
-              var mbean = getBrokerMBean(jolokia);
-              if (mbean) {
-                  jolokia.request({ type: 'exec',
-                     mbean: mbean,
-                     operation: 'closeConnectionWithID(java.lang.String)',
-                     arguments: [connectionID] },
-                     onSuccess($scope.loadTable(), { error: function (response) {
-                        Core.defaultJolokiaErrorHandler("Could not close connection: " + response);
-                     }}));
-              }
-           }
-        };
-        /**
-         *  Below here is utility.
-         *
-         *  TODO Refactor into new separate files
-         */
-
-        $scope.workspace = workspace;
-        $scope.objects = [];
-        $scope.totalServerItems = 0;
-        $scope.pagingOptions = {
-            pageSizes: [50, 100, 200],
-            pageSize: 100,
-            currentPage: 1
-        };
-        $scope.sortOptions = {
-            fields: ["connectionID"],
-            columns: ["connectionID"],
-            directions: ["asc"]
-        };
-        var refreshed = false;
-        $scope.showClose = false;
-        $scope.gridOptions = {
-            selectedItems: [],
-            data: 'objects',
-            showFooter: true,
-            showFilter: true,
-            showColumnMenu: true,
-            enableCellSelection: false,
-            enableHighlighting: true,
-            enableColumnResize: true,
-            enableColumnReordering: true,
-            selectWithCheckboxOnly: false,
-            showSelectionCheckbox: false,
-            multiSelect: false,
-            displaySelectionCheckbox: false,
-            pagingOptions: $scope.pagingOptions,
-            enablePaging: true,
-            totalServerItems: 'totalServerItems',
-            maintainColumnRatios: false,
-            columnDefs: attributes,
-            enableFiltering: true,
-            useExternalFiltering: true,
-            sortInfo: $scope.sortOptions,
-            useExternalSorting: true,
-        };
-        $scope.refresh = function () {
-            refreshed = true;
-            $scope.loadTable();
-        };
-        $scope.reset = function () {
-            $scope.filter.values.field = "";
-            $scope.filter.values.operation = "";
-            $scope.filter.values.value = "";
-            $scope.loadTable();
-        };
-        $scope.loadTable = function () {
-        	$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
-            $scope.filter.values.sortBy = $scope.sortOptions.directions[0];
-	        $scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
-            var mbean = getBrokerMBean(jolokia);
-            if (mbean.includes("undefined")) {
-                onBadMBean();
-            } else if (mbean) {
-                var filter = JSON.stringify($scope.filter.values);
-                console.log("Filter string: " + filter);
-                jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
-            }
-        };
-        $scope.selectGridRow = function () {
-            $scope.showClose =  $scope.gridOptions.selectedItems.length > 0;
-        };
-        function onError() {
-            Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
-        }
-        function onBadMBean() {
-            Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
-        }
-        function populateTable(response) {
-            $scope.gridOptions.selectedItems.length = 0;
-            $scope.showClose = false;
-            var data = JSON.parse(response.value);
-            $scope.objects = [];
-            angular.forEach(data["data"], function (value, idx) {
-                $scope.objects.push(value);
-            });
-            $scope.totalServerItems = data["count"];
-            if (refreshed == true) {
-                $scope.gridOptions.pagingOptions.currentPage = 1;
-                refreshed = false;
-            }
-            Core.$apply($scope);
-        }
-        $scope.$watch('sortOptions', function (newVal, oldVal) {
-            if (newVal !== oldVal) {
-                $scope.loadTable();
-            }
-        }, true);
-        $scope.$watch('pagingOptions', function (newVal, oldVal) {
-            if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
-                $scope.loadTable();
-            }
-            if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
-                $scope.pagingOptions.currentPage = 1;
-                $scope.loadTable();
-            }
-        }, true);
-
-        function getBrokerMBean(jolokia) {
-            var mbean = null;
-            var selection = workspace.selection;
-            var folderNames = selection.folderNames;
-            mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
-            ARTEMIS.log.info("broker=" + mbean);
-            return mbean;
-        };
-        $scope.refresh();
-    };
-    return ARTEMIS;
-} (ARTEMIS || {}));
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js
deleted file mode 100644
index 515158a..0000000
--- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * 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
- *
... 2923 lines suppressed ...