karaf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jbono...@apache.org
Subject [35/51] [partial] karaf-decanter git commit: KARAF-3624 - Add Kibana 4.x static feature and support
Date Mon, 15 Feb 2016 13:28:18 GMT
http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/stats/editor.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/stats/editor.html b/kibana-3.x/src/main/resources/app/panels/stats/editor.html
new file mode 100644
index 0000000..08e93e6
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/stats/editor.html
@@ -0,0 +1,38 @@
+<div class="row-fluid">
+    <h5>Details</h5>
+    <div class="editor-option">
+      <label class="small">Featured Stat</label>
+      <select ng-change="set_refresh(true)" class="input-small" ng-model="panel.mode" ng-options="f for f in modes"></select>
+    </div>
+    <div class="editor-option">
+      <label class="small">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.field">
+    </div>
+    <div class="editor-option">
+      <label class="small">Unit</label>
+        <input type="text" class="input-large" ng-model="panel.unit">
+    </div>
+
+    <h5>Columns</h5>
+    <div class="editor-option" ng-repeat="stat in modes">
+      <label class="small">{{stat}}</label><input type="checkbox" ng-model="panel.show[stat]" ng-checked="panel.show[stat]">
+    </div>
+
+    <h5>Formating</h5>
+    <div class="editor-option">
+      <label class="small">Format</label>
+      <select ng-change="set_refresh(true)" class="input-small" ng-model="panel.format" ng-options="f for f in ['number','float','money','bytes']"></select>
+    </div>
+    <div class="editor-option">
+      <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">
+      <label class="small">Display Breakdowns</label>
+      <select class="input-mini" ng-model="panel.display_breakdown" ng-options="f for f in ['yes', 'no']"></select></span>
+    </div>
+    <div class="editor-option">
+      <label class="small">Query column name</label>
+        <input type="text" class="input-large" ng-model="panel.label_name">
+    </div>
+</div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/stats/module.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/stats/module.html b/kibana-3.x/src/main/resources/app/panels/stats/module.html
new file mode 100644
index 0000000..aca958e
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/stats/module.html
@@ -0,0 +1,37 @@
+<div ng-controller="stats" 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/0bcbfc59/kibana-3.x/src/main/resources/app/panels/stats/module.js
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/stats/module.js b/kibana-3.x/src/main/resources/app/panels/stats/module.js
new file mode 100644
index 0000000..17cefc8
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/stats/module.js
@@ -0,0 +1,213 @@
+/*
+
+  ## Stats 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'
+], function (
+  angular,
+  app,
+  _,
+  $,
+  kbn,
+  numeral
+) {
+
+  'use strict';
+
+  var module = angular.module('kibana.panels.stats', []);
+  app.useModule(module);
+
+  module.controller('stats', function ($scope, querySrv, dashboard, filterSrv) {
+
+    $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 statistical panel for displaying aggregations using the Elastic Search statistical facet query.'
+    };
+
+    $scope.modes = ['count','min','max','mean','total','variance','std_deviation','sum_of_squares'];
+
+    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,
+      show: {
+        count: true,
+        min: true,
+        max: true,
+        mean: true,
+        std_deviation: true,
+        sum_of_squares: true,
+        total: true,
+        variance: 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) {
+      console.log(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));
+      });
+
+      request = request
+        .facet($scope.ejs.StatisticalFacet('stats')
+          .field($scope.panel.field)
+          .facetFilter($scope.ejs.QueryFilter(
+            $scope.ejs.FilteredQuery(
+              boolQuery,
+              filterSrv.getBoolFilter(filterSrv.ids())
+              )))).size(0);
+
+      _.each(queries, function (q) {
+        var alias = q.alias || q.query;
+        var query = $scope.ejs.BoolQuery();
+        query.should(querySrv.toEjsObj(q));
+        request.facet($scope.ejs.StatisticalFacet('stats_'+alias)
+          .field($scope.panel.field)
+          .facetFilter($scope.ejs.QueryFilter(
+            $scope.ejs.FilteredQuery(
+              query,
+              filterSrv.getBoolFilter(filterSrv.ids())
+            )
+          ))
+        );
+      });
+
+      // Populate the inspector panel
+      $scope.inspector = request.toJSON();
+
+      results = $scope.ejs.doSearch(dashboard.indices, request);
+
+      results.then(function(results) {
+        $scope.panelMeta.loading = false;
+        var value = results.facets.stats[$scope.panel.mode];
+
+        var rows = queries.map(function (q) {
+          var alias = q.alias || q.query;
+          var obj = _.clone(q);
+          obj.label = alias;
+          obj.Label = alias.toLowerCase(); //sort field
+          obj.value = results.facets['stats_'+alias];
+          obj.Value = results.facets['stats_'+alias]; //sort field
+          return obj;
+        });
+
+        $scope.data = {
+          value: value,
+          rows: rows
+        };
+
+        console.log($scope.data);
+
+        $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/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/editor.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/editor.html b/kibana-3.x/src/main/resources/app/panels/table/editor.html
new file mode 100644
index 0000000..8988a9a
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/editor.html
@@ -0,0 +1,45 @@
+  <div class="row-fluid">
+    <div class="span6 section">
+      <h5>Options</h5>
+      <div class="editor-option">
+        <label class="small">Header</label><input type="checkbox" ng-model="panel.header" ng-checked="panel.header">
+      </div>
+      <div class="editor-option">
+        <label class="small">Sorting</label><input type="checkbox" ng-model="panel.sortable" ng-checked="panel.sortable">
+      </div>
+      <div class="editor-option" style="white-space:nowrap" ng-show='panel.sortable'>
+        <label class="small">Sort</label>
+        <input class="input-small" bs-typeahead="fields.list" ng-model="panel.sort[0]" type="text"></input>
+        <i ng-click="set_sort(panel.sort[0])" ng-class="{'icon-chevron-up': panel.sort[1] == 'asc','icon-chevron-down': panel.sort[1] == 'desc'}"></i>
+      </div>
+      <div class="editor-option"><label class="small">Font Size</label>
+        <select class="input-small" 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">
+        <label class="small">Trim Factor <tip>Trim fields to this long divided by # of rows. Requires data refresh.</tip></label>
+        <input type="number" class="input-small" ng-model="panel.trimFactor" ng-change="set_refresh(true)">
+      </div>
+      <br>
+      <div class="editor-option">
+        <label class="small">Local Time <tip>Adjust time field to browser's local time</tip></label><input type="checkbox" ng-change="set_refresh(true)" ng-model="panel.localTime" ng-checked="panel.localTime">
+      </div>
+      <div class="editor-option" ng-show="panel.localTime">
+        <label class="small">Time Field</label>
+        <input type="text" class="input-small" ng-model="panel.timeField" ng-change="set_refresh(true)" bs-typeahead="fields.list">
+      </div>
+    </div>
+    <div class="section span6">
+      <h5>Columns</h5>
+      <form class="input-append editor-option">
+        <input bs-typeahead="fields.list" type="text" class="input-small" ng-model='newfield'>
+        <button class="btn" ng-click="panel.fields = _.toggleInOut(panel.fields,newfield);newfield=''"><i class="icon-plus"></i></button>
+      </form><br>
+      <span style="margin-left:3px" ng-repeat="field in panel.fields" class="label">{{field}} <i class="pointer icon-remove-sign" ng-click="panel.fields = _.toggleInOut(panel.fields,field)"></i></span>
+      <h5>Highlighted Fields</h5>
+      <form class="input-append editor-option">
+        <input bs-typeahead="fields.list" type="text" class="input-small" ng-model='newhighlight' ng-change="set_refresh(true)">
+        <button class="btn" ng-click="panel.highlight = _.toggleInOut(panel.highlight,newhighlight);newhighlight=''"><i class="icon-plus"></i></button>
+      </form><br>
+      <span style="margin-left:3px" ng-repeat="field in panel.highlight" class="label">{{field}} <i class="pointer icon-remove-sign" ng-click="panel.highlight = _.toggleInOut(panel.highlight,field);set_refresh(true)" ></i></span>
+    </div>
+  </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/export.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/export.html b/kibana-3.x/src/main/resources/app/panels/table/export.html
new file mode 100644
index 0000000..c56a1fa
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/export.html
@@ -0,0 +1,12 @@
+  <div class="modal-body">
+    <div class="editor-option">
+      <h6>CSV filename</h6>
+      <input type="string" class="input-large" ng-model="csv.filename">
+    </div>
+    <form name="input" style="margin-bottom:0">
+    <button ng-click="exportAsCsv();" class="btn">Export</button>
+    </form>
+    <form name="input" style="margin-bottom:0">
+    <button ng-click="dismiss();" class="btn btn-danger">Close</button>
+    </form>
+  </div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/micropanel.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/micropanel.html b/kibana-3.x/src/main/resources/app/panels/table/micropanel.html
new file mode 100644
index 0000000..f7368fc
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/micropanel.html
@@ -0,0 +1,69 @@
+<a class="close" ng-click="dismiss()" href="">×</a>
+<style>
+
+</style>
+<span>
+  <i class="pointer icon-search" ng-click="fieldExists(micropanel.field,'must');dismiss();" bs-tooltip="'Find events with this field'"></i>
+  <i class="pointer icon-ban-circle" ng-click="fieldExists(micropanel.field,'mustNot');dismiss();" bs-tooltip="'Find events without this field'"></i>
+  <strong>Micro Analysis of {{micropanel.field}} <span ng-if='micropanel.type'>({{micropanel.type}})</span></strong>
+  <span ng-show="micropanel.hasArrays">
+    as
+    <a class="link" ng-class="{'strong':micropanel.grouped}" ng-click="toggle_micropanel(micropanel.field,true)">Groups</a> /
+    <a class="link" ng-class="{'strong':!micropanel.grouped}" ng-click="toggle_micropanel(micropanel.field,false)">Singles</a>
+  </span>
+</span>
+<table style="width:100%;table-layout:fixed" class='table table-striped table-unpadded'>
+  <thead>
+    <th style="width:15px"></th>
+    <th style="width:260px">Value</th>
+    <th style="width:40px">Action</th>
+    <th style="width:100px;text-align:right">Count / {{micropanel.count}} events</th>
+  </thead>
+  <tbody>
+    <tr ng-repeat='field in micropanel.values'>
+      <td>{{$index+1}}.</td>
+      <td style="word-wrap:break-word">{{{true: "__blank__", false:field[0] }[(field[0] == '' || field[0] == undefined) && field[0] != 0]|tableTruncate:panel.trimFactor:3}}</td>
+      <td>
+        <i class="pointer icon-search" ng-click="build_search(micropanel.field,field[0]);dismiss();"></i>
+        <i class="pointer icon-ban-circle" ng-click="build_search(micropanel.field,field[0],true);dismiss();"></i>
+      </td>
+      <td class="progress" style="position:relative">
+        <style scoped>
+          .progress {
+            overflow: visible;
+          }
+        </style>
+        <div bs-tooltip="percent(field[1],data.length)" class="bar" ng-class="micropanelColor($index)" ng-style="{width: (field[1]/data.length) > 1 ? '100%' : percent(field[1],data.length)}"></div>
+        <span style="position:absolute;right:20px;">{{field[1]}}</span>
+      </td>
+    </tr>
+  </tbody>
+</table>
+<div class="progress nomargin" ng-show="micropanel.grouped">
+  <div ng-repeat='field in micropanel.values' bs-tooltip="$index+1+'. ('+percent(field[1],data.length)+')'" class="bar {{micropanelColor($index)}}" ng-style="{width: percent(field[1],data.length)};"></div>
+</div>
+<div>
+  <span ng-repeat="field in micropanel.related|orderBy:'count':true|limitTo:micropanel.limit track by $index"><a ng-click="toggle_field(field.name)" bs-tooltip="'Toggle {{field.name}} column'">{{field.name}}</a> ({{Math.round((field.count / micropanel.count) * 100)}}%), </span>
+  <a class="link" ng-show="micropanel.related.length > micropanel.limit" ng-click="micropanel.limit = micropanel.limit + 10">More <i class="icon-caret-right"></i></a>
+</div>
+<div class="row-fluid">
+  <div class="span12">
+    <div class="btn-group">
+      <a class="btn dropdown-toggle pointer" data-toggle="dropdown">
+        <i class="icon-list-ol"></i> Terms
+        <span class="caret"></span>
+      </a>
+      <ul class="dropdown-menu">
+        <li><a ng-click="termsModal(field,'bar');dismiss();">Bar</a></li>
+        <li><a ng-click="termsModal(field,'pie');dismiss();">Pie</a></li>
+        <li><a ng-click="termsModal(field,'table');dismiss();">Table</a></li>
+      </ul>
+    </div>
+    <div class="btn-group" ng-show="micropanel.hasStats">
+      <a class="btn dropdown-toggle pointer" ng-click="statsModal(field);dismiss();">
+        <i class="icon-list-ol"></i> Stats
+      </a>
+    </div>
+
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/modal.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/modal.html b/kibana-3.x/src/main/resources/app/panels/table/modal.html
new file mode 100644
index 0000000..9d097dc
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/modal.html
@@ -0,0 +1,43 @@
+  <div class="modal-body">
+    <style>
+      .timepicker-to-column {
+        margin-top: 10px;
+      }
+
+      .timepicker-input input {
+        outline: 0 !important;
+        border: 0px !important;
+        -webkit-box-shadow: 0;
+        -moz-box-shadow: 0;
+        box-shadow: 0;
+        position: relative;
+      }
+
+      .timepicker-input input::-webkit-outer-spin-button,
+      .timepicker-input input::-webkit-inner-spin-button {
+          -webkit-appearance: none;
+          margin: 0;
+      }
+
+      input.timepicker-date {
+        width: 90px;
+      }
+      input.timepicker-hms {
+        width: 20px;
+      }
+      input.timepicker-ms {
+        width: 25px;
+      }
+      div.timepicker-now {
+        float: right;
+      }
+    </style>
+    <h4>Top 10 terms in field {{modalField}}</h4>
+    <kibana-simple-panel ng-click="dismiss();" type="'{{facetType}}'" panel='{{facetPanel}}' ng-cloak></kibana-simple-panel>
+  </div>
+
+  <div class="modal-footer">
+    <form name="input" style="margin-bottom:0">
+    <button ng-click="dismiss();" class="btn btn-danger">Close</button>
+    </form>
+  </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/module.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/module.html b/kibana-3.x/src/main/resources/app/panels/table/module.html
new file mode 100644
index 0000000..b1aa49f
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/module.html
@@ -0,0 +1,202 @@
+<div ng-controller='table' ng-init='init()'>
+  <style>
+    .table-doc-table {
+      margin-left: 0px !important;
+      overflow-y: auto;
+    }
+    .table-sidebar {
+      width: 200px;
+      display: table-cell;
+      padding-right: 10px;
+    }
+    .table-main {
+      width: 100%;
+      display: table-cell;
+    }
+    .table-container {
+      display: table;
+      height: 100px;
+      width: 100%;
+      table-layout: fixed;
+    }
+    .table-fieldname {
+      white-space: nowrap;
+    }
+
+    .table-fieldname a {
+      word-wrap:break-word;
+      white-space: normal;
+    }
+
+    .table-details {
+      table-layout: fixed;
+    }
+
+    .table-details-field {
+      width: 200px;
+    }
+
+    .table-details-action {
+      width: 60px;
+      text-align: center;
+    }
+
+    .table-details-value {
+    }
+
+    .table-field-value {
+      white-space: pre-wrap;
+    }
+
+    .table-facet {
+      padding: 10px;
+      border: 1px solid #666;
+    }
+  </style>
+
+  <div class="table-container">
+
+    <div bindonce ng-class="{'table-sidebar':panel.field_list}" ng-if="panel.field_list">
+      <div style="{{panel.overflow}}:{{panel.height||row.height}};overflow-y:auto">
+
+        <strong>Fields <i class=" icon-chevron-sign-left pointer " ng-click="panel.field_list = !panel.field_list" bs-tooltip="'Hide field list'"></i></strong><p>
+
+        <div class="small">
+          <span class="link small" ng-click="panel.all_fields = true;" ng-if="fields.list.length" ng-class="{strong:panel.all_fields}">
+            All ({{fields.list.length}})</span> /
+          <span class="link small" ng-click="panel.all_fields = false;" ng-class="{strong:!panel.all_fields}">
+            Current ({{current_fields.length || 0}})</span>
+        </div>
+
+        <div><input type="text" class="input-medium" placeholder="Type to filter..." ng-model="fieldFilter">
+        </div>
+
+        <div ng-show="panel.all_fields" class="small muted" style="margin-bottom:10px">
+          <strong>Note</strong> These fields have been<br>
+          extracted from your mapping.<br>
+          Not all fields may be available<br>
+          in your source document.
+        </div>
+
+        <ul class="unstyled" ng-if="panel.all_fields">
+          <li class="table-fieldname" ng-style="panel.style" ng-repeat="field in fields.list|filter:fieldFilter|orderBy:identity">
+            <i class="pointer" ng-class="{'icon-check': columns[field],'icon-check-empty': _.isUndefined(columns[field])}" ng-click="toggle_field(field)"></i>
+            <a class="pointer" data-unique="1" bs-popover="'app/panels/table/micropanel.html'" data-placement="rightTop" ng-click="toggle_micropanel(field,true)" ng-class="{label: columns[field]}" bo-text="field"></a>
+          </li>
+        </ul>
+
+        <ul class="unstyled" ng-if="!panel.all_fields">
+          <li class="table-fieldname"  ng-style="panel.style" ng-repeat="field in current_fields|filter:fieldFilter|orderBy:identity">
+            <i class="pointer" ng-class="{'icon-check': columns[field],'icon-check-empty': _.isUndefined(columns[field])}" ng-click="toggle_field(field)"></i>
+            <a class="pointer" data-unique="1" bs-popover="'app/panels/table/micropanel.html'" data-placement="rightTop" ng-click="toggle_micropanel(field,true)" ng-class="{label: columns[field]}" bo-text="field"></a>
+          </li>
+        </ul>
+
+      </div>
+    </div>
+
+    <div ng-class="{'table-main':panel.field_list}" class="table-doc-table">
+
+      <div style="{{panel.overflow}}:{{panel.height||row.height}};overflow-y:auto">
+        <div class="table-facet" ng-if="modalField">
+          <h4>
+            <button class="btn btn-mini btn-danger" ng-click="closeFacet();">close</button>
+            {{adhocOpts.title}}
+            <span class="pointer ng-scope ng-pristine ng-valid ui-draggable" bs-tooltip="'Drag to add to dashboard'"
+              data-drag="true"
+              data-jqyoui-options="kbnJqUiDraggableOptions"
+              jqyoui-draggable="{animate:false,mutate:false,onStart:'panelMoveStart',onStop:'panelMoveStop',embedded:true}"
+              ng-model="adhocOpts"
+              data-original-title=""
+              title=""
+              aria-disabled="false" style="position: relative;"><i class="icon-move"></i></span>
+          </h4>
+          <kibana-simple-panel type="'{{facetType}}'" panel='{{facetPanel}}' ng-cloak></kibana-simple-panel>
+        </div>
+
+        <i class="pull-left icon-chevron-sign-right pointer" ng-click="panel.field_list = !panel.field_list" bs-tooltip="'Show field list'" ng-show="!panel.field_list"></i>
+        <div class="row-fluid" ng-show="panel.paging">
+          <div class="span1 offset1" style="text-align:right">
+            <i ng-click="panel.offset = 0" ng-show="panel.offset > 0" class='icon-circle-arrow-left pointer'></i>
+            <i ng-click="panel.offset = (panel.offset - panel.size)" ng-show="panel.offset > 0" class='icon-arrow-left pointer'></i>
+          </div>
+          <div class="span8" style="text-align:center">
+            <strong>{{panel.offset}}</strong> to <strong>{{panel.offset + data.slice(panel.offset,panel.offset+panel.size).length}}</strong>
+            <small> of {{data.length}} available for paging</small>
+          </div>
+          <div class="span1" style="text-align:left">
+            <i ng-click="panel.offset = (panel.offset + panel.size)" ng-show="data.length > panel.offset+panel.size" class='icon-arrow-right pointer'></i>
+          </div>
+        </div>
+        <table class="table-hover table table-condensed" ng-style="panel.style">
+          <thead ng-show="panel.header">
+            <th ng-show="panel.fields.length<1">_source (select columns from the list to the left)</th>
+            <th style="white-space:nowrap" ng-repeat="field in panel.fields">
+              <i ng-show="!$first" class="pointer link icon-caret-left" ng-click="_.move(panel.fields,$index,$index-1)"></i>
+
+              <span  class="pointer" ng-click="set_sort(field)" ng-show='panel.sortable'>
+                {{field}}
+                <i ng-show='field == panel.sort[0]' class="pointer link" ng-class="{'icon-chevron-up': panel.sort[1] == 'asc','icon-chevron-down': panel.sort[1] == 'desc'}"></i>
+              </span>
+              <span ng-show='!panel.sortable'>{{field}}</span>
+              <i ng-show="!$last" class="pointer link icon-caret-right" ng-click="_.move(panel.fields,$index,$index+1)"></i>
+            </th>
+
+          </thead>
+          <tbody bindonce ng-repeat="event in data| slice:panel.offset:panel.offset+panel.size" ng-class-odd="'odd'">
+            <tr ng-click="toggle_details(event)" class="pointer">
+              <td ng-if="panel.fields.length<1" bo-text="event._source|stringify|tableTruncate:panel.trimFactor:1"></td>
+              <td ng-show="panel.fields.length>0" ng-repeat="field in panel.fields">
+                <span ng-if="!panel.localTime || panel.timeField != field" bo-html="(event.kibana.highlight[field]||event.kibana._source[field]) |tableHighlight | tableTruncate:panel.trimFactor:panel.fields.length" class="table-field-value"></span>
+                <span ng-if="panel.localTime && panel.timeField == field" bo-html="event.sort[1]|tableLocalTime:event" class="table-field-value"></span>
+              </td>
+            </tr>
+            <tr ng-if="event.kibana.details">
+              <td colspan={{panel.fields.length}} ng-switch="event.kibana.view">
+                <span>
+                  View:
+                  <a class="link" ng-class="{'strong':event.kibana.view == 'table'}" ng-click="event.kibana.view = 'table'">Table</a> /
+                  <a class="link" ng-class="{'strong':event.kibana.view == 'json'}" ng-click="event.kibana.view = 'json'">JSON</a> /
+                  <a class="link" ng-class="{'strong':event.kibana.view == 'raw'}" ng-click="event.kibana.view = 'raw'">Raw</a>
+                  <i class="link pull-right icon-chevron-up" ng-click="toggle_details(event)"></i>
+                </span>
+                <table class='table table-bordered table-condensed table-details' ng-switch-when="table">
+                  <thead>
+                    <th class="table-details-field">Field</th>
+                    <th class="table-details-action">Action</th>
+                    <th class="table-details-value">Value</th>
+                  </thead>
+                  <tr ng-repeat="(key,value) in event.kibana._source track by $index" ng-class-odd="'odd'">
+                    <td style="word-wrap:break-word" bo-text="key"></td>
+                    <td style="white-space:nowrap">
+                      <i class='icon-search pointer' ng-click="build_search(key,value)" bs-tooltip="'Add filter to match this value'"></i>
+                      <i class='icon-ban-circle pointer' ng-click="build_search(key,value,true)" bs-tooltip="'Add filter to NOT match this value'"></i>
+                      <i class="pointer icon-th" ng-click="toggle_field(key)" bs-tooltip="'Toggle table column'"></i>
+                    </td>
+                    <!-- At some point we need to create a more efficient way of applying the filter pipeline -->
+                    <td style="white-space:pre-wrap;word-wrap:break-word" bo-html="value|noXml|urlLink|stringify"></td>
+                  </tr>
+                </table>
+                <pre style="white-space:pre-wrap;word-wrap:break-word"  bo-html="without_kibana(event)|tableJson:2" ng-switch-when="json"></pre>
+                <pre bo-html="without_kibana(event)|tableJson:1" ng-switch-when="raw"></pre>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+        <div class="row-fluid" ng-show="panel.paging">
+          <div class="span1 offset3" style="text-align:right">
+            <i ng-click="panel.offset = 0" ng-show="panel.offset > 0" class='icon-circle-arrow-left pointer'></i>
+            <i ng-click="panel.offset = (panel.offset - panel.size)" ng-show="panel.offset > 0" class='icon-arrow-left pointer'></i>
+          </div>
+          <div class="span4" style="text-align:center">
+            <strong>{{panel.offset}}</strong> to <strong>{{panel.offset + data.slice(panel.offset,panel.offset+panel.size).length}}</strong>
+            <small> of {{data.length}} available for paging</small>
+          </div>
+          <div class="span1" style="text-align:left">
+            <i ng-click="panel.offset = (panel.offset + panel.size)" ng-show="data.length > panel.offset+panel.size" class='icon-arrow-right pointer'></i>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/module.js
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/module.js b/kibana-3.x/src/main/resources/app/panels/table/module.js
new file mode 100644
index 0000000..70ba7df
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/module.js
@@ -0,0 +1,574 @@
+/** @scratch /panels/5
+ *
+ * include::panels/table.asciidoc[]
+ */
+
+/** @scratch /panels/table/0
+ *
+ * == table
+ * Status: *Stable*
+ *
+ * The table panel contains a sortable, pagable view of documents that. It can be arranged into
+ * defined columns and offers several interactions, such as performing adhoc terms aggregations.
+ *
+ */
+define([
+  'angular',
+  'app',
+  'lodash',
+  'kbn',
+  'moment',
+  'jsonpath',
+  'filesaver',
+  'blob'
+],
+function (angular, app, _, kbn, moment) {
+  'use strict';
+
+  var module = angular.module('kibana.panels.table', []);
+  app.useModule(module);
+
+  module.controller('table', function($rootScope, $scope, $modal, $q, $compile, $timeout,
+    fields, querySrv, dashboard, filterSrv) {
+    $scope.panelMeta = {
+      modals : [
+        {
+          description: "Export",
+          icon: "icon-download-alt",
+          partial: "app/panels/table/export.html",
+          show: $scope.panel.exportable
+        },
+        {
+          description: "Inspect",
+          icon: "icon-info-sign",
+          partial: "app/partials/inspector.html",
+          show: $scope.panel.spyable
+        }
+      ],
+      editorTabs : [
+        {
+          title:'Paging',
+          src: 'app/panels/table/pagination.html'
+        },
+        {
+          title:'Queries',
+          src: 'app/partials/querySelect.html'
+        }
+      ],
+      status: "Stable",
+      description: "A paginated table of records matching your query or queries. Click on a row to "+
+        "expand it and review all of the fields associated with that document. <p>"
+    };
+
+    // Set and populate defaults
+    var _d = {
+      /** @scratch /panels/table/5
+       * === Parameters
+       *
+       * size:: The number of hits to show per page
+       */
+      size    : 100, // Per page
+      /** @scratch /panels/table/5
+       * pages:: The number of pages available
+       */
+      pages   : 5,   // Pages available
+      /** @scratch /panels/table/5
+       * offset:: The current page
+       */
+      offset  : 0,
+      /** @scratch /panels/table/5
+       * sort:: An array describing the sort order of the table. For example [`@timestamp',`desc']
+       */
+      sort    : ['_score','desc'],
+      /** @scratch /panels/table/5
+       * overflow:: The css overflow property. `min-height' (expand) or `auto' (scroll)
+       */
+      overflow: 'min-height',
+      /** @scratch /panels/table/5
+       * fields:: the fields used a columns of the table, in an array.
+       */
+      fields  : [],
+      /** @scratch /panels/table/5
+       * highlight:: The fields on which to highlight, in an array
+       */
+      highlight : [],
+      /** @scratch /panels/table/5
+       * sortable:: Set sortable to false to disable sorting
+       */
+      sortable: true,
+      /** @scratch /panels/table/5
+       * header:: Set to false to hide the table column names
+       */
+      header  : true,
+      /** @scratch /panels/table/5
+       * paging:: Set to false to hide the paging controls of the table
+       */
+      paging  : true,
+      /** @scratch /panels/table/5
+       * field_list:: Set to false to hide the list of fields. The user will be able to expand it,
+       * but it will be hidden by default
+       */
+      field_list: true,
+      /** @scratch /panels/table/5
+       * all_fields:: Set to true to show all fields in the mapping, not just the current fields in
+       * the table.
+       */
+      all_fields: false,
+      /** @scratch /panels/table/5
+       * trimFactor:: The trim factor is the length at which to truncate fields takinging into
+       * consideration the number of columns in the table. For example, a trimFactor of 100, with 5
+       * columns in the table, would trim each column at 20 character. The entirety of the field is
+       * still available in the expanded view of the event.
+       */
+      trimFactor: 300,
+      /** @scratch /panels/table/5
+       * localTime:: Set to true to adjust the timeField to the browser's local time
+       */
+      localTime: false,
+      /** @scratch /panels/table/5
+       * timeField:: If localTime is set to true, this field will be adjusted to the browsers local time
+       */
+      timeField: '@timestamp',
+      /** @scratch /panels/table/5
+       * spyable:: Set to false to disable the inspect icon
+       */
+      spyable : true,
+      /** @scratch /panels/table/5
+       * exportable:: Set to false to disable the export icon
+       */
+      exportable : true,
+      /** @scratch /panels/table/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         : []
+      },
+      style   : {'font-size': '9pt'},
+      normTimes : true,
+    };
+    _.defaults($scope.panel,_d);
+
+    $scope.init = function () {
+      $scope.columns = {};
+      _.each($scope.panel.fields,function(field) {
+        $scope.columns[field] = true;
+      });
+
+      $scope.Math = Math;
+      $scope.identity = angular.identity;
+      $scope.$on('refresh',function(){$scope.get_data();});
+
+      $scope.fields = fields;
+      $scope.get_data();
+    };
+
+    // Create a percent function for the view
+    $scope.percent = kbn.to_percent;
+
+    $scope.csv = {
+      showOptions: false,
+      separator: ',',
+      quoteValues: true,
+      filename: 'table.csv'
+    };
+    $scope.exportAsCsv = function() {
+      if (!$scope.data) return;
+
+      var text = '';
+      var nonAlphaNumRE = /[^a-zA-Z0-9]/;
+      var allDoubleQuoteRE = /"/g;
+      var escape = function (val) {
+        val = String(val);
+        if ($scope.csv.quoteValues && nonAlphaNumRE.test(val)) {
+          val = '"' + val.replace(allDoubleQuoteRE, '""') + '"';
+        }
+        return val;
+      };
+
+      var rows = _.map($scope.data, function(e) {
+        var exportFields = [];
+        _.each($scope.panel.fields, function(field) {
+          exportFields.push(escape(e._source[field]));
+        });
+        return exportFields.join($scope.csv.separator) + '\r\n';
+      });
+
+      var blob = new Blob(rows, { type: 'text/plain' });
+
+      window.saveAs(blob, $scope.csv.filename);
+    };
+
+    $scope.closeFacet = function() {
+      if($scope.modalField) {
+        delete $scope.modalField;
+      }
+    };
+
+    $scope.termsModal = function(field,chart) {
+      $scope.closeFacet();
+      $timeout(function() {
+        $scope.modalField = field;
+        $scope.adhocOpts = {
+          height: "200px",
+          chart: chart,
+          field: field,
+          span: $scope.panel.span,
+          type: 'terms',
+          title: 'Top 10 terms in field ' + field
+        };
+        showModal(
+          angular.toJson($scope.adhocOpts),'terms');
+      },0);
+    };
+
+    $scope.statsModal = function(field) {
+      $scope.closeFacet();
+      $timeout(function() {
+        $scope.modalField = field;
+        $scope.adhocOpts = {
+          height: "200px",
+          field: field,
+          mode: 'mean',
+          span: $scope.panel.span,
+          type: 'stats',
+          title: 'Statistics for ' + field
+        };
+        showModal(
+          angular.toJson($scope.adhocOpts),'stats');
+      },0);
+    };
+
+    var showModal = function(panel,type) {
+      $scope.facetPanel = panel;
+      $scope.facetType = type;
+    };
+
+    $scope.toggle_micropanel = function(field,groups) {
+      var docs = _.map($scope.data,function(_d){return _d.kibana._source;});
+      var topFieldValues = kbn.top_field_values(docs,field,10,groups);
+      $scope.micropanel = {
+        field: field,
+        grouped: groups,
+        values : topFieldValues.counts,
+        hasArrays : topFieldValues.hasArrays,
+        related : kbn.get_related_fields(docs,field),
+        limit: 10,
+        count: _.countBy(docs,function(doc){return _.contains(_.keys(doc),field);})['true']
+      };
+
+      var nodeInfo = $scope.ejs.getFieldMapping(dashboard.indices, field);
+
+      return nodeInfo.then(function(p) {
+        var types = _.uniq(jsonPath(p, '*.*.*.*.mapping.*.type'));
+        if (_.isArray(types)) {
+          $scope.micropanel.type = types.join(', ');
+        }
+
+
+        if(_.intersection(types, ['long','float','integer','double']).length > 0) {
+          $scope.micropanel.hasStats =  true;
+        }
+      });
+
+    };
+
+    $scope.micropanelColor = function(index) {
+      var _c = ['bar-success','bar-warning','bar-danger','bar-info','bar-primary'];
+      return index > _c.length ? '' : _c[index];
+    };
+
+    $scope.set_sort = function(field) {
+      if($scope.panel.sort[0] === field) {
+        $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc';
+      } else {
+        $scope.panel.sort[0] = field;
+      }
+      $scope.get_data();
+    };
+
+    $scope.toggle_field = function(field) {
+      if (_.indexOf($scope.panel.fields,field) > -1) {
+        $scope.panel.fields = _.without($scope.panel.fields,field);
+        delete $scope.columns[field];
+      } else {
+        $scope.panel.fields.push(field);
+        $scope.columns[field] = true;
+      }
+    };
+
+    $scope.toggle_highlight = function(field) {
+      if (_.indexOf($scope.panel.highlight,field) > -1) {
+        $scope.panel.highlight = _.without($scope.panel.highlight,field);
+      } else {
+        $scope.panel.highlight.push(field);
+      }
+    };
+
+    $scope.toggle_details = function(row) {
+      row.kibana.details = row.kibana.details ? false : true;
+      row.kibana.view = row.kibana.view || 'table';
+      //row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
+    };
+
+    $scope.page = function(page) {
+      $scope.panel.offset = page*$scope.panel.size;
+      $scope.get_data();
+    };
+
+    $scope.build_search = function(field,value,negate) {
+      var query;
+      // This needs to be abstracted somewhere
+      if(_.isArray(value)) {
+        query = "(" + _.map(value,function(v){return angular.toJson(v);}).join(" AND ") + ")";
+      } else if (_.isUndefined(value)) {
+        query = '*';
+        negate = !negate;
+      } else {
+        query = angular.toJson(value);
+      }
+      $scope.panel.offset = 0;
+      filterSrv.set({type:'field',field:field,query:query,mandate:(negate ? 'mustNot':'must')});
+    };
+
+    $scope.fieldExists = function(field,mandate) {
+      filterSrv.set({type:'exists',field:field,mandate:mandate});
+    };
+
+    $scope.get_data = function(segment,query_id) {
+      var
+        _segment,
+        request,
+        boolQuery,
+        queries,
+        sort;
+
+      $scope.panel.error =  false;
+
+      // Make sure we have everything for the request to complete
+      if(dashboard.indices.length === 0) {
+        return;
+      }
+
+      sort = [$scope.ejs.Sort($scope.panel.sort[0]).order($scope.panel.sort[1]).ignoreUnmapped(true)];
+      if($scope.panel.localTime) {
+        sort.push($scope.ejs.Sort($scope.panel.timeField).order($scope.panel.sort[1]).ignoreUnmapped(true));
+      }
+
+
+      $scope.panelMeta.loading = true;
+
+      _segment = _.isUndefined(segment) ? 0 : segment;
+      $scope.segment = _segment;
+
+      request = $scope.ejs.Request();
+
+      $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
+
+      queries = querySrv.getQueryObjs($scope.panel.queries.ids);
+
+      boolQuery = $scope.ejs.BoolQuery();
+      _.each(queries,function(q) {
+        boolQuery = boolQuery.should(querySrv.toEjsObj(q));
+      });
+
+      request = request.query(
+        $scope.ejs.FilteredQuery(
+          boolQuery,
+          filterSrv.getBoolFilter(filterSrv.ids())
+        ))
+        .highlight(
+          $scope.ejs.Highlight($scope.panel.highlight)
+          .fragmentSize(2147483647) // Max size of a 32bit unsigned int
+          .preTags('@start-highlight@')
+          .postTags('@end-highlight@')
+        ).sort(sort);
+
+      $scope.populate_modal(request);
+
+      // Populate scope when we have results
+      $scope.ejs.doSearch(dashboard.indices[_segment], request, $scope.panel.size*$scope.panel.pages).then(function(results) {
+        $scope.panelMeta.loading = false;
+
+        if(_segment === 0) {
+          $scope.panel.offset = 0;
+          $scope.hits = 0;
+          $scope.data = [];
+          $scope.current_fields = [];
+          query_id = $scope.query_id = new Date().getTime();
+        }
+
+        // Check for error and abort if found
+        if(!(_.isUndefined(results.error))) {
+          $scope.panel.error = $scope.parse_error(results.error);
+          return;
+        }
+
+        // Check that we're still on the same query, if not stop
+        if($scope.query_id === query_id) {
+
+          // This is exceptionally expensive, especially on events with a large number of fields
+          $scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) {
+            var
+              _h = _.clone(hit),
+              _p = _.omit(hit,'_source','sort','_score');
+
+            // _source is kind of a lie here, never display it, only select values from it
+            _h.kibana = {
+              _source : _.extend(kbn.flatten_json(hit._source),_p),
+              highlight : kbn.flatten_json(hit.highlight||{})
+            };
+
+            // Kind of cheating with the _.map here, but this is faster than kbn.get_all_fields
+            $scope.current_fields = $scope.current_fields.concat(_.keys(_h.kibana._source));
+
+            return _h;
+          }));
+
+          $scope.current_fields = _.uniq($scope.current_fields);
+          $scope.hits += results.hits.total;
+
+          // Sort the data
+          $scope.data = _.sortBy($scope.data, function(v){
+            if(!_.isUndefined(v.sort)) {
+              return v.sort[0];
+            } else {
+              return v._score;
+            }
+          });
+
+          // Reverse if needed
+          if($scope.panel.sort[1] === 'desc') {
+            $scope.data.reverse();
+          }
+
+          // Keep only what we need for the set
+          $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages);
+
+        } else {
+          return;
+        }
+
+        // If we're not sorting in reverse chrono order, query every index for
+        // size*pages results
+        // Otherwise, only get size*pages results then stop querying
+        if (($scope.data.length < $scope.panel.size*$scope.panel.pages ||
+          !((_.contains(filterSrv.timeField(),$scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) &&
+          _segment+1 < dashboard.indices.length) {
+          $scope.get_data(_segment+1,$scope.query_id);
+        }
+
+      });
+    };
+
+    $scope.populate_modal = function(request) {
+      $scope.inspector = request.toJSON();
+    };
+
+    $scope.without_kibana = function (row) {
+      var _c = _.clone(row);
+      delete _c.kibana;
+      return _c;
+    };
+
+    $scope.set_refresh = function (state) {
+      $scope.refresh = state;
+    };
+
+    $scope.close_edit = function() {
+      if($scope.refresh) {
+        $scope.get_data();
+      }
+      $scope.columns = [];
+      _.each($scope.panel.fields,function(field) {
+        $scope.columns[field] = true;
+      });
+      $scope.refresh =  false;
+    };
+
+    $scope.locate = function(obj, path) {
+      path = path.split('.');
+      var arrayPattern = /(.+)\[(\d+)\]/;
+      for (var i = 0; i < path.length; i++) {
+        var match = arrayPattern.exec(path[i]);
+        if (match) {
+          obj = obj[match[1]][parseInt(match[2],10)];
+        } else {
+          obj = obj[path[i]];
+        }
+      }
+      return obj;
+    };
+
+
+  });
+
+  // This also escapes some xml sequences
+  module.filter('tableHighlight', function() {
+    return function(text) {
+      if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) {
+        return text.toString().
+          replace(/&/g, '&amp;').
+          replace(/</g, '&lt;').
+          replace(/>/g, '&gt;').
+          replace(/\r?\n/g, '<br/>').
+          replace(/@start-highlight@/g, '<code class="highlight">').
+          replace(/@end-highlight@/g, '</code>');
+      }
+      return '';
+    };
+  });
+
+  module.filter('tableTruncate', function() {
+    return function(text,length,factor) {
+      if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) {
+        return text.length > length/factor ? text.substr(0,length/factor)+'...' : text;
+      }
+      return '';
+    };
+  });
+
+
+
+  module.filter('tableJson', function() {
+    var json;
+    return function(text,prettyLevel) {
+      if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) {
+        json = angular.toJson(text,prettyLevel > 0 ? true : false);
+        json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+        if(prettyLevel > 1) {
+          /* jshint maxlen: false */
+          json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+            var cls = 'number';
+            if (/^"/.test(match)) {
+              if (/:$/.test(match)) {
+                cls = 'key strong';
+              } else {
+                cls = '';
+              }
+            } else if (/true|false/.test(match)) {
+              cls = 'boolean';
+            } else if (/null/.test(match)) {
+              cls = 'null';
+            }
+            return '<span class="' + cls + '">' + match + '</span>';
+          });
+        }
+        return json;
+      }
+      return '';
+    };
+  });
+
+  // WIP
+  module.filter('tableLocalTime', function(){
+    return function(text,event) {
+      return moment(event.sort[1]).format("YYYY-MM-DDTHH:mm:ss.SSSZ");
+    };
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/table/pagination.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/table/pagination.html b/kibana-3.x/src/main/resources/app/panels/table/pagination.html
new file mode 100644
index 0000000..8eee4cc
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/table/pagination.html
@@ -0,0 +1,32 @@
+  <div class="editor-row">
+    <div class="section">
+      <div class="editor-option">
+        <h6>Show Controls</h6><input type="checkbox" ng-model="panel.paging" ng-checked="panel.paging">
+      </div>
+      <div class="editor-option">
+        <h6>Overflow</h6>
+        <select class="input-small" ng-model="panel.overflow" ng-options="f.value as f.key for f in [{key:'scroll',value:'height'},{key:'expand',value:'min-height'}]"></select>
+      </div>
+    </div>
+
+    <div class="section">
+      <div class="editor-option">
+        <h6>Per Page</h6>
+        <input type="number" class="input-mini" ng-model="panel.size" ng-change="get_data()">
+      </div>
+      <div class="editor-option">
+        <h6>&nbsp;</h6>
+        <center><i class='icon-remove'></i><center>
+      </div>
+      <div class="editor-option">
+        <h6>Page limit</h6>
+        <input type="number" class="input-mini" ng-model="panel.pages" ng-change="get_data()">
+      </div>
+      <div class="editor-option large">
+        <h6>Pageable</h6>
+        <strong class="large">= {{panel.size * panel.pages}}</strong>
+      </div>
+    </div>
+
+  </div>
+

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/terms/editor.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/terms/editor.html b/kibana-3.x/src/main/resources/app/panels/terms/editor.html
new file mode 100644
index 0000000..704bff3
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/terms/editor.html
@@ -0,0 +1,78 @@
+  <div class="editor-row">
+    <div class="section">
+      <h5>Parameters</h5>
+      <div class="editor-option">
+        <label class="small">Terms mode</label>
+        <select class="input-medium" ng-model="panel.tmode" ng-options="f for f in ['terms','terms_stats']" ng-change="set_refresh(true)"></select>
+      </div>
+      <div class="editor-option">
+        <label class="small">Field mode</label>
+        <select class="input-medium" ng-model="panel.fmode" ng-options="f for f in ['normal','script']" ng-change="set_refresh(true)"></select>
+      </div>
+      <div class="editor-option" ng-show="panel.tmode == 'terms_stats'">
+        <label class="small">Stats type</label>
+        <select class="input-medium" ng-model="panel.tstat" ng-options="f for f in ['count', 'total_count', 'min', 'max', 'total', 'mean']"></select>
+      </div>
+      <div class="editor-option" ng-show="panel.fmode == 'normal'">
+        <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-option" ng-show="panel.fmode == 'script'">
+        <label class="small">ScriptField</label>
+        <input type="text" class="input-large" ng-model="panel.script" ng-change="set_refresh(true)">
+      </div>
+      <div class="editor-option" ng-show="panel.tmode == 'terms_stats'">
+        <label class="small">Value field</label>
+        <input type="text" class="input-small" bs-typeahead="fields.list" ng-model="panel.valuefield" ng-change="set_refresh(true)">
+      </div>
+      <div class="editor-option">
+        <label class="small">Length</label>
+        <input class="input-small" type="number" ng-model="panel.size" ng-change="set_refresh(true)">
+      </div>
+      <div class="editor-option">
+        <label class="small">Order</label>
+        <select class="input-medium" ng-model="panel.order" ng-options="f for f in ['count','term','reverse_count','reverse_term']" ng-change="set_refresh(true)"  ng-show="panel.tmode == 'terms'"></select>
+        <select class="input-medium" ng-model="panel.order" ng-options="f for f in ['term', 'reverse_term', 'count', 'reverse_count', 'total', 'reverse_total', 'min', 'reverse_min', 'max', 'reverse_max', 'mean', 'reverse_mean']" ng-change="set_refresh(true)"  ng-show="panel.tmode == 'terms_stats'"></select>
+      </div>
+      <div class="editor-option" ng-show="panel.tmode == 'terms'">
+        <label class="small">Exclude Terms(s) (comma separated)</label>
+        <input array-join type="text" ng-model='panel.exclude'></input>
+      </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/0bcbfc59/kibana-3.x/src/main/resources/app/panels/terms/module.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/terms/module.html b/kibana-3.x/src/main/resources/app/panels/terms/module.html
new file mode 100644
index 0000000..6538986
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/terms/module.html
@@ -0,0 +1,111 @@
+<div ng-controller='terms' ng-init="init()">
+  <style>
+    .pieLabel { pointer-events: none }
+    .terms-legend-term {
+      word-break: break-all;
+    }
+
+    .terms-remaining {
+      bottom:0;
+      top:0;
+      background-color: #f00;
+    }
+
+    .terms-wrapper {
+      display: table;
+      width: 100%;
+    }
+
+    .terms-legend {
+      display: table-row;
+      height: 0;
+    }
+
+    .terms-legend {
+      display: table-row;
+    }
+  </style>
+
+
+  <div class="terms-wrapper">
+    <!-- LEGEND -->
+    <div class="terms-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="term in legend">
+          <td><i class="icon-circle" ng-style="{color:term.color}"></i></td>
+          <td class="terms-legend-term" style="padding-right:10px;padding-left:10px;">{{term.label}}</td>
+          <td>{{term.data[0][1]}}</td>
+        </tr>
+      </table>
+
+      <!-- horizontal legend above -->
+      <span class="small" ng-show="panel.arrangement == 'horizontal'" ng-repeat="term in legend" style="float:left;padding-left: 10px;">
+        <span>
+          <i class="icon-circle" ng-style="{color:term.color}"></i>
+          <span class="terms-legend-term">{{term.label}}</span> ({{term.data[0][1]}})
+        </span>
+      </span>
+
+      <span class="small pull-left" ng-show="panel.tmode == 'terms_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'" terms-chart params="{{panel}}" style="position:relative" class="pointer terms-chart">
+    </div>
+
+    <!-- LEGEND -->
+    <div class="terms-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="term in legend">
+          <td><i class="icon-circle" ng-style="{color:term.color}"></i></i></td>
+          <td class="terms-legend-term" style="padding-right:10px;padding-left:10px;">{{term.label}}</td>
+          <td>{{term.data[0][1]}}</td>
+        </tr>
+      </table>
+
+      <!-- horizontal legend below -->
+      <span class="small" ng-show="panel.arrangement == 'horizontal'" ng-repeat="term in legend" style="float:left;padding-left: 10px;">
+        <span>
+          <i class="icon-circle" ng-style="{color:term.color}"></i>
+          <span class="terms-legend-term">{{term.label}}</span> ({{term.data[0][1]}})
+        </span>
+      </span>
+
+      <span class="small pull-left" ng-show="panel.tmode == 'terms_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>Term</th> <th>{{ panel.tmode == 'terms_stats' ? panel.tstat : 'Count' }}</th>
+      <th ng-hide="panel.multiterms.length">Action</th>
+      <th ng-show="panel.multiterms.length"><button class="btn btn-mini btn-success" ng-click="multi_search()">Submit</button></th>
+    </thead>
+    <tr ng-repeat="term in data" ng-show="showMeta(term)">
+      <td class="terms-legend-term" ng-click="add_multi_search(term)">{{term.label}}</td>
+      <td>{{term.data[0][1]}}</td>
+      <td>
+        <span ng-hide="term.meta == 'other'">
+          <i class='icon-search pointer' ng-click="build_search(term)"></i>
+          <i class='icon-ban-circle pointer' ng-click="build_search(term,true)"></i>
+          <i class='icon-check pointer' ng-click="delete_multi_search(term)" ng-show="check_multi_search(term)"></i>
+        </span>
+      </td>
+    </tr>
+  </table>
+
+</div>

http://git-wip-us.apache.org/repos/asf/karaf-decanter/blob/0bcbfc59/kibana-3.x/src/main/resources/app/panels/terms/module.js
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/terms/module.js b/kibana-3.x/src/main/resources/app/panels/terms/module.js
new file mode 100644
index 0000000..533d11c
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/terms/module.js
@@ -0,0 +1,457 @@
+/** @scratch /panels/5
+ *
+ * include::panels/terms.asciidoc[]
+ */
+
+/** @scratch /panels/terms/0
+ *
+ * == terms
+ * Status: *Stable*
+ *
+ * A table, bar chart or pie chart based on the results of an Elasticsearch terms facet.
+ *
+ */
+define([
+  'angular',
+  'app',
+  'lodash',
+  'jquery',
+  'kbn'
+],
+function (angular, app, _, $, kbn) {
+  'use strict';
+
+  var module = angular.module('kibana.panels.terms', []);
+  app.useModule(module);
+
+  module.controller('terms', 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
+    var _d = {
+      /** @scratch /panels/terms/5
+       * === Parameters
+       *
+       * field:: The field on which to computer the facet
+       */
+      field   : '_type',
+      /** @scratch /panels/terms/5
+       * exclude:: terms to exclude from the results
+       */
+      exclude : [],
+      /** @scratch /panels/terms/5
+       * missing:: Set to false to disable the display of a counter showing how much results are
+       * missing the field
+       */
+      missing : true,
+      /** @scratch /panels/terms/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,
+      /** @scratch /panels/terms/5
+       * size:: Show this many terms
+       */
+      size    : 10,
+      /** @scratch /panels/terms/5
+       * order:: In terms mode: count, term, reverse_count or reverse_term,
+       * in terms_stats mode: term, reverse_term, count, reverse_count,
+       * total, reverse_total, min, reverse_min, max, reverse_max, mean or reverse_mean
+       */
+      order   : 'count',
+      style   : { "font-size": '10pt'},
+      /** @scratch /panels/terms/5
+       * donut:: In pie chart mode, draw a hole in the middle of the pie to make a tasty donut.
+       */
+      donut   : false,
+      /** @scratch /panels/terms/5
+       * tilt:: In pie chart mode, tilt the chart back to appear as more of an oval shape
+       */
+      tilt    : false,
+      /** @scratch /panels/terms/5
+       * lables:: In pie chart mode, draw labels in the pie slices
+       */
+      labels  : true,
+      /** @scratch /panels/terms/5
+       * arrangement:: In bar or pie mode, arrangement of the legend. horizontal or vertical
+       */
+      arrangement : 'horizontal',
+      /** @scratch /panels/terms/5
+       * chart:: table, bar or pie
+       */
+      chart       : 'bar',
+      /** @scratch /panels/terms/5
+       * counter_pos:: The location of the legend in respect to the chart, above, below, or none.
+       */
+      counter_pos : 'above',
+      /** @scratch /panels/terms/5
+       * spyable:: Set spyable to false to disable the inspect button
+       */
+      spyable     : true,
+      /** @scratch /panels/terms/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/terms/5
+       * multiterms:: Multi terms: used to either filterSrv
+       */
+      multiterms  : [],
+      /** @scratch /panels/terms/5
+       * fmode:: Field mode: normal or script
+       */
+      fmode       : 'normal',
+      /** @scratch /panels/terms/5
+       * tmode:: Facet mode: terms or terms_stats
+       */
+      tmode       : 'terms',
+      /** @scratch /panels/terms/5
+       * tstat:: Terms_stats facet stats field
+       */
+      tstat       : 'total',
+      /** @scratch /panels/terms/5
+       * valuefield:: Terms_stats facet value field
+       */
+      valuefield  : ''
+    };
+
+    _.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,
+        terms_facet,
+        termstats_facet,
+        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));
+      });
+
+      // Terms mode
+      if($scope.panel.tmode === 'terms') {
+        terms_facet = $scope.ejs.TermsFacet('terms')
+          .field($scope.field)
+          .size($scope.panel.size)
+          .order($scope.panel.order)
+          .exclude($scope.panel.exclude)
+          .facetFilter($scope.ejs.QueryFilter(
+            $scope.ejs.FilteredQuery(
+              boolQuery,
+              filterSrv.getBoolFilter(filterSrv.ids())
+            )));
+        if($scope.panel.fmode === 'script') {
+          terms_facet.scriptField($scope.panel.script)
+        }
+        request = request.facet(terms_facet).size(0);
+      }
+      if($scope.panel.tmode === 'terms_stats') {
+        termstats_facet = $scope.ejs.TermStatsFacet('terms')
+          .valueField($scope.panel.valuefield)
+          .keyField($scope.field)
+          .size($scope.panel.size)
+          .order($scope.panel.order)
+          .facetFilter($scope.ejs.QueryFilter(
+            $scope.ejs.FilteredQuery(
+              boolQuery,
+              filterSrv.getBoolFilter(filterSrv.ids())
+            )));
+        if($scope.panel.fmode === 'script') {
+          termstats_facet.scriptField($scope.panel.script)
+        }
+        request = request.facet(termstats_facet).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 === 'terms') {
+          $scope.hits = results.hits.total;
+        }
+
+        $scope.results = results;
+
+        $scope.$emit('render');
+      });
+    };
+
+    $scope.build_search = function(term,negate) {
+      if($scope.panel.fmode === 'script') {
+        filterSrv.set({type:'script',script:$scope.panel.script + ' == \"' + term.label + '\"',
+          mandate:(negate ? 'mustNot':'must')});
+      } else if(_.isUndefined(term.meta)) {
+        filterSrv.set({type:'terms',field:$scope.field,value:term.label,
+          mandate:(negate ? 'mustNot':'must')});
+      } else if(term.meta === 'missing') {
+        filterSrv.set({type:'exists',field:$scope.field,
+          mandate:(negate ? 'must':'mustNot')});
+      } else {
+        return;
+      }
+    };
+
+    var build_multi_search = function(term) {
+      if($scope.panel.fmode === 'script') {
+        return({type:'script',script:$scope.panel.script + ' == \"' + term.label + '\"',
+          mandate:'either', alias: term.label});
+      } else if(_.isUndefined(term.meta)) {
+        return({type:'terms',field:$scope.field,value:term.label, mandate:'either'});
+      } else if(term.meta === 'missing') {
+        return({type:'exists',field:$scope.field, mandate:'either'});
+      } else {
+        return;
+      }
+    };
+
+    $scope.multi_search = function() {
+      _.each($scope.panel.multiterms, function(t) {
+        var f = build_multi_search(t);
+        filterSrv.set(f, undefined, true)
+      });
+      dashboard.refresh();
+    };
+    $scope.add_multi_search = function(term) {
+      $scope.panel.multiterms.push(term);
+    };
+    $scope.delete_multi_search = function(term) {
+      _.remove($scope.panel.multiterms, term);
+    };
+    $scope.check_multi_search = function(term) {
+      return _.indexOf($scope.panel.multiterms, term) >= 0;
+    };
+
+    $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(term) {
+      if(_.isUndefined(term.meta)) {
+        return true;
+      }
+      if(term.meta === 'other' && !$scope.panel.other) {
+        return false;
+      }
+      if(term.meta === 'missing' && !$scope.panel.missing) {
+        return false;
+      }
+      return true;
+    };
+
+  });
+
+  module.directive('termsChart', 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.terms.terms, function(v) {
+            var slice;
+            if(scope.panel.tmode === 'terms') {
+              slice = { label : v.term, data : [[k,v.count]], actions: true};
+            }
+            if(scope.panel.tmode === 'terms_stats') {
+              slice = { label : v.term, data : [[k,v[scope.panel.tstat]]], actions: true};
+            }
+            scope.data.push(slice);
+            k = k + 1;
+          });
+
+          scope.data.push({label:'Missing field',
+            data:[[k,scope.results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0});
+
+          if(scope.panel.tmode === 'terms') {
+            scope.data.push({label:'Other values',
+              data:[[k+1,scope.results.facets.terms.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/0bcbfc59/kibana-3.x/src/main/resources/app/panels/text/editor.html
----------------------------------------------------------------------
diff --git a/kibana-3.x/src/main/resources/app/panels/text/editor.html b/kibana-3.x/src/main/resources/app/panels/text/editor.html
new file mode 100644
index 0000000..02177bc
--- /dev/null
+++ b/kibana-3.x/src/main/resources/app/panels/text/editor.html
@@ -0,0 +1,16 @@
+<div>
+  <div class="row-fluid">
+    <div class="span4">
+      <label class="small">Mode</label> <select class="input-medium" ng-model="panel.mode" ng-options="f for f in ['html','markdown','text']"></select>
+    </div>
+    <div class="span2" ng-show="panel.mode == 'text'">
+      <label class="small">Font Size</label> <select class="input-mini" ng-model="panel.style['font-size']" ng-options="f for f in ['6pt','7pt','8pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select>
+    </div>
+  </div>
+
+  <label class=small>Content 
+    <span ng-show="panel.mode == 'html'">(This area uses HTML sanitized via AngularJS's <a href='http://docs.angularjs.org/api/ngSanitize.$sanitize'>$sanitize</a> service)</span>
+    <span ng-show="panel.mode == 'markdown'">(This area uses <a target="_blank" href="http://en.wikipedia.org/wiki/Markdown">Markdown</a>. HTML is not supported)</span>
+  </label>
+  <textarea ng-model="panel.content" rows="6" style="width:95%"></textarea>
+</div>
\ No newline at end of file


Mime
View raw message