Skip to content

Commit

Permalink
added regular expression queries and esVersion service+directive+filt…
Browse files Browse the repository at this point in the history
…er to allow a given element to require a specified elasticsearch version
  • Loading branch information
Rashid Khan committed Oct 12, 2013
1 parent cfceadc commit c6b1503
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 17 deletions.
16 changes: 10 additions & 6 deletions src/app/controllers/dash.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,34 @@ 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;
$scope.panelMoveOver = panelMove.onOver;
$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();

Expand Down
3 changes: 2 additions & 1 deletion src/app/directives/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ define([
'./ngBlur',
'./ngModelOnBlur',
'./tip',
'./confirmClick'
'./confirmClick',
'./esVersion'
], function () {});
25 changes: 25 additions & 0 deletions src/app/directives/esVersion.js
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions src/app/filters/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
15 changes: 11 additions & 4 deletions src/app/panels/query/meta.html
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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>
12 changes: 7 additions & 5 deletions src/app/panels/query/module.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
<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>
</span>
</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">
Expand Down
3 changes: 2 additions & 1 deletion src/app/services/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ define([
'./kbnIndex',
'./querySrv',
'./timer',
'./panelMove'
'./panelMove',
'./esVersion'
],
function () {});
150 changes: 150 additions & 0 deletions src/app/services/esVersion.js
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 0 deletions src/app/services/querySrv.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 || '*');
}
Expand Down
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down

1 comment on commit c6b1503

@mattweber
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recent versions of elasticjs support node info so you don't need to use $http if you don't want to.

Please sign in to comment.