DISPATCH-221 - Check in hawtio plugin code
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/eb2e027a Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/eb2e027a Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/eb2e027a Branch: refs/heads/master Commit: eb2e027a4eb84d043e01b3e03abf02f0ac7d1b09 Parents: fc4f8e6 Author: Ernest Allen <[email protected]> Authored: Mon Feb 22 16:09:25 2016 -0500 Committer: Ernest Allen <[email protected]> Committed: Mon Feb 22 16:09:25 2016 -0500 ---------------------------------------------------------------------- LICENSE | 5 +- console/hawtio/README.md | 86 + console/hawtio/pom.xml | 240 +++ .../simpleplugin/PluginContextListener.java | 37 + .../hawtio/src/main/resources/WEB-INF/web.xml | 41 + .../hawtio/src/main/resources/log4j.properties | 6 + .../src/main/webapp/plugin/css/plugin.css | 725 ++++++++ .../src/main/webapp/plugin/css/qdrTopology.css | 495 ++++++ .../src/main/webapp/plugin/html/qdrCharts.html | 63 + .../src/main/webapp/plugin/html/qdrConnect.html | 38 + .../src/main/webapp/plugin/html/qdrGraphs.html | 15 + .../src/main/webapp/plugin/html/qdrLayout.html | 26 + .../src/main/webapp/plugin/html/qdrList.html | 55 + .../main/webapp/plugin/html/qdrOverview.html | 92 + .../src/main/webapp/plugin/html/qdrSchema.html | 21 + .../main/webapp/plugin/html/qdrTopology.html | 201 +++ .../src/main/webapp/plugin/js/dispatchPlugin.js | 241 +++ .../hawtio/src/main/webapp/plugin/js/navbar.js | 128 ++ .../main/webapp/plugin/js/qdrChartService.js | 1074 ++++++++++++ .../src/main/webapp/plugin/js/qdrCharts.js | 304 ++++ .../hawtio/src/main/webapp/plugin/js/qdrList.js | 543 ++++++ .../src/main/webapp/plugin/js/qdrOverview.js | 688 ++++++++ .../src/main/webapp/plugin/js/qdrSchema.js | 38 + .../src/main/webapp/plugin/js/qdrService.js | 731 ++++++++ .../src/main/webapp/plugin/js/qdrSettings.js | 125 ++ .../src/main/webapp/plugin/js/qdrTopology.js | 1651 ++++++++++++++++++ .../src/main/webapp/plugin/lib/rhea-min.js | 93 + 27 files changed, 7761 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/LICENSE ---------------------------------------------------------------------- diff --git a/LICENSE b/LICENSE index 5e0976f..3775103 100644 --- a/LICENSE +++ b/LICENSE @@ -205,4 +205,7 @@ # Thrid Party Dependency Licensing Information: ############################################### -console/stand-alone/plugin/lib/rhea-min.js is Licensed under the above Apache License, Version 2.0 +console/stand-alone/plugin/lib/rhea-min.js is licensed under the above Apache License, Version 2.0 + +console/hawtio/src/main/webapp/plugin/lib/rhea-min.js is licensed under the above Apache License, Version 2.0 + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/README.md ---------------------------------------------------------------------- diff --git a/console/hawtio/README.md b/console/hawtio/README.md new file mode 100644 index 0000000..206400c --- /dev/null +++ b/console/hawtio/README.md @@ -0,0 +1,86 @@ +# hawtio dispatch router plugin + +dispatch-plugin.war is a standalone hawtio plugin that can be deployed in a server alongside the main hawtio-web application. + +The project creates a war file that can be deployed in various application services and is also OSGi-ified so it deploys nicely into Apache Karaf. + +## Docker + +The fastest way to use the console is to run the [docker image](https://hub.docker.com/r/ernieallen/dispatch-console/). Follow the installation/run instruction on that page. + +## Building +The dispatch-plugin.war file is pre-built and can be installed alongside the hawtio.war on any system with a modern java installation. If you want to build the dispatch-plugin.war from source: + +- clone the hawtio git repo + + $ git clone https://github.com/hawtio/hawtio.git + +- build hawtio + + $ cd hawtio + + $ mvn clean install + + If you encounter any errors when building hawtio, visit [the hawtio build page](http://hawt.io/building/index.html) for help. + +- create a dispatch dir under the hawtio dir and copy the source code + + $ mkdir dispatch + + $ cp -r {dir where this file is located}/dispatch/* dispatch/ + +- do a maven build of dispatch + + $ cd dispach + + $ mvn package + +The dispatch-plugin-1.4.60.war file should now be in the target directory. + +## Apache Tomcat installation + +Copy the dispatch-plugin-1.4.60.war file as the following name + + dispatch-plugin.war +to the deploy directory of Apache Tomcat or similar Java web container. Ensure the hawtio.war file is present in the same directory. Point a browser at http://\<tomcathost:post\>/hawtio +Dispatch Router should be available as a tab in the console. + +## Connecting to a router + +On the Dispatch Router's console page, select the Connect sub tab. Enter the address of a dispatch router. Enter the port of a websockets to tcp proxy and click the Connect button. + +### Websockts to tcp proxy + +The console communicates to a router using Qpid Proton's [rhea](https://github.com/grs/rhea) javascript binding. When run from a browser, it uses websockets. +The router communicates using tcp. Therefore a websockts/tcp proxy is required. + +#### Manually running a python websockets/tcp proxy + +A popular python based proxy is [websockify](https://github.com/kanaka/websockify). To use it: + + $ git clone https://github.com/kanaka/websockify.git + $ cd websockify + $ ./run 5673 0.0.0.0:20009 & + +In the above, websockify is listening for ws traffic on port 5673 and will proxy it to 0.0.0.0:20009. One of the routers will need a listener on the proxied port. An example router .conf file entry is: + + listener { + name: ProxyListener + role: normal + addr: 0.0.0.0 + port: 20009 + sasl-mechanisms: ANONYMOUS + } + +#### Automatically running a proxy with a router + +You can automatically start the proxy program when a router starts. Add the listener above and the following console section to a router's config file. + + console { + listener: ProxyListener + proxy: /pathToWebsockify/run + wsport: 5673 + } + +The value for proxy: can be any program that has execute permission. The router will execute it and pass <wsport> <addr:port> as arguments. + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/pom.xml ---------------------------------------------------------------------- diff --git a/console/hawtio/pom.xml b/console/hawtio/pom.xml new file mode 100644 index 0000000..effdfb4 --- /dev/null +++ b/console/hawtio/pom.xml @@ -0,0 +1,240 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>io.hawt</groupId> + <artifactId>project</artifactId> + <version>1.4.60</version> + </parent> +<!-- + <parent> + <groupId>io.hawt</groupId> + <artifactId>hawtio-plugin-examples</artifactId> + <version>1.4.60</version> + <relativePath>..</relativePath> + </parent> +--> + <modelVersion>4.0.0</modelVersion> + <artifactId>dispatch-plugin</artifactId> + <name>${project.artifactId}</name> + <description>hawtio :: hawtio Dispatch plugin</description> + + <!-- hawtio plugins are almost always war files --> + <packaging>war</packaging> + + <properties> + <!-- filtered plugin properties, we don't define plugin-scripts here + as we build that dynamically using maven-antrun-plugin below. --> + <!-- plugin-context is what context this plugin will handle requests on + in the application server --> + <plugin-context>/dispatch-plugin</plugin-context> + + <!-- plugin-name is the name of our plugin, affects the name used for + the plugin's mbean --> + <plugin-name>${project.artifactId}</plugin-name> + + <!-- plugin-domain is currently unused, we just define it to an empty + string --> + <plugin-domain /> + + <!-- this lets this plugin deploy nicely into karaf, these get used + for the ImportPackage directive for maven-bundle-plugin --> + <fuse.osgi.import> + javax.servlet, + *;resolution:=optional + </fuse.osgi.import> + </properties> + + <dependencies> + + <!-- we only need to embed this dependency in the war, this contains + a nice helper class that our plugin can use to export it's plugin + mbean --> + <dependency> + <groupId>io.hawt</groupId> + <artifactId>hawtio-plugin-mbean</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- servlet API is provided by the container --> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>${servlet-api-version}</version> + <scope>provided</scope> + </dependency> + + <!-- logging --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j-version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>${slf4j-version}</version> + </dependency> + + </dependencies> + + <build> + + <!-- we want to ensure src/main/resources/WEB-INF/web.xml is being filtered + so that it picks up all of our javascript files --> + <resources> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>**/*.xml</include> + </includes> + </resource> + </resources> + + <plugins> + + <!-- We use maven-antrun-plugin to build up a list of + javascript files for our plugin mbean, this means + it needs to run before the maven-resources-plugin + copies and filters the web.xml, since for this + example we use contextParam settings to configure + our plugin mbean --> + + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <version>${maven-antrun-plugin-version}</version> + <executions> + + <execution> + <!-- we run this early in the build process before + maven-resources-plugin is run. We're exporting the + plugin-scripts property from here, so we need to + use maven-antrun-plugin 1.6 or up --> + <id>generate-sources</id> + <phase>generate-sources</phase> + <goals> + <goal>run</goal> + </goals> + <configuration> + <target> + <echo>Building plugin javascript file list</echo> + <!-- javascript-files will contain all of the javascript in + our project --> + <fileset id="javascript-files" dir="${basedir}/src/main/webapp"> + <include name="**/*.js" /> + </fileset> + <!-- we need to strip out the top level path which is + our source directory and be sure to change the directory + separators to forward slashes --> + <pathconvert pathsep="," dirsep="/" property="plugin-scripts" refid="javascript-files"> + <map from="${basedir}/src/main/webapp/" to="" /> + </pathconvert> + <echo>Files: ${plugin-scripts}</echo> + + <echo>Copying log4j.properties</echo> + <copy file="src/main/resources/log4j.properties" todir="target/classes" /> + + </target> + <!-- this exports plugin-scripts to the maven build, without + this line ${plugin-scripts} in the web.xml file won't be + replaced --> + <exportAntProperties>true</exportAntProperties> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>${maven-resources-plugin-version}</version> + <executions> + <execution> + <!-- defining this maven plugin in the same phase as the + maven-antrun-plugin but *after* we've configured the + maven-antrun-plugin ensures we filter resources *after* + we've discovered the plugin .js files. --> + <id>copy-resources</id> + <phase>generate-sources</phase> + <goals> + <goal>resources</goal> + </goals> + </execution> + </executions> + </plugin> + + <!-- maven-bundle-plugin config, needed to make this war + deployable in karaf, defines the context that this bundle + should handle requests on --> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>${maven-bundle-plugin-version}</version> + <executions> + <execution> + <id>bundle-manifest</id> + <phase>process-classes</phase> + <goals> + <goal>manifest</goal> + </goals> + </execution> + </executions> + <configuration> + <manifestLocation>${webapp-outdir}/META-INF</manifestLocation> + <supportedProjectTypes> + <supportedProjectType>jar</supportedProjectType> + <supportedProjectType>bundle</supportedProjectType> + <supportedProjectType>war</supportedProjectType> + </supportedProjectTypes> + <instructions> + <Webapp-Context>${plugin-context}</Webapp-Context> + <Web-ContextPath>${plugin-context}</Web-ContextPath> + + <Embed-Directory>WEB-INF/lib</Embed-Directory> + <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + + <Export-Package>${fuse.osgi.export}</Export-Package> + <Import-Package>${fuse.osgi.import}</Import-Package> + <DynamicImport-Package>${fuse.osgi.dynamic}</DynamicImport-Package> + <Private-Package>${fuse.osgi.private.pkg}</Private-Package> + + <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath> + + <Bundle-Name>${project.description}</Bundle-Name> + <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName> + <Implementation-Title>HawtIO</Implementation-Title> + <Implementation-Version>${project.version}</Implementation-Version> + </instructions> + </configuration> + </plugin> + + <!-- We define the maven-war-plugin here and make sure it uses + the manifest file generated by the maven-bundle-plugin. We + also ensure it picks up our filtered web.xml and not the one + in src/main/resources --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>${war-plugin-version}</version> + <configuration> + <outputFileNameMapping>@{artifactId}@-@{baseVersion}@@{dashClassifier?}@.@{extension}@</outputFileNameMapping> + <packagingExcludes>**/classes/OSGI-INF/**</packagingExcludes> + <failOnMissingWebXml>false</failOnMissingWebXml> + <archive> + <manifestFile>${webapp-outdir}/META-INF/MANIFEST.MF</manifestFile> + </archive> + <webResources> + <resource> + <filtering>true</filtering> + <directory>src/main/resources</directory> + <includes> + <include>**/*.*</include> + </includes> + </resource> + </webResources> + </configuration> + </plugin> + + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/java/io/hawt/example/simpleplugin/PluginContextListener.java ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/java/io/hawt/example/simpleplugin/PluginContextListener.java b/console/hawtio/src/main/java/io/hawt/example/simpleplugin/PluginContextListener.java new file mode 100644 index 0000000..a417786 --- /dev/null +++ b/console/hawtio/src/main/java/io/hawt/example/simpleplugin/PluginContextListener.java @@ -0,0 +1,37 @@ +package io.hawt.dispatch; + +import io.hawt.web.plugin.HawtioPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +public class PluginContextListener implements ServletContextListener { + + private static final Logger LOG = LoggerFactory.getLogger(PluginContextListener.class); + + HawtioPlugin plugin = null; + + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + + ServletContext context = servletContextEvent.getServletContext(); + + plugin = new HawtioPlugin(); + plugin.setContext((String)context.getInitParameter("plugin-context")); + plugin.setName(context.getInitParameter("plugin-name")); + plugin.setScripts(context.getInitParameter("plugin-scripts")); + plugin.setDomain(null); + plugin.init(); + + LOG.info("Initialized {} plugin", plugin.getName()); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + plugin.destroy(); + LOG.info("Destroyed {} plugin", plugin.getName()); + } +} http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/resources/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/resources/WEB-INF/web.xml b/console/hawtio/src/main/resources/WEB-INF/web.xml new file mode 100644 index 0000000..30ae7f0 --- /dev/null +++ b/console/hawtio/src/main/resources/WEB-INF/web.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<web-app xmlns="http://java.sun.com/xml/ns/j2ee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee + http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" + version="2.4"> + + <description>Qpid Dispatch Router console hawt.io plugin</description> + <display-name>Dispatch Router console</display-name> + + <context-param> + <description>Plugin's path on the server</description> + <param-name>plugin-context</param-name> + <param-value>${plugin-context}</param-value> + </context-param> + + <context-param> + <description>Plugin's path on the server</description> + <param-name>plugin-name</param-name> + <param-value>${project.artifactId}</param-value> + </context-param> + + <context-param> + <description>Plugin's path on the server</description> + <param-name>plugin-domain</param-name> + <param-value>${plugin-domain}</param-value> + </context-param> + + <context-param> + <description>Plugin's path on the server</description> + <param-name>plugin-scripts</param-name> + <param-value>${plugin-scripts}</param-value> + </context-param> + + <listener> + <listener-class>io.hawt.dispatch.PluginContextListener</listener-class> + </listener> + + +</web-app> + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/resources/log4j.properties b/console/hawtio/src/main/resources/log4j.properties new file mode 100644 index 0000000..a2ecc8d --- /dev/null +++ b/console/hawtio/src/main/resources/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootLogger=INFO, console + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/css/plugin.css ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/css/plugin.css b/console/hawtio/src/main/webapp/plugin/css/plugin.css new file mode 100644 index 0000000..c6f5cc1 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/css/plugin.css @@ -0,0 +1,725 @@ +/* +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. +*/ +main-display > .span8 { + height: 100%; + position: relative; +} + +ul.qdrListNodes > li > span { + padding: 6px 20px; 6px; 6px; + display: block; +} + +.qdrList .gridStyle { + width: 20em; + margin-right: 0; + float: left; +} + + +.qdrList div.gridDetails { + + width: auto; +} + +.selectedItems { +/* margin-left: 21em; */ +} + +.qdrListPane { + top: 110px; +} + +.qdrListActions { + width: auto; +} + +div.listAttrName { + padding-top: 5px; +} + +div.listAttrName i.icon-bar-chart { + float: right; + margin: 3px 5px; +} + +div.listAttrName i.icon-bar-chart.active, div.hastip i.icon-bar-chart.active, li.haschart i { + background-color: #AAFFAA; +} + +div#main div ul.nav li a:not(.btn) { + background: initial !important; +} + +div#main div ul.nav li.active a { + background-color: #f0f0ff !important; +} + +div#main.qdr { + margin-top: 44px !important; +} + +div.charts-header { + font-size: 1.2em; + color: #666666; + margin: 1em 0; +} + +.selectedNode, .selectedAction, .selectedEntity { + font-weight: 600; + color: #606066; +} + +.okButton { + text-align: center; + margin: 1em; +} + +span.showChartsLink { + border: 1px solid blue; + padding: 1px 2px; +} + +div.listGraphs p { + margin: 1em 0 2em 2em; + text-align: center; +} + +div.centered { + text-align: center; + margin: 4em; +} + +.modal-body.centered { + margin: 0; +} + +/* dialog */ +div.aChart { + height: 200px; + width: 400px; + margin: 1em; +} + +/* dashboard */ +div.aChart.hDash { + /* width: 21em; */ + /* height: 17em; */ + width: 100%; + height: 87%; + margin: 0; + padding: 0; + +} +div.chartContainer { + float: left; + width: 100%; + height: 100%; + overflow: hidden; +} + +/* the x and y axis lines */ +.d3Chart g.axis path.domain { + stroke-width: 1; + stroke: black; +} + +/* the line surrounding the area chart */ +div.d3Chart path { +/* stroke: black; */ + stroke-width: 0; +/* opacity: 0.5; */ +} + +/* the line above the area chart */ +/* the color gets overridden */ +div.d3Chart path.line { + stroke: steelblue; + stroke-width: 1.5; + fill: none; + opacity: 1; +} + +.mo-rect { + fill: #ffffdd; + stroke: #f0f0f0; + stroke-width: 1; +} + +.mo-guide { + fill: none; + stroke: #d0d0d0; + stroke-width: 2; + stroke-dasharray: 3,3; +} + +div.d3Chart .title { + text-decoration: underline; +} + + +.axis line, .axis path { + fill: none; + shape-rendering: crispEdges; + stroke-width: 1; + stroke: #000000; +} + +.axis line { + stroke: #C0C0C0; + stroke-dasharray: 1,1; + opacity: 0.5; +} + +.y.axis text, .x.axis text, .focus text, div.d3Chart .title { + font-size: 12px; +} + +.y.axis path { + stroke: #000; + } + +.overlay { + fill: none; + pointer-events: all; + } + +.focus circle { + fill: none; + stroke: steelblue; + } +.focus .fo-table { + /* box-shadow: 2px 2px 3px #EEE; */ +} + +div.d3Chart { + padding: 1em 0; + border: 1px solid #C0C0C0; +} +div.d3Chart.hDash { + border: 0px; +} + +div.d3Chart .axis path { + display: inherit; +} +.c3-circle { + display: none; +} + +.fo-table { + border: 1px solid darkgray; + background-color: white; + font-size: .85em; +} + +.fo-table td { + padding: 4px; + border-left: 1px solid darkgray; +} +.fo-table tr.detail td { + padding: 1px 4px; +} +.fo-title { + color: white; + background-color: darkgray; +} + +.fo-table-legend { + width: 8px; + height: 8px; + border: 1px solid black; + margin: 0 4px; + display: inline-block; +} + +svg .legend { + dominant-baseline: central; +} + +div.chartContainer div.aChart { + margin-top: 0.5em; +} + +div.qdr-attributes .tree-header select { + width: 100%; +} + +div#main.qdr div ul.nav li.active a { + background-color: #e0e0ff !important; + color: #000000; +} + +div#main.qdr .selected, .box.selected { + color: #000000; + text-shadow: none; +} + +/* the selected node on the list page */ +div.qdrList li.active, ul.qdrListNodes li.active { + background-color: #e0e0ff; +} + +div.qdr-attributes span.dynatree-selected a { + background-color: #e0e0ff; +} +div.qdr-attributes.pane { + position: absolute; + margin-left: 10px; +} + +/* the selected row in the name table */ +div#main.qdr div.qdrList div.selected { + background-color: #e0e0ff !important; +} + +#dialogChart { + height: 200px; +} + +div.qdrCharts p.chartLabels button { + float: right; +} + +div.qdrCharts p.chartLabels { + padding-right: 1em;; + } + +p.dialogHeader { + text-align: center; +} + +p.dialogHeader input { + margin-top: 10px; + width: 480px; +} + +.ui-slider-tick { + position: absolute; + background-color: #666; + width: 2px; + height: 8px; + top: 12px; + z-index: -1; +} + +label.rateGroup { + float: left; +} + +div.chartOptions div.dlg-slider { + float: left; + margin-left: 2em; + width: 28em; + font-size: 14px; +} + +div.chartOptions div.duration { + width: 35em !important; +} + +div.chartOptions .slider { + margin-top: 1em; + margin-bottom: 1em; +} + +input[type="radio"] { + margin-top: 0 !important; +} + +div.chartOptions legend { + font-size: 1.2em; + margin-bottom: 10px; +} + +div.chartOptions span.minicolors-swatch { + width: 14px; + height: 14px; +} + +.minicolors-input { + width: 4em; + padding: 0 0 0 24px !important; +} + +div.colorPicker div.colorText { + display: inline-block; + width: 10em; +} + +div.chartOptions p.sep { + height: 1em; +} + +ul.nav-tabs { + border-bottom: 1px solid #ddd !important; +} + +.chartOptions ul.nav-tabs { + margin-bottom: 0px !important; +} + +div.tabbable div.tab-content { + overflow: visible; +} + +div.tabbable ul.nav-tabs > .active > a { + background-color: #f8f8f8; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +div.tabbable .tab-pane { + background-color: #f8f8f8; + padding: 12px; + border-right: 1px solid #ddd; + border-left: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} +div.dlg-large div.tabbable .tab-pane { + margin-left: 11em; +} + +div.tabbable ul.nav-tabs { + margin-bottom: 0; +} + +ul.qdrTopoModes { + position: relative; + top: -10px; +} +.overview.section { + /* width: 35em; */ +} +.overview.section .ngGrid { + height: 12em !important; + min-height: 12em !important; +} + +.overview.routers.section .ngGrid { + height: 16em !important; + min-height: 16em !important; +} +.overview.routers.section { + /*width: 15em; */ + } + +.grid-align-value { + text-align: right; +} + +.overview .ngRow:hover { + background:#e0e0ff; +} + +.qdr-overview.pane.left, .qdr-attributes.pane.left { + top: 100px; +} +.qdr-overview.pane.left { + left: 10px; +} + +.treeContainer { + /*width: 250px; + float: left; + overflow-y: auto; + border-right: 1px solid lightgrey; + height: 100vh; +*/ +} + +#entityNames { + width: 20em; + float: left; +} + +.treeDetails { + /* margin-left: 300px; */ +} + +.gridStyle:not(.noHighlight) .ui-grid-row:hover .ui-grid-cell-contents { + background-color: #e0e0ff; +} + +.ngCellText { + padding: 4px 0 0 4px; +} + +.overview { + border-bottom: 1px solid #d4d4d4; +} + +.ui-grid-row.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell { + background-color: #e0e0ff; +} + +.tab-content .tab-pane { + background-color: #f8f8f8; + padding: 12px; + border-right: 1px solid #ddd; + border-left: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} + +div.chartOptions ul.nav-tabs > .active > a { + background-color: #f8f8f8; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +div.chartOptions label:nth-of-type(2) { + margin-left: 1em; +} +div.chartOptions label { + font-weight: normal; + display: inline-block; +} + +/* +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + margin-left: 180px; +} + +.form-horizontal input, { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; +} + +input[type="text"], input[type="number"], input[type="password"] { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +input[type="text"], input[type="number"], input[type="password"] { + display: inline-block; + width: 200px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 14px; + line-height: 20px; + color: #555555; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.login input[type="checkbox"] { + margin-top: 0.75em; +} +*/ + +#dispatch-login-container { + /* width: 18.5em; */ + margin-top: 2em; +} +/* +div.login.container { + width: 550px; +} +*/ + + +#overtree .fancytree-container { +/* border: 0px; */ +} + +#overtree span.fancytree-alert-icon.ui-icon-refresh { + /*background-position: -64px -80px; */ +} +#overtree span.fancytree-alert-icon.ui-icon-transfer-e-w { + /*background-position: -112px -80px;*/ +} + +#alerts { + position: fixed; + right: 0; + top: 0; + z-index: 100; +} + +.alert-enter, +.alert-leave, +.alert-move { + -webkit-transition: 1s linear all; + -moz-transition: 1s linear all; + -o-transition: 1s linear all; + transition: 1s linear all; + position:relative; +} + +.alert-enter { + left:-10px; + opacity:0; +} +.alert-enter.alert-enter-active { + left:0; + opacity:1; +} + +.alert-leave { + left:0; + opacity:1; +} +.alert-leave.alert-leave-active { + left:-10px; + opacity:0; +} + +.alert-move { + opacity:0.5; +} +.alert-move.alert-move-active { + opacity:1; +} + +.overview .table-striped tr:hover td { + background-color: #e0e0ff !important; +} + +#entityNames div.ngViewport { + overflow-x: hidden; +} + +.connect-column.connect-form { + width: 30em; +} + +.chartLabels button a { + text-decoration: none; +} + +.fancytree-ico-c.router .fancytree-icon { + +} + +.tabs-left .nav-tabs { + float: left; +} +.tabs-left .nav-tabs > li { +/* float: initial; */ +} + +div.modal.dlg-large { + width: 53em; +} + +button.hdash-button a { + text-decoration: none; + color: #fff; +} + +div.widget-body > div { + height: 100%; +} + +div.qdrCharts { + height: 100%; +} + +ul.dispatch-view { + margin-bottom: 0 !important; +} + +.qdr-overview.pane.left span:not(.dynatree-has-children) .dynatree-icon:before, +.qdr-attributes.pane.left span:not(.dynatree-has-children) .dynatree-icon:before { + color: green; +} + +span:not(.dynatree-has-children).address .dynatree-icon:before, +span:not(.dynatree-has-children).router\.address .dynatree-icon:before { + content: "\f0ac"; +} + +span:not(.dynatree-has-children).connection.external .dynatree-icon:before, +span:not(.dynatree-has-children).connection.normal .dynatree-icon:before { + content: "\f08e"; +} +span:not(.dynatree-has-children).connection.inter-router .dynatree-icon:before { + content: "\f152"; +} +span:not(.dynatree-has-children).no-data .dynatree-icon:before { + content: "\f05e"; + color: red !important; +} +span:not(.dynatree-has-children).loading .dynatree-icon:before { + content: "\f254"; +} +span:not(.dynatree-has-children).router\.node .dynatree-icon:before { + content: "\f013"; +} +span:not(.dynatree-has-children).connector .dynatree-icon:before { + content: "\f126"; +} +span:not(.dynatree-has-children).container .dynatree-icon:before { + content: "\f16c"; +} +span:not(.dynatree-has-children).log .dynatree-icon:before { + content: "\f0f6"; +} +span:not(.dynatree-has-children).router\.link.inter-router .dynatree-icon:before { + content: "\f04e"; +} +span:not(.dynatree-has-children).router\.link.endpoint .dynatree-icon:before { + content: "\f051"; +} +span:not(.dynatree-has-children).listener .dynatree-icon:before { + content: "\f025"; +} +span:not(.dynatree-has-children).connection .dynatree-icon:before { + content: "\f07e"; +} +span:not(.dynatree-has-children).waypoint .dynatree-icon:before { + content: "\f0ec"; +} +span:not(.dynatree-has-children).router .dynatree-icon:before { + content: "\f047"; +} +span:not(.dynatree-has-children).fixedAddress .dynatree-icon:before { + content: "\f015"; +} +span:not(.dynatree-has-children).linkRoutePattern .dynatree-icon:before { + content: "\f039"; +} +span:not(.dynatree-has-children).allocator .dynatree-icon:before { + content: "\f170"; +} + +.ngCellText { +/* color: #333333; */ +} + +.changed { + color: #339933; +} http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css b/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css new file mode 100644 index 0000000..0eac80d --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css @@ -0,0 +1,495 @@ +/* +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 { + background-color: transparent; + cursor: default; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +svg:not(.active):not(.ctrl) { + cursor: crosshair; +} +#end-arrow-selected, #start-arrow-selected { + stroke: #00F; + fill: #00F; +} + +path.link { + fill: none; + stroke: #000; + stroke-width: 4px; + cursor: default; +} + +svg:not(.active):not(.ctrl) path.link { + cursor: pointer; +} + +path.link.selected { + stroke-dasharray: 10,2; + stroke: #00F !important; +} + + +path.link.highlighted { + stroke: #0F0 !important; + +} + +path.link.temp { + opacity: 0.3; +} +path.link.temp.over { + opacity: 0.8; + stroke-dasharray: 10,2; +} + +path.link.dragline { + pointer-events: none; +} + +path.link.hidden { + stroke-width: 0; +} + + +circle.node { + stroke-width: 1.5px; + cursor: pointer; + stroke: darkgray; + fill: lightgray; +} + +circle.node.reflexive { + stroke: #F00 !important; + stroke-width: 2.5px; +} +circle.node.selected { + stroke: #F00 !important; + stroke-width: 2px; + fill: #e0e0ff !important; +} +circle.node.inter-router { + fill: #EAEAEA; +} +circle.node.normal { + fill: #F0F000; +} +circle.node.on-demand { + fill: #00F000; +} + +circle.node.fixed { + stroke-dasharray: 10,2; +} +circle.node.temp { + stroke: #f80; + fill: #f0f0ff; +} + +text { + font: 12px sans-serif; + pointer-events: none; + /*font-family: monospace;*/ + +} + +.tooltipsy +{ + padding: 10px; +/* max-width: 320px;*/ + color: #303030; + background-color: #fcfcfe; + border: 1px solid #deca7e; + border-radius: 5px; +} + +.tiptable { + +} +.tiptable tr { + border-bottom: 1px solid #ccc; +} + +.tiptable tr:last-child { + border-bottom: 0px; +} + +.tiptable tr:nth-child(even) { + background: #fcfcfe; +} +.tiptable tr:nth-child(odd) { + background: #FFF +} + +text.id { + text-anchor: middle; + font-weight: bold; +} + +.row-fluid.tertiary { + position: relative; + left: 20px; +} + +.row-fluid.tertiary.left { + float: left; +} + +.row-fluid.tertiary.panel { + width: 410px; + height: 100%; +} + +.panel-adjacent { + margin-left: 430px; +} + +#topologyForm.selected { + border: 1px solid red; +} +#topologyForm { + border: 1px solid white; + padding: 2px; + position: relative; + top: -8px; +} + +#topologyForm > div { + width:396px; + /*height: 100vh;*/ +} + +/* globe */ +.land { + fill: #999; + stroke-opacity: 1; +} + +.graticule { + fill: none; + stroke: black; + stroke-width:.5; + opacity:.1; +} + +.labels { + font: 18px sans-serif; + fill: black; + opacity: .85; + text-anchor: middle; +} + +.noclicks { pointer-events:none; } + +.point { opacity:.6; } + +.arcs { + opacity:.7; + stroke: darkgreen; + stroke-width: 3; +} +.flyers { + stroke-width:1; + opacity: 0; + stroke: darkred; +} +.arc, .flyer { + stroke-linejoin: round; + fill:none; +} +.arc { } +.arc:hover { + stroke: darkred; +} +.flyer { } +.flyer:hover { + stroke: darkgreen; +} +.arc.inter-router { + stroke: darkblue; +} + +#addNodeForm { + padding: 1em; +} + + +li.currentStep { + font-weight: bold; +} + +.qdrTopology div.panel { + position: absolute; +} +/* +.ui-dialog-titlebar { + border: 0; + background: transparent; +} +*/ + +/* +.ui-tabs.ui-tabs-vertical { + padding: 0; + width: 48em; +} +.ui-tabs.ui-tabs-vertical .ui-widget-header { + border: none; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-nav { + float: left; + width: 10em; + background: #CCC; + border-radius: 4px 0 0 4px; + border-right: 1px solid gray; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-nav li { + clear: left; + width: 100%; + margin: 0.1em 0; + border: 1px solid gray; + border-width: 1px 0 1px 1px; + border-radius: 4px 0 0 4px; + overflow: hidden; + position: relative; + right: -2px; + z-index: 2; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a { + display: block; + width: 100%; + padding: 0.1em 1em; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover { + cursor: pointer; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active { + margin-bottom: 0.2em; + padding-bottom: 0; + border-right: 1px solid white; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child { + margin-bottom: 10px; +} +.ui-tabs.ui-tabs-vertical .ui-tabs-panel { + float: left; + width: 34em; + border-left: 1px solid gray; + border-radius: 0; + position: relative; + left: -1px; +} + +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { + right: -3px !important; +} + +.ui-tabs li i.ui-icon { + display: inline-block; +} +*/ +.ui-tabs .ui-tabs-panel { + /* padding-top: 0 !important; */ +} + +.ui-widget-content fieldset { + float: left; + padding: 0 1em 0 0; +} + +.entity-description { + color: #960; + font-size: 90%; +} + +.attr-description { + padding-top: 1.5em; + float: right; + width: 17em; +} +.attr-annotations { + padding-top: 2.5em; + clear: both; +} +.attr-annotations > span { + padding-top: 0.5em; + border-top: 1px dashed darkgray; + display: block; +} + +.attr-type { + color: #990; + font-size: 85%; +} +.attr-required { + color: red; + font-size: 85%; +} +.attr-unique { + color: green; + font-size: 85%; +} + +#tabs.nodeEntities { + border: 0; +} + +#tabs ul.nodeTabs { + background: #fff; +} + +#tabs #Container { + border-left: 1px solid #aaa; +} + +#tabs.ui-tabs .ui-tabs-nav li { + border-bottom: 1px solid #aaa !important; +} + +.entity-fields { + /* height: 400px; */ + overflow-y: scroll; + overflow-x: hidden; +} + +div.boolean label:first-child { + float: left; + margin-right: 1em; +} +div.boolean { + padding-bottom: 1em; +} + +.entity-fields label { + font-weight: 600; + margin-top: 0.5em; + display: inline; +} + +.aggregate { + text-align: right; +} + +.aggregate i { + float: right; + margin: 3px 3px 3px 8px; +} + +.aggregate .hastip { + padding: 5px; +} + +.subTip .tipsy-inner { + background-color: white; + color: black; + font-size: 1.3em; + border: 1px solid black; +} + +.subTip .tipsy-arrow-n { border-bottom-color: black; } +.subTip .tipsy-arrow-s { border-top-color: black; } +.subTip .tipsy-arrow-e { border-left-color: black; } +.subTip .tipsy-arrow-w { border-right-color: black; } + + +.contextMenu { + display:none; + position:absolute; + left:30px; + top:-30px; + z-index:999; + /* width:300px; */ +} +.contextMenu ul { + width:300px; + margin:0; + /* padding:10px; */ + list-style:none; + background:#fff; + color:#333; + font-weight: 600; + /* -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; */ + -moz-box-shadow:5px 5px 5px #ddd; -webkit-box-shadow:5px 5px 5px #999; box-shadow:5px 5px 5px #ddd; + border: 1px solid #aaa; +} +.contextMenu ul li { + padding:5px 10px; + /* border-bottom: solid 1px #ccc; */ +} +.contextMenu ul li:hover { + background:#4a90d9; color:#fff; +} +.contextMenu ul li:last-child { + border:none; +} + +.na { + display: none; +} +.contextMenu ul li.new { + display: block; +} +.contextMenu ul li.adding, .contextMenu ul li.adding + li { + display: block; +} +.contextMenu ul li.force-display { + display: block; +} +.contextMenu ul li.context-separator { + background-color: lightgray; + height: 1px; + padding: 0; +} + +#crosssection { + display: none; + position: absolute; + top: 200px; + left: 600px; +} + +.node circle { +/* fill: rgb(31, 119, 180); + fill-opacity: .25; */ + fill: #cfe2f3; + fill-opacity: .98; + stroke: black; + stroke-width: 3px; +} + +.leaf circle { + fill: #6fa8dc; + fill-opacity: 0.95; + stroke-width: 3px; +} + +.leaf circle[title] { + font-family: monospace; + +} + +.qdrListActions .ngGrid { + height: 100vh; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html b/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html new file mode 100644 index 0000000..90df9b3 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html @@ -0,0 +1,63 @@ +<div class="main-display row-fluid qdrCharts" ng-controller="QDR.ChartsController"> + <div ng-hide="dashLogin" ng-repeat="chart in svgCharts" class="chartContainer "> + <p class="chartLabels"> + <button ng-click="editChart(chart)" title="Configure"><i class="icon-edit"></i></button> + <button ng-click="zoomChart(chart)" title="Zoom {{chart.zoomed ? 'in' : 'out'}}" ng-if="!chart.chart.request().nodeList"><i ng-class="chart.zoomed ? 'icon-zoom-in' : 'icon-zoom-out'"></i></button> + </p><div style="clear:both"></div> + <div id="{{chart.chart.id()}}" class="hDash aChart d3Chart"></div> + </div> + <div ng-init="chartsLoaded()"></div> + <div ng-show="dashLogin" class="centered alert alert-warning"> + <p>You need to <a ng-href="{{loginHref}}">login</a> to Dispatch Router before viewing this chart.</p> + </div> +</div> + +<!-- + This is the template for the graph dialog that is displayed. It uses the + dialogCtrl controller in qdrCharts.js. +--> +<script type="text/ng-template" id="chart-config-template.html"> +<div class="chartOptions"> + <div class="modal-header"> + <h3 class="modal-title">Chart {{chart.attr() | humanify}}</h3> + </div> + <div class="modal-body"> + <div id="{{svgDivId}}" class="d3Chart"></div> + <tabset> + <tab heading="Type"> + <legend>Chart type</legend> + <label><input type="radio" ng-model="dialogChart.type" value="value" /> Value Chart</label> + <label><input type="radio" ng-model="dialogChart.type" value="rate" /> Rate Chart</label> + <div class="dlg-slider" ng-show="dialogChart.type=='rate'"> + <span>Rate Window: {{rateWindow}} second{{rateWindow > 1 ? "s" : ""}}</span> + <div class="slider" ui-slider="slider.options" ng-model="rateWindow"></div> + </div> + <div style="clear:both;"> </div> + </tab> + <tab ng-hide="$parent.chart.aggregate()" heading="Colors"> + <legend>Chart colors</legend> + <div class="colorPicker"> + <div class="colorText">Area ({{dialogChart.areaColor}}):</div><div hawtio-color-picker="dialogChart.areaColor"></div> + </div> + <div class="colorPicker"> + <div class="colorText">Line ({{dialogChart.lineColor}}):</div><div hawtio-color-picker="dialogChart.lineColor"></div> + </div> + <div style="clear:both;"> </div> + </tab> + <tab heading="Duration"> + <legend>Chart duration</legend> + <div class="dlg-slider duration"> + <span>Show data for past {{dialogChart.visibleDuration}} minute{{dialogChart.visibleDuration > 1 ? "s" : ""}}</span> <div class="slider" ui-slider="duration.options" ng-model="dialogChart.visibleDuration"></div> + </div> + <div style="clear:both;"> </div> + + </tab> + </tabset> + </div> + <div class="modal-footer"> + <button class="btn btn-success" type="button" ng-click="apply()">Apply</button> + <button class="btn btn-primary" type="button" ng-click="okClick()">Close</button> + </div> +</div> +</script> + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html b/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html new file mode 100644 index 0000000..83b5e2d --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html @@ -0,0 +1,38 @@ +<div class="row-fluid" ng-controller="QDR.SettingsController"> + <div class="login container" ng-hide="connecting"> + <div class="row" id="dispatch-login-container"> + <div class="connect-column"> + <div class="alert alert-success"> + <p> + Enter the address and port of a <strong><a href="http://qpid.apache.org/components/dispatch-router/" target="_blank">Qpid Dispatch Router</a></strong> to connect.. + </p> + + <p> + The port should be a websockets <==> tcp proxy. + </p> + + <p> + When Autostart is checked, you will be automatically logged in to the router the next time you start the console. + </p> + + </div> + </div> + <div class="connect-column connect-form"> + <div simple-form name="settings" data="formConfig" entity="formEntity"></div> + <p></p> + <div> + <button class="btn btn-primary pull-right" ng-disabled="settings.$invalid" ng-click="connect()">{{buttonText()}}</button> + </div> + </div> + </div> + </div> + + <div class="centered" ng-show="connecting"> + <i class="icon-spin icon-spinner icon-4x"></i> + <p>Please wait, connecting now...</p> + </div> + <div class="centered" ng-show="connectionError"> + <p>There was a connection error: {{connectionErrorText}}</p> + </div> + +</div> http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrGraphs.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrGraphs.html b/console/hawtio/src/main/webapp/plugin/html/qdrGraphs.html new file mode 100644 index 0000000..c311246 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrGraphs.html @@ -0,0 +1,15 @@ +<div ng-controller="QDR.ListController" title="" + class="prefs"> + <div class="row-fluid"> + <div class="tabbable"> + <div value="graphs" + class="tab-pane" + title="graphs"> + <div> + <div id="graph"></div> + + </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html b/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html new file mode 100644 index 0000000..80cd5ea --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html @@ -0,0 +1,26 @@ +<!-- +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. +--> +<ul class="nav nav-tabs connected dispatch-view" ng-controller="QDR.NavBarController"> + <li ng-repeat="link in breadcrumbs" title="{{link.title}}" ng-show="isValid(link)" ng-class='{active : isActive(link.href), "pull-right" : isRight(link)}'> + <a ng-href="{{link.href}}" ng-bind-html-unsafe="link.content"></a> + </li> +</ul> +<div class="row-fluid dispatch-router"> + <div ng-view></div> +</div> http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrList.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrList.html b/console/hawtio/src/main/webapp/plugin/html/qdrList.html new file mode 100644 index 0000000..adb249f --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrList.html @@ -0,0 +1,55 @@ +<!-- +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. +--> + +<div ng-controller="QDR.ListController"> + <hawtio-pane class="qdr-attributes" position="left" width="200"> + <div class="treeContainer"> + <div class="tree-header"><select ng-options="node as node.name for node in nodes" ng-model="currentNode" ng-change="selectNode(currentNode)"></select></div> + <div id="entityTree" onSelect="onTreeSelected" onRoot="onRootReady" hideRoot="true"></div> + <div ng-init="treeReady()"></div> + </div> + </hawtio-pane> + <div class="row-fluid qdrListActions"> + <h4>{{selectedRecordName}}</h4> + <div ng-show="currentMode.id === 'attributes'" class="selectedItems"> + <div ng-grid="details"></div> + </div> + <div ng-show="currentMode.id === 'operations'"> + Operations are not implemented yet. + </div> + </div> +</div> + +<!-- + This is the template for the graph dialog that is displayed. +--> +<script type="text/ng-template" id="template-from-script.html"> + <div class="modal-header"> + <h3 class="modal-title">Chart {{chart.attr() | humanify}}</h3> + </div> + <div class="modal-body"> + <div id="{{svgDivId}}" class="d3Chart"></div> + </div> + <div class="modal-footer"> + <span> + <button class="btn btn-success hdash-button" type="button" ng-click="addHChart()" title="Add this chart to a dashboard"><a ng-href="{{addToDashboardLink()}}"><i class="icon-share"></i> Add this chart to a dashboard</a></button> + </span> + <button class="btn btn-primary" type="button" ng-click="ok()">Close</button> + </div> +</script> http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html new file mode 100644 index 0000000..61d5143 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html @@ -0,0 +1,92 @@ +<!-- +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. +--> +<!-- +<div ng-controller="QDR.OverviewController"> + + <div class="treeContainer"> + <div id="overtree"></div> + </div> + + <div class="treeDetails" ng-include="template.url"></div> +</div> +--> +<div ng-controller="QDR.OverviewController"> + <hawtio-pane class="qdr-overview" position="left" width="300"> + <div class="treeContainer"> + <div id="overtree"></div> + </div> + </hawtio-pane> + <div class="treeDetails" ng-include="template.url"></div> +</div> + +<!-- the following scripts are content that gets loaded into the above div that has the temple.url --> +<script type="text/ng-template" id="routers.html"> + <div class="row-fluid"> + <h3>Routers</h3> + <div class="overview"> + <div class="gridStyle" ng-grid="allRouters"></div> + </div> + </div> +</script> + +<script type="text/ng-template" id="router.html"> + <div class="row-fluid"> + <h3>Router {{router.data.title}}</h3> + <div class="gridStyle noHighlight" ng-grid="routerGrid"></div> + </div> +</script> + +<script type="text/ng-template" id="addresses.html"> + <div class="row-fluid"> + <h3>Addresses</h3> + <div class="overview"> + <div class="gridStyle" ng-grid="addressGrid"></div> + </div> + </div> +</script> +<script type="text/ng-template" id="address.html"> + <div class="row-fluid"> + <h3>Address {{address.data.title}}</h3> + <div class="gridStyle noHighlight" ng-grid="addressGrid"></div> + </div> +</script> +<script type="text/ng-template" id="connections.html"> + <div class="row-fluid"> + <h3>Connections</h3> + <div class="overview"> + <div class="gridStyle" ng-grid="allConnectionGrid"></div> + </div> + </div> +</script> +<script type="text/ng-template" id="connection.html"> + <div class="row-fluid"> + <h3>Connection {{connection.data.title}}</h3> + <div class="gridStyle noHighlight" ng-grid="connectionGrid"></div> + </div> +</script> +<script type="text/ng-template" id="logs.html"> + <div class="row-fluid"> + <h3>Logs</h3> + </div> +</script> +<script type="text/ng-template" id="log.html"> + <div class="row-fluid"> + <h3>Log {{log.data.title}}</h3> + </div> +</script> http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html b/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html new file mode 100644 index 0000000..15ebb46 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html @@ -0,0 +1,21 @@ +<!-- +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. +--> +<div class="main-display row-fluid" ng-controller="QDR.SchemaController"> + <json-formatter json="schema" open="2"></json-formatter> +</div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html new file mode 100644 index 0000000..704c8e2 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html @@ -0,0 +1,201 @@ +<!-- +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. +--> +<div class="qdrTopology row-fluid" ng-controller="QDR.TopologyController"> + <div class="tertiary left panel"> + <div id="topologyForm" ng-class="{selected : isSelected()}"> + <!-- <div ng-repeat="form in forms" ng-show="isVisible(form)" ng-class='{selected : isSelected(form)}'> --> + + <div ng-show="isGeneral()"> + <h4>Router Info</h4> + <div class="gridStyle" ng-grid="topoGridOptions"></div> + </div> + <div ng-show="isConnections()"> + <h4>Connection Info</h4> + <div class="gridStyle" ng-grid="topoConnOptions"></div> + </div> + <div id="addNodeForm" ng-show="isAddNode()"> + <h4>Add a new router</h4> + <ul> + <li>Click on an existing router to create a connection to the new router</li> + <li>Double-click on the new router to <button ng-click="editNewRouter()">edit</button> its properties</li> + <li ng-show="addingNode.hasLink" >Right-click on a new connection to edit its properties</li> + </ul> + <button ng-click="cancel()">Cancel</button> + </div> + </div> + </div> + <div class="panel-adjacent"> + +<!-- + <ul class="nav nav-tabs ng-scope qdrTopoModes"> + <li ng-repeat="mode in modes" ng-class="{active : isModeActive(mode.name), 'pull-right' : isRight(mode)}" ng-click="selectMode('{{mode.name}}')" > + <a data-placement="bottom" class="ng-binding"> {{mode.name}} </a></li> + </ul> +--> + <div id="topology" ng-show="mode == 'Diagram'"><!-- d3 toplogy here --></div> + <div id="crosssection"><!-- d3 pack here --></div> + <!-- <div id="addRouter" ng-show="mode == 'Add Node'"></div> --> + <div id="node_context_menu" class="contextMenu"> + <ul> + <li class="na" ng-class="{new: contextNode.cls == 'temp'}" ng-click="addingNode.trigger = 'editNode'">Edit...</li> + <li class="na" ng-class="{adding: addingNode.step > 0}" ng-click="addingNode.step = 0">Cancel add</li> + <li class="context-separator"></li> + <li class="na" ng-class="{'force-display': !isFixed()}" ng-click="setFixed(true)">Freeze in place</li> + <li class="na" ng-class="{'force-display': isFixed()}" ng-click="setFixed(false)">Unfreeze</li> + </ul> + </div> + <div id="svg_context_menu" class="contextMenu"> + <ul> + <li ng-click="addingNode.step = 2">Add a new router</li> + </ul> + </div> + <div id="link_context_menu" class="contextMenu"> + <ul> + <li ng-click="reverseLink()">Reverse connection direction</li> + <li ng-click="removeLink()">Remove connection</li> + </ul> + </div> + + </div> +</div> +<!-- + This is the template for the node edit dialog that is displayed. +--> +<script type="text/ng-template" id="node-config-template.html"> + <div class="modal-header"> + <h3 class="modal-title">Configure new router</h3> + </div> + <div class="modal-body"> + <form novalidate name="editForm"> + + <tabset vertical="true" class="tabs-left"> + <tab ng-repeat="entity in entities"> <!-- ng-class="{separated: entity.tabName == 'listener0'}" --> + <tab-heading> + <i ng-if="entity.icon !== ''" ng-class="entity.icon ? 'ui-icon-arrowthick-1-w' : 'ui-icon-arrowthick-1-e'" class="ui-icon"></i>{{entity.humanName}} + </tab-heading> + <div class="entity-description">{{entity.description}}</div> + <fieldset> + <div ng-mouseenter="showDescription(attribute, $event)" ng-repeat="attribute in entity.attributes"> + <label for="{{attribute.name}}">{{attribute.humanName}}</label> +<!-- we can't do <input type="{angular expression}"> because... jquery throws an exception because... --> + <div ng-if="attribute.input == 'input'"> + <!-- ng-pattern="testPattern(attribute)" --> + <input ng-if="attribute.type == 'number'" type="number" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/> + <input ng-if="attribute.type == 'text'" type="text" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/> + </div> + <div ng-if="attribute.input == 'select'"> + <select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype"></select> + </div> + <div ng-if="attribute.input == 'boolean'" class="boolean"> + <label><input type="radio" ng-model="attribute.value" value="true"> True</label> + <label><input type="radio" ng-model="attribute.value" value="false"> False</label> + </div> + </div> + </fieldset> + <div class="attr-description">{{attributeDescription}} + <div class="attr-type">{{attributeType}}</div> + <div class="attr-required">{{attributeRequired}}</div> + <div class="attr-unique">{{attributeUnique}}</div> + </div> + <div class="attr-annotations" ng-repeat="annotation in entity.annotatedBy"> + <span>You can also enter the <button ng-click="selectAnnotationTab(annotation)">{{annotation}}</button> values.</span> + </div> + </tab> + </tabset> + + + </form> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" type="button" ng-click="download()">Download</button> + <button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button> + </div> +</script> + +<script type="text/ng-template" id="config-file-header.html">## +## 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 +## +</script> + +<script type="text/ng-template" id="download-dialog-template.html"> + <div class="modal-header"> + <h3 class="modal-title">Configure new router</h3> + </div> + <div class="modal-body"> + + <label title="Show descriptions and default values in confile files"><input type="checkbox" ng-model="verbose"> Verbose output</label> + <div> + <button ng-click="download()">Download</button> + <button class="btn" zero-clipboard data-clipboard-text="{{output}}" title="Copy to clipboard"> + <i class="icon-copy"></i> + </button> configuration file for {{newRouterName}} + </div> + <div ng-repeat="part in parts"> + <button ng-click="downloadPart(part)">Download</button> + <button class="btn" zero-clipboard data-clipboard-text="{{part.output}}" title="Copy to clipboard"> + <i class="icon-copy"></i> + </button> connector section for {{part.name}} + </div> + + </div> + <div class="modal-footer"> + <button class="btn btn-primary" type="button" ng-click="done()">Done</button> + </div> + +<!-- + + <div title="Configure new router"> + + <label title="Show descriptions and default values in confile files"><input type="checkbox" ng-model="verbose"> Verbose output</label> + <div> + <button ng-click="download()">Download</button> + <button class="btn" zero-clipboard data-clipboard-text="{{output}}" title="Copy to clipboard"> + <i class="icon-copy"></i> + </button> configuration file for {{newRouterName}} + </div> + <div ng-repeat="part in parts"> + <button ng-click="downloadPart(part)">Download</button> + <button class="btn" zero-clipboard data-clipboard-text="{{part.output}}" title="Copy to clipboard"> + <i class="icon-copy"></i> + </button> connector section for {{part.name}} + </div> + + <div class="okButton"> + <button ng-click="done()">Done</button> + </div> + + </div> +--> +</script> + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js b/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js new file mode 100644 index 0000000..59ea4d3 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js @@ -0,0 +1,241 @@ +/** + * @module QDR + * @mail QDR + * + * The main entry point for the QDR module + * + */ +var QDR = (function(QDR) { + + /** + * @property pluginName + * @type {string} + * + * The name of this plugin + */ + QDR.pluginName = 'dispatch_plugin'; + QDR.pluginRoot = "/" + QDR.pluginName; + /** + * @property log + * @type {Logging.Logger} + * + * This plugin's logger instance + */ + QDR.log = Logger.get('QDR'); + + /** + * @property contextPath + * @type {string} + * + * The top level path of this plugin on the server + * + */ + QDR.contextPath = "/dispatch-plugin/"; + + /** + * @property templatePath + * @type {string} + * + * The path to this plugin's partials + */ + QDR.templatePath = QDR.contextPath + "plugin/html/"; + + QDR.SETTINGS_KEY = 'QDRSettings'; + QDR.LAST_LOCATION = "QDRLastLocation"; + + /** + * @property module + * @type {object} + * + * This plugin's angularjs module instance. This plugin only + * needs hawtioCore to run, which provides services like + * workspace, viewRegistry and layoutFull used by the + * run function + */ + QDR.module = angular.module('dispatch_plugin', ['bootstrap', 'jsonFormatter', 'hawtio-ui', 'hawtio-forms', 'ui.bootstrap.dialog', 'hawtioCore']) + .config(function($routeProvider) { + /** + * Here we define the route for our plugin. One note is + * to avoid using 'otherwise', as hawtio has a handler + * in place when a route doesn't match any routes that + * routeProvider has been configured with. + */ + $routeProvider + .when('/dispatch_plugin', { + templateUrl: QDR.templatePath + 'qdrConnect.html' + }) + .when('/dispatch_plugin/overview', { + templateUrl: QDR.templatePath + 'qdrOverview.html' + }) + .when('/dispatch_plugin/topology', { + templateUrl: QDR.templatePath + 'qdrTopology.html' + }) + .when('/dispatch_plugin/list', { + templateUrl: QDR.templatePath + 'qdrList.html' + }) + .when('/dispatch_plugin/schema', { + templateUrl: QDR.templatePath + 'qdrSchema.html' + }) + .when('/dispatch_plugin/charts', { + templateUrl: QDR.templatePath + 'qdrCharts.html' + }) + .when('/dispatch_plugin/connect', { + templateUrl: QDR.templatePath + 'qdrConnect.html' + }) + }) + .config(function ($compileProvider) { + var cur = $compileProvider.urlSanitizationWhitelist(); + $compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|blob):/); + cur = $compileProvider.urlSanitizationWhitelist(); + }) + .config(function (JSONFormatterConfigProvider) { + // Enable the hover preview feature + JSONFormatterConfigProvider.hoverPreviewEnabled = true; + }) + .filter('to_trusted', function($sce){ + return function(text) { + return $sce.trustAsHtml(text); + }; + }) + .filter('humanify', function (QDRService) { + return function (input) { + return QDRService.humanify(input); + }; + }) + .filter('shortName', function () { + return function (name) { + var nameParts = name.split('/') + return nameParts.length > 1 ? nameParts[nameParts.length-1] : name; + }; + }); +/* + QDR.module.config(['$locationProvider', function($locationProvider) { + $locationProvider.html5Mode(true); + }]); +*/ + /** + * Here we define any initialization to be done when this angular + * module is bootstrapped. In here we do a number of things: + * + * 1. We log that we've been loaded (kinda optional) + * 2. We load our .css file for our views + * 3. We configure the viewRegistry service from hawtio for our + * route; in this case we use a pre-defined layout that uses + * the full viewing area + * 4. We configure our top-level tab and provide a link to our + * plugin. This is just a matter of adding to the workspace's + * topLevelTabs array. + */ + QDR.module.run(function(workspace, viewRegistry, layoutFull, $rootScope, $location, localStorage, QDRService, QDRChartService) { + QDR.log.info(QDR.pluginName, " loaded"); + Core.addCSS(QDR.contextPath + "plugin/css/dispatch.css"); + Core.addCSS(QDR.contextPath + "plugin/css/qdrTopology.css"); + Core.addCSS(QDR.contextPath + "plugin/css/plugin.css"); + Core.addCSS("https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.min.css"); + Core.addCSS("https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.2/jquery.tipsy.css"); + Core.addCSS("https://code.jquery.com/ui/1.8.24/themes/base/jquery-ui.css"); + + // tell hawtio that we have our own custom layout for + // our view + viewRegistry["dispatch_plugin"] = QDR.templatePath + "qdrLayout.html"; + + var settings = angular.fromJson(localStorage[QDR.SETTINGS_KEY]); + QDRService.addConnectAction(function() { + QDRChartService.init(); // initialize charting service after we are connected + }); + if (settings && settings.autostart) { + QDRService.addConnectAction(function() { + if ($location.path().startsWith(QDR.pluginRoot)) { + var lastLocation = localStorage[QDR.LAST_LOCATION]; + if (!angular.isDefined(lastLocation)) + lastLocation = QDR.pluginRoot + "/overview"; + $location.path(lastLocation); + $location.replace(); + $rootScope.$apply(); + } + }); + QDRService.connect(settings); + } + + $rootScope.$on('$routeChangeSuccess', function() { + var path = $location.path(); + if (path.startsWith(QDR.pluginRoot)) { + if (path != QDR.pluginRoot && path != QDR.pluginRoot + "/connect") { + localStorage[QDR.LAST_LOCATION] = $location.path(); + } + } + }); + + $rootScope.$on( "$routeChangeStart", function(event, next, current) { + if (next.templateUrl == QDR.templatePath + "qdrConnect.html" && QDRService.connected) { + // clicked connect from another dispatch page + if (current.loadedTemplateUrl.startsWith(QDR.contextPath)) { + return; + } + // clicked the Dispatch Router top level tab from a different plugin + var lastLocation = localStorage[QDR.LAST_LOCATION]; + if (!angular.isDefined(lastLocation)) + lastLocation = QDR.pluginRoot + "/overview"; + // show the last page visited + $location.path(lastLocation) + } + }); + /* Set up top-level link to our plugin. Requires an object + with the following attributes: + + id - the ID of this plugin, used by the perspective plugin + and by the preferences page + content - The text or HTML that should be shown in the tab + title - This will be the tab's tooltip + isValid - A function that returns whether or not this + plugin has functionality that can be used for + the current JVM. The workspace object is passed + in by hawtio's navbar controller which lets + you inspect the JMX tree, however you can do + any checking necessary and return a boolean + href - a function that returns a link, normally you'd + return a hash link like #/foo/bar but you can + also return a full URL to some other site + isActive - Called by hawtio's navbar to see if the current + $location.url() matches up with this plugin. + Here we use a helper from workspace that + checks if $location.url() starts with our + route. + */ + workspace.topLevelTabs.push({ + id: "dispatch", + content: "Dispatch Router", + title: "Dispatch console", + isValid: function(workspace) { return true; }, + href: function() { return "#/dispatch_plugin"; }, + isActive: function(workspace) { return workspace.isLinkActive("dispatch_plugin"); } + }); + + }); + + return QDR; + +})(QDR || {}); + + +// tell the hawtio plugin loader about our plugin so it can be +// bootstrapped with the rest of angular +hawtioPluginLoader.addModule(QDR.pluginName); + +$.getScript('https://cdn.rawgit.com/angular-ui/ui-slider/master/src/slider.js', function() { + hawtioPluginLoader.addModule('ui.slider'); +}); +$.getScript('https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.min.js', function() { + hawtioPluginLoader.addModule('jsonFormatter'); +}); + +// force an more modern version of d3 to load +$.getScript('https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.14/d3.min.js', function() {}); +// tooltips on the list page +$.getScript('https://cdn.rawgit.com/jaz303/tipsy/master/src/javascripts/jquery.tipsy.js', function() {}); +// tooltips on the topology page +$.getScript('https://cdn.rawgit.com/briancray/tooltipsy/master/tooltipsy.min.js', function() {}); + + + + http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eb2e027a/console/hawtio/src/main/webapp/plugin/js/navbar.js ---------------------------------------------------------------------- diff --git a/console/hawtio/src/main/webapp/plugin/js/navbar.js b/console/hawtio/src/main/webapp/plugin/js/navbar.js new file mode 100644 index 0000000..d305f38 --- /dev/null +++ b/console/hawtio/src/main/webapp/plugin/js/navbar.js @@ -0,0 +1,128 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ +/** + * @module QDR + */ +var QDR = (function (QDR) { + + /** + * @property breadcrumbs + * @type {{content: string, title: string, isValid: isValid, href: string}[]} + * + * Data structure that defines the sub-level tabs for + * our plugin, used by the navbar controller to show + * or hide tabs based on some criteria + */ + QDR.breadcrumbs = [ + { + content: '<i class="icon-cogs"></i> Connect', + title: "Connect to a router", + isValid: function () { return true; }, + href: "#/dispatch_plugin/connect" + }, + { + content: '<i class="fa fa-home"></i> Overview', + title: "View router overview", + isValid: function (QDRService) { return QDRService.isConnected(); }, + href: "#/dispatch_plugin/overview" + }, + { + content: '<i class="icon-list "></i> Details', + title: "View the attributes of the router nodes", + isValid: function (QDRService) { return QDRService.isConnected(); }, + href: "#/dispatch_plugin/list" + }, + { + content: '<i class="icon-star-empty"></i> Topology', + title: "View router network topology", + isValid: function (QDRService) { return QDRService.isConnected(); }, + href: "#/dispatch_plugin/topology" + }, +/* + { + content: '<i class="icon-bar-chart"></i> Charts', + title: "View charts", + isValid: function (QDRService, $location) { return QDRService.isConnected(); }, + href: "#/dispatch_plugin/charts" + }, +*/ + { + content: '<i class="icon-align-left"></i> Schema', + title: "View dispatch schema", + isValid: function (QDRService) { return QDRService.isConnected(); }, + href: "#/dispatch_plugin/schema", + right: true + + } + ]; + /** + * @function NavBarController + * + * @param $scope + * @param workspace + * + * The controller for this plugin's navigation bar + * + */ +QDR.NavBarController = function($scope, QDRService, QDRChartService, $location, $routeParams) { + $scope.breadcrumbs = QDR.breadcrumbs; + $scope.isValid = function(link) { + return link.isValid(QDRService, $location); + }; + + $scope.isActive = function(href) { + return href.split("#")[1] == $location.path(); + }; + + $scope.isRight = function (link) { + return angular.isDefined(link.right); + }; + + $scope.hasChart = function (link) { + if (link.href == "#/dispatch_plugin/charts") { + return QDRChartService.charts.some(function (c) { return c.dashboard }); + } + } + + $scope.isDashboardable = function () { + return ($location.path().indexOf("schema") < 0 && $location.path().indexOf("connect") < 0); + } + + $scope.addToDashboardLink = function () { + var href = "#" + $location.path(); + var size = angular.toJson({ + size_x: 2, + size_y: 2 + }); + + var routeParams = angular.toJson($routeParams); + var title = "Dispatch Router"; + return "/hawtio/#/dashboard/add?tab=dashboard" + + "&href=" + encodeURIComponent(href) + + "&routeParams=" + encodeURIComponent(routeParams) + + "&title=" + encodeURIComponent(title) + + "&size=" + encodeURIComponent(size); + }; + + }; + + + return QDR; + +} (QDR || {})); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
