incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amccu...@apache.org
Subject [06/19] Moving blur console to the root of the project.
Date Tue, 17 Jun 2014 20:24:14 GMT
http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/scripts/grunt.sh
----------------------------------------------------------------------
diff --git a/blur-console/src/main/scripts/grunt.sh b/blur-console/src/main/scripts/grunt.sh
new file mode 100755
index 0000000..f202477
--- /dev/null
+++ b/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/e599710c/blur-console/src/main/webapp/.bowerrc
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/.bowerrc b/blur-console/src/main/webapp/.bowerrc
new file mode 100644
index 0000000..4e5e51b
--- /dev/null
+++ b/blur-console/src/main/webapp/.bowerrc
@@ -0,0 +1,3 @@
+{
+    "directory": "libs"
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/.editorconfig
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/.editorconfig b/blur-console/src/main/webapp/.editorconfig
new file mode 100644
index 0000000..8a80734
--- /dev/null
+++ b/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/e599710c/blur-console/src/main/webapp/.gitattributes
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/.gitattributes b/blur-console/src/main/webapp/.gitattributes
new file mode 100644
index 0000000..2125666
--- /dev/null
+++ b/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/e599710c/blur-console/src/main/webapp/.gitignore
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/.gitignore b/blur-console/src/main/webapp/.gitignore
new file mode 100644
index 0000000..80661cd
--- /dev/null
+++ b/blur-console/src/main/webapp/.gitignore
@@ -0,0 +1,7 @@
+build/
+libs/*
+jsc/*
+public/*
+test/reports
+.tmp
+.sass-cache

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/.jshintrc
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/.jshintrc b/blur-console/src/main/webapp/.jshintrc
new file mode 100644
index 0000000..abc9b0a
--- /dev/null
+++ b/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/e599710c/blur-console/src/main/webapp/Gruntfile.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/Gruntfile.js b/blur-console/src/main/webapp/Gruntfile.js
new file mode 100644
index 0000000..f3802b3
--- /dev/null
+++ b/blur-console/src/main/webapp/Gruntfile.js
@@ -0,0 +1,289 @@
+/*
+
+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);
+
+    var all_js_files = [
+        'libs/jquery/dist/jquery.js',
+        'js/utils/*\.js',
+        'libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/tooltip.js',
+        'libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/modal.js',
+        'libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/transition.js',
+        'libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/popover.js',
+        'libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/collapse.js',
+        'libs/twbs-bootstrap-sass/vendor/assets/javascripts/bootstrap/tab.js',
+        'libs/flot/jquery.flot.js',
+        'libs/flot/jquery.flot.pie.js',
+        'libs/flot/jquery.flot.categories.js',
+        'libs/flot/jquery.flot.stack.js',
+        'libs/typeahead.js/dist/typeahead.jquery.js',
+        'js/blurconsole.js',
+        'js/*\.js'
+    ];
+
+    // Define the configuration for all the tasks
+    grunt.initConfig({
+        pkg: grunt.file.readJSON('package.json'),
+        banner: grunt.file.read('banner'),
+
+        clean: ['public'],
+
+        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: {
+                    'public/css/blurconsole.css': 'sass/blurconsole.scss'
+                }
+            },
+            production: {
+                files: {
+                    'public/css/blurconsole.css': 'sass/blurconsole.scss'
+                },
+                options: {
+                    style: 'compressed'
+                }
+            }
+        },
+
+        uglify: {
+            js: {
+                options: {
+                    sourceMap: true,
+                    sourceMapIncludeSources: true,
+                    banner:'/*\n<%= banner %>\n*/',
+                    compress: {
+                        drop_console: true
+                    }
+                },
+                files: {
+                    'public/js/blurconsole.js': all_js_files
+                }
+            }
+        },
+
+        // Make sure code styles are up to par and there are no obvious mistakes
+        jshint: {
+            options: {
+                jshintrc: true,
+            },
+            development: {
+                src: ['js/**/*\.js', '!js/utils/**/*\.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', 'version-assets-css-map', 'version-assets-css', 'notify:css']
+            },
+            js: {
+                files: ['js/**/*.js'],
+                tasks: ['jshint:development', 'uglify:js', 'version-assets-js-map', 'version-assets-js']
+            },
+            html: {
+                files: ['index.html', 'views/*.html'],
+                tasks: ['copy:main', 'version-assets']
+            },
+            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',
+                base: 'public'
+            },
+            livereload: {
+                options: {
+                    open: 'http://0.0.0.0:3000/?fakeIt=true'
+                }
+            }
+        },
+
+        copy: {
+            main: {
+                files: [
+                    {expand: true, src: ['index.html','img/*','views/*'], dest: 'public/'},
+                    {expand: true, flatten: true, src: ['libs/modernizr/modernizr.js'], dest: 'public/js'},
+                    {expand: true, flatten: true, src: ['libs/twbs-bootstrap-sass/vendor/assets/fonts/bootstrap/*'], dest: 'public/css'}
+                ]
+            }
+        }
+    });
+
+    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');
+    grunt.loadNpmTasks('grunt-contrib-uglify');
+    grunt.loadNpmTasks('grunt-contrib-copy');
+
+    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 for development', ['clean', 'sass:development', 'uglify:js', 'copy:main', 'version-assets']);
+    grunt.registerTask('production', 'Build for production', ['clean', 'sass:production', 'uglify:js', 'copy:main', 'version-assets']);
+    grunt.registerTask('serve', 'Run development server', ['clean','development', 'connect:livereload','watch']);
+    grunt.registerTask('default', ['clean', 'style:development', 'development', 'watch']);
+    grunt.registerTask('version-assets-css-map', function() {
+        var Version = require("node-version-assets");
+        var versionInstance = new Version({
+            assets: ['public/css/blurconsole.css.map'],
+            grepFiles: ['public/css/blurconsole.css'],
+            keepOriginal: true
+        });
+        versionInstance.run(this.async());
+    });
+    grunt.registerTask('version-assets-js-map', function() {
+        var Version = require("node-version-assets");
+        var versionInstance = new Version({
+            assets: ['public/js/blurconsole.js.map'],
+            grepFiles: ['public/js/blurconsole.js'],
+            keepOriginal: true
+        });
+        versionInstance.run(this.async());
+    });
+    grunt.registerTask('version-assets-js', function() {
+        var Version = require("node-version-assets");
+        var versionInstance = new Version({
+            assets: ['public/js/blurconsole.js'],
+            grepFiles: ['public/index.html'],
+            keepOriginal: true
+        });
+        versionInstance.run(this.async());
+    });
+    grunt.registerTask('version-assets-css', function() {
+        var Version = require("node-version-assets");
+        var versionInstance = new Version({
+            assets: ['public/css/blurconsole.css'],
+            grepFiles: ['public/index.html'],
+            keepOriginal: true
+        });
+        versionInstance.run(this.async());
+    });
+    grunt.registerTask('version-assets', 'version the static assets just created', ['version-assets-js-map', 'version-assets-js', 'version-assets-css-map', 'version-assets-css']);
+};

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/banner
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/banner b/blur-console/src/main/webapp/banner
new file mode 100644
index 0000000..90705e0
--- /dev/null
+++ b/blur-console/src/main/webapp/banner
@@ -0,0 +1,16 @@
+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.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/bower.json
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/bower.json b/blur-console/src/main/webapp/bower.json
new file mode 100644
index 0000000..6c54da7
--- /dev/null
+++ b/blur-console/src/main/webapp/bower.json
@@ -0,0 +1,16 @@
+{
+  "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",
+    "typeahead.js":"0.10.2"
+  },
+  "devDependencies": {
+    "mocha": "~1.18.0",
+    "chai": "~1.9.0"
+  }
+}

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

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/index.html
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/index.html b/blur-console/src/main/webapp/index.html
new file mode 100644
index 0000000..f38c923
--- /dev/null
+++ b/blur-console/src/main/webapp/index.html
@@ -0,0 +1,67 @@
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+ -->
+
+<!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="js/modernizr.js"></script>
+    </head>
+    <body>
+        <nav class="navbar navbar-inverse navbar-fixed-top">
+            <a class="navbar-brand" href="#">Blur Console</a>
+            <div class="pull-right">
+                <button type="button" id="view_logging_trigger" class="btn btn-default btn-sm">
+                    Logs
+                    <span class="badge badge-warning"></span>
+                </button>
+            </div>
+        </nav>
+        <nav class="side-nav">
+            <ul>
+                <li title="Dashboard" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#!tab=dashboard"><i class="glyphicon glyphicon-dashboard"></i></a>
+                </li>
+                <li title="Tables" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#!tab=tables"><i class="glyphicon glyphicon-list"></i></a>
+                </li>
+                <li title="Queries" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#!tab=queries"><i class="glyphicon glyphicon-tasks"></i></a>
+                </li>
+                <li title="Search" data-toggle="tooltip" data-placement="right" data-container="body">
+                    <a href="#!tab=search"><i class="glyphicon glyphicon-search"></i></a>
+                </li>
+            </ul>
+        </nav>
+        <div id="blurconsole"></div>
+        <script src="js/blurconsole.js"></script>
+        <script type="text/javascript">
+            $(function () { blurconsole.initModule( $('#blurconsole') ); });
+        </script>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/js/blurconsole.b_utils.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.b_utils.js b/blur-console/src/main/webapp/js/blurconsole.b_utils.js
new file mode 100644
index 0000000..8ffd146
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.b_utils.js
@@ -0,0 +1,121 @@
+/*
+
+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';
+
+	function table(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;
+	}
+
+	function modal(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;
+	}
+
+	function cleanId(str) {
+		return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '_');
+	}
+
+	function booleanImg(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/e599710c/blur-console/src/main/webapp/js/blurconsole.dashboard.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.dashboard.js b/blur-console/src/main/webapp/js/blurconsole.dashboard.js
new file mode 100644
index 0000000..005645f
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.dashboard.js
@@ -0,0 +1,271 @@
+/*
+
+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';
+	//------------------- Configuration and State -------------------------
+	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:10pt;font-weight:bold;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 = {};
+
+	//--------------------- Utilities ---------------------
+	function _setJqueryMap() {
+		var $container = stateMap.$container;
+		jqueryMap = {
+			$container : $container,
+			$zkChartHolder : $('#zookeeperNodes'),
+			$zkInfoHolder : $('#zookeeperInfo'),
+			$controllerChartHolder : $('#controllerNodes'),
+			$controllerInfoHolder : $('#controllerInfo'),
+			$shardChartHolder : $('#shardNodes'),
+			$tableChartHolder : $('#tableCounts'),
+			$queryLoadChartHolder : $('#queryLoad')
+		};
+	}
+
+	function _registerPageEvents() {
+		$(document).on('click', '.swapper-trigger', _swapNodeChartAndData);
+		$(window).on('resize', _adjustChartsSizes);
+	}
+
+	function _unregisterPageEvents() {
+		$(document).off('click', '.swapper-trigger');
+		$(window).off('resize');
+	}
+
+	//----------------------- Event Handlers and DOM Modifiers ------------------
+	function _updateAllCharts() {
+		_updateNodeCharts();
+		_loadTableColumnChart();
+		_loadQueryPerfLineChart();
+	}
+
+	function _updateNodeCharts() {
+		if (blurconsole.model.nodes.isDataLoaded()) {
+			_loadZkPieChart();
+			_loadControllerPieChart();
+			_loadShardsPieChart();
+		}
+	}
+
+	function _swapNodeChartAndData(evt) {
+		var parent = $(evt.currentTarget).closest('div.swapper-parent');
+		var chart = parent.find('.swapper-chart');
+		var info = parent.find('.swapper-info');
+
+		chart.toggleClass('hidden');
+		info.toggleClass('hidden');
+	}
+
+	function _loadZkPieChart() {
+		$.plot(jqueryMap.$zkChartHolder, blurconsole.model.metrics.getZookeeperChartData(), configMap.pieOptions);
+		jqueryMap.$zkInfoHolder.html(_buildNodeTable(blurconsole.model.nodes.getOnlineZookeeperNodes(), blurconsole.model.nodes.getOfflineZookeeperNodes()));
+	}
+
+	function _loadControllerPieChart() {
+		$.plot(jqueryMap.$controllerChartHolder, blurconsole.model.metrics.getControllerChartData(), configMap.pieOptions);
+		jqueryMap.$controllerInfoHolder.html(_buildNodeTable(blurconsole.model.nodes.getOnlineControllerNodes(), blurconsole.model.nodes.getOfflineControllerNodes()));
+	}
+
+	function _loadShardsPieChart() {
+		if (jqueryMap.$shardChartHolder.find('img').length > 0) {
+			jqueryMap.$shardChartHolder.html('');
+		}
+
+		$.each(blurconsole.model.metrics.getClusters(), function(idx, cluster) {
+			var clusterData = blurconsole.model.metrics.getShardChartData(cluster);
+
+			if (clusterData) {
+				var clusterHolder = jqueryMap.$shardChartHolder.find('#cluster_' + cluster + '_chart_holder');
+				var 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);
+					var 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)));
+			}
+		});
+	}
+
+	function _loadTableColumnChart() {
+		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'
+				}
+			});
+		}
+	}
+
+	function _loadQueryPerfLineChart() {
+		$.plot(jqueryMap.$queryLoadChartHolder, blurconsole.model.metrics.getQueryLoadChartData(), {
+			series : {
+				shadowSize : 0
+			},
+			yaxis : {
+				min : 0
+			},
+			xaxis : {
+				show : false
+			}
+		});
+	}
+
+	function _buildNodeTable(online, offline) {
+		var table = '<table class="table table-condensed"><thead><tr><th>Offline Node</th></tr></thead><tbody>';
+		if (offline.length === 0) {
+			table += '<tr><td>Everything is Online!</td></tr>';
+		} else {
+			$.each(offline, function(idx, node) {
+				table += '<tr><td>' + node + '</td></tr>';
+			});
+		}
+		table += '</tbody></table>';
+
+		if (online.length > 0) {
+			table += '<table class="table table-condensed"><thead><tr><th>Online Node</th></tr></thead><tbody>';
+			$.each(online, function(idx, node) {
+				table += '<tr><td>' + node + '</td></tr>';
+			});
+			table += '</tbody></table>';
+		}
+		return $(table);
+	}
+
+	function _adjustChartSize(holder) {
+		var size;
+		size = jqueryMap[holder].parent()[0].clientWidth - 150;
+		jqueryMap[holder].css({
+			'height' : size,
+			'width' : size
+		});
+	}
+
+	function _adjustChartsSizes() {
+		_adjustChartSize('$zkChartHolder');
+		_adjustChartSize('$controllerChartHolder');
+		_adjustChartSize('$tableChartHolder');
+		_adjustChartSize('$queryLoadChartHolder');
+
+		var size = jqueryMap.$shardChartHolder.parent()[0].clientWidth - 150;
+		var shardCharts = jqueryMap.$shardChartHolder.find('.shardClusterChartHolder');
+		shardCharts.each(function(){
+			$(this).css({
+				'height' : size,
+				'width' : size
+			});
+		});
+		_updateAllCharts();
+	}
+
+	function _checkForSlowQueries() {
+		if (blurconsole.model.metrics.getSlowQueryWarnings()) {
+			$('#slow-query-warnings').slideDown();
+		} else {
+			$('#slow-query-warnings').slideUp();
+		}
+	}
+
+	//----------------------- Public API ----------------------------
+
+	function initModule( $container ) {
+		$container.load ( configMap.view, function() {
+			stateMap.$container = $container;
+			_setJqueryMap();
+			_updateAllCharts();
+			_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);
+			_adjustChartsSizes();
+			_registerPageEvents();
+		});
+		return true;
+	}
+
+	function unloadModule() {
+		$.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');
+		_unregisterPageEvents();
+	}
+
+	return {
+		initModule   : initModule,
+		unloadModule : unloadModule
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/js/blurconsole.data.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.data.js b/blur-console/src/main/webapp/js/blurconsole.data.js
new file mode 100644
index 0000000..b89ff80
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.data.js
@@ -0,0 +1,131 @@
+/*
+
+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';
+
+	//------------------- Private methods --------------------------
+	function _logError (errorMsg, status, module, callback) {
+		blurconsole.model.logs.logError(status + ' - ' + errorMsg, module);
+		if (callback) {
+			callback('error');
+		}
+	}
+
+	//------------------- Public API -------------------------------
+	function getTableList(callback) {
+		$.getJSON('/service/tables', callback).fail(function(xhr) {
+			_logError(xhr.responseText, xhr.status, 'tables', callback);
+		});
+	}
+
+	function getNodeList(callback) {
+		$.getJSON('/service/nodes', callback).fail(function(xhr) {
+			_logError(xhr.responseText, xhr.status, 'tables', callback);
+		});
+	}
+	function getQueryPerformance(callback) {
+		$.getJSON('/service/queries/performance', callback).fail(function(xhr) {
+			_logError(xhr.responseText, xhr.status, 'tables', callback);
+		});
+	}
+
+	function getQueries(callback) {
+		$.getJSON('/service/queries', callback).fail(function(xhr) {
+			_logError(xhr.responseText, xhr.status, 'tables', callback);
+		});
+	}
+
+	function cancelQuery(table, uuid) {
+		$.ajax('/service/queries/' + uuid + '/cancel', {
+			data: {
+				table: table
+			},
+			error: function(xhr) {
+				_logError(xhr.responseText, xhr.status, 'tables');
+			}
+		});
+	}
+
+	function disableTable(table) {
+		$.ajax('/service/tables/' + table + '/disable', {
+			error: function(xhr) {
+				_logError(xhr.responseText, xhr.status, 'tables');
+			}
+		});
+	}
+
+	function enableTable (table){
+		$.ajax('/service/tables/' + table + '/enable', {
+			error: function(xhr) {
+				_logError(xhr.responseText, xhr.status, 'tables');
+			}
+		});
+	}
+
+	function deleteTable (table, includeFiles) {
+		$.ajax('/service/tables/' + table + '/delete', {
+			data: {
+				includeFiles: includeFiles
+			},
+			error: function(xhr) {
+				_logError(xhr.responseText, xhr.status, 'tables');
+			}
+		});
+	}
+
+	function getSchema(table, callback) {
+		$.getJSON('/service/tables/' + table + '/schema', callback).fail(function(xhr) {
+			_logError(xhr.responseText, xhr.status, 'tables');
+		});
+	}
+
+	function findTerms (table, family, column, startsWith, callback) {
+		$.getJSON('/service/tables/' + table + '/' + family + '/' + column + '/terms', {startsWith: startsWith}, callback).fail(function(xhr) {
+			_logError(xhr.responseText, xhr.status, 'tables');
+		});
+	}
+
+	function sendSearch(query, table, args, callback) {
+		var params = $.extend({table:table, query:query}, args);
+		$.ajax('/service/search', {
+			'type': 'POST',
+			'data': params,
+			'success': callback,
+			'error': function(xhr) {
+				_logError(xhr.responseText, xhr.status, 'tables');
+			}
+		});
+	}
+
+	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/e599710c/blur-console/src/main/webapp/js/blurconsole.fake.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.fake.js b/blur-console/src/main/webapp/js/blurconsole.fake.js
new file mode 100644
index 0000000..14abc17
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.fake.js
@@ -0,0 +1,281 @@
+/*
+
+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 frozen = false;
+	var tableList, schema, nodeList, queries;
+
+	//----------------------- Private Methods ----------------------
+	function _randomNumber(max, includeZero) {
+		var random = Math.random()*max;
+
+		if (!includeZero) {
+			random++;
+		}
+
+		return Math.floor(random);
+	}
+
+	function _randomBoolean() {
+		return _randomNumber(2) % 2 === 0;
+	}
+
+	function _randomString() {
+		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;
+	}
+
+	function _buildSchema() {
+		var schema = {}, familyCount = _randomNumber(20), types = ['string', 'long', 'int', 'date', 'stored', 'customType'];
+
+		for(var f=0; f < familyCount; f++) {
+			var c, fam = {}, columnCount = _randomNumber(30);
+			for(c=0; c < columnCount; c++) {
+				var col_name = 'col' + c;
+				if(_randomNumber(10) === 1) {
+					col_name += '.sub';
+				}
+				fam[col_name] = {
+					'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_name].extra = props;
+				}
+			}
+			schema['fam'+f] = fam;
+		}
+		return schema;
+	}
+
+	function _sendCallback(callback, data) {
+		setTimeout(function() {
+			callback(data);
+		}, _randomNumber(1000));
+	}
+
+	function _toggleFreeze() {
+		var button = $('#fake_freeze');
+		if(button.html() === 'Freeze'){
+			frozen = true;
+			button.html('Unfreeze');
+			console.log('Fake data frozen');
+		} else {
+			frozen = false;
+			button.html('Freeze');
+			console.log('Fake data resumed');
+		}
+	}
+
+	//-------------------------- Public API ---------------------------
+	function getTableList(callback) {
+		//console.log('getting fake table list');
+		if(!frozen || !tableList) {
+			var clusters = ['prodA', 'prodB'], data = [];
+
+			for (var i = 0; i < 5; i++) {
+				var cluster = clusters[_randomNumber(2, true)];
+				var rows = _randomNumber(1000);
+				var records = _randomNumber(10000)+1000;
+				var enabled = _randomBoolean();
+
+				data.push({cluster:cluster, name:'testtable'+i, enabled:enabled, rows:rows, records:records, families: blurconsole.utils.keys(_buildSchema())});
+
+			}
+			tableList = {'tables':data, 'clusters':clusters};
+		}
+		_sendCallback(callback, tableList);
+	}
+
+	function getNodeList(callback) {
+		//console.log('getting fake node list');
+		if(!frozen || !nodeList) {
+			var controllers = {online:[], offline:[]},
+				clusters = [{name:'prodA', online:[], offline:[]}, {name:'prodB', online:[], offline:[]}],
+				zookeepers = {online: [], offline:[]};
+
+			for(var i = 0; i < 3; i++) {
+				var 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');
+				}
+			}
+			nodeList = {controllers: controllers, clusters: clusters, zookeepers: zookeepers};
+		}
+		_sendCallback(callback, nodeList);
+	}
+
+	function getQueryPerformance(callback) {
+		//console.log('getting fake query performance');
+		_sendCallback(callback, _randomNumber(1000, true));
+	}
+
+	function getQueries(callback) {
+		//console.log('getting fake queries');
+		if(!frozen || !queries) {
+			var randomQueries = [];
+
+			for (var i=0; i < _randomNumber(50); i++) {
+				randomQueries.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().getTime()
+				});
+			}
+			queries = { slowQueries : _randomNumber(10) === 1, queries : randomQueries };
+		}
+		_sendCallback(callback, queries);
+	}
+
+	function cancelQuery(table, uuid) {
+		console.log('Fake sending request to cancel query [' + uuid + '] on table [' + table + ']');
+	}
+
+	function disableTable(table) {
+		console.log('Fake sending request to disable table [' + table + ']');
+	}
+
+	function enableTable(table) {
+		console.log('Fake sending request to enable table [' + table + ']');
+	}
+
+	function deleteTable(table, includeFiles) {
+		console.log('Fake sending request to delete table [' + table + '] with files [' + includeFiles + ']');
+	}
+
+	function getSchema(table, callback) {
+		console.log('getting fake schema for table [' + table + ']');
+		if(!frozen || !schema){
+			schema = _buildSchema();
+		}
+		_sendCallback(callback, schema);
+	}
+
+	function findTerms(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());
+		});
+		_sendCallback(callback, terms);
+	}
+
+	function sendSearch(query, table, args, callback) {
+		console.log('sending fake search [' + query + '] on table [' + table + ']');
+
+		var fams = args.families, results = {}, total = (fams !== null && fams.indexOf('rowid') >= 0) ? 1 : _randomNumber(1000);
+
+		if (fams !== null) {
+			$.each(fams, function(i, fam){
+				var cols = _randomNumber(30, true), toFetch = (fams !== null && fams.indexOf('rowid') >= 0)? 1 : args.fetch;
+				if (total - args.start < toFetch) {
+					toFetch = total - args.start;
+				}
+
+				if (args.rowRecordOption === 'recordrecord') {
+					results[fam] = [];
+					for (var recordIndex = 0; recordIndex < _randomNumber(toFetch); recordIndex++) {
+						var recordRow = {};
+						recordRow.recordid = _randomNumber(1000000).toString();
+						for (var recordColIndex=0; recordColIndex < cols; recordColIndex++) {
+							recordRow['col'+recordColIndex] = _randomString();
+						}
+						results[fam].push(recordRow);
+					}
+				} else {
+					results[fam] = [];
+					for (var rowIndex = 0; rowIndex < _randomNumber(toFetch); rowIndex++) {
+						var rowid = _randomNumber(10000000).toString();
+						results[fam][rowIndex] = {rowid: rowid, records: []};
+						for (var rowRecordIndex = 0; rowRecordIndex < _randomNumber(10); rowRecordIndex++) {
+							var row = {};
+							row.recordid = _randomNumber(1000000).toString();
+							for (var rowRecordColIndex=0; rowRecordColIndex < cols; rowRecordColIndex++) {
+								row['col'+rowRecordColIndex] = _randomString();
+							}
+							results[fam][rowIndex]['records'].push(row);
+						}
+					}
+				}
+			});
+		}
+
+		if (fams.indexOf('rowid') >= 0) {
+			_sendCallback(callback, { total: total, results: results, families: fams });
+		} else if (fams === null || fams.length === 0) {
+			_sendCallback(callback, { total: total });
+		} else {
+			_sendCallback(callback, { families: fams, results: results, total: total });
+		}
+	}
+	function initModule() {
+		$('nav.navbar .pull-right').append('<button type="button" id="fake_freeze" class="btn btn-default btn-sm">Freeze</button>');
+		$('#fake_freeze').click(_toggleFreeze);
+	}
+
+	return {
+		initModule: initModule,
+		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/e599710c/blur-console/src/main/webapp/js/blurconsole.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.js b/blur-console/src/main/webapp/js/blurconsole.js
new file mode 100644
index 0000000..310df79
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.js
@@ -0,0 +1,35 @@
+/*
+
+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';
+
+	//---------------------- Public API -------------------------
+	function initModule( $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/e599710c/blur-console/src/main/webapp/js/blurconsole.logging.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.logging.js b/blur-console/src/main/webapp/js/blurconsole.logging.js
new file mode 100644
index 0000000..e3a35d5
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.logging.js
@@ -0,0 +1,87 @@
+/*
+
+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.logging = (function () {
+	'use strict';
+
+	//------------------------ Configuration and State -----------------------
+	var configMap = {
+		emptyLogMsg: 'No Errors! Yay!',
+		mainHtml: '<div class="log_display"></div>',
+		buttons: [
+			{ 'classes': 'btn-default', 'id': 'clear-log-button', 'label': 'Clear Logs' },
+			{ 'classes': 'btn-primary', 'id': 'close-logs', 'label': 'Close', 'data': {'dismiss':'modal'} }
+		]
+	},
+	jqueryMap = {
+		modal: null
+	};
+
+	//------------------ Event Handling and DOM Methods -------------
+	function _showLogging() {
+		if (jqueryMap.modal === null) {
+			jqueryMap.modal = $(blurconsole.browserUtils.modal('error_log_modal', 'Error Logs', configMap.mainHtml, configMap.buttons, 'large'));
+			jqueryMap.modal.modal()
+			.on('shown.bs.modal', function(){
+				jqueryMap.logHolder = $('.log_display', jqueryMap.modal);
+				_drawLogs();
+			})
+			.on('click', '#clear-log-button', _clearLogging);
+		} else {
+			jqueryMap.modal.modal('show');
+		}
+	}
+
+	function _clearLogging() {
+		jqueryMap.logHolder.html(configMap.emptyLogMsg);
+		blurconsole.model.logs.clearErrors();
+	}
+
+	function _drawLogs() {
+		var errors = blurconsole.model.logs.getLogs();
+
+		if (jqueryMap.logHolder) {
+			if (errors.length === 0) {
+				jqueryMap.logHolder.html(configMap.emptyLogMsg);
+			} else {
+				var errorList = '<ul>';
+				errors.sort(function(a, b) {
+					return a.timestamp.getTime() > b.timestamp.getTime();
+				});
+				$.each(errors, function(i, error){
+					errorList += '<li><strong>' + error.error + ' (' + error.module + ')</strong><div class="pull-right"><em>' + error.timestamp.toTimeString() + '</em></div></li>';
+				});
+				errorList += '</ul>';
+				jqueryMap.logHolder.html(errorList);
+			}
+		}
+	}
+
+	//------------------ Public API ---------------------------------
+	function initModule() {
+		$.gevent.subscribe($(document), 'show-logging', _showLogging);
+		$.gevent.subscribe($(document), 'logging-updated', _drawLogs);
+	}
+
+	return {
+		initModule : initModule
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/js/blurconsole.model.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.model.js b/blur-console/src/main/webapp/js/blurconsole.model.js
new file mode 100644
index 0000000..61a15c2
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.model.js
@@ -0,0 +1,573 @@
+/*
+
+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';
+
+	//----------------------- Configuration and State ------------------
+	var
+		configMap = {
+			poller : null
+		},
+		stateMap = {
+			currentTables: null,
+			currentClusters: [],
+			nodeMap : null,
+			queryPerformance : [],
+			queries : {},
+			errors: [],
+			schema: {}
+		};
+
+	//----------------------- Models ----------------------------------
+	var tables = (function() {
+		//-------------- Public API -----------------
+		function getClusters() {
+			if (stateMap.currentClusters === null) {
+				return [];
+			}
+
+			return blurconsole.utils.unique(stateMap.currentClusters, true);
+		}
+
+		function getEnabledTables(cluster) {
+			var data = [];
+
+			$.each(stateMap.currentTables, function(idx, table) {
+				if (table.cluster === cluster && table.enabled) {
+					data.push({name:table.name, rowCount:table.rows, recordCount:table.records});
+				}
+			});
+
+			return data;
+		}
+
+		function getDisabledTables(cluster) {
+			var data = [];
+
+			$.each(stateMap.currentTables, function(idx, table) {
+				if (table.cluster === cluster && !table.enabled) {
+					data.push({name:table.name, rowCount:table.rows, recordCount:table.records});
+				}
+			});
+
+			return data;
+		}
+
+		function getAllEnabledTables() {
+			var tableMap = {};
+
+			$.each(getClusters(), function(c, cluster){
+				tableMap[cluster] = getEnabledTables(cluster);
+			});
+
+			return tableMap;
+		}
+
+		function isDataLoaded() {
+			return stateMap.currentTables !== null;
+		}
+
+		function disableTable(tableName) {
+			configMap.poller.disableTable(tableName);
+		}
+
+		function enableTable(tableName) {
+			configMap.poller.enableTable(tableName);
+		}
+
+		function deleteTable(tableName, includeFiles) {
+			configMap.poller.deleteTable(tableName, includeFiles);
+		}
+
+		function getSchema(tableName, callback) {
+			if(stateMap.schema && stateMap.schema.tableName === tableName && new Date() - stateMap.schema.date < 60000) {
+				setTimeout(function(){
+					callback(stateMap.schema.data);
+				}, 0);
+			} else {
+				configMap.poller.getSchema(tableName, function(schema) {
+					stateMap.schema.tableName = tableName;
+					stateMap.schema.data = schema;
+					stateMap.schema.date = new Date();
+					callback(schema);
+				});
+			}
+		}
+
+		function getFamilies(tableName) {
+			var table;
+
+			$.each(stateMap.currentTables, function(idx, t) {
+				if (t.name === tableName) {
+					table = t;
+					return false;
+				}
+			});
+			if(table) {
+				return table.families;
+			} else {
+				return [];
+			}
+		}
+
+		function findTerms(table, family, column, startsWith, callback) {
+			configMap.poller.findTerms(table, family, column, startsWith, callback);
+		}
+
+		return {
+			getClusters : getClusters,
+			getEnabledTables : getEnabledTables,
+			getDisabledTables : getDisabledTables,
+			isDataLoaded : isDataLoaded,
+			disableTable : disableTable,
+			enableTable : enableTable,
+			deleteTable : deleteTable,
+			getSchema : getSchema,
+			findTerms : findTerms,
+			getAllEnabledTables : getAllEnabledTables,
+			getFamilies : getFamilies
+		};
+	}());
+
+	var nodes = (function() {
+		//------------- Private Methods -----------------
+		function _getClusterData(clusterName) {
+			var clusterData = $.grep(stateMap.nodeMap.clusters, function(cluster) {
+				return cluster.name === clusterName;
+			});
+			return clusterData.length > 0 ? clusterData[0] : null;
+		}
+
+		//------------- Public API ----------------------
+		function getOnlineZookeeperNodes() {
+			return stateMap.nodeMap.zookeepers.online;
+		}
+
+		function getOfflineZookeeperNodes() {
+			return stateMap.nodeMap.zookeepers.offline;
+		}
+
+		function getOnlineControllerNodes() {
+			return stateMap.nodeMap.controllers.online;
+		}
+
+		function getOfflineControllerNodes() {
+			return stateMap.nodeMap.controllers.offline;
+		}
+
+		function getOfflineShardNodes(clusterName) {
+			var clusterData = _getClusterData(clusterName);
+			return clusterData ? clusterData.offline : [];
+		}
+
+		function getOnlineShardNodes(clusterName) {
+			var clusterData = _getClusterData(clusterName);
+			return clusterData ? clusterData.online : [];
+		}
+
+		function isDataLoaded() {
+			return stateMap.nodeMap !== null;
+		}
+
+		return {
+			getOnlineZookeeperNodes : getOnlineZookeeperNodes,
+			getOfflineZookeeperNodes : getOfflineZookeeperNodes,
+			getOfflineControllerNodes : getOfflineControllerNodes,
+			getOnlineControllerNodes : getOnlineControllerNodes,
+			getOfflineShardNodes : getOfflineShardNodes,
+			getOnlineShardNodes : getOnlineShardNodes,
+			isDataLoaded : isDataLoaded
+		};
+	}());
+
+	var metrics = (function() {
+		//------------- Private Methods ------------------
+		function _buildPieChartData(onlineCount, offlineCount) {
+			var onlineChart = {
+				'label':'Online',
+				'color':'#66CDCC',
+				'data':[[0,onlineCount]]
+			};
+
+			var offlineChart = {
+				'label':'Offline',
+				'color':'#FF1919',
+				'data':[[0,offlineCount]]
+			};
+
+			return [onlineChart, offlineChart];
+		}
+
+		//------------- Public API -----------------------
+		function getZookeeperChartData() {
+			return _buildPieChartData(stateMap.nodeMap.zookeepers.online.length, stateMap.nodeMap.zookeepers.offline.length);
+		}
+
+		function getControllerChartData() {
+			return _buildPieChartData(stateMap.nodeMap.controllers.online.length, stateMap.nodeMap.controllers.offline.length);
+		}
+
+		function getClusters() {
+			return $.map(stateMap.nodeMap.clusters, function(cluster) {
+				return cluster.name;
+			});
+		}
+
+		function getShardChartData(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;
+		}
+
+		function getTableChartData() {
+			var enabledData = blurconsole.utils.reduce(stateMap.currentTables, [], 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.currentTables, [], 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
+				}
+			];
+		}
+
+		function getQueryLoadChartData() {
+			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 [{label: 'Queries', data: queryArray}, {label:'Average', data:meanArray}];
+		}
+
+		function getSlowQueryWarnings() {
+			return stateMap.queries.slowQueries;
+		}
+
+		return {
+			getZookeeperChartData : getZookeeperChartData,
+			getControllerChartData : getControllerChartData,
+			getClusters : getClusters,
+			getShardChartData : getShardChartData,
+			getTableChartData : getTableChartData,
+			getQueryLoadChartData : getQueryLoadChartData,
+			getSlowQueryWarnings : getSlowQueryWarnings
+		};
+	}());
+
+	var queries = (function() {
+		var states = ['running', 'interrupted', 'complete', 'backpressureinterrupted'];
+
+		//-------------- Private Methods -------------------
+		function _matchesFilter(queryData, filterText) {
+			var queryStr = queryData.user + '~~~' + queryData.query + '~~~' + states[queryData.state];
+
+			if (filterText === null || filterText === '') {
+				return true;
+			}
+
+			return queryStr.toLowerCase().indexOf(filterText.toLowerCase()) !== -1;
+		}
+
+		//-------------- Public API -----------------------
+		function queriesForTable(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;
+		}
+
+		function cancelQuery(table, uuid) {
+			configMap.poller.cancelQuery(uuid);
+		}
+
+		function tableHasActivity(table) {
+			var hasActivity = false;
+			$.each(stateMap.queries.queries, function(i, query){
+				if (query.table === table) {
+					hasActivity = true;
+					return false;
+				}
+			});
+			return hasActivity;
+		}
+
+		return {
+			queriesForTable : queriesForTable,
+			cancelQuery : cancelQuery,
+			tableHasActivity : tableHasActivity
+		};
+	}());
+
+	var search = (function() {
+		var results = {}, totalRecords = 0, currentQuery, currentTable, currentArgs = {start: 0, fetch: 10, rowRecordOption: 'rowrow', families: null};
+
+		//-------------- Private Methods -------------------------
+		function _sendSearch() {
+			configMap.poller.sendSearch(currentQuery, currentTable, currentArgs, _processResults);
+		}
+
+		function _processResults(data) {
+			var dataFamilies = data.families;
+			var dataResults = data.results;
+			totalRecords = data.total;
+
+			if (typeof dataResults !== 'undefined' && dataResults !== null) {
+				$.each(dataResults, function(family, resultList){
+					var dataList = results[family] || [];
+					results[family] = dataList.concat(resultList);
+				});
+			}
+			$.gevent.publish('results-updated', [dataFamilies]);
+		}
+
+		//-------------- Public API ------------------------------
+		function runSearch( query, table, searchArgs ) {
+			var parsedFamilies = blurconsole.utils.findFamilies(query);
+
+			currentQuery = query;
+			currentTable = table;
+			currentArgs = $.extend(currentArgs, searchArgs);
+			currentArgs.families = parsedFamilies;
+			results = {};
+
+			if (query.indexOf('rowid:') === -1 && query.indexOf('recordid:') === -1) {
+				_sendSearch();
+			}
+		}
+
+		function getResults() {
+			return results;
+		}
+
+		function getTotal() {
+			return totalRecords;
+		}
+
+		function loadMoreResults(family) {
+			var alreadyLoadedResults = results[family];
+
+			if (typeof alreadyLoadedResults === 'undefined' || alreadyLoadedResults === null) {
+				currentArgs.start = 0;
+			} else if ($.isArray(alreadyLoadedResults)) {
+				currentArgs.start = alreadyLoadedResults.length;
+			} else {
+				currentArgs.start = blurconsole.utils.keys(alreadyLoadedResults).length;
+			}
+
+			// currentArgs.start = alreadyLoadedResults ? alreadyLoadedResults.length : 0;
+			currentArgs.fetch = 10;
+			currentArgs.families = [family];
+			_sendSearch();
+		}
+
+		return {
+			runSearch: runSearch,
+			getResults: getResults,
+			loadMoreResults: loadMoreResults,
+			getTotal: getTotal
+		};
+	}());
+
+	var logs = (function() {
+		//------------- Public API -------------------
+		function logError(error, module) {
+			stateMap.errors.push({error: error, module: module, timestamp: new Date()});
+			$.gevent.publish('logging-updated');
+		}
+
+		function clearErrors() {
+			delete stateMap.errors;
+			stateMap.errors = [];
+			$.gevent.publish('logging-updated');
+		}
+
+		function getLogs() {
+			return stateMap.errors;
+		}
+
+		return {
+			logError: logError,
+			clearErrors: clearErrors,
+			getLogs: getLogs
+		};
+	}());
+
+	//----------------------- Private Methods -------------------------
+	function _nodePoller() {
+		configMap.poller.getNodeList(_updateNodes);
+	}
+
+	function _tablePoller() {
+		configMap.poller.getTableList(_updateTables);
+	}
+
+	function _queryPerformancePoller() {
+		configMap.poller.getQueryPerformance(_updateQueryPerformance);
+	}
+
+	function _queryPoller() {
+		configMap.poller.getQueries(_updateQueries);
+	}
+
+	//----------------------- Event Handlers --------------------------
+	function _updateNodes(nodes) {
+		if (nodes !== 'error' && !blurconsole.utils.equals(nodes, stateMap.nodeMap)) {
+			stateMap.nodeMap = nodes;
+			$.gevent.publish('node-status-updated');
+		}
+		setTimeout(_nodePoller, 5000);
+	}
+
+	function _updateTables(data) {
+		if (data !== 'error') {
+			var tables = data.tables, clusters = data.clusters;
+			if (!blurconsole.utils.equals(tables, stateMap.currentTables) || !blurconsole.utils.equals(clusters, stateMap.currentClusters)) {
+				stateMap.currentTables = tables;
+				stateMap.currentClusters = clusters;
+				$.gevent.publish('tables-updated');
+			}
+		}
+		setTimeout(_tablePoller, 5000);
+	}
+
+	function _updateQueryPerformance(performanceMetric) {
+		if (performanceMetric !== 'error') {
+			if (stateMap.queryPerformance.length === 100) {
+				stateMap.queryPerformance.shift();
+			}
+
+			stateMap.queryPerformance.push(performanceMetric);
+			$.gevent.publish('query-perf-updated');
+		}
+		setTimeout(_queryPerformancePoller, 5000);
+	}
+
+	function _updateQueries(queries) {
+		if (queries !== 'error' && !blurconsole.utils.equals(queries, stateMap.queries)) {
+			stateMap.queries = queries;
+			$.gevent.publish('queries-updated');
+		}
+		setTimeout(_queryPoller, 5000);
+	}
+
+	//----------------------- Public API ------------------------------
+	function initModule() {
+		if(window.location.href.indexOf('fakeIt=') > -1) {
+			blurconsole.fake.initModule();
+			configMap.poller = blurconsole.fake;
+		} else {
+			configMap.poller = blurconsole.data;
+		}
+		setTimeout(function() {
+			_nodePoller();
+			_tablePoller();
+			_queryPerformancePoller();
+			_queryPoller();
+		}, 1000);
+	}
+
+	return {
+		initModule : initModule,
+		tables : tables,
+		metrics: metrics,
+		nodes : nodes,
+		queries : queries,
+		search : search,
+		logs: logs
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/e599710c/blur-console/src/main/webapp/js/blurconsole.queries.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.queries.js b/blur-console/src/main/webapp/js/blurconsole.queries.js
new file mode 100644
index 0000000..9b3d6b0
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.queries.js
@@ -0,0 +1,198 @@
+/*
+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';
+  
+    //------------------------ Configuration and State --------------------
+    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: function(row) {
+                var start = new Date(row.startTime);
+                return start.toTimeString(); //start.getHours() + ':' + start.getMinutes() + ':' + start.getSeconds();
+            } },
+            { 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 + '" data-table="' + row.table + '"><i class="glyphicon glyphicon-ban-circle"></i> Cancel</a> ';
+                }
+                return actions;
+            } }
+        ],
+    },
+    stateMap = {
+        $container: null,
+        currentTable: null,
+        currentFilter: null,
+        currentSort: null
+    },
+    jqueryMap = {};
+  
+    //----------------------------------- Private methods ----------------------------
+
+    function _setJqueryMap() {
+        var $container = stateMap.$container;
+        jqueryMap = {
+            $container: $container,
+            $tableHolder: $('#tableHolder'),
+            $queryHolder: $('#queryHolder'),
+            $filterHolder: $('#filterOptions'),
+            $filterText: $('#filterOptions .filterText')
+        };
+    }
+
+    function _registerPageEvents() {
+        jqueryMap.$tableHolder.on('click', '.list-group-item', _showQueriesForTable);
+        jqueryMap.$queryHolder.on('click', 'a.cancelTrigger', _cancelSelectedQuery);
+        jqueryMap.$filterHolder.on('click', '.filterTrigger', _filterQueries);
+    }
+
+    function _unregisterPageEvents() {
+        if(jqueryMap.$tableHolder) {
+            jqueryMap.$tableHolder.off();
+        }
+    }
+
+    function _waitForData() {
+        var clusters = blurconsole.model.tables.getClusters();
+        if(clusters && clusters.length > 0) {
+            _drawTableList();
+            _drawQueries();
+        } else {
+            setTimeout(_waitForData, 100);
+        }
+    }
+    //----------------------------- Event Handlers and DOM Methods -----------------------------
+
+    function _showQueriesForTable(evt) {
+        stateMap.currentTable = $(evt.currentTarget).attr('href');
+        $('.list-group-item', jqueryMap.$tableHolder).removeClass('active');
+        $('.list-group-item[href="' + stateMap.currentTable + '"]', jqueryMap.$tableHolder).addClass('active');
+        _drawQueries();
+        return false;
+    }
+
+    function _cancelSelectedQuery(evt) {
+        var uuid = $(evt.currentTarget).data('uuid'),
+          query = $(evt.currentTarget).data('query'),
+          table = $(evt.currentTarget).data('table');
+        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(table, uuid);
+                modal.modal('hide');
+            });
+        }).on('hidden.bs.modal', function(e) {
+            $(e.currentTarget).remove();
+        });
+        return false;
+    }
+
+    function _filterQueries() {
+        var filterVal = jqueryMap.$filterText.val();
+        stateMap.currentFilter = filterVal;
+        _drawQueries();
+    }
+
+    function _drawTableList() {
+        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>');
+        }
+    }
+
+    function _drawQueries() {
+        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>');
+        }
+    }
+  
+    //-------------------------- Public API ---------------------------------
+
+    function initModule($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();
+            _waitForData();
+        });
+        return true;
+    }
+
+    function unloadModule() {
+        $.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/e599710c/blur-console/src/main/webapp/js/blurconsole.schema.js
----------------------------------------------------------------------
diff --git a/blur-console/src/main/webapp/js/blurconsole.schema.js b/blur-console/src/main/webapp/js/blurconsole.schema.js
new file mode 100644
index 0000000..ebb36dd
--- /dev/null
+++ b/blur-console/src/main/webapp/js/blurconsole.schema.js
@@ -0,0 +1,190 @@
+/*
+
+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';
+    
+    //----------------------------- Configuration and State -------------------------
+	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 = {};
+
+	//------------------------------ Private Methods -----------------------------------------------------
+	function _findTerms() {
+		blurconsole.model.tables.findTerms(stateMap.table, stateMap.termFamily, stateMap.termColumn, jqueryMap.termSearch.val(), _loadTerms);
+	}
+
+	//------------------------------ Event Handling and DOM Methods --------------------------------------
+	function _showSchema(event, table) {
+		stateMap.table = table;
+		stateMap.modalId = stateMap.table + '_modal';
+		blurconsole.model.tables.getSchema(stateMap.table, _popupSchemaView);
+	}
+
+	function _popupSchemaView(schema) {
+		stateMap.schema = schema;
+		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);
+	}
+
+	function _buildTreeSection() {
+		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" data-toggle="collapse" data-parent=".schemaList" data-target="#' + famId + '">' + family + '</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 + '';
+				tree += '</a><div class="pull-right">';
+				if (def.type !== 'stored') {
+					tree += ' <span class="badge">searchable</span>';
+				}
+				tree += '<i class="glyphicon glyphicon-chevron-right"></i></div></li>';
+			});
+			tree += '</ul></div></div></div>';
+		});
+		return tree;
+	}
+
+	function _buildInfoSection() {
+		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>Field Name:</strong> ' + col + '</li>';
+				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;
+	}
+
+	function _viewTerms(evt) {
+		jqueryMap.termList.html('<div class="center-block"><img src="img/ajax-loader.gif"></div>');
+		jqueryMap.termSearch.val('');
+		jqueryMap.columnTermsSection.show();
+		var $this = $(evt.currentTarget);
+
+		stateMap.termFamily = $this.data('fam');
+		stateMap.termColumn = $this.data('col');
+
+		jqueryMap.termSearchButton.trigger('click');
+	}
+
+	function _loadTerms(terms) {
+		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>');
+		});
+	}
+
+	function _switchToSearch(evt){
+		blurconsole.shell.changeAnchorPart({
+			tab: 'search',
+			_tab: {
+				query: encodeURIComponent(stateMap.termFamily + '.' + stateMap.termColumn + ':' + $(evt.currentTarget).data('value')),
+				table: $(evt.currentTarget).data('table'),
+				rr: 'rowrow'
+			}
+		});
+		jqueryMap.modal.modal('hide');
+	}
+
+    //----------------------------- Public API ----------------------------
+	function initModule() {
+		$.gevent.subscribe($(document), 'schema-show', _showSchema);
+	}
+
+	return {
+		initModule : initModule
+	};
+}());
\ No newline at end of file


Mime
View raw message