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

This commit is contained in:
Rashid Khan 2013-10-12 17:08:16 +02:00
parent cfceadc87d
commit c6b1503950
10 changed files with 228 additions and 17 deletions

View File

@ -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();

View File

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

View File

@ -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();
}
}
};
});
});

View File

@ -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)) {

View File

@ -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>

View File

@ -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">

View File

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

View File

@ -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();
});
});

View File

@ -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 || '*');
}

View File

@ -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">