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> <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>  <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'">
+   | {{ 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'">
+   | {{ 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