incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cr...@apache.org
Subject [50/50] [abbrv] git commit: Moved the UI directory and starting to get the server side working... still broken
Date Sun, 18 May 2014 21:42:25 GMT
Moved the UI directory and starting to get the server side working... still broken


Project: http://git-wip-us.apache.org/repos/asf/incubator-blur/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-blur/commit/d276fd61
Tree: http://git-wip-us.apache.org/repos/asf/incubator-blur/tree/d276fd61
Diff: http://git-wip-us.apache.org/repos/asf/incubator-blur/diff/d276fd61

Branch: refs/heads/console-v2
Commit: d276fd61017f30e42133470884eed6399370a570
Parents: 904be3b
Author: Chris Rohr <crohr@nearinfinity.com>
Authored: Sun May 18 17:41:07 2014 -0400
Committer: Chris Rohr <crohr@nearinfinity.com>
Committed: Sun May 18 17:41:07 2014 -0400

----------------------------------------------------------------------
 contrib/blur-console/.gitignore                 |   4 +
 contrib/blur-console/pom.xml                    | 153 +++++-
 .../org/apache/blur/console/JettyServer.java    |   4 +-
 contrib/blur-console/src/main/scripts/grunt.sh  |  37 ++
 contrib/blur-console/src/main/webapp/.bowerrc   |   3 +
 .../blur-console/src/main/webapp/.editorconfig  |  21 +
 .../blur-console/src/main/webapp/.gitattributes |   1 +
 contrib/blur-console/src/main/webapp/.gitignore |   7 +
 contrib/blur-console/src/main/webapp/.jshintrc  |  21 +
 .../blur-console/src/main/webapp/Gruntfile.js   | 200 +++++++
 contrib/blur-console/src/main/webapp/bower.json |  15 +
 .../src/main/webapp/img/ajax-loader.gif         | Bin 0 -> 8787 bytes
 contrib/blur-console/src/main/webapp/index.html |  96 ++++
 .../src/main/webapp/js/blurconsole.b_utils.js   | 122 +++++
 .../src/main/webapp/js/blurconsole.dashboard.js | 261 ++++++++++
 .../src/main/webapp/js/blurconsole.data.js      |  23 +
 .../src/main/webapp/js/blurconsole.fake.js      | 221 ++++++++
 .../src/main/webapp/js/blurconsole.js           |  33 ++
 .../src/main/webapp/js/blurconsole.model.js     | 483 +++++++++++++++++
 .../src/main/webapp/js/blurconsole.queries.js   | 177 +++++++
 .../src/main/webapp/js/blurconsole.schema.js    | 182 +++++++
 .../src/main/webapp/js/blurconsole.search.js    | 299 +++++++++++
 .../src/main/webapp/js/blurconsole.shell.js     | 180 +++++++
 .../src/main/webapp/js/blurconsole.tables.js    | 223 ++++++++
 .../src/main/webapp/js/blurconsole.utils.js     |  91 ++++
 .../main/webapp/js/utils/jquery.event.gevent.js | 140 +++++
 .../main/webapp/js/utils/jquery.uriAnchor.js    | 518 +++++++++++++++++++
 .../blur-console/src/main/webapp/karma.conf.js  |  85 +++
 .../blur-console/src/main/webapp/package.json   |  44 ++
 .../src/main/webapp/sass/_colors.scss           |  24 +
 .../main/webapp/sass/blurconsole.dashboard.scss |  50 ++
 .../main/webapp/sass/blurconsole.queries.scss   |  22 +
 .../main/webapp/sass/blurconsole.schema.scss    |  38 ++
 .../src/main/webapp/sass/blurconsole.scss       |  30 ++
 .../main/webapp/sass/blurconsole.search.scss    |  31 ++
 .../src/main/webapp/sass/blurconsole.shell.scss |  75 +++
 .../blur-console/src/main/webapp/test/.bowerrc  |   3 +
 .../src/main/webapp/test/bower.json             |  10 +
 .../src/main/webapp/test/index.html             |  60 +++
 .../src/main/webapp/test/spec/test.js           |  32 ++
 .../src/main/webapp/test/spec/utils.js          |  32 ++
 .../src/main/webapp/views/dashboard.tpl.html    |  61 +++
 .../src/main/webapp/views/queries.tpl.html      |  40 ++
 .../src/main/webapp/views/search.tpl.html       |  50 ++
 .../src/main/webapp/views/tables.tpl.html       |  20 +
 .../apache/blur/console/ConsoleTestBase.java    |   6 +-
 .../apache/blur/console/util/HttpUtilTest.java  |   3 +-
 contrib/blur-console/ui/.bowerrc                |   3 -
 contrib/blur-console/ui/.editorconfig           |  21 -
 contrib/blur-console/ui/.gitattributes          |   1 -
 contrib/blur-console/ui/.gitignore              |   6 -
 contrib/blur-console/ui/.jshintrc               |  21 -
 contrib/blur-console/ui/Gruntfile.js            | 434 ----------------
 contrib/blur-console/ui/app/favicon.ico         | Bin 4286 -> 0 bytes
 .../blur-console/ui/app/images/ajax-loader.gif  | Bin 8787 -> 0 bytes
 contrib/blur-console/ui/app/images/loading.gif  | Bin 19239 -> 0 bytes
 contrib/blur-console/ui/app/index.html          | 120 -----
 .../ui/app/lib/jquery.event.gevent.js           | 140 -----
 .../blur-console/ui/app/lib/jquery.uriAnchor.js | 518 -------------------
 .../ui/app/scripts/blurconsole.b_utils.js       | 122 -----
 .../ui/app/scripts/blurconsole.dashboard.js     | 259 ----------
 .../ui/app/scripts/blurconsole.data.js          |  23 -
 .../ui/app/scripts/blurconsole.fake.js          | 221 --------
 .../blur-console/ui/app/scripts/blurconsole.js  |  33 --
 .../ui/app/scripts/blurconsole.model.js         | 484 -----------------
 .../ui/app/scripts/blurconsole.queries.js       | 177 -------
 .../ui/app/scripts/blurconsole.schema.js        | 182 -------
 .../ui/app/scripts/blurconsole.search.js        | 299 -----------
 .../ui/app/scripts/blurconsole.shell.js         | 180 -------
 .../ui/app/scripts/blurconsole.tables.js        | 223 --------
 .../ui/app/scripts/blurconsole.utils.js         |  91 ----
 contrib/blur-console/ui/app/styles/_colors.scss |   4 -
 .../ui/app/styles/blurconsole.dashboard.scss    |  50 --
 .../ui/app/styles/blurconsole.queries.scss      |  22 -
 .../ui/app/styles/blurconsole.schema.scss       |  38 --
 .../blur-console/ui/app/styles/blurconsole.scss |  80 ---
 .../ui/app/styles/blurconsole.search.scss       |  11 -
 .../ui/app/views/dashboard.tpl.html             |  61 ---
 .../blur-console/ui/app/views/queries.tpl.html  |  40 --
 .../blur-console/ui/app/views/search.tpl.html   |  50 --
 .../blur-console/ui/app/views/tables.tpl.html   |  20 -
 contrib/blur-console/ui/bower.json              |  11 -
 contrib/blur-console/ui/package.json            |  40 --
 contrib/blur-console/ui/test/.bowerrc           |   3 -
 contrib/blur-console/ui/test/bower.json         |  10 -
 contrib/blur-console/ui/test/index.html         |  60 ---
 contrib/blur-console/ui/test/spec/test.js       |  32 --
 contrib/blur-console/ui/test/spec/utils.js      |  32 --
 pom.xml                                         |  26 +-
 89 files changed, 4224 insertions(+), 4155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/blur-console/.gitignore b/contrib/blur-console/.gitignore
index 61faf4d..5e40c1f 100644
--- a/contrib/blur-console/.gitignore
+++ b/contrib/blur-console/.gitignore
@@ -1 +1,5 @@
 test-data
+src/main/webapp/libs/*
+src/main/webapp/node_modules/*
+src/main/webapp/css/*
+src/main/webapp/test/bower_components/*

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/blur-console/pom.xml b/contrib/blur-console/pom.xml
index 2ef4a2c..4df3445 100644
--- a/contrib/blur-console/pom.xml
+++ b/contrib/blur-console/pom.xml
@@ -17,7 +17,7 @@
 	<parent>
 		<groupId>org.apache.blur</groupId>
 		<artifactId>blur</artifactId>
-		<version>0.2.2-incubating-SNAPSHOT</version>
+		<version>0.2.2-incubating</version>
 		<relativePath>../../pom.xml</relativePath>
 	</parent>
 
@@ -26,7 +26,26 @@
 	<packaging>jar</packaging>
 	<name>Blur Console</name>
 
+    <properties>
+        <!-- Default Jetty Configuration Properties -->
+        <jetty-version>9.2.0.M1</jetty-version>
+        <jetty.port>2880</jetty.port>
+        <jetty.maxIdleTime>60000</jetty.maxIdleTime>
+
+        <!-- Library Versions -->
+        <jersey-version>2.8</jersey-version>
+        <atmosphere-version>0.8.5</atmosphere-version>
+
+        <!-- Grunt Execution Target. Valid values are [ development | production ] -->
+        <grunt.target>development</grunt.target>
+
+        <!-- Maven Plugin Versions -->
+        <plugin.maven.exec.version>1.2.1</plugin.maven.exec.version>
+        <plugin.maven.war.version>2.4</plugin.maven.war.version>
+    </properties>
+
 	<dependencies>
+        <!-- Blur Dependencies -->
 		<dependency>
 			<groupId>org.apache.blur</groupId>
 			<artifactId>blur-thrift</artifactId>
@@ -37,6 +56,8 @@
 			<artifactId>blur-core</artifactId>
 			<version>${project.version}</version>
 		</dependency>
+
+        <!-- Development and Runtime Libraries -->
 		<dependency>
 			<groupId>org.codehaus.jackson</groupId>
 			<artifactId>jackson-mapper-asl</artifactId>
@@ -52,14 +73,14 @@
 		<dependency>
 			<groupId>org.apache.blur</groupId>
 			<artifactId>blur-core</artifactId>
-			<version>0.3.0-incubating-SNAPSHOT</version>
+			<version>${project.version}</version>
 			<type>test-jar</type>
 			<scope>test</scope>
 		</dependency>
 		<dependency>
 			<groupId>org.apache.blur</groupId>
 			<artifactId>blur-util</artifactId>
-			<version>0.3.0-incubating-SNAPSHOT</version>
+			<version>${project.version}</version>
 			<type>test-jar</type>
 			<scope>test</scope>
 		</dependency>
@@ -72,7 +93,44 @@
 	</dependencies>
 
 	<build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/blur-console-build.properties</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>false</filtering>
+                <excludes>
+                    <exclude>**/blur-console-build.properties</exclude>
+                </excludes>
+            </resource>
+        </resources>
+
 		<plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-clean-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-compiler-plugin</artifactId>
