Просмотр исходного кода

added regular expression queries and esVersion service+directive+filter to allow a given element to require a specified elasticsearch version

Rashid Khan 12 лет назад
Родитель
Сommit
c6b1503950

+ 10 - 6
src/app/controllers/dash.js

@@ -10,13 +10,15 @@ function (angular, config, _) {
   var module = angular.module('kibana.controllers');
 
   module.controller('DashCtrl', function(
-    $scope, $route, ejsResource, fields, dashboard, alertSrv, panelMove) {
+    $scope, $route, ejsResource, fields, dashboard, alertSrv, panelMove, esVersion) {
+
+    $scope.requiredElasticSearchVersion = ">=0.20.5";
+
     $scope.editor = {
       index: 0
     };
 
-    // For moving stuff around the dashboard. Needs better names
-    $scope.panelMove = panelMove;
+    // For moving stuff around the dashboard.
     $scope.panelMoveDrop = panelMove.onDrop;
     $scope.panelMoveStart = panelMove.onStart;
     $scope.panelMoveStop = panelMove.onStop;
@@ -24,16 +26,18 @@ function (angular, config, _) {
     $scope.panelMoveOut = panelMove.onOut;
 
 
-
     $scope.init = function() {
       $scope.config = config;
-      // Make underscore.js available to views
+      // Make stuff, including underscore.js available to views
       $scope._ = _;
       $scope.dashboard = dashboard;
       $scope.dashAlerts = alertSrv;
+      $scope.esVersion = esVersion;
+
+      // Clear existing alerts
       alertSrv.clearAll();
 
-      // Provide a global list of all see fields
+      // Provide a global list of all seen fields
       $scope.fields = fields;
       $scope.reset_row();
 

+ 2 - 1
src/app/directives/all.js

@@ -7,5 +7,6 @@ define([
   './ngBlur',
   './ngModelOnBlur',
   './tip',
-  './confirmClick'
+  './confirmClick',
+  './esVersion'
 ], function () {});

+ 25 - 0
src/app/directives/esVersion.js

@@ -0,0 +1,25 @@
+/*
+  Only show an element if it meets an Elasticsearch version requirement
+*/
+
+define([
+  'angular',
+  'app',
+],
+function (angular) {
+  'use strict';
+
+  angular
+    .module('kibana.directives')
+    .directive('esVersion', function(esVersion) {
+      return {
+        restrict: 'A',
+        link: function(scope, elem, attr) {
+          if(!esVersion.is(attr.esVersion)) {
+            console.log('hiding');
+            elem.hide();
+          }
+        }
+      };
+    });
+});

+ 12 - 0
src/app/filters/all.js

@@ -24,6 +24,18 @@ define(['angular', 'jquery', 'underscore', 'moment'], function (angular, $, _, m
     };
   });
 
+  /*
+    Filter an array of objects by elasticsearch version requirements
+  */
+  module.filter('esVersion', function(esVersion) {
+    return function(items, require) {
+      var ret = _.filter(items,function(qt) {
+        return esVersion.is(qt[require]) ? true : false;
+      });
+      return ret;
+    };
+  });
+
   module.filter('slice', function() {
     return function(arr, start, end) {
       if(!_.isUndefined(arr)) {

+ 11 - 4
src/app/panels/query/meta.html

@@ -1,4 +1,4 @@
-<div class="panel-query-meta row-fluid" style="width:170px">
+<div class="panel-query-meta row-fluid" style="width:220px">
 
   <style>
     .input-query-alias {
@@ -10,12 +10,19 @@
 
   </style>
   <a class="close" ng-click="render();dismiss();" href="">×</a>
-  <i ng-click="toggle_pin(id);dismiss();" class="small pointer icon-pushpin"></i> 
-  <label class="strong small ">Query Alias</label> 
+  <label class="strong small ">Query Alias <button class="btn btn-mini" ng-class="{active:querySrv.list[id].pin}" ng-click="toggle_pin(id);dismiss();" class="pointer"><i class="icon-pushpin"></i></button></label>
+
   <form>
-    <input class="input-medium input-query-alias" type="text" ng-model="querySrv.list[id].alias" placeholder='Alias...' />
+    <input class="input-large input-query-alias" type="text" ng-model="querySrv.list[id].alias" placeholder='Alias...' />
     <div>
       <i ng-repeat="color in querySrv.colors" class="pointer" ng-class="{'icon-circle-blank':querySrv.list[id].color == color,'icon-circle':querySrv.list[id].color != color}" ng-style="{color:color}" ng-click="querySrv.list[id].color = color;render();"> </i>
     </div>
   </form>
+
+  <span>
+    <label class="small">Query type</label>
+    <select ng-change="dismiss();" class="input-small" ng-model="querySrv.list[id].type">
+      <option ng-repeat="type in querySrv.queryTypes|esVersion:'require'">{{type.name}}</option>
+    </select>
+  </span>
 </div>

+ 7 - 5
src/app/panels/query/module.html

@@ -2,10 +2,12 @@
   <div ng-repeat="id in (unPinnedQueries = (querySrv.ids|pinnedQuery:false))" ng-class="{'short-query': unPinnedQueries.length>1}">
     <form class="form-search" style="position:relative;margin-bottom:5px;" ng-submit="refresh()">
       <span class="begin-query">
-        <i class="icon-circle pointer" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="rightTop" ng-style="{color: querySrv.list[id].color}"></i>
+        <i class="icon-circle pointer" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft" ng-style="{color: querySrv.list[id].color}"></i>
         <i class="icon-remove-sign pointer remove-query" ng-show="querySrv.ids.length > 1" ng-click="querySrv.remove(id);refresh()"></i>
       </span>
-      <input class="search-query panel-query" ng-class="{ 'input-block-level': unPinnedQueries.length==1, 'last-query': $last, 'has-remove': querySrv.ids.length > 1 }" bs-typeahead="panel.history" data-min-length=0 data-items=100 type="text" ng-model="querySrv.list[id].query" />
+      <span>
+        <input class="search-query panel-query" ng-class="{ 'input-block-level': unPinnedQueries.length==1, 'last-query': $last, 'has-remove': querySrv.ids.length > 1 }" bs-typeahead="panel.history" data-min-length=0 data-items=100 type="text" ng-model="querySrv.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>
@@ -13,9 +15,9 @@
     </form>
   </div>
   <div style="display:inline-block" ng-repeat="id in querySrv.ids|pinnedQuery:true">
-    <span class="pointer" ng-show="$first" ng-click="panel.pinned = !panel.pinned"><small class="pins">Pinned</small> <i ng-class="{'icon-caret-right':panel.pinned,'icon-caret-left':!panel.pinned}"></i></span>
-    <span ng-show="panel.pinned" class="pinned badge">
-      <i class="icon-circle pointer" ng-style="{color: querySrv.list[id].color}" data-unique="1" bs-popover="'app/panels/query/meta.html'"></i><span bs-tooltip="querySrv.list[id].query"> {{querySrv.list[id].alias || querySrv.list[id].query}}</span>
+    <span class="pointer" ng-show="$first" ng-click="panel.pinned = !panel.pinned"><span class="pins">Pinned</span> <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-style="{color: querySrv.list[id].color}" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft"></i><span bs-tooltip="querySrv.list[id].query"> {{querySrv.list[id].alias || querySrv.list[id].query}}</span>
     </span>
   </div>
   <span style="display:inline-block" ng-show="unPinnedQueries.length == 0">

+ 2 - 1
src/app/services/all.js

@@ -6,6 +6,7 @@ define([
   './kbnIndex',
   './querySrv',
   './timer',
-  './panelMove'
+  './panelMove',
+  './esVersion'
 ],
 function () {});

+ 150 - 0
src/app/services/esVersion.js

@@ -0,0 +1,150 @@
+define([
+  'angular',
+  'underscore',
+  'config'
+],
+function (angular, _, config) {
+  'use strict';
+
+  var module = angular.module('kibana.services');
+
+  module.service('esVersion', function($http, alertSrv) {
+
+    this.versions = [];
+
+    // save a reference to this
+    var self = this;
+
+    this.init = function() {
+      getVersions();
+    };
+
+    var getVersions = function() {
+      var nodeInfo = $http({
+        url: config.elasticsearch + '/_nodes',
+        method: "GET"
+      }).error(function(data, status) {
+        if(status === 0) {
+          alertSrv.set('Error',"Could not contact Elasticsearch at "+config.elasticsearch+
+            ". Please ensure that Elasticsearch is reachable from your system." ,'error');
+        } else {
+          alertSrv.set('Error',"Could not reach "+config.elasticsearch+"/_nodes. If you"+
+          " are using a proxy, ensure it is configured correctly",'error');
+        }
+      });
+
+      return nodeInfo.then(function(p) {
+        _.each(p.data.nodes, function(v) {
+          self.versions.push(v.version.split('-')[0]);
+        });
+        self.versions = sortVersions(_.uniq(self.versions));
+      });
+    };
+
+    // Get the max version in this cluster
+    this.max = function() {
+      return _.last(self.versions);
+    };
+
+    // Return the lowest version in the cluster
+    this.min = function() {
+      return _.first(self.versions);
+    };
+
+    // Sort versions from lowest to highest
+    var sortVersions = function(versions) {
+      var _versions = _.clone(versions),
+        _r = [];
+
+      while(_r.length < versions.length) {
+        var _h = "0";
+        /*jshint -W083 */
+        _.each(_versions,function(v){
+          if(self.compare(_h,v)) {
+            _h = v;
+          }
+        });
+        _versions = _.without(_versions,_h);
+        _r.push(_h);
+      }
+      return _r.reverse();
+    };
+
+    /*
+      Takes a version string with one of the following optional comparison prefixes: >,>=,<.<=
+      and evaluates if the cluster meets the requirement. If the prefix is omitted exact match
+      is assumed
+    */
+    this.is = function(equation) {
+      var _v = equation,
+        _cf;
+
+      if(_v.charAt(0) === '>') {
+        _cf = _v.charAt(1) === '=' ? self.gte(_v.slice(2)) : self.gt(_v.slice(1));
+      } else if (_v.charAt(0) === '<') {
+        _cf = _v.charAt(1) === '=' ? self.lte(_v.slice(2)) : self.lt(_v.slice(1));
+      } else {
+        _cf = self.eq(_v);
+      }
+
+      return _cf;
+    };
+
+    // check if lowest version in cluster = `version`
+    this.eq = function(version) {
+      return version === self.min() ? true : false;
+    };
+
+    // version > lowest version in cluster?
+    this.gt = function(version) {
+      return version === self.min() ? false : self.gte(version);
+    };
+
+    // version < highest version in cluster?
+    this.lt = function(version) {
+      return version === self.max() ? false : self.lte(version);
+    };
+
+    // Check if the lowest version in the cluster is >= to `version`
+    this.gte = function(version) {
+      return self.compare(version,self.min());
+    };
+
+    // Check if the highest version in the cluster is <= to `version`
+    this.lte = function(version) {
+      return self.compare(self.max(),version);
+    };
+
+    // Determine if a specific version is greater than or equal to another
+    this.compare = function (required,installed) {
+      var a = installed.split('.');
+      var b = required.split('.');
+      var i;
+
+      for (i = 0; i < a.length; ++i) {
+        a[i] = Number(a[i]);
+      }
+      for (i = 0; i < b.length; ++i) {
+        b[i] = Number(b[i]);
+      }
+      if (a.length === 2) {
+        a[2] = 0;
+      }
+
+      if (a[0] > b[0]){return true;}
+      if (a[0] < b[0]){return false;}
+
+      if (a[1] > b[1]){return true;}
+      if (a[1] < b[1]){return false;}
+
+      if (a[2] > b[2]){return true;}
+      if (a[2] < b[2]){return false;}
+
+      return true;
+    };
+
+    this.init();
+
+  });
+
+});

+ 8 - 0
src/app/services/querySrv.js

@@ -39,6 +39,12 @@ function (angular, _, config) {
       "#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7"  //7
     ];
 
+    // Define the query types and the version of elasticsearch they were first available in
+    this.queryTypes = [
+      {name:'lucene',require:">=0.17.0"},
+      {name:'regex',require:">=0.90.3"}
+    ];
+
 
     // Save a reference to this
     var self = this;
@@ -104,6 +110,8 @@ function (angular, _, config) {
       {
       case 'lucene':
         return ejs.QueryStringQuery(q.query || '*');
+      case 'regex':
+        return ejs.RegexpQuery('_all',q.query);
       default:
         return _.isUndefined(q.query) ? false : ejs.QueryStringQuery(q.query || '*');
       }

+ 1 - 0
src/index.html

@@ -22,6 +22,7 @@
 
   <body ng-cloak>
 
+
     <link rel="stylesheet" ng-href="css/bootstrap.{{dashboard.current.style||'dark'}}.min.css">
     <link rel="stylesheet" href="css/bootstrap-responsive.min.css">
     <link rel="stylesheet" href="css/font-awesome.min.css">