You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2015/07/16 09:09:16 UTC

[34/51] [partial] karaf-decanter git commit: [KARAF-3849] Add karaf kibana dashboard

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/percentiles/module.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/percentiles/module.html b/kibana/src/main/resources/app/panels/percentiles/module.html
new file mode 100644
index 0000000..ef2b95b
--- /dev/null
+++ b/kibana/src/main/resources/app/panels/percentiles/module.html
@@ -0,0 +1,37 @@
+<div ng-controller="percentiles" ng-init="init()">
+  <style>
+    table.stats-table th, table.stats-table td {
+      text-align: right;
+    }
+
+    table.stats-table th:first-child,  table.stats-table td:first-child {
+      text-align: left !important;
+    }
+
+
+  </style>
+
+  <h1 ng-style="panel.style" style="text-align: center; line-height: .6em">{{data.value|formatstats:panel.format}} <small style="font-size: .5em; line-height: 0;">{{panel.unit}} ({{panel.mode}})</small></h1>
+  <table ng-show="panel.display_breakdown == 'yes'" cellspacing="0" class="table-hover table table-condensed stats-table" style="margin-top: 38px;">
+    <tbody>
+      <thead>
+        <tr>
+         <th><a href="" ng-click="set_sort('label')" ng-class="{'icon-chevron-down': panel.sort_field == 'label' && panel.sort_reverse == true, 'icon-chevron-up': panel.sort_field == 'label' && panel.sort_reverse == false}"> {{panel.label_name}} </a></th>
+         <th ng-repeat="stat in modes" ng-show="panel.show[stat]">
+          <a href=""
+            ng-click="set_sort(stat)"
+            ng-class="{'icon-chevron-down': panel.sort_field == stat && panel.sort_reverse == true, 'icon-chevron-up': panel.sort_field == stat && panel.sort_reverse == false}">
+            {{stat}}%
+          </a>
+          </th>
+        </tr>
+      </thead>
+      <tr ng-repeat="item in data.rows | orderBy:(panel.sort_field == 'label' ? 'label' : 'value.'+panel.sort_field):panel.sort_reverse">
+        <td><i class="icon-circle" ng-style="{color:item.color}"></i> {{item.label}}</td>
+        <td ng-repeat="stat in modes" ng-show="panel.show[stat]">{{item.value[stat]|formatstats:panel.format}} {{panel.unit}}</td>
+
+        <!--<td style="text-align: right;">{{item.value|formatstats:panel.format}} {{panel.unit}}</td>-->
+      </tr>
+    </tbody>
+  </table>
+</div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/percentiles/module.js
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/percentiles/module.js b/kibana/src/main/resources/app/panels/percentiles/module.js
new file mode 100644
index 0000000..f4b6e64
--- /dev/null
+++ b/kibana/src/main/resources/app/panels/percentiles/module.js
@@ -0,0 +1,258 @@
+/*
+
+  ## Percentiles Module
+
+  ### Parameters
+  * format :: The format of the value returned. (Default: number)
+  * style :: The font size of the main number to be displayed.
+  * mode :: The aggergate value to use for display
+  * spyable ::  Dislay the 'eye' icon that show the last elasticsearch query
+
+*/
+define([
+  'angular',
+  'app',
+  'lodash',
+  'jquery',
+  'kbn',
+  'numeral',
+  'config'
+], function (
+  angular,
+  app,
+  _,
+  $,
+  kbn,
+  numeral,
+  config
+) {
+
+  'use strict';
+
+  var module = angular.module('kibana.panels.percentiles', []);
+  app.useModule(module);
+
+  module.controller('percentiles', function ($scope, querySrv, dashboard, filterSrv, $http, esVersion) {
+
+    $scope.panelMeta = {
+      modals : [
+        {
+          description: "Inspect",
+          icon: "icon-info-sign",
+          partial: "app/partials/inspector.html",
+          show: $scope.panel.spyable
+        }
+      ],
+      editorTabs : [
+        {title:'Queries', src:'app/partials/querySelect.html'}
+      ],
+      status: 'Beta',
+      description: 'A percentiles panel for displaying aggregations using the Elastic Search percentiles aggregation query.'
+    };
+
+    $scope.modes = ['25','50','75','90','95','99'];
+
+    var defaults = {
+      queries     : {
+        mode        : 'all',
+        ids         : []
+      },
+      style   : { "font-size": '24pt'},
+      format: 'number',
+      mode: 'count',
+      display_breakdown: 'yes',
+      sort_field: '',
+      sort_reverse: false,
+      label_name: 'Query',
+      value_name: 'Value',
+      spyable     : true,
+      compression : 100,
+      show: {
+        '25': true,
+        '75': true,
+        '95': true,
+        '99': true,
+      }
+    };
+
+    _.defaults($scope.panel, defaults);
+
+    $scope.init = function () {
+      $scope.ready = false;
+      $scope.$on('refresh', function () {
+        $scope.get_data();
+      });
+      $scope.get_data();
+    };
+
+    $scope.set_sort = function(field) {
+      if($scope.panel.sort_field === field && $scope.panel.sort_reverse === false) {
+        $scope.panel.sort_reverse = true;
+      } else if($scope.panel.sort_field === field && $scope.panel.sort_reverse === true) {
+        $scope.panel.sort_field = '';
+        $scope.panel.sort_reverse = false;
+      } else {
+        $scope.panel.sort_field = field;
+        $scope.panel.sort_reverse = false;
+      }
+    };
+
+    $scope.get_data = function () {
+      if(dashboard.indices.length === 0) {
+        return;
+      }
+
+      $scope.panelMeta.loading = true;
+
+      var request,
+        results,
+        boolQuery,
+        queries;
+
+      request = $scope.ejs.Request();
+
+      $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
+      queries = querySrv.getQueryObjs($scope.panel.queries.ids);
+
+      // This could probably be changed to a BoolFilter
+      boolQuery = $scope.ejs.BoolQuery();
+      _.each(queries,function(q) {
+        boolQuery = boolQuery.should(querySrv.toEjsObj(q));
+      });
+
+      var percents = _.keys($scope.panel.show);
+
+      request = request
+        .aggregation(
+          $scope.ejs.FilterAggregation('stats')
+            .filter($scope.ejs.QueryFilter(
+              $scope.ejs.FilteredQuery(
+                boolQuery,
+                filterSrv.getBoolFilter(filterSrv.ids())
+              )
+            ))
+            .aggregation($scope.ejs.PercentilesAggregation('stats')
+              .field($scope.panel.field)
+              .percents(percents)
+              .compression($scope.panel.compression)
+            )
+          ).size(0);
+
+      $.each(queries, function (i, q) {
+        var query = $scope.ejs.BoolQuery();
+        query.should(querySrv.toEjsObj(q));
+        var qname = 'stats_'+i;
+
+        request.aggregation(
+          $scope.ejs.FilterAggregation(qname)
+            .filter($scope.ejs.QueryFilter(
+              $scope.ejs.FilteredQuery(
+                query,
+                filterSrv.getBoolFilter(filterSrv.ids())
+              )
+            ))
+            .aggregation($scope.ejs.PercentilesAggregation(qname)
+              .field($scope.panel.field)
+              .percents(percents)
+              .compression($scope.panel.compression)
+            )
+          );
+      });
+      // Populate the inspector panel
+      $scope.inspector = request.toJSON();
+
+      results = $scope.ejs.doSearch(dashboard.indices, request);
+
+      results.then(function(results) {
+        $scope.panelMeta.loading = false;
+        esVersion.gte('1.3.0').then(function(is) {
+          if (is) {
+            var value = results.aggregations.stats['stats']['values'][$scope.panel.mode+'.0'];
+            var rows = queries.map(function (q, i) {
+              var alias = q.alias || q.query;
+              var obj = _.clone(q);
+              obj.label = alias;
+              obj.Label = alias.toLowerCase(); //sort field
+              obj.value = {};
+              obj.Value = {};
+              var data = results.aggregations['stats_'+i]['stats_'+i]['values'];
+              for ( var keys in data ) {
+                obj.value[parseInt(keys)] = data[keys];
+                obj.Value[parseInt(keys)] = data[keys]; //sort field
+              };
+              return obj;                                           
+            });
+    
+            $scope.data = {
+              value: value,
+              rows: rows
+            };
+    
+            $scope.$emit('render');
+          } else {
+            esVersion.gte('1.1.0').then(function(is) {
+              if (is) {
+                var value = results.aggregations.stats['stats'][$scope.panel.mode+'.0'];
+                var rows = queries.map(function (q, i) {
+                  var alias = q.alias || q.query;
+                  var obj = _.clone(q);
+                  obj.label = alias;
+                  obj.Label = alias.toLowerCase(); //sort field
+                  obj.value = {};
+                  obj.Value = {};
+                  var data = results.aggregations['stats_'+i]['stats_'+i];
+                  for ( var keys in data ) {
+                    obj.value[parseInt(keys)] = data[keys];
+                    obj.Value[parseInt(keys)] = data[keys]; //sort field
+                  };
+                  return obj;                                           
+                });
+        
+                $scope.data = {
+                  value: value,
+                  rows: rows
+                };
+        
+                $scope.$emit('render');
+              }
+            });
+          };
+        });
+
+      });
+    };
+
+    $scope.set_refresh = function (state) {
+      $scope.refresh = state;
+    };
+
+    $scope.close_edit = function() {
+      if($scope.refresh) {
+        $scope.get_data();
+      }
+      $scope.refresh =  false;
+      $scope.$emit('render');
+    };
+
+  });
+
+  module.filter('formatstats', function(){
+    return function (value,format) {
+      switch (format) {
+      case 'money':
+        value = numeral(value).format('$0,0.00');
+        break;
+      case 'bytes':
+        value = numeral(value).format('0.00b');
+        break;
+      case 'float':
+        value = numeral(value).format('0.000');
+        break;
+      default:
+        value = numeral(value).format('0,0');
+      }
+      return value;
+    };
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/editor.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/editor.html b/kibana/src/main/resources/app/panels/query/editor.html
index 021fc58..3100415 100644
--- a/kibana/src/main/resources/app/panels/query/editor.html
+++ b/kibana/src/main/resources/app/panels/query/editor.html
@@ -1 +1,7 @@
-<div><div class="row-fluid"><div class="span12">No options here</div></div></div>
\ No newline at end of file
+<div>
+  <div class="row-fluid">    
+    <div class="span12">
+      No options here
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/editors/topN.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/editors/topN.html b/kibana/src/main/resources/app/panels/query/editors/topN.html
index 57679fc..5fe4566 100644
--- a/kibana/src/main/resources/app/panels/query/editors/topN.html
+++ b/kibana/src/main/resources/app/panels/query/editors/topN.html
@@ -1 +1,12 @@
-<fieldset><label class="small">Field</label><br><input ng-model="dashboard.current.services.query.list[id].field" type="text" bs-typeahead="fields.list" placeholder="Field"><p><label class="small">Count</label><br><input ng-model="dashboard.current.services.query.list[id].size" type="number"></p><p><label class="small">Union</label><br><select class="input-small" ng-model="dashboard.current.services.query.list[id].union"><option ng-repeat="mode in ['none','AND','OR']">{{mode}}</option></select></p></fieldset>
\ No newline at end of file
+  <fieldset>
+    <label class="small">Field</label><br>
+    <input ng-model="dashboard.current.services.query.list[id].field" type="text" bs-typeahead="fields.list" placeholder="Field">
+    <p>
+    <label class="small">Count</label><br>
+    <input ng-model="dashboard.current.services.query.list[id].size" type="number">
+    <p>
+    <label class="small">Union</label><br>
+      <select class="input-small" ng-model="dashboard.current.services.query.list[id].union">
+      <option ng-repeat="mode in ['none','AND','OR']">{{mode}}</option>
+    </select>
+  </fieldset>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/help/lucene.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/help/lucene.html b/kibana/src/main/resources/app/panels/query/help/lucene.html
index c9b49dd..9e860e9 100644
--- a/kibana/src/main/resources/app/panels/query/help/lucene.html
+++ b/kibana/src/main/resources/app/panels/query/help/lucene.html
@@ -1 +1,30 @@
-The lucene query type uses <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax">LUCENE query string syntax</a> to find matching documents or events within Elasticsearch.<h4>Examples</h4><ul class="unstyled" type="disc"><li class="listitem"><p class="simpara"><code class="literal">status</code> field contains <code class="literal">active</code></p><pre class="literallayout">status:active</pre></li><li class="listitem"><p class="simpara"><code class="literal">title</code> field contains <code class="literal">quick</code> or <code class="literal">brown</code></p><pre class="literallayout">title:(quick brown)</pre></li><li class="listitem"><p class="simpara"><code class="literal">author</code> field contains the exact phrase <code class="literal">"john smith"</code></p><pre class="literallayout">author:"John Smith"</pre></li></ul><p>Wildcard searches can be run on individual terms, using <co
 de class="literal">?</code> to replace a single character, and <code class="literal">*</code> to replace zero or more characters:</p><pre class="literallayout">qu?ck bro*</pre><ul class="unstyled" type="disc"><li class="listitem"><p class="simpara">Numbers 1..5</p><pre class="literallayout">count:[1 TO 5]</pre></li><li class="listitem"><p class="simpara">Tags between <code class="literal">alpha</code> and <code class="literal">omega</code>, excluding <code class="literal">alpha</code> and <code class="literal">omega</code>:</p><pre class="literallayout">tag:{alpha TO omega}</pre></li><li class="listitem"><p class="simpara">Numbers from 10 upwards</p><pre class="literallayout">count:[10 TO *]</pre></li></ul>
\ No newline at end of file
+The lucene query type uses <a target="_blank" href='http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax'>LUCENE query string syntax</a> to find matching documents or events within Elasticsearch.
+
+<h4>Examples</h4>
+<ul class="unstyled" type="disc">
+  <li class="listitem"><p class="simpara">
+  <code class="literal">status</code> field contains <code class="literal">active</code>
+  </p><pre class="literallayout">status:active</pre></li>
+  <li class="listitem"><p class="simpara">
+  <code class="literal">title</code> field contains <code class="literal">quick</code> or <code class="literal">brown</code>
+  </p><pre class="literallayout">title:(quick brown)</pre></li>
+  <li class="listitem"><p class="simpara">
+  <code class="literal">author</code> field contains the exact phrase <code class="literal">"john smith"</code>
+  </p><pre class="literallayout">author:"John Smith"</pre></li>
+</ul>
+
+<p>Wildcard searches can be run on individual terms, using <code class="literal">?</code> to replace
+a single character, and <code class="literal">*</code> to replace zero or more characters:</p>
+<pre class="literallayout">qu?ck bro*</pre>
+
+<ul class="unstyled" type="disc">
+  <li class="listitem"><p class="simpara">
+  Numbers 1..5
+  </p><pre class="literallayout">count:[1 TO 5]</pre></li>
+  <li class="listitem"><p class="simpara">
+  Tags between <code class="literal">alpha</code> and <code class="literal">omega</code>, excluding <code class="literal">alpha</code> and <code class="literal">omega</code>:
+  </p><pre class="literallayout">tag:{alpha TO omega}</pre></li>
+  <li class="listitem"><p class="simpara">
+  Numbers from 10 upwards
+  </p><pre class="literallayout">count:[10 TO *]</pre></li>
+</ul>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/help/regex.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/help/regex.html b/kibana/src/main/resources/app/panels/query/help/regex.html
index deff863..8e38ab9 100644
--- a/kibana/src/main/resources/app/panels/query/help/regex.html
+++ b/kibana/src/main/resources/app/panels/query/help/regex.html
@@ -1 +1,10 @@
-The regex query allows you to use regular expressions to match terms in the <i>_all</i> field. A detailed overview of lucene's regex engine is available here: <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#regexp-syntax">Regular expressions in Elasticsearch</a><h5>A note on anchoring</h5>Lucene’s patterns are always anchored. The pattern provided must match the entire string. For string "abcde":<p><code>ab.*</code> will match<br><code>abcd</code> will not match</p>
\ No newline at end of file
+The regex query allows you to use regular expressions to match terms in the <i>_all</i> field.
+
+A detailed overview of lucene's regex engine is available here: <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#regexp-syntax">Regular expressions in Elasticsearch</a>
+
+<h5>A note on anchoring</h5>
+Lucene’s patterns are always anchored. The pattern provided must match the entire string. For string "abcde":
+<p>
+<code>ab.*</code> will match<br>
+<code>abcd</code> will not match</br>
+

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/help/topN.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/help/topN.html b/kibana/src/main/resources/app/panels/query/help/topN.html
index c8580b6..9fc7c3a 100644
--- a/kibana/src/main/resources/app/panels/query/help/topN.html
+++ b/kibana/src/main/resources/app/panels/query/help/topN.html
@@ -1 +1,14 @@
-The topN query uses an <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html">Elasticsearch terms facet</a> to find the most common terms in a field and build queries from the result. The topN query uses <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax">LUCENE query string syntax</a><h4>Parameters</h4><ul><li><strong>Field</strong> / The field to facet on. Fields with a large number of unique terms will <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html#_memory_considerations_2">use more memory</a> to calculate.</li><li><strong>Count</strong> / How many queries to generate. The resulting queries will use brightness variations on the original query's color for their own.</li><li><strong>Union</strong> / The relation the generated queries hav
 e to the original. For example, if your field was set to 'extension', your original query was "user:B.Awesome" and your union was AND. Kibana might generate the following example query: <code>extension:"html" AND (user:B.Awesome)</code></li></ul>
\ No newline at end of file
+The topN query uses an <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html">Elasticsearch terms facet</a> to find the most common terms in a field and build queries from the result. The topN query uses <a target="_blank" href='http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax'>LUCENE query string syntax</a>
+
+<h4>Parameters</h4>
+<ul>
+  <li>
+    <strong>Field</strong> / The field to facet on. Fields with a large number of unique terms will <a target="_blank" href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html#_memory_considerations_2">use more memory</a> to calculate.
+  </li>
+  <li>
+    <strong>Count</strong> / How many queries to generate. The resulting queries will use brightness variations on the original query's color for their own.
+  </li>
+  <li>
+    <strong>Union</strong> / The relation the generated queries have to the original. For example, if your field was set to 'extension', your original query was "user:B.Awesome" and your union was AND. Kibana might generate the following example query: <code>extension:"html" AND (user:B.Awesome)</code>
+  </li>
+</ul>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/helpModal.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/helpModal.html b/kibana/src/main/resources/app/panels/query/helpModal.html
index f21e1af..3cbbf8c 100644
--- a/kibana/src/main/resources/app/panels/query/helpModal.html
+++ b/kibana/src/main/resources/app/panels/query/helpModal.html
@@ -1 +1,12 @@
-<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h3>About the {{help.type}} query</h3></div><div class="modal-body"><div ng-include="queryHelpPath(help.type)"></div></div><div class="modal-footer"><button type="button" class="btn btn-danger" ng-click="dismiss()">Close</button></div>
\ No newline at end of file
+<div class="modal-header">
+  <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+  <h3>About the {{help.type}} query</h3>
+</div>
+<div class="modal-body">
+
+  <div ng-include="queryHelpPath(help.type)"></div>
+
+</div>
+<div class="modal-footer">
+  <button type="button" class="btn btn-danger" ng-click="dismiss()">Close</button>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/meta.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/meta.html b/kibana/src/main/resources/app/panels/query/meta.html
index 0cf0281..3adf2d1 100644
--- a/kibana/src/main/resources/app/panels/query/meta.html
+++ b/kibana/src/main/resources/app/panels/query/meta.html
@@ -1,3 +1,34 @@
-<div class="panel-query-meta row-fluid" style="width:260px"><style>.panel-query-meta fieldset label {
+<div class="panel-query-meta row-fluid" style="width:260px">
+
+  <style>
+    .panel-query-meta fieldset label {
       margin-top: 3px;
-    }</style><fieldset><select class="input-small" ng-model="dashboard.current.services.query.list[id].type" ng-change="typeChange(dashboard.current.services.query.list[id])"><option ng-repeat="type in queryTypes">{{type}}</option></select>&nbsp<a href="" class="small" ng-click="queryHelp(dashboard.current.services.query.list[id].type)">About the {{dashboard.current.services.query.list[id].type}} query</a><hr class="small"><label class="small">Legend value</label><input type="text" ng-model="dashboard.current.services.query.list[id].alias" placeholder="Alias..."></fieldset><div ng-include="" src="queryConfig(dashboard.current.services.query.list[id].type)"></div><hr class="small"><div><i ng-repeat="color in querySrv.colors" class="pointer" ng-class="{'icon-circle-blank':dashboard.current.services.query.list[id].color == color,'icon-circle':dashboard.current.services.query.list[id].color != color}" ng-style="{color:color}" ng-click="dashboard.current.services.query.list[id].color = c
 olor;render();"></i></div><div class="pull-right"><a class="btn btn-mini" ng-click="dashboard.current.services.query.list[id].enable=false;dashboard.refresh();dismiss();" class="pointer">Deactivate</a> <a class="btn btn-mini" ng-class="{active:dashboard.current.services.query.list[id].pin}" ng-click="toggle_pin(id);dismiss();" class="pointer">Pin <i class="icon-pushpin"></i></a><input class="btn btn-mini" ng-click="dashboard.refresh();dismiss();" type="submit" value="Close"></div></div>
\ No newline at end of file
+    }
+  </style>
+
+  <fieldset>
+    <select class="input-small" ng-model="dashboard.current.services.query.list[id].type" ng-change="typeChange(dashboard.current.services.query.list[id])">
+      <option ng-repeat="type in queryTypes">{{type}}</option>
+    </select> &nbsp<a href="" class="small" ng-click="queryHelp(dashboard.current.services.query.list[id].type)"> About the {{dashboard.current.services.query.list[id].type}} query</a>
+
+    <hr class="small">
+
+    <label class="small">Legend value</label>
+    <input type="text" ng-model="dashboard.current.services.query.list[id].alias" placeholder="Alias...">
+  </fieldset>
+
+  <div ng-include src="queryConfig(dashboard.current.services.query.list[id].type)"></div>
+
+
+  <hr class="small">
+  <div>
+    <i ng-repeat="color in querySrv.colors" class="pointer" ng-class="{'icon-circle-blank':dashboard.current.services.query.list[id].color == color,'icon-circle':dashboard.current.services.query.list[id].color != color}" ng-style="{color:color}" ng-click="dashboard.current.services.query.list[id].color = color;render();"> </i>
+  </div>
+
+
+  <div class="pull-right">
+    <a class="btn btn-mini" ng-click="dashboard.current.services.query.list[id].enable=false;dashboard.refresh();dismiss();" class="pointer">Deactivate</a>
+    <a class="btn btn-mini" ng-class="{active:dashboard.current.services.query.list[id].pin}" ng-click="toggle_pin(id);dismiss();" class="pointer">Pin <i class="icon-pushpin"></i></a>
+    <input class="btn btn-mini" ng-click="dashboard.refresh();dismiss();" type="submit"/ value="Close">
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/module.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/module.html b/kibana/src/main/resources/app/panels/query/module.html
index d6b0098..4aefcdf 100644
--- a/kibana/src/main/resources/app/panels/query/module.html
+++ b/kibana/src/main/resources/app/panels/query/module.html
@@ -1 +1,56 @@
-<div ng-controller="query" ng-init="init()" class="query-panel"><div ng-repeat="id in (unPinnedQueries = (dashboard.current.services.query.ids|pinnedQuery:false))" ng-class="{'short-query': unPinnedQueries.length>1}"><form class="form-search" style="position:relative;margin:5px 0" ng-submit="refresh()"><span class="begin-query"><i class="pointer" ng-class="queryIcon(dashboard.current.services.query.list[id].type)" ng-show="dashboard.current.services.query.list[id].enable" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft" ng-style="{color: dashboard.current.services.query.list[id].color}"></i> <i class="pointer icon-circle-blank" ng-click="dashboard.current.services.query.list[id].enable=true;dashboard.refresh();" ng-hide="dashboard.current.services.query.list[id].enable" bs-tooltip="'Activate query'" ng-style="{color: dashboard.current.services.query.list[id].color}"></i> <i class="icon-remove-sign pointer remove-query" ng-show="dashboard.current.
 services.query.ids.length > 1" ng-click="querySrv.remove(id);refresh()"></i></span> <span><input class="search-query panel-query" ng-disabled="!dashboard.current.services.query.list[id].enable" ng-class="{ 'input-block-level': unPinnedQueries.length==1, 'last-query': $last, 'has-remove': dashboard.current.services.query.ids.length > 1 }" bs-typeahead="panel.history" data-min-length="0" data-items="100" type="text" ng-model="dashboard.current.services.query.list[id].query"></span> <span class="end-query"><i class="icon-search pointer" ng-click="refresh()" ng-show="$last"></i> <i class="icon-plus pointer" ng-click="querySrv.set({})" ng-show="$last"></i></span></form></div><div style="display:inline-block" ng-repeat="id in dashboard.current.services.query.ids|pinnedQuery:true"><span class="pointer badge pins" ng-show="$first" ng-click="panel.pinned = !panel.pinned">Pinned <i ng-class="{'icon-caret-right':panel.pinned,'icon-caret-left':!panel.pinned}"></i></span> <span ng-show="panel.pi
 nned" class="badge pinned"><i class="icon-circle pointer" ng-show="dashboard.current.services.query.list[id].enable" ng-style="{color: dashboard.current.services.query.list[id].color}" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft"></i> <i class="pointer icon-circle-blank" bs-tooltip="'Activate query'" ng-click="dashboard.current.services.query.list[id].enable=true;dashboard.refresh();" ng-hide="dashboard.current.services.query.list[id].enable" ng-style="{color: dashboard.current.services.query.list[id].color}"></i> <span bs-tooltip="dashboard.current.services.query.list[id].query | limitTo:45">{{dashboard.current.services.query.list[id].alias || dashboard.current.services.query.list[id].query}}</span></span></div><span style="display:inline-block" ng-show="unPinnedQueries.length == 0"><i class="icon-search pointer" ng-click="refresh()"></i> <i class="icon-plus pointer" ng-click="querySrv.set({})"></i></span></div>
\ No newline at end of file
+<div ng-controller='query' ng-init="init()" class="query-panel">
+  <div ng-repeat="id in (unPinnedQueries = (dashboard.current.services.query.ids|pinnedQuery:false))" ng-class="{'short-query': unPinnedQueries.length>1}">
+    <form class="form-search" style="position:relative;margin:5px 0;" ng-submit="refresh()">
+      <span class="begin-query">
+        <i class="pointer" ng-class="queryIcon(dashboard.current.services.query.list[id].type)" ng-show="dashboard.current.services.query.list[id].enable" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft" ng-style="{color: dashboard.current.services.query.list[id].color}"></i>
+        <i class="pointer icon-circle-blank" ng-click="dashboard.current.services.query.list[id].enable=true;dashboard.refresh();" ng-hide="dashboard.current.services.query.list[id].enable" bs-tooltip="'Activate query'" ng-style="{color: dashboard.current.services.query.list[id].color}"></i>
+        <i class="icon-remove-sign pointer remove-query" ng-show="dashboard.current.services.query.ids.length > 1" ng-click="querySrv.remove(id);refresh()"></i>
+      </span>
+      <span>
+        <input class="search-query panel-query" ng-disabled="!dashboard.current.services.query.list[id].enable" ng-class="{ 'input-block-level': unPinnedQueries.length==1, 'last-query': $last, 'has-remove': dashboard.current.services.query.ids.length > 1 }" bs-typeahead="panel.history" data-min-length=0 data-items=100 type="text" ng-model="dashboard.current.services.query.list[id].query" />
+      </span>
+      <span class="end-query">
+        <i class="icon-search pointer" ng-click="refresh()" ng-show="$last"></i>
+        <i class="icon-plus pointer" ng-click="querySrv.set({})" ng-show="$last"></i>
+      </span>
+    </form>
+  </div>
+  <div style="display:inline-block" ng-repeat="id in dashboard.current.services.query.ids|pinnedQuery:true">
+    <span class="pointer badge pins" ng-show="$first" ng-click="panel.pinned = !panel.pinned">Pinned <i ng-class="{'icon-caret-right':panel.pinned,'icon-caret-left':!panel.pinned}"></i></span>
+    <span ng-show="panel.pinned" class="badge pinned">
+      <i class="icon-circle pointer" ng-show="dashboard.current.services.query.list[id].enable" ng-style="{color: dashboard.current.services.query.list[id].color}" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft"></i>
+      <i class="pointer icon-circle-blank" bs-tooltip="'Activate query'" ng-click="dashboard.current.services.query.list[id].enable=true;dashboard.refresh();" ng-hide="dashboard.current.services.query.list[id].enable" ng-style="{color: dashboard.current.services.query.list[id].color}"></i>
+      <span bs-tooltip="dashboard.current.services.query.list[id].query | limitTo:45"> {{dashboard.current.services.query.list[id].alias || dashboard.current.services.query.list[id].query}}</span>
+    </span>
+  </div>
+  <span style="display:inline-block" ng-show="unPinnedQueries.length == 0">
+    <i class="icon-search pointer" ng-click="refresh()"></i>
+    <i class="icon-plus pointer" ng-click="querySrv.set({})"></i>
+  </span>
+  <div>
+    <a class="link small" ng-click="panel.generate=!panel.generate">
+      Query Generator: <i ng-show="!panel.generate" class="icon-caret-right"></i><i ng-show="panel.generate" class="icon-caret-down"></i>
+    </a>
+  <div>
+  <div ng-show="panel.generate">
+    <div id="listContainer" ng-show="add_cond" ng-repeat="value in panel.values">
+      <div>
+        <select class="input-small" ng-model="value.sem" ng-options="y for y in fields.list" ng-change="selected_sem()">
+          <option>--</option>
+        </select>
+        <select class="input-small" ng-model="value.select_comp" ng-options="z for z in value.comp_list">
+          <option>--</option>
+        </select>
+        <input class="search-query panel-query input-medium myinput" ng-model="value.input">
+        <i class="icon-remove-sign pointer ng-scope" ng-click="panel.values = _.without(panel.values, value)"></i>
+      </div>
+    </div>
+    <span ng-show="true">
+      <i class="icon-search pointer" ng-click="showMuSelectValues()"></i>
+      <i class="icon-plus pointer" ng-click="addCond(panel)"></i>
+    </span>
+    <select id ="sela" multiple="multiple" size="1" ng-model="typesSel" ng-options="x for x in fields.types">
+      <option>--</option>
+    </select>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/module.js
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/module.js b/kibana/src/main/resources/app/panels/query/module.js
index 901702c..8fdbeeb 100644
--- a/kibana/src/main/resources/app/panels/query/module.js
+++ b/kibana/src/main/resources/app/panels/query/module.js
@@ -1,4 +1,178 @@
-/*! kibana - v3.1.2 - 2014-11-07
- * Copyright (c) 2014 Rashid Khan; Licensed Apache License */
+/*
 
-define("css-embed",function(){function a(a){var b=document.getElementsByTagName("head")[0],c=document.createElement("style"),d=document.createTextNode(a);c.type="text/css",c.styleSheet?c.styleSheet.cssText=d.nodeValue:c.appendChild(d),b.appendChild(c)}return a}),define("css!panels/query/query.css",["css-embed"],function(a){return a(".short-query{display:inline-block;margin-right:10px}.short-query input.search-query{width:280px}.begin-query{position:absolute;left:10px;top:5px}.end-query{position:absolute;right:10px;top:5px}.end-query i,.begin-query i{margin:0}.panel-query{padding-left:25px!important;height:31px!important;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.query-disabled{opacity:.3}.form-search:hover .has-remove{padding-left:40px!important}.remove-query{opacity:0}.last-query{padding-right:45px!important}.form-search:hover .remove-query{opacity:1}.query-panel .pinned{margin-right:5px}"),!0}),define("panels/query/module",["angular","app","lod
 ash","css!./query.css"],function(a,b,c){var d=a.module("kibana.panels.query",[]);b.useModule(d),d.controller("query",["$scope","querySrv","$rootScope","dashboard","$q","$modal",function(a,b,d,e,f,g){a.panelMeta={status:"Stable",description:"Manage all of the queries on the dashboard. You almost certainly need one of these somewhere. This panel allows you to add, remove, label, pin and color queries"};var h={query:"*",pinned:!0,history:[],remember:10};c.defaults(a.panel,h),a.querySrv=b,a.dashboard=e,a.queryTypes=b.types;var i=g({template:"./app/panels/query/helpModal.html",persist:!0,show:!1,scope:a});a.init=function(){},a.refresh=function(){j(c.pluck(a.dashboard.current.services.query.list,"query")),e.refresh()},a.render=function(){d.$broadcast("render")},a.toggle_pin=function(a){e.current.services.query.list[a].pin=e.current.services.query.list[a].pin?!1:!0},a.queryIcon=function(a){return b.queryTypes[a].icon},a.queryConfig=function(a){return"./app/panels/query/editors/"+(a||"lucen
 e")+".html"},a.queryHelpPath=function(a){return"./app/panels/query/help/"+(a||"lucene")+".html"},a.queryHelp=function(b){a.help={type:b},f.when(i).then(function(a){a.modal("show")})},a.typeChange=function(a){var c={id:a.id,type:a.type,query:a.query,alias:a.alias,color:a.color};e.current.services.query.list[c.id]=b.defaults(c)};var j=function(b){if(a.panel.remember>0){a.panel.history=c.union(b.reverse(),a.panel.history);var d=a.panel.history.length;d>a.panel.remember&&(a.panel.history=a.panel.history.slice(0,a.panel.remember))}};a.init()}])});
\ No newline at end of file
+  ## query
+
+  ### Parameters
+  * query ::  A string or an array of querys. String if multi is off, array if it is on
+              This should be fixed, it should always be an array even if its only
+              one element
+*/
+define([
+  'angular',
+  'app',
+  'lodash',
+  'multiselect',
+
+  'css!./query.css'
+], function (angular, app, _) {
+  'use strict';
+
+  var module = angular.module('kibana.panels.query', []);
+  app.useModule(module);
+
+  module.controller('query', function($scope, querySrv, $rootScope, dashboard, $q, $modal, fields) {
+    $scope.panelMeta = {
+      status  : "Stable",
+      description : "Manage all of the queries on the dashboard. You almost certainly need one of "+
+        "these somewhere. This panel allows you to add, remove, label, pin and color queries"
+    };
+
+    $scope.typesSel = [];
+    $scope.add_cond = false;
+    $scope.defaultValue = {
+      sem        : fields.list[0],
+      comp_list  : ['ne', 'eq'],
+      select_comp: 'eq',
+      input      : ''
+    };
+
+    // Set and populate defaults
+    var _d = {
+      values  : [angular.copy($scope.defaultValue)],
+      generate: false,
+      query   : "*",
+      pinned  : true,
+      history : [],
+      remember: 10 // max: 100, angular strap can't take a variable for items param
+    };
+    _.defaults($scope.panel,_d);
+
+    $scope.querySrv = querySrv;
+    $scope.dashboard = dashboard;
+
+    // A list of query types for the query config popover
+    $scope.queryTypes = querySrv.types;
+
+    var queryHelpModal = $modal({
+      template: './app/panels/query/helpModal.html',
+      persist: true,
+      show: false,
+      scope: $scope,
+    });
+
+    $scope.showMuSelectValues = function() {
+      var queryString = createQuery();
+      var newQueryObj = _.clone($scope.dashboard.current.services.query.list[0]); 
+      var newId = _.max($scope.dashboard.current.services.query.ids) + 1;
+      newQueryObj.color = '#'+('00000'+(Math.random()*0x1000000<<0).toString(16)).slice(-6);
+      newQueryObj.query = queryString;
+      newQueryObj.id = newId;
+      $scope.dashboard.current.services.query.list[newId] = newQueryObj;
+      $scope.dashboard.current.services.query.ids.push(newId);
+      $scope.refresh();
+    };
+ 
+    var createQuery = function() {
+      var queryString = "_type:" + $scope.typesSel.join(',');
+      _.each($scope.panel.values, function(value) {
+        if( value.select_comp == 'eq' ) {
+          queryString += ' AND '+value.sem+':"'+value.input+'" ';
+        } else if( value.select_comp == 'ne' ) {
+          queryString += ' AND NOT '+value.sem+':"'+value.input+'" ';
+        } else {
+          queryString += ' AND '+value.sem+':'+value.select_comp+value.input;
+        }
+      });
+      return queryString;
+    }
+
+    $scope.selected_sem = function() {
+      var item = _.last($scope.panel.values);
+      var nodeInfo = $scope.ejs.getFieldMapping(dashboard.indices, item.sem);
+      return nodeInfo.then(function(p) {
+        var types = _.uniq(jsonPath(p, '*.*.*.*.mapping.*.type'));
+        if(_.intersection(types, ['long','float','integer','double']).length > 0) {
+          item.comp_list =  ['<', '>', '='];
+        } else {
+          item.comp_list =  ['eq', 'ne'];
+        }
+      });
+    };
+ 
+    $scope.addCond = function(){
+      if ( $scope.add_cond == false ) {
+        $scope.add_cond = true;
+        return;
+      };
+      $scope.panel.values.push(angular.copy($scope.defaultValue));
+    };
+
+    $scope.init = function() {
+      setTimeout(function(){
+        $("#sela").multiselect({
+            selectedList:50,
+            maxHeight:300
+        });
+      },50);
+    };
+
+    $scope.refresh = function() {
+      update_history(_.pluck($scope.dashboard.current.services.query.list,'query'));
+      dashboard.refresh();
+    };
+
+    $scope.render = function() {
+      $rootScope.$broadcast('render');
+    };
+
+    $scope.toggle_pin = function(id) {
+      dashboard.current.services.query.list[id].pin = dashboard.current.services.query.list[id].pin ? false : true;
+    };
+
+    $scope.queryIcon = function(type) {
+      return querySrv.queryTypes[type].icon;
+    };
+
+    $scope.queryConfig = function(type) {
+      return "./app/panels/query/editors/"+(type||'lucene')+".html";
+    };
+
+    $scope.queryHelpPath = function(type) {
+      return "./app/panels/query/help/"+(type||'lucene')+".html";
+    };
+
+    $scope.queryHelp = function(type) {
+      $scope.help = {
+        type: type
+      };
+      $q.when(queryHelpModal).then(function(modalEl) {
+        modalEl.modal('show');
+      });
+    };
+
+    $scope.typeChange = function(q) {
+      var _nq = {
+        id   : q.id,
+        type : q.type,
+        query: q.query,
+        alias: q.alias,
+        color: q.color
+      };
+      dashboard.current.services.query.list[_nq.id] = querySrv.defaults(_nq);
+    };
+
+    var update_history = function(query) {
+      if($scope.panel.remember > 0) {
+        $scope.panel.history = _.union(query.reverse(),$scope.panel.history);
+        var _length = $scope.panel.history.length;
+        if(_length > $scope.panel.remember) {
+          $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember);
+        }
+      }
+    };
+
+    $scope.init();
+
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/query/query.css
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/query/query.css b/kibana/src/main/resources/app/panels/query/query.css
index 2859eec..da6b8cc 100644
--- a/kibana/src/main/resources/app/panels/query/query.css
+++ b/kibana/src/main/resources/app/panels/query/query.css
@@ -1 +1,59 @@
-.short-query{display:inline-block;margin-right:10px}.short-query input.search-query{width:280px}.begin-query{position:absolute;left:10px;top:5px}.end-query{position:absolute;right:10px;top:5px}.end-query i,.begin-query i{margin:0}.panel-query{padding-left:25px!important;height:31px!important;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.query-disabled{opacity:.3}.form-search:hover .has-remove{padding-left:40px!important}.remove-query{opacity:0}.last-query{padding-right:45px!important}.form-search:hover .remove-query{opacity:1}.query-panel .pinned{margin-right:5px}
\ No newline at end of file
+.short-query {
+  display:inline-block;
+  margin-right: 10px;
+}
+.short-query input.search-query {
+    width: 280px;
+}
+.begin-query {
+  position:absolute;
+  left:10px;
+  top:5px;
+}
+.end-query {
+  position:absolute;
+  right:10px;
+  top:5px;
+}
+
+.end-query i, .begin-query i {
+  margin: 0px;
+}
+
+.panel-query {
+  padding-left: 25px !important;
+  height: 31px !important;
+  -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
+  -moz-box-sizing: border-box;    /* Firefox, other Gecko */
+  box-sizing: border-box;         /* Opera/IE 8+ */
+}
+
+.query-disabled {
+  opacity: 0.3;
+}
+
+.form-search:hover .has-remove {
+  padding-left: 40px !important;
+}
+.remove-query {
+  opacity: 0;
+}
+.last-query {
+  padding-right: 45px !important;
+}
+.form-search:hover .remove-query {
+  opacity: 1;
+}
+.query-panel .pinned {
+  margin-right: 5px;
+}
+
+.myinput {
+  height: 24px;
+  background-color: #4D4D4D;
+  border: 1px solid #666666;
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
+  transition: border 0.2s linear 0s, box-shadow 0.2s linear 0s;
+  color: #ADAFAE;
+  position:relative;top:-4px;
+}

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/ranges/editor.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/ranges/editor.html b/kibana/src/main/resources/app/panels/ranges/editor.html
new file mode 100644
index 0000000..2d36be7
--- /dev/null
+++ b/kibana/src/main/resources/app/panels/ranges/editor.html
@@ -0,0 +1,78 @@
+  <div class="editor-row">
+    <div class="section">
+      <h5>Parameters</h5>
+      <div class="editor-option">
+        <label class="small">Ranges mode</label>
+        <select class="input-medium" ng-model="panel.tmode" ng-options="f for f in ['ranges']" ng-change="set_refresh(true)"></select>
+      </div>
+      <div class="editor-option">
+        <label class="small">Field</label>
+        <input type="text" class="input-small" bs-typeahead="fields.list" ng-model="panel.field" ng-change="set_refresh(true)">
+      </div>
+      <div class="editor-row">
+        <table class="table table-condensed table-striped">
+          <thead>
+            <tr>
+              <th>From</th>
+              <th>To</th>
+              <th ng-show="panel.values.length > 1">Delete</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr ng-repeat="value in panel.values">
+              <td>
+                <div class="editor-option">
+                  <input class="input-small" type="number" ng-model="value.from" ng-change="set_refresh(true)">
+                </div>
+              </td>
+              <td>
+                <div class="editor-option">
+                  <input class="input-small" type="number" ng-model="value.to" ng-change="set_refresh(true)">
+                </div>
+              </td>
+              <td ng-show="panel.values.length > 1">
+                <i ng-click="panel.values = _.without(panel.values, value);set_refresh(true)" class="pointer icon-remove"></i>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+        <button type="button" class="btn btn-success" ng-click="add_new_value(panel);set_refresh(true)"><i class="icon-plus-sign"></i> Add value</button>
+      </div>
+    </div>
+  </div>
+  <div class="editor-row">
+    <div class="section">
+      <h5>View Options</h5>
+      <div class="editor-option">
+        <label class="small">Style</label>
+        <select class="input-small" ng-model="panel.chart" ng-options="f for f in ['bar','pie','table']"></select></span>
+      </div>
+      <div class="editor-option" ng-show="panel.chart == 'table'">
+        <label class="small">Font Size</label>
+        <select class="input-mini" ng-model="panel.style['font-size']" ng-options="f for f in ['7pt','8pt','9pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select></span>
+      </div>
+      <div class="editor-option" ng-show="panel.chart == 'bar' || panel.chart == 'pie'">
+        <label class="small">Legend</label>
+        <select class="input-small" ng-model="panel.counter_pos" ng-options="f for f in ['above','below','none']"></select></span>
+      </div>
+      <div class="editor-option" ng-show="panel.chart != 'table' && panel.counter_pos != 'none'">
+        <label class="small" >Legend Format</label>
+        <select class="input-small" ng-model="panel.arrangement" ng-options="f for f in ['horizontal','vertical']"></select></span>
+      </div>
+      <div class="editor-option">
+        <label class="small">Missing</label><input type="checkbox" ng-model="panel.missing" ng-checked="panel.missing">
+      </div>
+      <div class="editor-option">
+        <label class="small">Other</label><input type="checkbox" ng-model="panel.other" ng-checked="panel.other">
+      </div>
+      <div class="editor-option" ng-show="panel.chart == 'pie'">
+        <label class="small">Donut</label><input type="checkbox" ng-model="panel.donut" ng-checked="panel.donut">
+      </div>
+      <div class="editor-option" ng-show="panel.chart == 'pie'">
+        <label class="small">Tilt</label><input type="checkbox" ng-model="panel.tilt" ng-checked="panel.tilt">
+      </div>
+      <div class="editor-option" ng-show="panel.chart == 'pie'">
+        <label class="small">Labels</label><input type="checkbox" ng-model="panel.labels" ng-checked="panel.labels">
+      </div>
+    </div>
+  </div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/ranges/module.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/ranges/module.html b/kibana/src/main/resources/app/panels/ranges/module.html
new file mode 100644
index 0000000..b4d1a94
--- /dev/null
+++ b/kibana/src/main/resources/app/panels/ranges/module.html
@@ -0,0 +1,108 @@
+<div ng-controller='ranges' ng-init="init()">
+  <style>
+    .pieLabel { pointer-events: none }
+    .ranges-legend-range {
+      word-break: break-all;
+    }
+
+    .ranges-remaining {
+      bottom:0;
+      top:0;
+      background-color: #f00;
+    }
+
+    .ranges-wrapper {
+      display: table;
+      width: 100%;
+    }
+
+    .ranges-legend {
+      display: table-row;
+      height: 0;
+    }
+
+    .ranges-legend {
+      display: table-row;
+    }
+  </style>
+
+
+  <div class="ranges-wrapper">
+    <!-- LEGEND -->
+    <div class="ranges-legend" ng-show="panel.counter_pos == 'above' && (panel.chart == 'bar' || panel.chart == 'pie')" id='{{$id}}-legend'>
+      <!-- vertical legend above -->
+      <table class="small" ng-show="panel.arrangement == 'vertical'">
+        <tr ng-repeat="range in legend">
+          <td><i class="icon-circle" ng-style="{color:range.color}"></i></td>
+          <td class="ranges-legend-range" style="padding-right:10px;padding-left:10px;">{{range.label}}</td>
+          <td>{{range.data[0][1]}}</td>
+        </tr>
+      </table>
+
+      <!-- horizontal legend above -->
+      <span class="small" ng-show="panel.arrangement == 'horizontal'" ng-repeat="range in legend" style="float:left;padding-left: 10px;">
+        <span>
+          <i class="icon-circle" ng-style="{color:range.color}"></i>
+          <span class="ranges-legend-range">{{range.label}}</span> ({{range.data[0][1]}})
+        </span>
+      </span>
+
+      <span class="small pull-left" ng-show="panel.tmode == 'ranges_stats'">
+        &nbsp | {{ panel.tstat }} of <strong>{{ panel.valuefield }}</strong>
+      </span>
+
+    </div>
+    <!-- keep legend from over lapping -->
+    <div style="clear:both"></div>
+
+
+    <!-- CHART -->
+    <div ng-show="panel.chart == 'pie' || panel.chart == 'bar'" ranges-chart params="{{panel}}" style="position:relative" class="pointer ranges-chart">
+    </div>
+
+    <!-- LEGEND -->
+    <div class="ranges-legend" ng-show="panel.counter_pos == 'below' && (panel.chart == 'bar' || panel.chart == 'pie')" id='{{$id}}-legend'>
+      <!-- vertical legend below -->
+      <table class="small" ng-show="panel.arrangement == 'vertical'">
+        <tr ng-repeat="range in legend">
+          <td><i class="icon-circle" ng-style="{color:range.color}"></i></i></td>
+          <td class="ranges-legend-range" style="padding-right:10px;padding-left:10px;">{{range.label}}</td>
+          <td>{{range.data[0][1]}}</td>
+        </tr>
+      </table>
+
+      <!-- horizontal legend below -->
+      <span class="small" ng-show="panel.arrangement == 'horizontal'" ng-repeat="range in legend" style="float:left;padding-left: 10px;">
+        <span>
+          <i class="icon-circle" ng-style="{color:range.color}"></i>
+          <span class="ranges-legend-range">{{range.label}}</span> ({{range.data[0][1]}})
+        </span>
+      </span>
+
+      <span class="small pull-left" ng-show="panel.tmode == 'ranges_stats'">
+        &nbsp | {{ panel.tstat }} of <strong>{{ panel.valuefield }}</strong>
+      </span>
+
+      <div style="clear:both"></div>
+    </div>
+    <!-- END Pie or Bar chart -->
+
+
+  <!-- TABLE -->
+  <table ng-style="panel.style" class="table table-striped table-condensed" ng-show="panel.chart == 'table'">
+    <thead>
+      <th>Ranges</th> <th>Count</th> <th>Action</th>
+    </thead>
+    <tr ng-repeat="range in data" ng-show="showMeta(range)">
+      <td class="ranges-legend-range">{{range.label}}</td>
+      <td>{{range.data[0][1]}}</td>
+      <td>
+        <span ng-hide="range.meta == 'other'">
+          <i class='icon-search pointer' ng-click="build_search(range)"></i>
+          <i class='icon-ban-circle pointer' ng-click="build_search(range,true)"></i>
+        </span>
+      </td>
+    </tr>
+  </table>
+
+</div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/ranges/module.js
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/ranges/module.js b/kibana/src/main/resources/app/panels/ranges/module.js
new file mode 100644
index 0000000..48adde9
--- /dev/null
+++ b/kibana/src/main/resources/app/panels/ranges/module.js
@@ -0,0 +1,390 @@
+/** @scratch /panels/5
+ *
+ * include::panels/ranges.asciidoc[]
+ */
+
+/** @scratch /panels/ranges/0
+ *
+ * == ranges
+ * Status: *Experimental*
+ *
+ * A table, bar chart or pie chart based on the results of an Elasticsearch ranges facet.
+ *
+ */
+define([
+  'angular',
+  'app',
+  'lodash',
+  'jquery',
+  'kbn'
+],
+function (angular, app, _, $, kbn) {
+  'use strict';
+
+  var module = angular.module('kibana.panels.ranges', []);
+  app.useModule(module);
+
+  module.controller('ranges', function($scope, querySrv, dashboard, filterSrv, fields) {
+    $scope.panelMeta = {
+      modals : [
+        {
+          description: "Inspect",
+          icon: "icon-info-sign",
+          partial: "app/partials/inspector.html",
+          show: $scope.panel.spyable
+        }
+      ],
+      editorTabs : [
+        {title:'Queries', src:'app/partials/querySelect.html'}
+      ],
+      status  : "Stable",
+      description : "Displays the results of an elasticsearch facet as a pie chart, bar chart, or a "+
+        "table"
+    };
+
+    // Set and populate defaults
+    $scope.defaultValue = {
+      'from': 0,
+      'to'  : 100
+    };
+
+    // Set and populate defaults
+    var _d = {
+      /** @scratch /panels/ranges/5
+       * === Parameters
+       *
+       * values:: The range values add to the facet
+       */
+      values  : [angular.copy($scope.defaultValue)],
+      /** @scratch /panels/ranges/5
+       * === Parameters
+       *
+       * field:: The field on which to computer the facet
+       */
+      field   : '_type',
+      /** @scratch /panels/ranges/5
+       * missing:: Set to false to disable the display of a counter showing how much results are
+       * missing the field
+       */
+      missing : true,
+      /** @scratch /panels/ranges/5
+       * other:: Set to false to disable the display of a counter representing the aggregate of all
+       * values outside of the scope of your +size+ property
+       */
+      other   : true,
+      style   : { "font-size": '10pt'},
+      /** @scratch /panels/ranges/5
+       * donut:: In pie chart mode, draw a hole in the middle of the pie to make a tasty donut.
+       */
+      donut   : false,
+      /** @scratch /panels/ranges/5
+       * tilt:: In pie chart mode, tilt the chart back to appear as more of an oval shape
+       */
+      tilt    : false,
+      /** @scratch /panels/ranges/5
+       * lables:: In pie chart mode, draw labels in the pie slices
+       */
+      labels  : true,
+      /** @scratch /panels/ranges/5
+       * arrangement:: In bar or pie mode, arrangement of the legend. horizontal or vertical
+       */
+      arrangement : 'horizontal',
+      /** @scratch /panels/ranges/5
+       * chart:: table, bar or pie
+       */
+      chart       : 'bar',
+      /** @scratch /panels/ranges/5
+       * counter_pos:: The location of the legend in respect to the chart, above, below, or none.
+       */
+      counter_pos : 'above',
+      /** @scratch /panels/ranges/5
+       * spyable:: Set spyable to false to disable the inspect button
+       */
+      spyable     : true,
+      /** @scratch /panels/ranges/5
+       *
+       * ==== Queries
+       * queries object:: This object describes the queries to use on this panel.
+       * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+
+       * queries.ids::: In +selected+ mode, which query ids are selected.
+       */
+      queries     : {
+        mode        : 'all',
+        ids         : []
+      },
+      /** @scratch /panels/ranges/5
+       * tmode:: Facet mode: ranges
+       */
+      tmode       : 'ranges'
+    };
+
+    _.defaults($scope.panel,_d);
+
+    $scope.init = function () {
+      $scope.hits = 0;
+
+      $scope.$on('refresh',function(){
+        $scope.get_data();
+      });
+      $scope.get_data();
+
+    };
+
+    $scope.get_data = function() {
+      // Make sure we have everything for the request to complete
+      if(dashboard.indices.length === 0) {
+        return;
+      }
+
+      $scope.panelMeta.loading = true;
+      var request,
+        rangefacet,
+        results,
+        boolQuery,
+        queries;
+
+      $scope.field = _.contains(fields.list,$scope.panel.field+'.raw') ?
+        $scope.panel.field+'.raw' : $scope.panel.field;
+
+      request = $scope.ejs.Request();
+
+      $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
+      queries = querySrv.getQueryObjs($scope.panel.queries.ids);
+
+      // This could probably be changed to a BoolFilter
+      boolQuery = $scope.ejs.BoolQuery();
+      _.each(queries,function(q) {
+        boolQuery = boolQuery.should(querySrv.toEjsObj(q));
+      });
+
+      // Ranges mode
+      if($scope.panel.tmode === 'ranges') {
+        rangefacet = $scope.ejs.RangeFacet('ranges');
+        // AddRange
+        _.each($scope.panel.values, function(v) {
+          rangefacet.addRange(v.from, v.to);
+        });
+        request = request
+          .facet(rangefacet
+          .field($scope.field)
+          .facetFilter($scope.ejs.QueryFilter(
+            $scope.ejs.FilteredQuery(
+              boolQuery,
+              filterSrv.getBoolFilter(filterSrv.ids())
+            )))).size(0);
+      }
+
+      // Populate the inspector panel
+      $scope.inspector = request.toJSON();
+
+      results = $scope.ejs.doSearch(dashboard.indices, request);
+
+      // Populate scope when we have results
+      results.then(function(results) {
+        $scope.panelMeta.loading = false;
+        if($scope.panel.tmode === 'ranges') {
+          $scope.hits = results.hits.total;
+        }
+
+        $scope.results = results;
+
+        $scope.$emit('render');
+      });
+    };
+
+    $scope.build_search = function(range,negate) {
+      console.log(range);
+      if(_.isUndefined(range.meta)) {
+        filterSrv.set({type:'range',field:$scope.field,from:range.label[0],to:range.label[1],
+          mandate:(negate ? 'mustNot':'must')});
+      } else if(range.meta === 'missing') {
+        filterSrv.set({type:'exists',field:$scope.field,
+          mandate:(negate ? 'must':'mustNot')});
+      } else {
+        return;
+      }
+    };
+
+    $scope.set_refresh = function (state) {
+      $scope.refresh = state;
+    };
+
+    $scope.close_edit = function() {
+      if($scope.refresh) {
+        $scope.get_data();
+      }
+      $scope.refresh =  false;
+      $scope.$emit('render');
+    };
+
+    $scope.showMeta = function(range) {
+      if(_.isUndefined(range.meta)) {
+        return true;
+      }
+      if(range.meta === 'other' && !$scope.panel.other) {
+        return false;
+      }
+      if(range.meta === 'missing' && !$scope.panel.missing) {
+        return false;
+      }
+      return true;
+    };
+
+    $scope.add_new_value = function(panel) {
+      panel.values.push(angular.copy($scope.defaultValue));
+    };
+
+  });
+
+  module.directive('rangesChart', function(querySrv) {
+    return {
+      restrict: 'A',
+      link: function(scope, elem) {
+        var plot;
+
+        // Receive render events
+        scope.$on('render',function(){
+          render_panel();
+        });
+
+        function build_results() {
+          var k = 0;
+          scope.data = [];
+          _.each(scope.results.facets.ranges.ranges, function(v) {
+            var slice;
+            if(scope.panel.tmode === 'ranges') {
+              slice = { label : [v.from,v.to], data : [[k,v.count]], actions: true};
+            }
+            scope.data.push(slice);
+            k = k + 1;
+          });
+
+          scope.data.push({label:'Missing field',
+            data:[[k,scope.results.facets.ranges.missing]],meta:"missing",color:'#aaa',opacity:0});
+
+          if(scope.panel.tmode === 'ranges') {
+            scope.data.push({label:'Other values',
+              data:[[k+1,scope.results.facets.ranges.other]],meta:"other",color:'#444'});
+          }
+        }
+
+        // Function for rendering panel
+        function render_panel() {
+          var chartData;
+
+          build_results();
+
+          // IE doesn't work without this
+          elem.css({height:scope.panel.height||scope.row.height});
+
+          // Make a clone we can operate on.
+          chartData = _.clone(scope.data);
+          chartData = scope.panel.missing ? chartData :
+            _.without(chartData,_.findWhere(chartData,{meta:'missing'}));
+          chartData = scope.panel.other ? chartData :
+          _.without(chartData,_.findWhere(chartData,{meta:'other'}));
+
+          // Populate element.
+          require(['jquery.flot.pie'], function(){
+            // Populate element
+            try {
+              // Add plot to scope so we can build out own legend
+              if(scope.panel.chart === 'bar') {
+                plot = $.plot(elem, chartData, {
+                  legend: { show: false },
+                  series: {
+                    lines:  { show: false, },
+                    bars:   { show: true,  fill: 1, barWidth: 0.8, horizontal: false },
+                    shadowSize: 1
+                  },
+                  yaxis: { show: true, min: 0, color: "#c8c8c8" },
+                  xaxis: { show: false },
+                  grid: {
+                    borderWidth: 0,
+                    borderColor: '#c8c8c8',
+                    color: "#c8c8c8",
+                    hoverable: true,
+                    clickable: true
+                  },
+                  colors: querySrv.colors
+                });
+              }
+              if(scope.panel.chart === 'pie') {
+                var labelFormat = function(label, series){
+                  return '<div ng-click="build_search(panel.field,\''+label+'\')'+
+                    ' "style="font-size:8pt;text-align:center;padding:2px;color:white;">'+
+                    label+'<br/>'+Math.round(series.percent)+'%</div>';
+                };
+
+                plot = $.plot(elem, chartData, {
+                  legend: { show: false },
+                  series: {
+                    pie: {
+                      innerRadius: scope.panel.donut ? 0.4 : 0,
+                      tilt: scope.panel.tilt ? 0.45 : 1,
+                      radius: 1,
+                      show: true,
+                      combine: {
+                        color: '#999',
+                        label: 'The Rest'
+                      },
+                      stroke: {
+                        width: 0
+                      },
+                      label: {
+                        show: scope.panel.labels,
+                        radius: 2/3,
+                        formatter: labelFormat,
+                        threshold: 0.1
+                      }
+                    }
+                  },
+                  //grid: { hoverable: true, clickable: true },
+                  grid:   { hoverable: true, clickable: true, color: '#c8c8c8' },
+                  colors: querySrv.colors
+                });
+              }
+
+              // Populate legend
+              if(elem.is(":visible")){
+                setTimeout(function(){
+                  scope.legend = plot.getData();
+                  if(!scope.$$phase) {
+                    scope.$apply();
+                  }
+                });
+              }
+
+            } catch(e) {
+              elem.text(e);
+            }
+          });
+        }
+
+        elem.bind("plotclick", function (event, pos, object) {
+          if(object) {
+            scope.build_search(scope.data[object.seriesIndex]);
+          }
+        });
+
+        var $tooltip = $('<div>');
+        elem.bind("plothover", function (event, pos, item) {
+          if (item) {
+            var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1];
+            $tooltip
+              .html(
+                kbn.query_color_dot(item.series.color, 20) + ' ' +
+                item.series.label + " (" + value.toFixed(0) +
+                (scope.panel.chart === 'pie' ? (", " + Math.round(item.datapoint[0]) + "%") : "") + ")"
+              )
+              .place_tt(pos.pageX, pos.pageY);
+          } else {
+            $tooltip.remove();
+          }
+        });
+
+      }
+    };
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/sparklines/editor.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/sparklines/editor.html b/kibana/src/main/resources/app/panels/sparklines/editor.html
index 1ff1818..65fc07e 100644
--- a/kibana/src/main/resources/app/panels/sparklines/editor.html
+++ b/kibana/src/main/resources/app/panels/sparklines/editor.html
@@ -1 +1,23 @@
-<div class="editor-row"><div class="section"><h5>Values</h5><div class="editor-option"><label class="small">Chart value</label><select ng-change="set_refresh(true)" class="input-small" ng-model="panel.mode" ng-options="f for f in ['count','min','mean','max','total']"></select></div><div class="editor-option"><label class="small">Time Field</label><input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.time_field"></div><div class="editor-option" ng-show="panel.mode != 'count'"><label class="small">Value Field<tip>This field must contain a numeric value</tip></label><input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-large" ng-model="panel.value_field"></div></div><div class="section"><h5>Transform Series</h5><div class="editor-option"><label class="small">Derivative<tip>Plot the change per interval in the series</tip></label><input type="
 checkbox" ng-model="panel.derivative" ng-checked="panel.derivative" ng-change="set_refresh(true)"></div></div></div>
\ No newline at end of file
+<div class="editor-row">
+  <div class="section">
+    <h5>Values</h5>
+    <div class="editor-option">
+      <label class="small">Chart value</label>
+      <select ng-change="set_refresh(true)" class="input-small" ng-model="panel.mode" ng-options="f for f in ['count','min','mean','max','total']"></select>
+    </div>
+    <div class="editor-option">
+      <label class="small">Time Field</label>
+      <input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.time_field">
+    </div>
+    <div class="editor-option" ng-show="panel.mode != 'count'">
+      <label class="small">Value Field <tip>This field must contain a numeric value</tip></label>
+        <input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-large" ng-model="panel.value_field">
+    </div>
+  </div>
+  <div class="section">
+    <h5>Transform Series</h5>
+    <div class="editor-option">
+      <label class="small">Derivative <tip>Plot the change per interval in the series</tip></label><input type="checkbox" ng-model="panel.derivative" ng-checked="panel.derivative" ng-change="set_refresh(true)">
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/sparklines/interval.js
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/sparklines/interval.js b/kibana/src/main/resources/app/panels/sparklines/interval.js
new file mode 100644
index 0000000..ed5ae01
--- /dev/null
+++ b/kibana/src/main/resources/app/panels/sparklines/interval.js
@@ -0,0 +1,57 @@
+define([
+  'kbn'
+],
+function (kbn) {
+  'use strict';
+
+  /**
+   * manages the interval logic
+   * @param {[type]} interval_string  An interval string in the format '1m', '1y', etc
+   */
+  function Interval(interval_string) {
+    this.string = interval_string;
+
+    var info = kbn.describe_interval(interval_string);
+    this.type = info.type;
+    this.ms = Math.ceil(info.sec * 1000 * info.count);
+
+    // does the length of the interval change based on the current time?
+    if (this.type === 'y' || this.type === 'M') {
+      // we will just modify this time object rather that create a new one constantly
+      this.get = this.get_complex;
+      this.date = new Date(0);
+    } else {
+      this.get = this.get_simple;
+    }
+  }
+
+  Interval.prototype = {
+    toString: function () {
+      return this.string;
+    },
+    after: function(current_ms) {
+      return this.get(current_ms, 1);
+    },
+    before: function (current_ms) {
+      return this.get(current_ms, -1);
+    },
+    get_complex: function (current, delta) {
+      this.date.setTime(current);
+      switch(this.type) {
+      case 'M':
+        this.date.setUTCMonth(this.date.getUTCMonth() + delta);
+        break;
+      case 'y':
+        this.date.setUTCFullYear(this.date.getUTCFullYear() + delta);
+        break;
+      }
+      return this.date.getTime();
+    },
+    get_simple: function (current, delta) {
+      return current + (delta * this.ms);
+    }
+  };
+
+  return Interval;
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/a24aae9b/kibana/src/main/resources/app/panels/sparklines/module.html
----------------------------------------------------------------------
diff --git a/kibana/src/main/resources/app/panels/sparklines/module.html b/kibana/src/main/resources/app/panels/sparklines/module.html
index 34dda3f..e34701c 100644
--- a/kibana/src/main/resources/app/panels/sparklines/module.html
+++ b/kibana/src/main/resources/app/panels/sparklines/module.html
@@ -1 +1,10 @@
-<div ng-controller="sparklines" ng-init="init()" style="min-height:{{panel.height || row.height}}"><center><img ng-show="panel.loading && _.isUndefined(data)" src="img/load_big.gif"></center><div ng-repeat="series in data" style="margin-right:5px;text-align:center;display:inline-block"><small class="strong"><i class="icon-circle" ng-style="{color: series.info.color}"></i> {{series.info.alias}}</small><br><div style="display:inline-block" sparklines-chart="" series="series" panel="panel"></div></div></div>
\ No newline at end of file
+<div ng-controller='sparklines' ng-init="init()" style="min-height:{{panel.height || row.height}}">
+  <center><img ng-show='panel.loading && _.isUndefined(data)' src="img/load_big.gif"></center>
+
+
+  <div ng-repeat="series in data" style="margin-right:5px;text-align:center;display:inline-block">
+    <small class="strong"><i class="icon-circle" ng-style="{color: series.info.color}"></i> {{series.info.alias}}</small><br>
+    <div style="display:inline-block" sparklines-chart series="series" panel="panel"></div>
+  </div>
+
+</div>
\ No newline at end of file