@@ -83,21 +141,80 @@
 					<target>1.6</target>
 				</configuration>
 			</plugin>
-			<plugin>
-				<groupId>org.codehaus.mojo</groupId>
-				<artifactId>exec-maven-plugin</artifactId>
-				<version>1.2.1</version>
-				<executions>
-					<execution>
-						<goals>
-							<goal>java</goal>
-						</goals>
-					</execution>
-				</executions>
-				<configuration>
-					<mainClass>org.apache.blur.console.Main</mainClass>
-				</configuration>
-			</plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>org.apache.blur.console.Main</mainClass>
+                        </manifest>
+                    </archive>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
 		</plugins>
 	</build>
+
+    <profiles>
+        <profile>
+            <id>hadoop-1x</id>
+            <activation>
+                <property>
+                    <name>hadoop1</name>
+                </property>
+            </activation>
+            <properties>
+                <projectVersion>${project.parent.version}-hadoop1</projectVersion>
+            </properties>
+        </profile>
+        <profile>
+            <id>hadoop-2.2</id>
+            <activation>
+                <property>
+                    <name>hadoop2</name>
+                </property>
+            </activation>
+            <properties>
+                <projectVersion>${project.parent.version}-hadoop2</projectVersion>
+            </properties>
+        </profile>
+        <profile>
+            <id>grunt</id>
+            <activation><os><family>!windows</family></os></activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <version>${plugin.maven.exec.version}</version>
+                        <executions>
+                            <!-- Install all webapp dependencies -->
+                            <execution>
+                                <id>WebApp Dependencies and Minification</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>exec</goal>
+                                </goals>
+                                <configuration>
+                                    <executable>${basedir}/src/main/scripts/grunt.sh</executable>
+                                    <commandlineArgs>${grunt.target}</commandlineArgs>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/java/org/apache/blur/console/JettyServer.java
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/java/org/apache/blur/console/JettyServer.java b/contrib/blur-console/src/main/java/org/apache/blur/console/JettyServer.java
index de7381b..2a7436d 100644
--- a/contrib/blur-console/src/main/java/org/apache/blur/console/JettyServer.java
+++ b/contrib/blur-console/src/main/java/org/apache/blur/console/JettyServer.java
@@ -61,13 +61,13 @@ public class JettyServer {
 	    final URL warUrl = this.getClass().getClassLoader().getResource(WEBAPPDIR);
 	    final String warUrlString = warUrl.toExternalForm();
 	    server.setHandler(new WebAppContext(warUrlString, CONTEXTPATH));
-	      
+
 	    // for localhost:port/service/dashboard, etc.
 	    final Context context = new Context(server, "/service", Context.SESSIONS);
 	    context.addServlet(new ServletHolder(new DashboardServlet()), "/dashboard/*");
 	    context.addServlet(new ServletHolder(new TablesServlet()), "/tables/*");
 	    context.addServlet(new ServletHolder(new QueriesServlet()), "/queries/*");
-	      
+
 	    try {
 			server.start();
 		} catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/scripts/grunt.sh
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/scripts/grunt.sh b/contrib/blur-console/src/main/scripts/grunt.sh
new file mode 100755
index 0000000..f202477
--- /dev/null
+++ b/contrib/blur-console/src/main/scripts/grunt.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+SOURCE="${BASH_SOURCE[0]}"
+while [ -h "$SOURCE" ]; do
+  DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
+  SOURCE="$(readlink "$SOURCE")"
+  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
+done
+DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
+
+# Check for grunt-cli installed: log `npm install -g grunt-cli`
+command -v grunt >/dev/null 2>&1 || { echo >&2 "[ERROR] grunt not found! install: npm install -g grunt-cli"; exit 1; }
+
+# Check for bower: log `npm install -g bower`
+command -v bower >/dev/null 2>&1 || { echo >&2 "[ERROR] bower not found! install: npm install -g bower"; exit 1; }
+
+# run `npm install` in src/main/webapp
+cd $DIR/../webapp >/dev/null 
+npm install --quiet
+
+# Run `bower list` for previous `bower list` output
+mkdir -p ${DIR}/../../../target
+filename=${DIR}/../../../target/.webapp-build.$(id -un)
+filename_previous=${DIR}/../../../target/.webapp-build.previous.$(id -un)
+
+touch $filename
+mv $filename $filename_previous
+bower list --offline > $filename
+
+if diff $filename $filename_previous >/dev/null ; then
+  grunt $1
+else
+  grunt deps $1
+fi
+
+cd - >/dev/null
+

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/.bowerrc
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/.bowerrc b/contrib/blur-console/src/main/webapp/.bowerrc
new file mode 100644
index 0000000..4e5e51b
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/.bowerrc
@@ -0,0 +1,3 @@
+{
+    "directory": "libs"
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/.editorconfig
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/.editorconfig b/contrib/blur-console/src/main/webapp/.editorconfig
new file mode 100644
index 0000000..8a80734
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/.editorconfig
@@ -0,0 +1,21 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+
+[*]
+
+# Change these settings to your own preference
+indent_style = space
+indent_size = 4
+
+# We recommend you to keep these unchanged
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/.gitattributes
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/.gitattributes b/contrib/blur-console/src/main/webapp/.gitattributes
new file mode 100644
index 0000000..2125666
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/.gitattributes
@@ -0,0 +1 @@
+* text=auto
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/.gitignore b/contrib/blur-console/src/main/webapp/.gitignore
new file mode 100644
index 0000000..9b6b25c
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/.gitignore
@@ -0,0 +1,7 @@
+build/
+libs/*
+css/*
+jsc/*
+test/reports
+.tmp
+.sass-cache
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/.jshintrc b/contrib/blur-console/src/main/webapp/.jshintrc
new file mode 100644
index 0000000..abc9b0a
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/.jshintrc
@@ -0,0 +1,21 @@
+{
+    "node": true,
+    "browser": true,
+    "esnext": true,
+    "bitwise": true,
+    "camelcase": false,
+    "curly": true,
+    "eqeqeq": true,
+    "immed": true,
+    "indent": 4,
+    "latedef": true,
+    "newcap": true,
+    "noarg": true,
+    "quotmark": "single",
+    "undef": true,
+    "unused": true,
+    "strict": true,
+    "trailing": true,
+    "smarttabs": true,
+    "jquery": true
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/Gruntfile.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/Gruntfile.js b/contrib/blur-console/src/main/webapp/Gruntfile.js
new file mode 100644
index 0000000..2b450f5
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/Gruntfile.js
@@ -0,0 +1,200 @@
+/*
+
+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.
+*/
+
+'use strict';
+
+module.exports = function (grunt) {
+
+    // Load grunt tasks automatically
+    require('load-grunt-tasks')(grunt);
+
+    // Time how long tasks take. Can help when optimizing build times
+    require('time-grunt')(grunt);
+
+    // Define the configuration for all the tasks
+    grunt.initConfig({
+        pkg: grunt.file.readJSON('package.json'),
+
+        clean: ['css'],
+
+        bower: {
+            install: {
+                options: {
+                    targetDir: './libs',
+                    install: true,
+                    copy: false,
+                    quiet: true
+                }
+            },
+            prune: {
+                options: {
+                    targetDir: './libs',
+                    copy: false,
+                    offline: true,
+                    quiet: true
+                }
+            }
+        },
+
+        // Compiles Sass to CSS and generates necessary files if requested
+        sass: {
+            options: {
+                sourcemap: true,
+                lineNumbers: true,
+                loadPath: ['libs']
+            },
+            development: {
+                files: {
+                    'css/blurconsole.css': 'sass/blurconsole.scss'
+                }
+            },
+            production: {
+                files: {
+                    'css/blurconsole.css': 'sass/blurconsole.scss'
+                },
+                options: {
+                    compress: true
+                }
+            }
+        },
+
+        // Make sure code styles are up to par and there are no obvious mistakes
+        jshint: {
+            options: {
+                jshintrc: true,
+            },
+            development: {
+                src: ['js/**/*\.js']
+            },
+            ci: {
+                src: ['js/**/*\.js'],
+                options: {
+                    reporter: 'checkstyle',
+                    reporterOutput: 'build/jshint-checkstyle.xml'
+                }
+            }
+        },
+
+        // Watches files for changes and runs tasks based on the changed files
+        watch: {
+            options: {
+                dateFormat: function(time) {
+                    grunt.log.ok('The watch finished in ' + (time / 1000).toFixed(2) + 's. Waiting...');
+                },
+                spawn: false,
+                interrupt: false
+            },
+            css: {
+                files: ['sass/**/*.scss', 'libs/**/*.css', 'libs/**/*.scss'],
+                tasks: ['sass:development', 'notify:css']
+            },
+            lint: {
+                files: ['js/**/*.js'],
+                tasks: ['jshint:development']
+            },
+            livereload: {
+                options: {
+                    livereload: '<%= connect.options.livereload %>'
+                },
+                files: [
+                    './{,*/}*.html',
+                    './img/{,*/}*.{gif,jpeg,jpg,png,svg,webp}'
+                ]
+            }
+        },
+
+        notify: {
+            css: {
+                options: {
+                    title: 'Blur Console',
+                    message: 'Sass finished'
+                }
+            }
+        },
+
+        mochaSelenium: {
+            options: {
+                screenshotAfterEach: true,
+                screenshotDir: 'test/reports',
+                reporter: 'spec',
+                viewport: { width: 900, height: 700 },
+                timeout: 30e3,
+                slow: 10e3,
+                implicitWaitTimeout: 100,
+                asyncScriptTimeout: 5000,
+                usePromises: true,
+                useChaining: true,
+                ignoreLeaks: false
+            },
+            firefox: { src: ['test/functional/spec/**/*.js'], options: { browserName: 'firefox' } },
+            chrome: { src: ['text/function/spec/**/*.js'], options: { browserName: 'chrome' } }
+        },
+
+        karma: {
+            unit: {
+                configFile: 'karma.conf.js',
+                runnerPort: 9999,
+                singleRun: true
+            }
+        },
+
+        connect: {
+            options: {
+                port: 3000,
+                livereload: 4000,
+                // Change this to '0.0.0.0' to access the server from outside
+                hostname: '0.0.0.0'
+            },
+            livereload: {
+                options: {
+                    open: 'http://0.0.0.0:3000/?fakeIt=true'
+                }
+            }
+        },
+    });
+
+    grunt.loadNpmTasks('grunt-bower-task');
+    grunt.loadNpmTasks('grunt-exec');
+    grunt.loadNpmTasks('grunt-contrib-clean');
+    grunt.loadNpmTasks('grunt-contrib-sass');
+    grunt.loadNpmTasks('grunt-contrib-watch');
+    grunt.loadNpmTasks('grunt-contrib-jshint');
+    grunt.loadNpmTasks('grunt-notify');
+    grunt.loadNpmTasks('grunt-mocha-selenium');
+    grunt.loadNpmTasks('grunt-karma');
+
+    var initialHintSrc = grunt.config('jshint.development.src');
+    grunt.event.on('watch', function(action, filepath){
+        var matchingHint = grunt.file.match(initialHintSrc, filepath);
+        grunt.config('jshint.development.src', matchingHint);
+    });
+
+    grunt.registerTask('deps', 'Install Webapp Dependencies', ['bower:install', 'bower:prune']);
+    grunt.registerTask('test:functional:chrome', 'Run JavaScript Functional Tests in Chrome', ['mochaSelenium:chrome']);
+    grunt.registerTask('test:functional:firefox', 'Run JavaScript Functional Tests in Firefox', ['mochaSelenium:firefox']);
+    grunt.registerTask('test:functional', 'Run JavaScript Functional Tests', ['test:functional:chrome', 'test:functional:firefox']);
+    grunt.registerTask('test:unit', 'Run JavaScript Unit Tests', ['karma']);
+    grunt.registerTask('test:style', 'Run JavaScript CodeStyle reports', ['jshint:ci'/*, 'plato:ci' */]);
+    grunt.registerTask('style:development', 'Run JavaScript CodeStyle reports', ['jshint:development']);
+    grunt.registerTask('development', 'Build sass for development', ['sass:development']);
+    grunt.registerTask('production', 'Build sass for production', ['sass:production']);
+    grunt.registerTask('serve', 'Run development server', ['clean','sass:development', 'connect:livereload','watch']);
+    grunt.registerTask('default', ['clean', 'development', 'style:development', 'watch']);
+};

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/bower.json
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/bower.json b/contrib/blur-console/src/main/webapp/bower.json
new file mode 100644
index 0000000..f9296cb
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/bower.json
@@ -0,0 +1,15 @@
+{
+  "name": "blur-console",
+  "version": "0.0.1",
+  "private": true,
+  "dependencies": {
+    "twbs-bootstrap-sass": "3.1.1",
+    "modernizr": "2.7.1",
+    "jquery": "1.11.0",
+    "flot":"0.8.2"
+  },
+  "devDependencies": {
+    "mocha": "~1.18.0",
+    "chai": "~1.9.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/img/ajax-loader.gif
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/img/ajax-loader.gif b/contrib/blur-console/src/main/webapp/img/ajax-loader.gif
new file mode 100644
index 0000000..c8c22f2
Binary files /dev/null and b/contrib/blur-console/src/main/webapp/img/ajax-loader.gif differ

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/index.html
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/index.html b/contrib/blur-console/src/main/webapp/index.html
new file mode 100644
index 0000000..5f82068
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/index.html
@@ -0,0 +1,96 @@
+<!--
+
+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.
+ -->
+
+<!doctype html>
+<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
+    <head>
+        <meta charset="utf-8">
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
+        <title>Blur Console</title>
+        <meta name="description" content="System Monitor and Console for Blur">
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" href="css/blurconsole.css">
+        <script src="libs/modernizr/modernizr.js"></script>
+
+    </head>
+    <body>
+        <nav class="navbar navbar-inverse navbar-fixed-top">
+            <a class="navbar-brand" href="#">Blur Console</a>
+
+        </nav>
+        <nav class="side-nav">
+            <ul>
+                <li title="Dashboard" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#/dashboard"><i class="glyphicon glyphicon-dashboard"></i></a>
+                </li>
+                <li title="Tables" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#/tables"><i class="glyphicon glyphicon-list"></i></a>
+                </li>
+                <li title="Queries" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#/queries"><i class="glyphicon glyphicon-tasks"></i></a>
+                </li>
+                <li title="Search" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#/search"><i class="glyphicon glyphicon-search"></i></a>
+                </li>
+            </ul>
+        </nav>
+        <div id="blurconsole"></div>
+
+        <script src="libs/jquery/dist/jquery.js"></script>
+        <script src="js/utils/jquery.uriAnchor.js"></script>
+        <script src="js/utils/jquery.event.gevent.js"></script>
+
+        <!-- <script src="bower_components/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/affix.js"></script>
+        <script src="bower_components/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/alert.js"></script>
+        <script src="bower_components/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/dropdown.js"></script> -->
+        <script src="libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/tooltip.js"></script>
+        <script src="libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/modal.js"></script>
+        <script src="libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/transition.js"></script>
+        <!-- <script src="bower_components/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/button.js"></script> -->
+        <script src="libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/popover.js"></script>
+        <!-- <script src="bower_components/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/carousel.js"></script>
+        <script src="bower_components/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/scrollspy.js"></script> -->
+        <script src="libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/collapse.js"></script>
+        <script src="libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/tab.js"></script>
+        <script src="libs/flot/jquery.flot.js"></script>
+        <script src="libs/flot/jquery.flot.pie.js"></script>
+        <script src="libs/flot/jquery.flot.categories.js"></script>
+        <script src="libs/flot/jquery.flot.stack.js"></script>
+
+        <script src="js/blurconsole.js"></script>
+        <script src="js/blurconsole.utils.js"></script>
+        <script src="js/blurconsole.b_utils.js"></script>
+        <script src="js/blurconsole.shell.js"></script>
+        <script src="js/blurconsole.dashboard.js"></script>
+        <script src="js/blurconsole.tables.js"></script>
+        <script src="js/blurconsole.queries.js"></script>
+        <script src="js/blurconsole.search.js"></script>
+        <script src="js/blurconsole.schema.js"></script>
+        <script src="js/blurconsole.data.js"></script>
+        <script src="js/blurconsole.fake.js"></script>
+        <script src="js/blurconsole.model.js"></script>
+        <script type="text/javascript">
+            $(function () { blurconsole.initModule( $('#blurconsole') ); });
+        </script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.b_utils.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.b_utils.js b/contrib/blur-console/src/main/webapp/js/blurconsole.b_utils.js
new file mode 100644
index 0000000..fc8d6ea
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.b_utils.js
@@ -0,0 +1,122 @@
+/*
+
+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.
+*/
+/*global blurconsole:false */
+blurconsole.browserUtils = (function(){
+	'use strict';
+	var table, modal, cleanId, booleanImg;
+
+	table = function(def, data) {
+		var tableMarkup;
+
+		tableMarkup = '<table class="table table-bordered table-condensed table-hover table-striped"><thead><tr>';
+
+		// Add headers
+		$.each(def, function(idx, colDef){
+			tableMarkup += '<th>' + colDef.label + '</th>';
+		});
+
+		tableMarkup += '</tr></thead><tbody>';
+
+		// Add content
+		if (data && data.length > 0) {
+			$.each(data, function(ir, row){
+				tableMarkup += '<tr>';
+				$.each(def, function(ic, col) {
+					tableMarkup += '<td>';
+					if ($.isFunction(col.key)) {
+						tableMarkup += col.key(row);
+					} else {
+						tableMarkup += row[col.key];
+					}
+					tableMarkup += '</td>';
+				});
+				tableMarkup += '</tr>';
+			});
+		} else {
+			tableMarkup += '<tr><td colspan="' + def.length + '">There are no items here</td></tr>';
+		}
+
+		tableMarkup += '</tbody></table>';
+		return tableMarkup;
+	};
+
+	modal = function(id, title, content, buttons, size) {
+		var mSize, markup, mButtons = buttons;
+
+		switch(size) {
+		case 'large':
+			mSize = 'modal-lg';
+			break;
+		case 'medium':
+			mSize = 'modal-md';
+			break;
+		default:
+			mSize = 'modal-sm';
+		}
+
+		markup = '<div class="modal fade" id="' + id + '">';
+		markup += '<div class="modal-dialog ' + mSize + '">';
+		markup += '<div class="modal-content">';
+		markup += '<div class="modal-header"><button type="button" class="close" data-dismiss="modal">&times;</button><h4 class="modal-title">' + title + '</h4></div>';
+		markup += '<div class="modal-body">' + ($.type(content) === 'string' ? content : $(content).html()) + '</div>';
+
+		if (mButtons) {
+			if (!$.isArray(mButtons)) {
+				mButtons = [mButtons];
+			}
+
+			markup += '<div class="modal-footer">';
+			$.each(mButtons, function(i, button) {
+				markup += '<button type="button" class="btn ' + button.classes + '" id="' + button.id + '" ';
+
+				if (button.data) {
+					$.each(button.data, function(key, dataAttr) {
+						markup += 'data-' + key + '="' + dataAttr + '" ';
+					});
+				}
+				
+				markup += '>' + button.label + '</button> ';
+			});
+			markup += '</div>';
+		}
+
+		markup += '</div></div></div>';
+
+		return markup;
+	};
+
+	cleanId = function(str) {
+		return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
+	};
+
+	booleanImg = function(val) {
+		if (val && (val === true || val === 'yes' || val === 'true')) {
+			return '<div class="label label-success"><i class="glyphicon glyphicon-ok-sign"></i></div>';
+		}
+		return '<div class="label label-danger"><i class="glyphicon glyphicon-minus-sign"></i></div>';
+	};
+
+	return {
+		table: table,
+		modal : modal,
+		cleanId : cleanId,
+		booleanImg : booleanImg
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.dashboard.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.dashboard.js b/contrib/blur-console/src/main/webapp/js/blurconsole.dashboard.js
new file mode 100644
index 0000000..1d84357
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.dashboard.js
@@ -0,0 +1,261 @@
+/*
+
+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.
+*/
+
+/*
+ * blurconsole.dashboard.js
+ * Dashboard feature module for Blur Console
+ */
+/*global blurconsole:false */
+blurconsole.dashboard = (function () {
+	'use strict';
+	var
+		configMap = {
+			view: 'views/dashboard.tpl.html',
+			pieOptions : {
+				series : {
+					pie : {
+						show : true,
+						radius : 1,
+						label : {
+							show : true,
+							radius : 2/3,
+							formatter : function(label, series) {
+								return '<div style="font-size:8pt;text-align:center;padding:2px;color:white">' + label + '<br/>' + Math.round(series.percent) + '% (' + series.data[0][1] + ')</div>';
+							},
+							threshold : 0.1
+						}
+					}
+				},
+				legend : {
+					show : false
+				},
+				title: 'Test title'
+			}
+		},
+		stateMap = {
+			$container : null,
+			zookeeperNodes: 'chart',
+			controllerNodes: 'chart'
+		},
+		jqueryMap = {},
+		setJqueryMap, initModule, unloadModule, updateNodeCharts, adjustChartSize,
+		loadZkPieChart,	loadControllerPieChart, loadShardsPieChart, loadTableColumnChart, loadQueryPerfLineChart,
+		buildNodeTable, checkForSlowQueries;
+
+	setJqueryMap = function() {
+		var $container = stateMap.$container;
+		jqueryMap = {
+			$container : $container,
+			$zkChartHolder : $('#zookeeperNodes'),
+			$zkInfoHolder : $('#zookeeperInfo'),
+			$controllerChartHolder : $('#controllerNodes'),
+			$controllerInfoHolder : $('#controllerInfo'),
+			$shardChartHolder : $('#shardNodes'),
+			$tableChartHolder : $('#tableCounts'),
+			$queryLoadChartHolder : $('#queryLoad')
+		};
+	};
+
+	unloadModule = function() {
+		$.gevent.unsubscribe(jqueryMap.$container, 'node-status-updated');
+		$.gevent.unsubscribe(jqueryMap.$container, 'tables-updated');
+		$.gevent.unsubscribe(jqueryMap.$container, 'query-perf-updated');
+		$.gevent.unsubscribe(jqueryMap.$container, 'queries-updated');
+	};
+
+	updateNodeCharts = function() {
+		if (blurconsole.model.nodes.isDataLoaded()) {
+			loadZkPieChart();
+			loadControllerPieChart();
+			loadShardsPieChart();
+		}
+	};
+
+	loadZkPieChart = function() {
+		$.plot(jqueryMap.$zkChartHolder, blurconsole.model.metrics.getZookeeperChartData(), configMap.pieOptions);
+		jqueryMap.$zkInfoHolder.html(buildNodeTable(blurconsole.model.nodes.getOfflineZookeeperNodes()));
+	};
+
+	loadControllerPieChart = function() {
+		$.plot(jqueryMap.$controllerChartHolder, blurconsole.model.metrics.getControllerChartData(), configMap.pieOptions);
+		jqueryMap.$controllerInfoHolder.html(buildNodeTable(blurconsole.model.nodes.getOfflineControllerNodes()));
+	};
+
+	loadShardsPieChart = function() {
+		if (jqueryMap.$shardChartHolder.find('img').length > 0) {
+			jqueryMap.$shardChartHolder.html('');
+		}
+
+		$.each(blurconsole.model.metrics.getClusters(), function(idx, cluster) {
+			var clusterData, clusterHolder, clusterInfo, parentSize;
+
+			clusterData = blurconsole.model.metrics.getShardChartData(cluster);
+
+			if (clusterData) {
+				clusterHolder = jqueryMap.$shardChartHolder.find('#cluster_' + cluster + '_chart_holder');
+				clusterInfo = jqueryMap.$shardChartHolder.find('#cluster_' + cluster + '_info');
+
+				if (clusterHolder.length === 0) {
+					var wrapper = $('<div class="swapper-parent"></div>');
+					wrapper.append($('<div class="text-center"><strong>' + cluster + '</strong> <small class="text-muted"><i class="glyphicon glyphicon-retweet swapper-trigger" title="Swap Chart/Info"></i></small></div>'));
+					clusterHolder = $('<div id="cluster_'+ cluster + '_chart_holder" class="shardClusterChartHolder simple-chart swapper-chart"></div>');
+					wrapper.append(clusterHolder);
+					parentSize = jqueryMap.$shardChartHolder.parent()[0].clientWidth - 150;
+					clusterHolder.css({
+						'height' : parentSize,
+						'width' : parentSize
+					});
+					clusterInfo = $('<div id="cluster_' + cluster + '_info" class="swapper-info hidden"></div>');
+					wrapper.append(clusterInfo);
+
+					jqueryMap.$shardChartHolder.append(wrapper);
+				}
+
+				$.plot(clusterHolder, clusterData, configMap.pieOptions);
+				clusterInfo.html(buildNodeTable(blurconsole.model.nodes.getOfflineShardNodes(cluster)));
+			}
+		});
+	};
+
+	loadTableColumnChart = function() {
+		if (blurconsole.model.tables.isDataLoaded()) {
+			$.plot(jqueryMap.$tableChartHolder, blurconsole.model.metrics.getTableChartData(), {
+				bars : {
+					show : true,
+					barWidth : 0.6,
+					align : 'center'
+				},
+				yaxis : {
+					min : 0,
+					tickDecimals : 0
+				},
+				xaxis : {
+					mode : 'categories'
+				}
+			});
+		}
+	};
+
+	loadQueryPerfLineChart = function() {
+		$.plot(jqueryMap.$queryLoadChartHolder, blurconsole.model.metrics.getQueryLoadChartData(), {
+			series : {
+				shadowSize : 0
+			},
+			yaxis : {
+				min : 0
+			},
+			xaxis : {
+				show : false
+			}
+		});
+	};
+
+	buildNodeTable = function(data) {
+		var table = '<table class="table table-condensed"><thead><tr><th>Offline Node</th></tr></thead><tbody>';
+		if (data.length === 0) {
+			table += '<tr><td>Everything is Online!</td></tr>';
+		} else {
+			$.each(data, function(idx, node) {
+				table += '<tr><td>' + node + '</td></tr>';
+			});
+		}
+		table += '</tbody></table>';
+		return $(table);
+	};
+
+	adjustChartSize = function() {
+		var size, shardCharts;
+
+		size = jqueryMap.$zkChartHolder.parent()[0].clientWidth - 150;
+		jqueryMap.$zkChartHolder.css({
+			'height' : size,
+			'width' : size
+		});
+
+		size = jqueryMap.$controllerChartHolder.parent()[0].clientWidth - 150;
+		jqueryMap.$controllerChartHolder.css({
+			'height' : size,
+			'width' : size
+		});
+
+		size = jqueryMap.$shardChartHolder.parent()[0].clientWidth - 150;
+		shardCharts = jqueryMap.$shardChartHolder.find('.shardClusterChartHolder');
+		shardCharts.each(function(){
+			$(this).css({
+				'height' : size,
+				'width' : size
+			});
+		});
+
+		size = jqueryMap.$tableChartHolder.parent()[0].clientWidth - 150;
+		jqueryMap.$tableChartHolder.css({
+			'height' : size,
+			'width' : size
+		});
+
+		size = jqueryMap.$queryLoadChartHolder.parent()[0].clientWidth - 150;
+		jqueryMap.$queryLoadChartHolder.css({
+			'height' : size,
+			'width' : size
+		});
+	};
+
+	checkForSlowQueries = function() {
+		if (blurconsole.model.metrics.getSlowQueryWarnings()) {
+			$('#slow-query-warnings').removeClass('hidden');
+		} else {
+			$('#slow-query-warnings').addClass('hidden');
+		}
+	};
+
+	initModule = function( $container ) {
+		$container.load ( configMap.view, function() {
+			stateMap.$container = $container;
+			setJqueryMap();
+			updateNodeCharts();
+			loadTableColumnChart();
+			loadQueryPerfLineChart();
+			checkForSlowQueries();
+			$.gevent.subscribe(jqueryMap.$container, 'node-status-updated', updateNodeCharts);
+			$.gevent.subscribe(jqueryMap.$container, 'tables-updated', loadTableColumnChart);
+			$.gevent.subscribe(jqueryMap.$container, 'query-perf-updated', loadQueryPerfLineChart);
+			$.gevent.subscribe(jqueryMap.$container, 'queries-updated', checkForSlowQueries);
+			adjustChartSize();
+			$(document).on('click', '.swapper-trigger', function() {
+			    console.log(this);
+				var parent = $(this).closest('div.swapper-parent');
+				console.log(parent);
+				var chart = parent.find('.swapper-chart');
+				var info = parent.find('.swapper-info');
+
+				chart.toggleClass('hidden');
+				info.toggleClass('hidden');
+			});
+			
+		});
+		$(window).resize(adjustChartSize);
+		return true;
+	};
+
+	return {
+		initModule   : initModule,
+		unloadModule : unloadModule
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.data.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.data.js b/contrib/blur-console/src/main/webapp/js/blurconsole.data.js
new file mode 100644
index 0000000..441fb43
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.data.js
@@ -0,0 +1,23 @@
+/*
+
+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.
+*/
+/*global blurconsole:false */
+blurconsole.data = (function() {
+	'use strict';
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.fake.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.fake.js b/contrib/blur-console/src/main/webapp/js/blurconsole.fake.js
new file mode 100644
index 0000000..aa85975
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.fake.js
@@ -0,0 +1,221 @@
+/*
+
+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.
+*/
+/*global blurconsole:false */
+blurconsole.fake = (function() {
+	'use strict';
+	var getTableList, getNodeList, getQueryPerformance, getQueries, cancelQuery, disableTable, enableTable, deleteTable, getSchema, findTerms, sendSearch,
+		randomNumber, randomBoolean, randomString;
+
+	getTableList = function() {
+		console.log('getting fake table list');
+		var clusters = ['prodA', 'prodB'], data = [], i, cluster, rows, records, enabled;
+
+		for (i = 0; i < 5; i++) {
+			cluster = clusters[randomNumber(2, true)];
+			rows = randomNumber(1000);
+			records = randomNumber(10000)+1000;
+			enabled = randomBoolean();
+
+			data.push({cluster:cluster, name:'testtable'+i, enabled:enabled, rows:rows, records:records, families: blurconsole.utils.keys(getSchema('testtable'+i))});
+
+		}
+		return data;
+	};
+
+	getNodeList = function() {
+		console.log('getting fake node list');
+		var controllers = {online:[], offline:[]},
+			clusters = [{name:'prodA', online:[], offline:[]}, {name:'prodB', online:[], offline:[]}],
+			zookeepers = {online: [], offline:[]},
+			i, state;
+
+		for(i = 0; i < 3; i++) {
+			state = randomBoolean();
+			if (state) {
+				controllers.online.push('controller' + i + '.localhost');
+				clusters[0].online.push('prodA.shard' + i + '.localhost');
+				clusters[1].online.push('prodB.shard' + i + '.localhost');
+				zookeepers.online.push('zookeeper' + i + '.localhost');
+			} else {
+				controllers.offline.push('controller' + i + '.localhost');
+				clusters[0].offline.push('prodA.shard' + i + '.localhost');
+				clusters[1].offline.push('prodB.shard' + i + '.localhost');
+				zookeepers.offline.push('zookeeper' + i + '.localhost');
+			}
+		}
+		return {controllers: controllers, clusters: clusters, zookeepers: zookeepers};
+	};
+
+	getQueryPerformance = function() {
+		console.log('getting fake query performance');
+		return randomNumber(1000);
+	};
+
+	getQueries = function() {
+		console.log('getting fake queries');
+		var queries = [];
+
+		for (var i=0; i < randomNumber(50); i++) {
+			queries.push({
+				uuid: randomString(),
+				user: 'user_' + randomNumber(10, true),
+				query: randomString(),
+				table: 'testtable' + randomNumber(5, true),
+				state: randomNumber(3, true),
+				percent: randomNumber(100, true),
+				startTime: new Date()
+			});
+		}
+
+		return {
+			slowQueries : randomNumber(100) % 10 === 0,
+			queries : queries
+		};
+	};
+
+	cancelQuery = function(uuid) {
+		console.log('Fake sending request to cancel query [' + uuid + ']');
+	};
+
+	disableTable = function(table) {
+		console.log('Fake sending request to disable table [' + table + ']');
+	};
+
+	enableTable = function(table) {
+		console.log('Fake sending request to enable table [' + table + ']');
+	};
+
+	deleteTable = function(table, includeFiles) {
+		console.log('Fake sending request to delete table [' + table + '] with files [' + includeFiles + ']');
+	};
+
+	getSchema = function(table) {
+		console.log('getting fake schema for table [' + table + ']');
+		var f, schema = {}, familyCount = randomNumber(20), types = ['string', 'long', 'int', 'date', 'stored', 'customType'];
+
+		for(f=0; f < familyCount; f++) {
+			var c, fam = {}, columnCount = randomNumber(30);
+			for(c=0; c < columnCount; c++) {
+				fam['col'+c] = {
+					'fieldLess' : randomBoolean(),
+					'type' : types[randomNumber(6, true)],
+					'extra' : null
+				};
+
+				if (randomBoolean()) {
+					var e, extraPropCount = randomNumber(3), props = {};
+					for (e=0; e < extraPropCount; e++) {
+						props['extra'+e] = 'val'+e;
+					}
+					fam['col'+c].extra = props;
+				}
+			}
+			schema['fam'+f] = fam;
+		}
+
+		return schema;
+	};
+
+	findTerms = function(table, family, column, startsWith, callback) {
+		console.log('getting fake terms from [' + table + '] for family [' + family + '] and column [' + column + '] starting with [' + startsWith + ']');
+
+		var terms = [];
+
+		for (var i = 0; i < 10; i++) {
+			var randStr = randomString();
+			if (startsWith) {
+				randStr = startsWith + randStr;
+			}
+			terms.push(randStr);
+		}
+
+		terms = terms.sort(function (a, b) {
+			return a.toLowerCase().localeCompare(b.toLowerCase());
+		});
+
+		callback(terms);
+	};
+
+	sendSearch = function(query, table, args, callback) {
+		console.log('sending fake search [' + query + '] on table [' + table + ']');
+
+		var fams = args.families, results = {}, total = randomNumber(1000);
+
+		$.each(fams, function(i, fam){
+			var cols = randomNumber(30, true), toFetch = args.fetch;
+			if (total - args.start < toFetch) {
+				toFetch = total - args.start;
+			}
+			results[fam] = [];
+			for (var r = 0; r < randomNumber(toFetch); r++) {
+				var row = {};
+				for (var c=0; c < cols; c++) {
+					row['col'+c] = randomString();
+				}
+				results[fam].push(row);
+			}
+		});
+
+		callback({
+			families: args.families,
+			results: results,
+			total: total
+		});
+	};
+
+	randomNumber = function(max, includeZero) {
+		var random = Math.random()*max;
+
+		if (!includeZero) {
+			random++;
+		}
+
+		return Math.floor(random);
+	};
+
+	randomBoolean = function() {
+		return randomNumber(2) % 2 === 0;
+	};
+
+	randomString = function() {
+		var text = '';
+		var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+		for( var i=0; i < Math.floor(Math.random() * 30 + 1); i++ ) {
+			text += possible.charAt(Math.floor(Math.random() * possible.length));
+		}
+
+		return text;
+	};
+
+	return {
+		getTableList : getTableList,
+		getNodeList : getNodeList,
+		getQueryPerformance : getQueryPerformance,
+		getQueries : getQueries,
+		cancelQuery : cancelQuery,
+		disableTable : disableTable,
+		enableTable : enableTable,
+		deleteTable : deleteTable,
+		getSchema : getSchema,
+		findTerms : findTerms,
+		sendSearch : sendSearch
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.js b/contrib/blur-console/src/main/webapp/js/blurconsole.js
new file mode 100644
index 0000000..ccbedec
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.js
@@ -0,0 +1,33 @@
+/*
+
+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.
+*/
+
+/*
+ * blur.js
+ * Root namespace module
+ */
+var blurconsole = (function () {
+	'use strict';
+	var initModule = function ( $container ) {
+		blurconsole.model.initModule();
+		blurconsole.shell.initModule( $container );
+	};
+
+	return { initModule: initModule };
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.model.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.model.js b/contrib/blur-console/src/main/webapp/js/blurconsole.model.js
new file mode 100644
index 0000000..8eefec3
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.model.js
@@ -0,0 +1,483 @@
+/*
+
+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.
+*/
+/*global blurconsole:false */
+blurconsole.model = (function() {
+	'use strict';
+	var
+		configMap = {
+			poller : null
+		},
+		stateMap = {
+			tableNameMap: null,
+			nodeMap : null,
+			queryPerformance : [],
+			queries : {}
+		},
+		tables, metrics, nodes, queries, search, initModule, nodePoller, tablePoller, queryPerformancePoller, queryPoller;
+
+	tables = (function() {
+		var getClusters, getEnabledTables, getDisabledTables, isDataLoaded, disableTable, enableTable, deleteTable, getSchema, findTerms, getAllEnabledTables, getFamilies;
+
+		getClusters = function() {
+			if (stateMap.tableNameMap === null) {
+				return [];
+			}
+
+			return blurconsole.utils.unique($.map(stateMap.tableNameMap, function(table){
+				return table.cluster;
+			}), true);
+		};
+
+		getEnabledTables = function(cluster) {
+			var data = [];
+
+			$.each(stateMap.tableNameMap, function(idx, table) {
+				if (table.cluster === cluster && table.enabled) {
+					data.push({name:table.name, rowCount:table.rows, recordCount:table.records});
+				}
+			});
+
+			return data;
+		};
+
+		getDisabledTables = function(cluster) {
+			var data = [];
+
+			$.each(stateMap.tableNameMap, function(idx, table) {
+				if (table.cluster === cluster && !table.enabled) {
+					data.push({name:table.name, rowCount:table.rows, recordCount:table.records});
+				}
+			});
+
+			return data;
+		};
+
+		getAllEnabledTables = function() {
+			var tableMap = {};
+
+			$.each(getClusters(), function(c, cluster){
+				tableMap[cluster] = getEnabledTables(cluster);
+			});
+
+			return tableMap;
+		};
+
+		isDataLoaded = function() {
+			return stateMap.tableNameMap !== null;
+		};
+
+		disableTable = function(tableName) {
+			configMap.poller.disableTable(tableName);
+		};
+
+		enableTable = function(tableName) {
+			configMap.poller.enableTable(tableName);
+		};
+
+		deleteTable = function(tableName, includeFiles) {
+			configMap.poller.deleteTable(tableName, includeFiles);
+		};
+
+		getSchema = function(tableName) {
+			return configMap.poller.getSchema(tableName);
+		};
+
+		getFamilies = function(tableName) {
+			var table;
+
+			$.each(stateMap.tableNameMap, function(idx, t) {
+				if (t.name === tableName) {
+					table = t;
+					return false;
+				}
+			});
+
+			return table.families;
+		};
+
+		findTerms = function(table, family, column, startsWith) {
+			configMap.poller.findTerms(table, family, column, startsWith, function(terms) {
+				$.gevent.publish('terms-updated', terms);
+			});
+		};
+
+		return {
+			getClusters : getClusters,
+			getEnabledTables : getEnabledTables,
+			getDisabledTables : getDisabledTables,
+			isDataLoaded : isDataLoaded,
+			disableTable : disableTable,
+			enableTable : enableTable,
+			deleteTable : deleteTable,
+			getSchema : getSchema,
+			findTerms : findTerms,
+			getAllEnabledTables : getAllEnabledTables,
+			getFamilies : getFamilies
+		};
+	}());
+
+	nodes = (function() {
+		var getOfflineZookeeperNodes, getOfflineControllerNodes, getOfflineShardNodes, isDataLoaded;
+
+		getOfflineZookeeperNodes = function() {
+			return stateMap.nodeMap.zookeepers.offline;
+		};
+
+		getOfflineControllerNodes = function() {
+			return stateMap.nodeMap.controllers.offline;
+		};
+
+		getOfflineShardNodes = function(clusterName) {
+			var clusterData = $.grep(stateMap.nodeMap.clusters, function(cluster) {
+				return cluster.name === clusterName;
+			});
+
+			if (clusterData.length > 0) {
+				return clusterData[0].offline;
+			}
+			return [];
+		};
+
+		isDataLoaded = function() {
+			return stateMap.nodeMap !== null;
+		};
+
+		return {
+			getOfflineZookeeperNodes : getOfflineZookeeperNodes,
+			getOfflineControllerNodes : getOfflineControllerNodes,
+			getOfflineShardNodes : getOfflineShardNodes,
+			isDataLoaded : isDataLoaded
+		};
+	}());
+
+	metrics = (function() {
+		var getZookeeperChartData, getControllerChartData, getClusters, getShardChartData, getTableChartData,
+			getQueryLoadChartData, buildPieChartData, getSlowQueryWarnings;
+
+		getZookeeperChartData = function() {
+			return buildPieChartData(stateMap.nodeMap.zookeepers.online.length, stateMap.nodeMap.zookeepers.offline.length);
+		};
+
+		getControllerChartData = function() {
+			return buildPieChartData(stateMap.nodeMap.controllers.online.length, stateMap.nodeMap.controllers.offline.length);
+		};
+
+		getClusters = function() {
+			return $.map(stateMap.nodeMap.clusters, function(cluster) {
+				return cluster.name;
+			});
+		};
+
+		getShardChartData = function(clusterName) {
+			var clusterData = $.grep(stateMap.nodeMap.clusters, function(cluster) {
+				return cluster.name === clusterName;
+			});
+
+			if (clusterData.length > 0) {
+				return buildPieChartData(clusterData[0].online.length, clusterData[0].offline.length);
+			}
+			return null;
+		};
+
+		getTableChartData = function() {
+			var enabledData = blurconsole.utils.reduce(stateMap.tableNameMap, [], function(accumulator, table){
+				var currentCluster = $.grep(accumulator, function(item){
+					return item[0] === table.cluster;
+				});
+
+				if (currentCluster.length === 0) {
+					currentCluster = [table.cluster, 0];
+					accumulator.push(currentCluster);
+				} else {
+					currentCluster = currentCluster[0];
+				}
+
+				if (table.enabled) {
+					currentCluster[1] = currentCluster[1]+1;
+				}
+				return accumulator;
+			});
+
+			var disabledData = blurconsole.utils.reduce(stateMap.tableNameMap, [], function(accumulator, table){
+				var currentCluster = $.grep(accumulator, function(item){
+					return item[0] === table.cluster;
+				});
+
+				if (currentCluster.length === 0) {
+					currentCluster = [table.cluster, 0];
+					accumulator.push(currentCluster);
+				} else {
+					currentCluster = currentCluster[0];
+				}
+
+				if (!table.enabled) {
+					currentCluster[1] = currentCluster[1]+1;
+				}
+				return accumulator;
+			});
+
+			return [
+				{
+					'data' : enabledData,
+					'label' : 'Enabled',
+					'color' : '#66CDCC',
+					'stack' : true
+				},
+				{
+					'data' : disabledData,
+					'label' : 'Disabled',
+					'color' : '#333333',
+					'stack' : true
+				}
+			];
+		};
+
+		getQueryLoadChartData = function() {
+			var total = 0,
+				queryArray = [],
+				meanArray = [],
+				queryData, mean;
+
+			queryData = stateMap.queryPerformance;
+
+			$.each(queryData, function(idx, increment) {
+				total += increment;
+			});
+
+			mean = queryData.length === 0 ? 0 : total/queryData.length;
+
+			$.each(queryData, function(idx, increment) {
+				queryArray.push([idx, increment]);
+				meanArray.push([idx, mean]);
+			});
+
+			return [queryArray, meanArray];
+		};
+
+		buildPieChartData = function(onlineCount, offlineCount) {
+			var onlineChart = {
+				'label':'Online',
+				'color':'#66CDCC',
+				'data':[[0,onlineCount]]
+			};
+
+			var offlineChart = {
+				'label':'Offline',
+				'color':'#FF1919',
+				'data':[[0,offlineCount]]
+			};
+
+			return [onlineChart, offlineChart];
+		};
+
+		getSlowQueryWarnings = function() {
+			return stateMap.queries.slowQueries;
+		};
+
+		return {
+			getZookeeperChartData : getZookeeperChartData,
+			getControllerChartData : getControllerChartData,
+			getClusters : getClusters,
+			getShardChartData : getShardChartData,
+			getTableChartData : getTableChartData,
+			getQueryLoadChartData : getQueryLoadChartData,
+			getSlowQueryWarnings : getSlowQueryWarnings
+		};
+	}());
+
+	queries = (function() {
+		var queriesForTable, cancelQuery, tableHasActivity, matchesFilter,
+			states = ['running', 'interrupted', 'complete', 'backpressureinterrupted'];
+
+		queriesForTable = function(table, sort, filter) {
+			var queries = [], qSort, sortField, sortDir;
+
+			qSort = (sort || 'startTime~desc').split('~');
+			sortField = qSort[0];
+			sortDir = qSort.length > 1 ? qSort[1] : 'asc';
+
+			$.each(stateMap.queries.queries, function(i, query){
+				if (query.table === table && matchesFilter(query, filter)) {
+					queries.push(query);
+				}
+			});
+
+			queries.sort(function(a, b){
+				if (sortDir === 'asc') {
+					return a[sortField] > b[sortField];
+				} else {
+					return b[sortField] > b[sortField];
+				}
+			});
+
+			return queries;
+		};
+
+		cancelQuery = function(uuid) {
+			configMap.poller.cancelQuery(uuid);
+		};
+
+		tableHasActivity = function(table) {
+			var hasActivity = false;
+			$.each(stateMap.queries.queries, function(i, query){
+				if (query.table === table) {
+					hasActivity = true;
+					return false;
+				}
+			});
+			return hasActivity;
+		};
+
+		matchesFilter = function(queryData, filterText) {
+			var queryStr = queryData.user + '~~~' + queryData.query + '~~~' + states[queryData.state];
+
+			if (filterText === null || filterText === '') {
+				return true;
+			}
+
+			return queryStr.toLowerCase().indexOf(filterText.toLowerCase()) !== -1;
+		};
+
+		return {
+			queriesForTable : queriesForTable,
+			cancelQuery : cancelQuery,
+			tableHasActivity : tableHasActivity
+		};
+	}());
+
+	search = (function() {
+		var results = {}, totalRecords = 0, currentQuery, currentTable, currentArgs = {start: 0, fetch: 10, rowRecordOption: 'rowrow', families: null},
+			runSearch, getResults, getFamilies, loadMoreResults, getTotal,
+			sendSearch, processResults;
+
+		runSearch = function( query, table, searchArgs ) {
+			var parsedFamilies = blurconsole.utils.findFamilies(query);
+
+			currentQuery = query;
+			currentTable = table;
+			currentArgs = $.extend(currentArgs, searchArgs);
+			if (parsedFamilies.length > 0) {
+				currentArgs.families = parsedFamilies;
+			}
+			results = {};
+			sendSearch();
+		};
+
+		getResults = function() {
+			return results;
+		};
+
+		getTotal = function() {
+			return totalRecords;
+		};
+
+		loadMoreResults = function(family) {
+			var alreadyLoadedResults = results[family];
+
+			currentArgs.start = alreadyLoadedResults ? alreadyLoadedResults.length : 0;
+			currentArgs.fetch = 10;
+			currentArgs.families = [family];
+			sendSearch();
+		};
+
+		sendSearch = function() {
+			configMap.poller.sendSearch(currentQuery, currentTable, currentArgs, processResults);
+		};
+
+		processResults = function(data) {
+			var dataFamilies, dataResults;
+
+			dataFamilies = data.families;
+			dataResults = data.results;
+			totalRecords = data.total;
+
+			if (typeof dataResults !== 'undefined' && dataResults !== null) {
+				$.each(dataResults, function(family, resultList){
+					var tmpList = results[family] || [];
+					results[family] = tmpList.concat(resultList);
+				});
+			}
+			$.gevent.publish('results-updated', [dataFamilies]);
+		};
+
+		return {
+			runSearch: runSearch,
+			getResults: getResults,
+			getFamilies: getFamilies,
+			loadMoreResults: loadMoreResults,
+			getTotal: getTotal
+		};
+	}());
+
+	nodePoller = function() {
+		var tmpNodeMap = configMap.poller.getNodeList();
+		if (!blurconsole.utils.equals(tmpNodeMap, stateMap.nodeMap)) {
+			stateMap.nodeMap = tmpNodeMap;
+			$.gevent.publish('node-status-updated');
+		}
+		setTimeout(nodePoller, 5000);
+	};
+
+	tablePoller = function() {
+		var tmpTableMap = configMap.poller.getTableList();
+		if (!blurconsole.utils.equals(tmpTableMap, stateMap.tableNameMap)) {
+			stateMap.tableNameMap = tmpTableMap;
+			$.gevent.publish('tables-updated');
+		}
+		setTimeout(tablePoller, 5000);
+	};
+
+	queryPerformancePoller = function() {
+		if (stateMap.queryPerformance.length === 100) {
+			stateMap.queryPerformance.shift();
+		}
+
+		stateMap.queryPerformance.push(configMap.poller.getQueryPerformance());
+		$.gevent.publish('query-perf-updated');
+		setTimeout(queryPerformancePoller, 5000);
+	};
+
+	queryPoller = function() {
+		var tmpQueries = configMap.poller.getQueries();
+		if (!blurconsole.utils.equals(tmpQueries, stateMap.queries)) {
+			stateMap.queries = tmpQueries;
+			$.gevent.publish('queries-updated');
+		}
+		setTimeout(queryPoller, 5000);
+	};
+
+	initModule = function() {
+		configMap.poller = window.location.href.indexOf('fakeIt=') > -1 ? blurconsole.fake : blurconsole.data;
+		setTimeout(function() {
+			nodePoller();
+			tablePoller();
+			queryPerformancePoller();
+			queryPoller();
+		}, 1000);
+	};
+	return {
+		initModule : initModule,
+		tables : tables,
+		metrics: metrics,
+		nodes : nodes,
+		queries : queries,
+		search : search
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.queries.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.queries.js b/contrib/blur-console/src/main/webapp/js/blurconsole.queries.js
new file mode 100644
index 0000000..ce0298c
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.queries.js
@@ -0,0 +1,177 @@
+/*
+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.
+*/
+/*jshint laxbreak: true */
+/*global blurconsole:false */
+blurconsole.queries = (function () {
+	'use strict';
+	var configMap = {
+		view : 'views/queries.tpl.html',
+		states : ['Running', 'Interrupted', 'Complete', 'Back Pressure Interrupted'],
+		queryDef : [
+			{label:'User', key:'user'},
+			{label:'Query', key: 'query'},
+			{label:'Time Started', key: 'startTime'},
+			{label:'State', key: function(row) {
+				var stateInfo = configMap.states[row.state];
+
+				if (row.state === 0) {
+					stateInfo += ' <div class="badge badge-info">' + row.percent + '%</div>';
+				}
+				return stateInfo;
+			}},
+			{label:'Actions', key: function(row) {
+				var actions = '';
+				if (row.state === 0) {
+					actions += '<a href="#" class="cancelTrigger btn btn-danger" data-uuid="' + row.uuid + '" data-query="' + row.query + '"><i class="glyphicon glyphicon-ban-circle"></i> Cancel</a> ';
+				}
+				return actions;
+			}}
+		],
+	},
+	stateMap = {
+		$container : null,
+		currentTable : null,
+		currentFilter : null,
+		currentSort : null
+	},
+	jqueryMap = {},
+	setJqueryMap, initModule, unloadModule, drawTableList, drawQueries, registerPageEvents, unregisterPageEvents;
+
+	setJqueryMap = function() {
+		var $container = stateMap.$container;
+		jqueryMap = {
+			$container : $container,
+			$tableHolder : $('#tableHolder'),
+			$queryHolder : $('#queryHolder'),
+			$filterHolder : $('#filterOptions'),
+			$filterText : $('#filterOptions .filterText')
+		};
+	};
+
+	registerPageEvents = function() {
+		jqueryMap.$tableHolder.on('click', '.list-group-item', function(){
+			stateMap.currentTable = $(this).attr('href');
+
+			$('.list-group-item', jqueryMap.$tableHolder).removeClass('active');
+			$('.list-group-item[href="' + stateMap.currentTable + '"]', jqueryMap.$tableHolder).addClass('active');
+			drawQueries();
+			return false;
+		});
+		jqueryMap.$queryHolder.on('click', 'a.cancelTrigger', function(){
+			var uuid = $(this).data('uuid'), query = $(this).data('query');
+			var modalContent = blurconsole.browserUtils.modal('confirmDelete', 'Confirm Query Cancel', 'You are about to cancel the query [' + query + '].  Are you sure you want to do this?', [
+				{classes: 'btn-primary killQuery', label: 'Stop Query'},
+				{classes: 'btn-default cancel', label: 'Cancel', data: {dismiss:'modal'}}
+			], 'medium');
+
+			var modal = $(modalContent).modal().on('shown.bs.modal', function(e){
+				$(e.currentTarget).on('click', '.killQuery', function() {
+					blurconsole.model.queries.cancelQuery(uuid);
+					modal.modal('hide');
+				});
+			}).on('hidden.bs.modal', function(e) {
+				$(e.currentTarget).remove();
+			});
+			return false;
+		});
+
+		jqueryMap.$filterHolder.on('click', '.filterTrigger', function() {
+			var filterVal = jqueryMap.$filterText.val();
+
+			stateMap.currentFilter = filterVal;
+			drawQueries();
+		});
+	};
+
+	unregisterPageEvents = function() {
+		if (jqueryMap.$tableHolder) {
+			jqueryMap.$tableHolder.off();
+		}
+	};
+
+	drawTableList = function() {
+		var clusters = blurconsole.model.tables.getClusters();
+
+		if (clusters) {
+			jqueryMap.$tableHolder.html('');
+			clusters.sort();
+			$.each(clusters, function(i, cluster){
+				var panelContent, tables = blurconsole.model.tables.getEnabledTables(cluster);
+
+				panelContent =
+					'<div class="panel panel-default">'
+						+ '<div class="panel-heading">'
+							+ '<h3 class="panel-title">' + cluster + '</h3>'
+						+ '</div>'
+						+ '<div class="panel-body">';
+				if (tables.length > 0) {
+					tables.sort(function(a, b){ return a.name > b.name; });
+					panelContent += '<div class="list-group">';
+
+					$.each(tables, function(i, table){
+						panelContent += '<a href="' + table.name + '" class="list-group-item';
+						if (table.name === stateMap.currentTable) {
+							panelContent += ' active';
+							drawQueries();
+						}
+						panelContent += '">' + table.name + '</a>';
+					});
+
+					panelContent += '</div>';
+				} else {
+					panelContent += '<div class="alert alert-warning">There are not any enabled tables!</div>';
+				}
+				panelContent += '</div></div>';
+				jqueryMap.$tableHolder.append(panelContent);
+			});
+		} else {
+			jqueryMap.$tableHolder.html('<div class="alert alert-warning">There are no clusters of tables!</div>');
+		}
+	};
+
+	drawQueries = function() {
+		if (stateMap.currentTable){
+			jqueryMap.$queryHolder.html(blurconsole.browserUtils.table(configMap.queryDef, blurconsole.model.queries.queriesForTable(stateMap.currentTable, stateMap.currentSort, stateMap.currentFilter)));
+		} else {
+			jqueryMap.$queryHolder.html('<div class="alert alert-info">Select a table on the left to see the current queries</div>');
+		}
+	};
+
+	initModule = function($container) {
+		$container.load(configMap.view, function() {
+			stateMap.$container = $container;
+			setJqueryMap();
+			$.gevent.subscribe(jqueryMap.$container, 'queries-updated', drawQueries);
+			$.gevent.subscribe(jqueryMap.$container, 'tables-updated', drawTableList);
+			registerPageEvents();
+		});
+		return true;
+	};
+
+	unloadModule = function() {
+		$.gevent.unsubscribe(jqueryMap.$container, 'queries-updated');
+		$.gevent.unsubscribe(jqueryMap.$container, 'tables-updated');
+		unregisterPageEvents();
+	};
+
+	return {
+		initModule : initModule,
+		unloadModule : unloadModule
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.schema.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.schema.js b/contrib/blur-console/src/main/webapp/js/blurconsole.schema.js
new file mode 100644
index 0000000..9f29f4f
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.schema.js
@@ -0,0 +1,182 @@
+/*
+
+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.
+*/
+/*jshint laxbreak: true */
+/*global blurconsole:false */
+blurconsole.schema = (function () {
+	'use strict';
+	var
+		configMap = {
+			mainHtml: String()
+				+ '<div class="container-fluid">'
+					+ '<div class="row">'
+						+ '<div class="col-md-6">'
+							+ '<div class="panel-group schemaList">'
+							+ '</div>'
+						+ '</div>'
+						+ '<div class="col-md-6">'
+							+ '<div class="row">'
+								+ '<div class="col-md-12 schemaColumnInfo">'
+									+ '<div class="schemaColumnDef in">'
+										+ '<strong>Choose a column on the left to see def</strong>'
+									+ '</div>'
+								+ '</div>'
+							+ '</div>'
+							+ '<div class="row">'
+								+ '<div class="col-md-12 schemaColumnTerms">'
+									+ '<div class="input-group">'
+										+ '<input class="form-control termSearch" placeholder="Starts With" type="text">'
+										+ '<span class="input-group-btn">'
+											+ '<button class="btn btn-default" type="button">Go!</button>'
+										+ '</span>'
+									+ '</div>'
+									+ '<ul class="list-group termList"></ul>'
+								+ '</div>'
+							+ '</div>'
+						+ '</div>'
+					+ '</div>'
+				+ '</div>'
+		},
+		stateMap = {},
+		jqueryMap = {},
+		initModule, showSchema, buildTreeSection, buildInfoSection, viewTerms, findTerms, loadTerms, switchToSearch;
+
+	showSchema = function(event, table) {
+		stateMap.table = table;
+		stateMap.modalId = stateMap.table + '_modal';
+		stateMap.schema = blurconsole.model.tables.getSchema(stateMap.table);
+
+		jqueryMap.contentHolder = $(configMap.mainHtml);
+		jqueryMap.contentHolder.find('.schemaList').html(buildTreeSection());
+		jqueryMap.contentHolder.find('.schemaColumnInfo').append(buildInfoSection());
+
+		jqueryMap.modal = $(blurconsole.browserUtils.modal(stateMap.modalId, 'Schema Definition for ' + stateMap.table, jqueryMap.contentHolder, null, 'large'));
+		jqueryMap.modal.modal()
+		.on('shown.bs.modal', function(e){
+			jqueryMap.columnTermsSection = $('.schemaColumnTerms', jqueryMap.modal);
+			jqueryMap.termSearch = $('.termSearch', jqueryMap.modal);
+			jqueryMap.termList = $('.termList', jqueryMap.modal);
+			jqueryMap.termSearchButton = $('.schemaColumnTerms button', jqueryMap.modal);
+			$('.collapse', e.currentTarget).collapse({ toggle: false });
+		})
+		.on('hidden.bs.modal', function(e) {
+			$(e.currentTarget).remove();
+			jqueryMap.contentHolder.remove();
+			jqueryMap = {};
+			stateMap = {};
+		})
+		.on('click', 'li.schemaColumn', function() {
+			var defId = $(this).find('a').attr('href');
+			$('div.schemaColumnDef').removeClass('in');
+			$(defId).addClass('in');
+			jqueryMap.columnTermsSection.hide();
+			return false;
+		})
+		.on('click', 'a.termsTrigger', viewTerms)
+		.on('click', '.schemaColumnTerms button', findTerms)
+		.on('click', '.searchTrigger', switchToSearch);
+	};
+
+	buildTreeSection = function() {
+		var tree = '';
+		$.each(stateMap.schema, function(family, cols){
+			var famId = blurconsole.browserUtils.cleanId(family);
+			tree += '<div class="panel panel-default"><div class="panel-heading">';
+			tree += '<h4 class="panel-title"><a data-toggle="collapse" data-parent=".schemaList" href="#' + famId + '">' + family + '</a></h4></div>';
+			tree += '<div id="' + famId + '" class="panel-collapse collapse"><div class="panel-body"><ul class="list-group">';
+			$.each(cols, function(col, def) {
+				var colId = blurconsole.browserUtils.cleanId(col);
+				tree += '<li class="list-group-item schemaColumn"><a href="#' + famId + '_' + colId + '">' + col + '';
+				if (def.type !== 'stored') {
+					tree += ' <span class="badge">searchable</span>';
+				}
+				tree += '</a><div class="pull-right"><i class="glyphicon glyphicon-chevron-right"></i></div></li>';
+			});
+			tree += '</ul></div></div></div>';
+		});
+		return tree;
+	};
+
+	buildInfoSection = function() {
+		var info = '';
+		$.each(stateMap.schema, function(family, cols){
+			var famId = blurconsole.browserUtils.cleanId(family);
+			$.each(cols, function(col, def){
+				var colId = blurconsole.browserUtils.cleanId(col);
+				info += '<div class="schemaColumnDef" id="' + famId + '_' + colId + '"><ul class="list-group">';
+				info += '<li class="list-group-item"><strong>Fieldless Searching:</strong> ' + blurconsole.browserUtils.booleanImg(def.fieldLess) + '</li>';
+				info += '<li class="list-group-item"><strong>Field Type:</strong> ' + def.type + '</li>';
+				if (def.extra) {
+					$.each(def.extra, function(key, value) {
+						info += '<li class="list-group-item"><strong>' + key + ':</strong> ' + value + '</li>';
+					});
+				}
+				if (def.type !== 'stored') {
+					info += '<li class="list-group-item"><a href="#" class="termsTrigger" data-fam="' + family + '" data-col="' + col + '">View Terms</a></li>';
+				}
+				info += '</ul></div>';
+			});
+		});
+		return info;
+	};
+
+	viewTerms = function() {
+		jqueryMap.termList.html('<div class="center-block"><img src="img/ajax-loader.gif"></div>');
+		jqueryMap.termSearch.val('');
+		jqueryMap.columnTermsSection.show();
+		var $this = $(this);
+
+		stateMap.termFamily = $this.data('fam');
+		stateMap.termColumn = $this.data('col');
+
+		jqueryMap.termSearchButton.trigger('click');
+	};
+
+	findTerms = function() {
+		blurconsole.model.tables.findTerms(stateMap.table, stateMap.termFamily, stateMap.termColumn, jqueryMap.termSearch.val());
+	};
+
+	loadTerms = function() {
+		var terms = Array.prototype.slice.call(arguments, 1);
+		jqueryMap.termList.html('');
+		$.each(terms, function(i, term){
+			jqueryMap.termList.append('<li class="list-group-item">' + term + ' <span class="badge badge-success searchTrigger" title="Search for this value" data-value="' + term + '" data-table="' + stateMap.table + '"><i class="glyphicon glyphicon-search"></i></span></li>');
+		});
+	};
+
+	switchToSearch = function(){
+		blurconsole.shell.changeAnchorPart({
+			tab: 'search',
+			_tab: {
+				query: encodeURIComponent(stateMap.termFamily + '.' + stateMap.termColumn + ':' + $(this).data('value')),
+				table: $(this).data('table')
+			}
+		});
+		jqueryMap.modal.modal('hide');
+	};
+
+	initModule = function() {
+		$.gevent.subscribe($(document), 'schema-show', showSchema);
+		$.gevent.subscribe($(document), 'terms-updated', loadTerms);
+	};
+
+	return {
+		initModule : initModule
+	};
+}());
\ No newline at end of file


Mime
View raw message