Commit c03373c6 by Rashid Khan

linting and added filter states

parent 254a553e
...@@ -12,9 +12,9 @@ var modules = [ ...@@ -12,9 +12,9 @@ var modules = [
'$strap.directives', '$strap.directives',
'kibana.panels', 'kibana.panels',
'ngSanitize', 'ngSanitize',
] ];
var scripts = [] var scripts = [];
var labjs = $LAB var labjs = $LAB
.script("common/lib/jquery-1.8.0.min.js").wait() .script("common/lib/jquery-1.8.0.min.js").wait()
...@@ -34,12 +34,12 @@ var labjs = $LAB ...@@ -34,12 +34,12 @@ var labjs = $LAB
.script("js/controllers.js") .script("js/controllers.js")
.script("js/filters.js") .script("js/filters.js")
.script("js/directives.js") .script("js/directives.js")
.script("js/panels.js").wait() .script("js/panels.js").wait();
_.each(config.modules, function(v) { _.each(config.modules, function(v) {
labjs = labjs.script('panels/'+v+'/module.js') labjs = labjs.script('panels/'+v+'/module.js');
modules.push('kibana.'+v) modules.push('kibana.'+v);
}) });
/* Application level module which depends on filters, controllers, and services */ /* Application level module which depends on filters, controllers, and services */
labjs.wait(function(){ labjs.wait(function(){
...@@ -59,7 +59,7 @@ labjs.wait(function(){ ...@@ -59,7 +59,7 @@ labjs.wait(function(){
}); });
}]); }]);
angular.element(document).ready(function() { angular.element(document).ready(function() {
$('body').attr('ng-controller', 'DashCtrl') $('body').attr('ng-controller', 'DashCtrl');
angular.bootstrap(document, ['kibana']); angular.bootstrap(document, ['kibana']);
}); });
}); });
...@@ -11,7 +11,7 @@ angular.module('kibana.controllers', []) ...@@ -11,7 +11,7 @@ angular.module('kibana.controllers', [])
editable: true, editable: true,
rows: [], rows: [],
last: null last: null
} };
$scope.init = function() { $scope.init = function() {
...@@ -22,16 +22,16 @@ angular.module('kibana.controllers', []) ...@@ -22,16 +22,16 @@ angular.module('kibana.controllers', [])
$scope.dashboard = dashboard; $scope.dashboard = dashboard;
// Provide a global list of all see fields // Provide a global list of all see fields
$scope.fields = fields $scope.fields = fields;
$scope.reset_row(); $scope.reset_row();
$scope.clear_all_alerts(); $scope.clear_all_alerts();
var ejs = $scope.ejs = ejsResource(config.elasticsearch); var ejs = $scope.ejs = ejsResource(config.elasticsearch);
} };
$scope.add_row = function(dash,row) { $scope.add_row = function(dash,row) {
dash.rows.push(row); dash.rows.push(row);
} };
$scope.reset_row = function() { $scope.reset_row = function() {
$scope.row = { $scope.row = {
...@@ -42,8 +42,8 @@ angular.module('kibana.controllers', []) ...@@ -42,8 +42,8 @@ angular.module('kibana.controllers', [])
}; };
$scope.row_style = function(row) { $scope.row_style = function(row) {
return { 'min-height': row.collapse ? '5px' : row.height } return { 'min-height': row.collapse ? '5px' : row.height };
} };
$scope.alert = function(title,text,severity,timeout) { $scope.alert = function(title,text,severity,timeout) {
var alert = { var alert = {
...@@ -52,30 +52,34 @@ angular.module('kibana.controllers', []) ...@@ -52,30 +52,34 @@ angular.module('kibana.controllers', [])
severity: severity || 'info', severity: severity || 'info',
}; };
$scope.global_alert.push(alert); $scope.global_alert.push(alert);
if (timeout > 0) if (timeout > 0) {
$timeout(function() { $timeout(function() {
$scope.global_alert = _.without($scope.global_alert,alert) $scope.global_alert = _.without($scope.global_alert,alert);
}, timeout); }, timeout);
} }
};
$scope.clear_alert = function(alert) { $scope.clear_alert = function(alert) {
$scope.global_alert = _.without($scope.global_alert,alert); $scope.global_alert = _.without($scope.global_alert,alert);
} };
$scope.clear_all_alerts = function() { $scope.clear_all_alerts = function() {
$scope.global_alert = [] $scope.global_alert = [];
} };
$scope.edit_path = function(type) { $scope.edit_path = function(type) {
if(type) if(type) {
return 'panels/'+type+'/editor.html'; return 'panels/'+type+'/editor.html';
} else {
return false;
} }
};
// This is whoafully incomplete, but will do for now // This is whoafully incomplete, but will do for now
$scope.parse_error = function(data) { $scope.parse_error = function(data) {
var _error = data.match("nested: (.*?);") var _error = data.match("nested: (.*?);");
return _.isNull(_error) ? data : _error[1]; return _.isNull(_error) ? data : _error[1];
} };
$scope.init(); $scope.init();
...@@ -89,31 +93,32 @@ angular.module('kibana.controllers', []) ...@@ -89,31 +93,32 @@ angular.module('kibana.controllers', [])
collapsable: true, collapsable: true,
editable: true, editable: true,
panels: [], panels: [],
} };
_.defaults($scope.row,_d)
_.defaults($scope.row,_d);
$scope.init = function() { $scope.init = function() {
$scope.reset_panel(); $scope.reset_panel();
} };
$scope.toggle_row = function(row) { $scope.toggle_row = function(row) {
row.collapse = row.collapse ? false : true; row.collapse = row.collapse ? false : true;
if (!row.collapse) { if (!row.collapse) {
$timeout(function() { $timeout(function() {
$scope.$broadcast('render') $scope.$broadcast('render');
}); });
} }
} };
// This can be overridden by individual panel // This can be overridden by individual panels
$scope.close_edit = function() { $scope.close_edit = function() {
$scope.$broadcast('render') $scope.$broadcast('render');
} };
$scope.add_panel = function(row,panel) { $scope.add_panel = function(row,panel) {
$scope.row.panels.push(panel); $scope.row.panels.push(panel);
} };
$scope.reset_panel = function() { $scope.reset_panel = function() {
$scope.panel = { $scope.panel = {
...@@ -121,7 +126,7 @@ angular.module('kibana.controllers', []) ...@@ -121,7 +126,7 @@ angular.module('kibana.controllers', [])
error : false, error : false,
span : 3, span : 3,
editable: true, editable: true,
group : ['default'], group : ['default']
}; };
}; };
......
...@@ -24,7 +24,7 @@ angular.module('kibana.directives', []) ...@@ -24,7 +24,7 @@ angular.module('kibana.directives', [])
var template = '<div ng-controller="'+scope.panel.type+'" ng-include src="\''+scope.edit_path(scope.panel.type)+'\'"></div>'; var template = '<div ng-controller="'+scope.panel.type+'" ng-include src="\''+scope.edit_path(scope.panel.type)+'\'"></div>';
elem.html($compile(angular.element(template))(scope)); elem.html($compile(angular.element(template))(scope));
} }
}) });
} }
}; };
}) })
...@@ -39,11 +39,13 @@ angular.module('kibana.directives', []) ...@@ -39,11 +39,13 @@ angular.module('kibana.directives', [])
} }
function join_array(text) { function join_array(text) {
if(_.isArray(text)) if(_.isArray(text)) {
return (text || '').join(','); return (text || '').join(',');
else } else {
return text return text;
}
} }
ngModel.$parsers.push(split_array); ngModel.$parsers.push(split_array);
ngModel.$formatters.push(join_array); ngModel.$formatters.push(join_array);
} }
...@@ -54,7 +56,9 @@ angular.module('kibana.directives', []) ...@@ -54,7 +56,9 @@ angular.module('kibana.directives', [])
restrict: 'A', restrict: 'A',
require: 'ngModel', require: 'ngModel',
link: function(scope, elm, attr, ngModelCtrl) { link: function(scope, elm, attr, ngModelCtrl) {
if (attr.type === 'radio' || attr.type === 'checkbox') return; if (attr.type === 'radio' || attr.type === 'checkbox') {
return;
}
elm.unbind('input').unbind('keydown').unbind('change'); elm.unbind('input').unbind('keydown').unbind('change');
elm.bind('blur', function() { elm.bind('blur', function() {
...@@ -65,5 +69,4 @@ angular.module('kibana.directives', []) ...@@ -65,5 +69,4 @@ angular.module('kibana.directives', [])
} }
}; };
}); });
;
...@@ -6,5 +6,5 @@ angular.module('kibana.filters', []) ...@@ -6,5 +6,5 @@ angular.module('kibana.filters', [])
.filter('stringSort', function() { .filter('stringSort', function() {
return function(input) { return function(input) {
return input.sort(); return input.sort();
} };
}); });
\ No newline at end of file
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
/*global angular:true */ /*global angular:true */
'use strict'; 'use strict';
angular.module('kibana.panels', []) angular.module('kibana.panels', []);
/*jshint globalstrict:true */ /*jshint globalstrict:true */
/*global angular:true */ /*global angular:true */
/*global Blob:false*/
'use strict'; 'use strict';
angular.module('kibana.services', []) angular.module('kibana.services', [])
.service('eventBus', function($rootScope) { .service('eventBus', function($rootScope) {
// An array of registed types // An array of registed types
var _types = [] var _types = [];
this.broadcast = function(from,to,type,data) { this.broadcast = function(from,to,type,data) {
if(_.isUndefined(data)) if(_.isUndefined(data)) {
var data = from data = from;
}
var packet = { var packet = {
time: new Date(), time: new Date(),
...@@ -18,37 +20,40 @@ angular.module('kibana.services', []) ...@@ -18,37 +20,40 @@ angular.module('kibana.services', [])
from: from, from: from,
to: to, to: to,
data: data data: data
} };
if(_.contains(_types,'$kibana_debug')) if(_.contains(_types,'$kibana_debug')) {
$rootScope.$broadcast('$kibana_debug',packet); $rootScope.$broadcast('$kibana_debug',packet);
}
$rootScope.$broadcast(type,{ $rootScope.$broadcast(type,{
from: from, from: from,
to: to, to: to,
data: data data: data
}); });
} };
// This sets up an $on listener that checks to see if the event (packet) is // This sets up an $on listener that checks to see if the event (packet) is
// addressed to the scope in question and runs the registered function if it // addressed to the scope in question and runs the registered function if it
// is. // is.
this.register = function(scope,type,fn) { this.register = function(scope,type,fn) {
_types = _.union(_types,[type]) _types = _.union(_types,[type]);
scope.$on(type,function(event,packet){ scope.$on(type,function(event,packet){
var _id = scope.$id; var _id = scope.$id;
var _to = packet.to; var _to = packet.to;
var _from = packet.from; var _from = packet.from;
var _type = packet.type var _type = packet.type;
var _time = packet.time var _time = packet.time;
var _group = (!(_.isUndefined(scope.panel))) ? scope.panel.group : ["NONE"] var _group = (!(_.isUndefined(scope.panel))) ? scope.panel.group : ["NONE"];
if(!(_.isArray(_to))) if(!(_.isArray(_to))) {
_to = [_to]; _to = [_to];
if(!(_.isArray(_group))) }
if(!(_.isArray(_group))) {
_group = [_group]; _group = [_group];
}
// Transmit event only if the sender is not the receiver AND one of the following: // Transmit event only if the sender is not the receiver AND one of the following:
// 1) Receiver has group in _to 2) Receiver's $id is in _to // 1) Receiver has group in _to 2) Receiver's $id is in _to
...@@ -62,7 +67,7 @@ angular.module('kibana.services', []) ...@@ -62,7 +67,7 @@ angular.module('kibana.services', [])
fn(event,packet.data,{time:_time,to:_to,from:_from,type:_type}); fn(event,packet.data,{time:_time,to:_to,from:_from,type:_type});
} }
}); });
} };
}) })
/* /*
Service: fields Service: fields
...@@ -71,11 +76,11 @@ angular.module('kibana.services', []) ...@@ -71,11 +76,11 @@ angular.module('kibana.services', [])
.factory('fields', function($rootScope) { .factory('fields', function($rootScope) {
var fields = { var fields = {
list : [] list : []
} };
$rootScope.$on('fields', function(event,f) { $rootScope.$on('fields', function(event,f) {
fields.list = _.union(f.data.all,fields.list) fields.list = _.union(f.data.all,fields.list);
}) });
return fields; return fields;
...@@ -93,8 +98,8 @@ angular.module('kibana.services', []) ...@@ -93,8 +98,8 @@ angular.module('kibana.services', [])
return all_indices().then(function(p) { return all_indices().then(function(p) {
var indices = _.intersection(possible,p); var indices = _.intersection(possible,p);
indices.reverse(); indices.reverse();
return indices return indices;
}) });
}; };
// returns a promise containing an array of all indices in an elasticsearch // returns a promise containing an array of all indices in an elasticsearch
...@@ -110,7 +115,11 @@ angular.module('kibana.services', []) ...@@ -110,7 +115,11 @@ angular.module('kibana.services', [])
return something.then(function(p) { return something.then(function(p) {
var indices = []; var indices = [];
_.each(p.data, function(v,k) { _.each(p.data, function(v,k) {
indices.push(k) indices.push(k);
// Also add the aliases. Could be expensive on systems with a lot of them
_.each(v.aliases, function(v, k) {
indices.push(k);
});
}); });
return indices; return indices;
}); });
...@@ -122,7 +131,7 @@ angular.module('kibana.services', []) ...@@ -122,7 +131,7 @@ angular.module('kibana.services', [])
// Update: I just read this again. I died a little more inside. // Update: I just read this again. I died a little more inside.
// Update2: More death. // Update2: More death.
function fake_utc(date) { function fake_utc(date) {
date = moment(date).clone().toDate() date = moment(date).clone().toDate();
return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)); return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000));
} }
...@@ -136,20 +145,20 @@ angular.module('kibana.services', []) ...@@ -136,20 +145,20 @@ angular.module('kibana.services', [])
range.push(start.clone()); range.push(start.clone());
switch (interval) { switch (interval) {
case 'hour': case 'hour':
start.add('hours',1) start.add('hours',1);
break break;
case 'day': case 'day':
start.add('days',1) start.add('days',1);
break break;
case 'week': case 'week':
start.add('weeks',1) start.add('weeks',1);
break break;
case 'month': case 'month':
start.add('months',1) start.add('months',1);
break break;
case 'year': case 'year':
start.add('years',1) start.add('years',1);
break break;
} }
} }
range.push(moment(end).clone()); range.push(moment(end).clone());
...@@ -169,19 +178,19 @@ angular.module('kibana.services', []) ...@@ -169,19 +178,19 @@ angular.module('kibana.services', [])
this.register = function(promise) { this.register = function(promise) {
timers.push(promise); timers.push(promise);
return promise; return promise;
} };
this.cancel = function(promise) { this.cancel = function(promise) {
timers = _.without(timers,promise) timers = _.without(timers,promise);
$timeout.cancel(promise) $timeout.cancel(promise);
} };
this.cancel_all = function() { this.cancel_all = function() {
_.each(timers, function(t){ _.each(timers, function(t){
$timeout.cancel(t); $timeout.cancel(t);
}); });
timers = new Array(); timers = [];
} };
}) })
.service('query', function(dashboard) { .service('query', function(dashboard) {
...@@ -214,10 +223,10 @@ angular.module('kibana.services', []) ...@@ -214,10 +223,10 @@ angular.module('kibana.services', [])
self.list = dashboard.current.services.query.list; self.list = dashboard.current.services.query.list;
self.ids = dashboard.current.services.query.ids; self.ids = dashboard.current.services.query.ids;
if (self.ids.length == 0) { if (self.ids.length === 0) {
self.set({}); self.set({});
} }
} };
// This is used both for adding queries and modifying them. If an id is passed, the query at that id is updated // This is used both for adding queries and modifying them. If an id is passed, the query at that id is updated
this.set = function(query,id) { this.set = function(query,id) {
...@@ -235,42 +244,44 @@ angular.module('kibana.services', []) ...@@ -235,42 +244,44 @@ angular.module('kibana.services', [])
alias: '', alias: '',
color: colorAt(_id), color: colorAt(_id),
id: _id id: _id
} };
_.defaults(query,_query) _.defaults(query,_query);
self.list[_id] = query; self.list[_id] = query;
self.ids.push(_id) self.ids.push(_id);
return _id; return _id;
} }
} };
this.remove = function(id) { this.remove = function(id) {
if(!_.isUndefined(self.list[id])) { if(!_.isUndefined(self.list[id])) {
delete self.list[id]; delete self.list[id];
// This must happen on the full path also since _.without returns a copy // This must happen on the full path also since _.without returns a copy
self.ids = dashboard.current.services.query.ids = _.without(self.ids,id) self.ids = dashboard.current.services.query.ids = _.without(self.ids,id);
_q.idQueue.unshift(id) _q.idQueue.unshift(id);
_q.idQueue.sort(function(a,b){return a-b}); _q.idQueue.sort(function(v,k){
return v-k;
});
return true; return true;
} else { } else {
return false; return false;
} }
} };
this.findQuery = function(queryString) { this.findQuery = function(queryString) {
return _.findWhere(self.list,{query:queryString}) return _.findWhere(self.list,{query:queryString});
} };
var nextId = function() { var nextId = function() {
if(_q.idQueue.length > 0) { if(_q.idQueue.length > 0) {
return _q.idQueue.shift() return _q.idQueue.shift();
} else { } else {
return self.ids.length; return self.ids.length;
} }
} };
var colorAt = function(id) { var colorAt = function(id) {
return self.colors[id % self.colors.length] return self.colors[id % self.colors.length];
} };
self.init(); self.init();
...@@ -281,7 +292,7 @@ angular.module('kibana.services', []) ...@@ -281,7 +292,7 @@ angular.module('kibana.services', [])
_.defaults(dashboard.current.services.filter,{ _.defaults(dashboard.current.services.filter,{
idQueue : [], idQueue : [],
list : {}, list : {},
ids : [], ids : []
}); });
// For convenience // For convenience
...@@ -299,16 +310,16 @@ angular.module('kibana.services', []) ...@@ -299,16 +310,16 @@ angular.module('kibana.services', [])
_f = dashboard.current.services.filter; _f = dashboard.current.services.filter;
_.each(self.getByType('time',true),function(time) { _.each(self.getByType('time',true),function(time) {
self.list[time.id].from = new Date(time.from) self.list[time.id].from = new Date(time.from);
self.list[time.id].to = new Date(time.to) self.list[time.id].to = new Date(time.to);
}) });
} };
// This is used both for adding filters and modifying them. // This is used both for adding filters and modifying them.
// If an id is passed, the filter at that id is updated // If an id is passed, the filter at that id is updated
this.set = function(filter,id) { this.set = function(filter,id) {
_.defaults(filter,{mandate:'must'}) _.defaults(filter,{mandate:'must'});
filter.active = true; filter.active = true;
if(!_.isUndefined(id)) { if(!_.isUndefined(id)) {
if(!_.isUndefined(self.list[id])) { if(!_.isUndefined(self.list[id])) {
...@@ -325,18 +336,19 @@ angular.module('kibana.services', []) ...@@ -325,18 +336,19 @@ angular.module('kibana.services', [])
var _filter = { var _filter = {
alias: '', alias: '',
id: _id id: _id
} };
_.defaults(filter,_filter) _.defaults(filter,_filter);
self.list[_id] = filter; self.list[_id] = filter;
self.ids.push(_id) self.ids.push(_id);
return _id; return _id;
} }
} }
} };
this.getBoolFilter = function(ids) { this.getBoolFilter = function(ids) {
// A default match all filter, just in case there are no other filters // A default match all filter, just in case there are no other filters
var bool = ejs.BoolFilter().must(ejs.MatchAllFilter()); var bool = ejs.BoolFilter().must(ejs.MatchAllFilter());
var either_bool = ejs.BoolFilter().must(ejs.MatchAllFilter());
_.each(ids,function(id) { _.each(ids,function(id) {
if(self.list[id].active) { if(self.list[id].active) {
switch(self.list[id].mandate) switch(self.list[id].mandate)
...@@ -344,75 +356,69 @@ angular.module('kibana.services', []) ...@@ -344,75 +356,69 @@ angular.module('kibana.services', [])
case 'mustNot': case 'mustNot':
bool = bool.mustNot(self.getEjsObj(id)); bool = bool.mustNot(self.getEjsObj(id));
break; break;
case 'should': case 'either':
bool = bool.should(self.getEjsObj(id)); either_bool = either_bool.should(self.getEjsObj(id));
break; break;
default: default:
bool = bool.must(self.getEjsObj(id)); bool = bool.must(self.getEjsObj(id));
} }
} }
}) });
return bool; return bool.must(either_bool);
} };
this.getEjsObj = function(id) { this.getEjsObj = function(id) {
return self.toEjsObj(self.list[id]) return self.toEjsObj(self.list[id]);
} };
this.toEjsObj = function (filter) { this.toEjsObj = function (filter) {
if(!filter.active) { if(!filter.active) {
return false return false;
} }
switch(filter.type) switch(filter.type)
{ {
case 'time': case 'time':
return ejs.RangeFilter(filter.field) return ejs.RangeFilter(filter.field)
.from(filter.from) .from(filter.from)
.to(filter.to) .to(filter.to);
break;
case 'range': case 'range':
return ejs.RangeFilter(filter.field) return ejs.RangeFilter(filter.field)
.from(filter.from) .from(filter.from)
.to(filter.to) .to(filter.to);
break;
case 'querystring': case 'querystring':
return ejs.QueryFilter(ejs.QueryStringQuery(filter.query)) return ejs.QueryFilter(ejs.QueryStringQuery(filter.query));
break;
case 'terms': case 'terms':
return ejs.TermsFilter(filter.field,filter.value) return ejs.TermsFilter(filter.field,filter.value);
break;
case 'exists': case 'exists':
return ejs.ExistsFilter(filter.field) return ejs.ExistsFilter(filter.field);
break;
case 'missing': case 'missing':
return ejs.MissingFilter(filter.field) return ejs.MissingFilter(filter.field);
break;
default: default:
return false; return false;
} }
} };
this.getByType = function(type,inactive) { this.getByType = function(type,inactive) {
return _.pick(self.list,self.idsByType(type,inactive)) return _.pick(self.list,self.idsByType(type,inactive));
} };
this.removeByType = function(type) { this.removeByType = function(type) {
var ids = self.idsByType(type) var ids = self.idsByType(type);
_.each(ids,function(id) { _.each(ids,function(id) {
self.remove(id) self.remove(id);
}) });
return ids; return ids;
} };
this.idsByType = function(type,inactive) { this.idsByType = function(type,inactive) {
var _require = inactive ? {type:type} : {type:type,active:true} var _require = inactive ? {type:type} : {type:type,active:true};
return _.pluck(_.where(self.list,_require),'id') return _.pluck(_.where(self.list,_require),'id');
} };
// This special function looks for all time filters, and returns a time range according to the mode // This special function looks for all time filters, and returns a time range according to the mode
this.timeRange = function(mode) { this.timeRange = function(mode) {
var _t = _.where(self.list,{type:'time',active:true}) var _t = _.where(self.list,{type:'time',active:true});
if(_t.length == 0) { if(_t.length === 0) {
return false; return false;
} }
switch(mode) { switch(mode) {
...@@ -420,41 +426,38 @@ angular.module('kibana.services', []) ...@@ -420,41 +426,38 @@ angular.module('kibana.services', [])
return { return {
from: new Date(_.max(_.pluck(_t,'from'))), from: new Date(_.max(_.pluck(_t,'from'))),
to: new Date(_.min(_.pluck(_t,'to'))) to: new Date(_.min(_.pluck(_t,'to')))
} };
break;
case "max": case "max":
return { return {
from: new Date(_.min(_.pluck(_t,'from'))), from: new Date(_.min(_.pluck(_t,'from'))),
to: new Date(_.max(_.pluck(_t,'to'))) to: new Date(_.max(_.pluck(_t,'to')))
} };
break;
default: default:
return false; return false;
} }
};
}
this.remove = function(id) { this.remove = function(id) {
if(!_.isUndefined(self.list[id])) { if(!_.isUndefined(self.list[id])) {
delete self.list[id]; delete self.list[id];
// This must happen on the full path also since _.without returns a copy // This must happen on the full path also since _.without returns a copy
self.ids = dashboard.current.services.filter.ids = _.without(self.ids,id) self.ids = dashboard.current.services.filter.ids = _.without(self.ids,id);
_f.idQueue.unshift(id) _f.idQueue.unshift(id);
_f.idQueue.sort(function(a,b){return a-b}); _f.idQueue.sort(function(v,k){return v-k;});
return true; return true;
} else { } else {
return false; return false;
} }
} };
var nextId = function() { var nextId = function() {
if(_f.idQueue.length > 0) { if(_f.idQueue.length > 0) {
return _f.idQueue.shift() return _f.idQueue.shift();
} else { } else {
return self.ids.length; return self.ids.length;
} }
} };
// Now init // Now init
self.init(); self.init();
...@@ -491,7 +494,7 @@ angular.module('kibana.services', []) ...@@ -491,7 +494,7 @@ angular.module('kibana.services', [])
self.current = {}; self.current = {};
self.indices = []; self.indices = [];
route(); route();
}) });
var route = function() { var route = function() {
// Is there a dashboard type and id in the URL? // Is there a dashboard type and id in the URL?
...@@ -499,29 +502,36 @@ angular.module('kibana.services', []) ...@@ -499,29 +502,36 @@ angular.module('kibana.services', [])
var _type = $routeParams.type; var _type = $routeParams.type;
var _id = $routeParams.id; var _id = $routeParams.id;
if(_type === 'elasticsearch') switch(_type) {
self.elasticsearch_load('dashboard',_id) case ('elasticsearch'):
if(_type === 'temp') self.elasticsearch_load('dashboard',_id);
self.elasticsearch_load('temp',_id) break;
if(_type === 'file') case ('temp'):
self.file_load(_id) self.elasticsearch_load('temp',_id);
break;
case ('file'):
self.file_load(_id);
break;
default:
self.file_load('default.json');
}
// No dashboard in the URL // No dashboard in the URL
} else { } else {
// Check if browser supports localstorage, and if there's a dashboard // Check if browser supports localstorage, and if there's a dashboard
if (Modernizr.localstorage && if (window.Modernizr.localstorage &&
!(_.isUndefined(localStorage['dashboard'])) && !(_.isUndefined(window.localStorage['dashboard'])) &&
localStorage['dashboard'] !== '' window.localStorage['dashboard'] !== ''
) { ) {
var dashboard = JSON.parse(localStorage['dashboard']); var dashboard = JSON.parse(window.localStorage['dashboard']);
_.defaults(dashboard,_dash); _.defaults(dashboard,_dash);
self.dash_load(dashboard) self.dash_load(dashboard);
// No? Ok, grab default.json, its all we have now // No? Ok, grab default.json, its all we have now
} else { } else {
self.file_load('default.json') self.file_load('default.json');
}
} }
} }
};
// Since the dashboard is responsible for index computation, we can compute and assign the indices // Since the dashboard is responsible for index computation, we can compute and assign the indices
// here before telling the panels to refresh // here before telling the panels to refresh
...@@ -535,21 +545,21 @@ angular.module('kibana.services', []) ...@@ -535,21 +545,21 @@ angular.module('kibana.services', [])
if(p.length > 0) { if(p.length > 0) {
self.indices = p; self.indices = p;
} else { } else {
self.indices = [self.current.index.default] self.indices = [self.current.index.default];
} }
$rootScope.$broadcast('refresh') $rootScope.$broadcast('refresh');
}); });
} else { } else {
// This is not optimal, we should be getting the entire index list here, or at least every // This is not optimal, we should be getting the entire index list here, or at least every
// index that possibly matches the pattern // index that possibly matches the pattern
self.indices = [self.current.index.default] self.indices = [self.current.index.default];
$rootScope.$broadcast('refresh') $rootScope.$broadcast('refresh');
} }
} else { } else {
self.indices = [self.current.index.default] self.indices = [self.current.index.default];
$rootScope.$broadcast('refresh') $rootScope.$broadcast('refresh');
}
} }
};
this.dash_load = function(dashboard) { this.dash_load = function(dashboard) {
// Cancel all timers // Cancel all timers
...@@ -557,88 +567,89 @@ angular.module('kibana.services', []) ...@@ -557,88 +567,89 @@ angular.module('kibana.services', [])
// If not using time based indices, use the default index // If not using time based indices, use the default index
if(dashboard.index.interval === 'none') { if(dashboard.index.interval === 'none') {
self.indices = [dashboard.index.default] self.indices = [dashboard.index.default];
} }
self.current = _.clone(dashboard); self.current = _.clone(dashboard);
// Ok, now that we've setup the current dashboard, we can inject our services // Ok, now that we've setup the current dashboard, we can inject our services
query = $injector.get('query'); query = $injector.get('query');
filterSrv = $injector.get('filterSrv') filterSrv = $injector.get('filterSrv');
// Make sure these re-init // Make sure these re-init
query.init(); query.init();
filterSrv.init(); filterSrv.init();
if(dashboard.index.interval !== 'none' && filterSrv.idsByType('time').length == 0) { if(dashboard.index.interval !== 'none' && filterSrv.idsByType('time').length === 0) {
//if(dashboard.index.interval !== 'none') {
self.refresh(); self.refresh();
} }
return true; return true;
} };
this.gist_id = function(string) { this.gist_id = function(string) {
if(self.is_gist(string)) if(self.is_gist(string)) {
return string.match(gist_pattern)[0].replace(/.*\//, ''); return string.match(gist_pattern)[0].replace(/.*\//, '');
} }
};
this.is_gist = function(string) { this.is_gist = function(string) {
if(!_.isUndefined(string) && string != '' && !_.isNull(string.match(gist_pattern))) if(!_.isUndefined(string) && string !== '' && !_.isNull(string.match(gist_pattern))) {
return string.match(gist_pattern).length > 0 ? true : false; return string.match(gist_pattern).length > 0 ? true : false;
else } else {
return false return false;
} }
};
this.to_file = function() { this.to_file = function() {
var blob = new Blob([angular.toJson(self.current,true)], {type: "application/json;charset=utf-8"}); var blob = new Blob([angular.toJson(self.current,true)], {type: "application/json;charset=utf-8"});
// from filesaver.js // from filesaver.js
saveAs(blob, self.current.title+"-"+new Date().getTime()); window.saveAs(blob, self.current.title+"-"+new Date().getTime());
return true; return true;
} };
this.set_default = function(dashboard) { this.set_default = function(dashboard) {
if (Modernizr.localstorage) { if (window.Modernizr.localstorage) {
localStorage['dashboard'] = angular.toJson(dashboard || self.current); window.localStorage['dashboard'] = angular.toJson(dashboard || self.current);
return true; return true;
} else { } else {
return false; return false;
} }
} };
this.purge_default = function() { this.purge_default = function() {
if (Modernizr.localstorage) { if (window.Modernizr.localstorage) {
localStorage['dashboard'] = ''; window.localStorage['dashboard'] = '';
return true; return true;
} else { } else {
return false; return false;
} }
} };
// TOFIX: Pretty sure this breaks when you're on a saved dashboard already // TOFIX: Pretty sure this breaks when you're on a saved dashboard already
this.share_link = function(title,type,id) { this.share_link = function(title,type,id) {
return { return {
location : location.href.replace(location.hash,""), location : window.location.href.replace(window.location.hash,""),
type : type, type : type,
id : id, id : id,
link : location.href.replace(location.hash,"")+"#dashboard/"+type+"/"+id, link : window.location.href.replace(window.location.hash,"")+"#dashboard/"+type+"/"+id,
title : title title : title
}; };
} };
this.file_load = function(file) { this.file_load = function(file) {
return $http({ return $http({
url: "dashboards/"+file, url: "dashboards/"+file,
method: "GET", method: "GET",
}).then(function(result) { }).then(function(result) {
var _dashboard = result.data var _dashboard = result.data;
_.defaults(_dashboard,_dash); _.defaults(_dashboard,_dash);
self.dash_load(_dashboard); self.dash_load(_dashboard);
return true; return true;
},function(result) { },function(result) {
return false; return false;
}); });
} };
this.elasticsearch_load = function(type,id) { this.elasticsearch_load = function(type,id) {
var request = ejs.Request().indices(config.kibana_index).types(type); var request = ejs.Request().indices(config.kibana_index).types(type);
...@@ -649,19 +660,20 @@ angular.module('kibana.services', []) ...@@ -649,19 +660,20 @@ angular.module('kibana.services', [])
if(_.isUndefined(results)) { if(_.isUndefined(results)) {
return false; return false;
} else { } else {
self.dash_load(angular.fromJson(results.hits.hits[0]['_source']['dashboard'])) self.dash_load(angular.fromJson(results.hits.hits[0]['_source']['dashboard']));
return true; return true;
} }
}); });
} };
this.elasticsearch_save = function(type,title,ttl) { this.elasticsearch_save = function(type,title,ttl) {
// Clone object so we can modify it without influencing the existing obejct // Clone object so we can modify it without influencing the existing obejct
var save = _.clone(self.current) var save = _.clone(self.current);
var id;
// Change title on object clone // Change title on object clone
if (type === 'dashboard') { if (type === 'dashboard') {
var id = save.title = _.isUndefined(title) ? self.current.title : title; id = save.title = _.isUndefined(title) ? self.current.title : title;
} }
// Create request with id as title. Rethink this. // Create request with id as title. Rethink this.
...@@ -670,10 +682,10 @@ angular.module('kibana.services', []) ...@@ -670,10 +682,10 @@ angular.module('kibana.services', [])
group: 'guest', group: 'guest',
title: save.title, title: save.title,
dashboard: angular.toJson(save) dashboard: angular.toJson(save)
}) });
request = type === 'temp' ? request.ttl(ttl) : request;
if (type === 'temp')
request = request.ttl(ttl)
// TOFIX: Implement error handling here // TOFIX: Implement error handling here
return request.doIndex( return request.doIndex(
...@@ -686,7 +698,7 @@ angular.module('kibana.services', []) ...@@ -686,7 +698,7 @@ angular.module('kibana.services', [])
return false; return false;
} }
); );
} };
this.elasticsearch_delete = function(id) { this.elasticsearch_delete = function(id) {
return ejs.Document(config.kibana_index,'dashboard',id).doDelete( return ejs.Document(config.kibana_index,'dashboard',id).doDelete(
...@@ -699,7 +711,7 @@ angular.module('kibana.services', []) ...@@ -699,7 +711,7 @@ angular.module('kibana.services', [])
return false; return false;
} }
); );
} };
this.elasticsearch_list = function(query,count) { this.elasticsearch_list = function(query,count) {
var request = ejs.Request().indices(config.kibana_index).types('dashboard'); var request = ejs.Request().indices(config.kibana_index).types('dashboard');
...@@ -715,11 +727,11 @@ angular.module('kibana.services', []) ...@@ -715,11 +727,11 @@ angular.module('kibana.services', [])
return false; return false;
} }
); );
} };
// TOFIX: Gist functionality // TOFIX: Gist functionality
this.save_gist = function(title,dashboard) { this.save_gist = function(title,dashboard) {
var save = _.clone(dashboard || self.current) var save = _.clone(dashboard || self.current);
save.title = title || self.current.title; save.title = title || self.current.title;
return $http({ return $http({
url: "https://api.github.com/gists", url: "https://api.github.com/gists",
...@@ -738,16 +750,16 @@ angular.module('kibana.services', []) ...@@ -738,16 +750,16 @@ angular.module('kibana.services', [])
}, function(data, status, headers, config) { }, function(data, status, headers, config) {
return false; return false;
}); });
} };
this.gist_list = function(id) { this.gist_list = function(id) {
return $http.jsonp("https://api.github.com/gists/"+id+"?callback=JSON_CALLBACK" return $http.jsonp("https://api.github.com/gists/"+id+"?callback=JSON_CALLBACK"
).then(function(response) { ).then(function(response) {
var files = [] var files = [];
_.each(response.data.data.files,function(v,k) { _.each(response.data.data.files,function(v,k) {
try { try {
var file = JSON.parse(v.content) var file = JSON.parse(v.content);
files.push(file) files.push(file);
} catch(e) { } catch(e) {
// Nothing? // Nothing?
} }
...@@ -756,20 +768,6 @@ angular.module('kibana.services', []) ...@@ -756,20 +768,6 @@ angular.module('kibana.services', [])
}, function(data, status, headers, config) { }, function(data, status, headers, config) {
return false; return false;
}); });
} };
})
.service('keylistener', function($rootScope) {
var keys = [];
$(document).keydown(function (e) {
keys[e.which] = true;
});
$(document).keyup(function (e) {
delete keys[e.which];
});
this.keyActive = function(key) {
return keys[key] == true;
}
}); });
\ No newline at end of file
/*jshint globalstrict:true */
/*global angular:true */
/*global L:false*/
/* /*
## Better maps ## Better maps
...@@ -14,6 +17,8 @@ ...@@ -14,6 +17,8 @@
* spyable :: Show the 'eye' icon that reveals the last ES query * spyable :: Show the 'eye' icon that reveals the last ES query
*/ */
'use strict';
angular.module('kibana.bettermap', []) angular.module('kibana.bettermap', [])
.controller('bettermap', function($scope, query, dashboard, filterSrv) { .controller('bettermap', function($scope, query, dashboard, filterSrv) {
...@@ -26,61 +31,61 @@ angular.module('kibana.bettermap', []) ...@@ -26,61 +31,61 @@ angular.module('kibana.bettermap', [])
tooltip : "_id", tooltip : "_id",
field : null, field : null,
group : "default" group : "default"
} };
_.defaults($scope.panel,_d) _.defaults($scope.panel,_d);
$scope.init = function() { $scope.init = function() {
$scope.$on('refresh',function(){ $scope.$on('refresh',function(){
$scope.get_data(); $scope.get_data();
}) });
$scope.get_data(); $scope.get_data();
} };
$scope.get_data = function(segment,query_id) { $scope.get_data = function(segment,query_id) {
$scope.panel.error = false; $scope.panel.error = false;
// Make sure we have everything for the request to complete // Make sure we have everything for the request to complete
if(dashboard.indices.length == 0) { if(dashboard.indices.length === 0) {
return; return;
} }
if(_.isUndefined($scope.panel.field)) { if(_.isUndefined($scope.panel.field)) {
$scope.panel.error = "Please select a field that contains geo point in [lon,lat] format" $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format";
return return;
} }
// Determine the field to sort on // Determine the field to sort on
var timeField = _.uniq(_.pluck(filterSrv.getByType('time'),'field')) var timeField = _.uniq(_.pluck(filterSrv.getByType('time'),'field'));
if(timeField.length > 1) { if(timeField.length > 1) {
$scope.panel.error = "Time field must be consistent amongst time filters" $scope.panel.error = "Time field must be consistent amongst time filters";
} else if(timeField.length == 0) { } else if(timeField.length === 0) {
timeField = null; timeField = null;
} else { } else {
timeField = timeField[0] timeField = timeField[0];
} }
var _segment = _.isUndefined(segment) ? 0 : segment var _segment = _.isUndefined(segment) ? 0 : segment;
var boolQuery = ejs.BoolQuery(); var boolQuery = $scope.ejs.BoolQuery();
_.each(query.list,function(q) { _.each(query.list,function(q) {
boolQuery = boolQuery.should(ejs.QueryStringQuery((q.query || '*'))) boolQuery = boolQuery.should($scope.ejs.QueryStringQuery((q.query || '*')));
}) });
var request = $scope.ejs.Request().indices(dashboard.indices[_segment]) var request = $scope.ejs.Request().indices(dashboard.indices[_segment])
.query(ejs.FilteredQuery( .query($scope.ejs.FilteredQuery(
boolQuery, boolQuery,
filterSrv.getBoolFilter(filterSrv.ids).must(ejs.ExistsFilter($scope.panel.field)) filterSrv.getBoolFilter(filterSrv.ids).must($scope.ejs.ExistsFilter($scope.panel.field))
)) ))
.fields([$scope.panel.field,$scope.panel.tooltip]) .fields([$scope.panel.field,$scope.panel.tooltip])
.size($scope.panel.size) .size($scope.panel.size);
if(!_.isNull(timeField)) { if(!_.isNull(timeField)) {
request = request.sort(timeField,'desc'); request = request.sort(timeField,'desc');
} }
$scope.populate_modal(request) $scope.populate_modal(request);
var results = request.doSearch() var results = request.doSearch();
// Populate scope when we have results // Populate scope when we have results
results.then(function(results) { results.then(function(results) {
...@@ -89,7 +94,7 @@ angular.module('kibana.bettermap', []) ...@@ -89,7 +94,7 @@ angular.module('kibana.bettermap', [])
if(_segment === 0) { if(_segment === 0) {
$scope.hits = 0; $scope.hits = 0;
$scope.data = []; $scope.data = [];
query_id = $scope.query_id = new Date().getTime() query_id = $scope.query_id = new Date().getTime();
} }
// Check for error and abort if found // Check for error and abort if found
...@@ -101,31 +106,32 @@ angular.module('kibana.bettermap', []) ...@@ -101,31 +106,32 @@ angular.module('kibana.bettermap', [])
// Check that we're still on the same query, if not stop // Check that we're still on the same query, if not stop
if($scope.query_id === query_id) { if($scope.query_id === query_id) {
var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait() var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait();
scripts.wait(function(){ scripts.wait(function(){
$scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) { $scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) {
return { return {
coordinates : new L.LatLng(hit.fields[$scope.panel.field][1],hit.fields[$scope.panel.field][0]), coordinates : new L.LatLng(hit.fields[$scope.panel.field][1],hit.fields[$scope.panel.field][0]),
tooltip : hit.fields[$scope.panel.tooltip] tooltip : hit.fields[$scope.panel.tooltip]
} };
})); }));
}); });
// Keep only what we need for the set // Keep only what we need for the set
$scope.data = $scope.data.slice(0,$scope.panel.size) $scope.data = $scope.data.slice(0,$scope.panel.size);
} else { } else {
return; return;
} }
$scope.$emit('draw') $scope.$emit('draw');
// Get $size results then stop querying // Get $size results then stop querying
if($scope.data.length < $scope.panel.size && _segment+1 < dashboard.indices.length) if($scope.data.length < $scope.panel.size && _segment+1 < dashboard.indices.length) {
$scope.get_data(_segment+1,$scope.query_id) $scope.get_data(_segment+1,$scope.query_id);
}
}); });
} };
// I really don't like this function, too much dom manip. Break out into directive? // I really don't like this function, too much dom manip. Break out into directive?
$scope.populate_modal = function(request) { $scope.populate_modal = function(request) {
...@@ -135,8 +141,8 @@ angular.module('kibana.bettermap', []) ...@@ -135,8 +141,8 @@ angular.module('kibana.bettermap', [])
'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+ 'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+
angular.toJson(JSON.parse(request.toString()),true)+ angular.toJson(JSON.parse(request.toString()),true)+
"'</pre>", "'</pre>",
} };
} };
}) })
.directive('bettermap', function() { .directive('bettermap', function() {
...@@ -144,7 +150,7 @@ angular.module('kibana.bettermap', []) ...@@ -144,7 +150,7 @@ angular.module('kibana.bettermap', [])
restrict: 'A', restrict: 'A',
link: function(scope, elem, attrs) { link: function(scope, elem, attrs) {
elem.html('<center><img src="common/img/load_big.gif"></center>') elem.html('<center><img src="common/img/load_big.gif"></center>');
// Receive render events // Receive render events
scope.$on('draw',function(){ scope.$on('draw',function(){
...@@ -154,9 +160,9 @@ angular.module('kibana.bettermap', []) ...@@ -154,9 +160,9 @@ angular.module('kibana.bettermap', [])
scope.$on('render', function(){ scope.$on('render', function(){
if(!_.isUndefined(map)) { if(!_.isUndefined(map)) {
map.invalidateSize(); map.invalidateSize();
var panes = map.getPanes() var panes = map.getPanes();
} }
}) });
var map, markers, layerGroup, mcg; var map, markers, layerGroup, mcg;
...@@ -164,7 +170,7 @@ angular.module('kibana.bettermap', []) ...@@ -164,7 +170,7 @@ angular.module('kibana.bettermap', [])
scope.panel.loading = false; scope.panel.loading = false;
var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait() var scripts = $LAB.script("panels/bettermap/lib/leaflet.js").wait()
.script("panels/bettermap/lib/plugins.js") .script("panels/bettermap/lib/plugins.js");
//add markers dynamically //add markers dynamically
scripts.wait(function(){ scripts.wait(function(){
...@@ -185,16 +191,17 @@ angular.module('kibana.bettermap', []) ...@@ -185,16 +191,17 @@ angular.module('kibana.bettermap', [])
} }
_.each(scope.data, function(p) { _.each(scope.data, function(p) {
if(!_.isUndefined(p.tooltip) && p.tooltip !== '') if(!_.isUndefined(p.tooltip) && p.tooltip !== '') {
layerGroup.addLayer(L.marker(p.coordinates).bindLabel(p.tooltip)) layerGroup.addLayer(L.marker(p.coordinates).bindLabel(p.tooltip));
else } else {
layerGroup.addLayer(L.marker(p.coordinates)) layerGroup.addLayer(L.marker(p.coordinates));
}) }
});
layerGroup.addTo(map) layerGroup.addTo(map);
map.fitBounds(_.pluck(scope.data,'coordinates')); map.fitBounds(_.pluck(scope.data,'coordinates'));
}) });
} }
} }
}; };
......
/*jshint globalstrict:true */
/*global angular:true */
/* /*
## Column ## Column
...@@ -9,25 +11,22 @@ ...@@ -9,25 +11,22 @@
### Parameters ### Parameters
* panels :: an array of panel objects. All of their spans should be set to 12 * panels :: an array of panel objects. All of their spans should be set to 12
### Group Events
#### Sends
* time :: Object Includes from, to and index
*/ */
'use strict';
angular.module('kibana.column', []) angular.module('kibana.column', [])
.controller('column', function($scope, $rootScope) { .controller('column', function($scope, $rootScope, $timeout) {
// Set and populate defaults // Set and populate defaults
var _d = { var _d = {
status: "Stable", status: "Stable",
panels : [ panels : []
] };
}
_.defaults($scope.panel,_d); _.defaults($scope.panel,_d);
$scope.init = function(){ $scope.init = function(){
$scope.reset_panel(); $scope.reset_panel();
} };
$scope.toggle_row = function(panel) { $scope.toggle_row = function(panel) {
panel.collapse = panel.collapse ? false : true; panel.collapse = panel.collapse ? false : true;
...@@ -36,15 +35,15 @@ angular.module('kibana.column', []) ...@@ -36,15 +35,15 @@ angular.module('kibana.column', [])
$scope.send_render(); $scope.send_render();
}); });
} }
} };
$scope.send_render = function() { $scope.send_render = function() {
$scope.$broadcast('render'); $scope.$broadcast('render');
} };
$scope.add_panel = function(panel) { $scope.add_panel = function(panel) {
$scope.panel.panels.push(panel); $scope.panel.panels.push(panel);
} };
$scope.reset_panel = function(type) { $scope.reset_panel = function(type) {
$scope.new_panel = { $scope.new_panel = {
...@@ -76,17 +75,17 @@ angular.module('kibana.column', []) ...@@ -76,17 +75,17 @@ angular.module('kibana.column', [])
$timeout(function() { $timeout(function() {
// Create a reference to the new_panel as panel so that the existing // Create a reference to the new_panel as panel so that the existing
// editors work with our isolate scope // editors work with our isolate scope
scope.panel = scope.new_panel scope.panel = scope.new_panel;
var template = '<div ng-include src="\'panels/column/panelgeneral.html\'"></div>' var template = '<div ng-include src="\'panels/column/panelgeneral.html\'"></div>';
if(!(_.isUndefined(scope.type)) && scope.type != "") if(!(_.isUndefined(scope.type)) && scope.type !== "") {
template = template+'<div ng-include src="\'panels/'+scope.type+'/editor.html\'"></div>'; template = template+'<div ng-include src="\'panels/'+scope.type+'/editor.html\'"></div>';
//var new_elem = $compile(angular.element(template))(scope))
elem.html($compile(angular.element(template))(scope));
})
})
} }
elem.html($compile(angular.element(template))(scope));
});
});
} }
};
}).filter('withoutColumn', function() { }).filter('withoutColumn', function() {
return function() { return function() {
return _.without(config.modules,'column'); return _.without(config.modules,'column');
......
/*jshint globalstrict:true */
/*global angular:true */
/*global FileReader:false*/
/* /*
## Dashcontrol ## Dashcontrol
...@@ -20,11 +23,8 @@ ...@@ -20,11 +23,8 @@
* temp :: Allow saving of temp dashboards * temp :: Allow saving of temp dashboards
* temp_ttl :: How long should temp dashboards persist * temp_ttl :: How long should temp dashboards persist
### Group Events
#### Sends
* dashboard :: An object containing an entire dashboard to be loaded
*/ */
'use strict';
angular.module('kibana.dashcontrol', []) angular.module('kibana.dashcontrol', [])
.controller('dashcontrol', function($scope, $http, timer, dashboard) { .controller('dashcontrol', function($scope, $http, timer, dashboard) {
...@@ -49,7 +49,7 @@ angular.module('kibana.dashcontrol', []) ...@@ -49,7 +49,7 @@ angular.module('kibana.dashcontrol', [])
elasticsearch_size: 20, elasticsearch_size: 20,
temp: true, temp: true,
temp_ttl: '30d' temp_ttl: '30d'
} };
_.defaults($scope.panel,_d); _.defaults($scope.panel,_d);
// A hash of defaults for the dashboard object // A hash of defaults for the dashboard object
...@@ -58,63 +58,63 @@ angular.module('kibana.dashcontrol', []) ...@@ -58,63 +58,63 @@ angular.module('kibana.dashcontrol', [])
editable: true, editable: true,
rows: [], rows: [],
services: {} services: {}
} };
$scope.init = function() { $scope.init = function() {
$scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
$scope.gist = {}; $scope.gist = {};
$scope.elasticsearch = {}; $scope.elasticsearch = {};
} };
$scope.set_default = function() { $scope.set_default = function() {
if(dashboard.set_default()) { if(dashboard.set_default()) {
$scope.alert('Local Default Set',dashboard.current.title+' has been set as your local default','success',5000) $scope.alert('Local Default Set',dashboard.current.title+' has been set as your local default','success',5000);
} else { } else {
$scope.alert('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000) $scope.alert('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000);
}
} }
};
$scope.purge_default = function() { $scope.purge_default = function() {
if(dashboard.purge_default()) { if(dashboard.purge_default()) {
$scope.alert('Local Default Clear','Your local default dashboard has been cleared','success',5000) $scope.alert('Local Default Clear','Your local default dashboard has been cleared','success',5000);
} else { } else {
$scope.alert('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000) $scope.alert('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000);
}
} }
};
$scope.elasticsearch_save = function(type,ttl) { $scope.elasticsearch_save = function(type,ttl) {
dashboard.elasticsearch_save(type,($scope.elasticsearch.title || dashboard.current.title),ttl).then( dashboard.elasticsearch_save(type,($scope.elasticsearch.title || dashboard.current.title),ttl).then(
function(result) { function(result) {
if(!_.isUndefined(result._id)) { if(!_.isUndefined(result._id)) {
$scope.alert('Dashboard Saved','This dashboard has been saved to Elasticsearch as "' + $scope.alert('Dashboard Saved','This dashboard has been saved to Elasticsearch as "' +
result._id + '"','success',5000) result._id + '"','success',5000);
if(type === 'temp') { if(type === 'temp') {
$scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id) $scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id);
} }
} else { } else {
$scope.alert('Save failed','Dashboard could not be saved to Elasticsearch','error',5000) $scope.alert('Save failed','Dashboard could not be saved to Elasticsearch','error',5000);
}
})
} }
});
};
$scope.elasticsearch_delete = function(id) { $scope.elasticsearch_delete = function(id) {
dashboard.elasticsearch_delete(id).then( dashboard.elasticsearch_delete(id).then(
function(result) { function(result) {
if(!_.isUndefined(result)) { if(!_.isUndefined(result)) {
if(result.found) { if(result.found) {
$scope.alert('Dashboard Deleted',id+' has been deleted','success',5000) $scope.alert('Dashboard Deleted',id+' has been deleted','success',5000);
// Find the deleted dashboard in the cached list and remove it // Find the deleted dashboard in the cached list and remove it
var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0] var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0];
$scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete) $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete);
} else { } else {
$scope.alert('Dashboard Not Found','Could not find '+id+' in Elasticsearch','warning',5000) $scope.alert('Dashboard Not Found','Could not find '+id+' in Elasticsearch','warning',5000);
} }
} else { } else {
$scope.alert('Dashboard Not Deleted','An error occurred deleting the dashboard',error,5000) $scope.alert('Dashboard Not Deleted','An error occurred deleting the dashboard','error',5000);
}
} }
)
} }
);
};
$scope.elasticsearch_dblist = function(query) { $scope.elasticsearch_dblist = function(query) {
dashboard.elasticsearch_list(query,$scope.panel.elasticsearch_size).then( dashboard.elasticsearch_list(query,$scope.panel.elasticsearch_size).then(
...@@ -122,10 +122,10 @@ angular.module('kibana.dashcontrol', []) ...@@ -122,10 +122,10 @@ angular.module('kibana.dashcontrol', [])
if(!_.isUndefined(result.hits)) { if(!_.isUndefined(result.hits)) {
$scope.panel.error = false; $scope.panel.error = false;
$scope.hits = result.hits.total; $scope.hits = result.hits.total;
$scope.elasticsearch.dashboards = result.hits.hits $scope.elasticsearch.dashboards = result.hits.hits;
}
})
} }
});
};
$scope.save_gist = function() { $scope.save_gist = function() {
dashboard.save_gist($scope.gist.title).then( dashboard.save_gist($scope.gist.title).then(
...@@ -134,10 +134,10 @@ angular.module('kibana.dashcontrol', []) ...@@ -134,10 +134,10 @@ angular.module('kibana.dashcontrol', [])
$scope.gist.last = link; $scope.gist.last = link;
$scope.alert('Gist saved','You will be able to access your exported dashboard file at <a href="'+link+'">'+link+'</a> in a moment','success'); $scope.alert('Gist saved','You will be able to access your exported dashboard file at <a href="'+link+'">'+link+'</a> in a moment','success');
} else { } else {
$scope.alert('Save failed','Gist could not be saved','error',5000) $scope.alert('Save failed','Gist could not be saved','error',5000);
}
})
} }
});
};
$scope.gist_dblist = function(id) { $scope.gist_dblist = function(id) {
dashboard.gist_list(id).then( dashboard.gist_list(id).then(
...@@ -145,10 +145,10 @@ angular.module('kibana.dashcontrol', []) ...@@ -145,10 +145,10 @@ angular.module('kibana.dashcontrol', [])
if(files && files.length > 0) { if(files && files.length > 0) {
$scope.gist.files = files; $scope.gist.files = files;
} else { } else {
$scope.alert('Gist Failed','Could not retrieve dashboard list from gist','error',5000) $scope.alert('Gist Failed','Could not retrieve dashboard list from gist','error',5000);
}
})
} }
});
};
}) })
.directive('dashUpload', function(timer, dashboard){ .directive('dashUpload', function(timer, dashboard){
return { return {
...@@ -159,14 +159,15 @@ angular.module('kibana.dashcontrol', []) ...@@ -159,14 +159,15 @@ angular.module('kibana.dashcontrol', [])
// files is a FileList of File objects. List some properties. // files is a FileList of File objects. List some properties.
var output = []; var output = [];
for (var i = 0, f; f = files[i]; i++) { var readerOnload = function(theFile) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) { return function(e) {
dashboard.dash_load(JSON.parse(e.target.result)) dashboard.dash_load(JSON.parse(e.target.result));
scope.$apply(); scope.$apply();
}; };
})(f); };
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = (readerOnload)(f);
reader.readAsText(f); reader.readAsText(f);
} }
} }
...@@ -179,15 +180,16 @@ angular.module('kibana.dashcontrol', []) ...@@ -179,15 +180,16 @@ angular.module('kibana.dashcontrol', [])
alert('Sorry, the HTML5 File APIs are not fully supported in this browser.'); alert('Sorry, the HTML5 File APIs are not fully supported in this browser.');
} }
} }
} };
}).filter('gistid', function() { }).filter('gistid', function() {
var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
return function(input, scope) { return function(input, scope) {
//return input+"boners" //return input+"boners"
if(!(_.isUndefined(input))) { if(!(_.isUndefined(input))) {
var output = input.match(gist_pattern); var output = input.match(gist_pattern);
if(!_.isNull(output) && !_.isUndefined(output)) if(!_.isNull(output) && !_.isUndefined(output)) {
return output[0].replace(/.*\//, ''); return output[0].replace(/.*\//, '');
} }
} }
});; };
\ No newline at end of file });
\ No newline at end of file
...@@ -80,8 +80,12 @@ angular.module('kibana.fields', []) ...@@ -80,8 +80,12 @@ angular.module('kibana.fields', [])
} }
$scope.build_search = function(field,value,mandate) { $scope.build_search = function(field,value,mandate) {
var query = field+":"+angular.toJson(value) var query;
if(_.isArray(value)) {
query = field+":(" + _.map(value,function(v){return "\""+v+"\""}).join(",") + ")";
} else {
query = field+":"+angular.toJson(value);
}
filterSrv.set({type:'querystring',query:query,mandate:mandate}) filterSrv.set({type:'querystring',query:query,mandate:mandate})
dashboard.refresh(); dashboard.refresh();
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.filter-mustNot { .filter-mustNot {
border-bottom: #E24D42 3px solid; border-bottom: #E24D42 3px solid;
} }
.filter-should { .filter-either {
border-bottom: #EF843C 3px solid; border-bottom: #EF843C 3px solid;
} }
.filter-action { .filter-action {
...@@ -26,13 +26,24 @@ ...@@ -26,13 +26,24 @@
margin-bottom: 0px !important; margin-bottom: 0px !important;
margin-left: 3px; margin-left: 3px;
} }
.filter-mandate {
text-decoration: underline;
cursor: pointer;
}
</style> </style>
<div class='filtering-container'> <div class='filtering-container'>
<div ng-repeat="id in filterSrv.ids" class="small filter-panel-filter"> <div ng-repeat="id in filterSrv.ids" class="small filter-panel-filter">
<div class="filter-{{filterSrv.list[id].mandate}}"> <div class="filter-{{filterSrv.list[id].mandate}}">
<strong>{{filterSrv.list[id].type}}</strong> {{filterSrv.list[id].mandate}} <strong>{{filterSrv.list[id].type}}</strong>
<span ng-show="!filterSrv.list[id].editing" class="filter-mandate" ng-click="filterSrv.list[id].editing = true">{{filterSrv.list[id].mandate}}</span>
<span class="small" ng-show="filterSrv.list[id].editing">
<select class="input-small" ng-model="filterSrv.list[id].mandate" ng-options="f for f in ['must','mustNot','either']" ng-change='filterSrv.list[id].editing=undefined;refresh()'></select>
<i class="pointer icon-remove" bs-tooltip="'Cancel '" ng-click="filterSrv.list[id].editing=undefined"></i>
</span>
<i class="filter-action pointer icon-remove" bs-tooltip="'Remove'" ng-click="remove(id)"></i> <i class="filter-action pointer icon-remove" bs-tooltip="'Remove'" ng-click="remove(id)"></i>
<i class="filter-action pointer" ng-class="{'icon-check': filterSrv.list[id].active,'icon-check-empty': !filterSrv.list[id].active}" bs-tooltip="'Toggle'" ng-click="toggle(id)"></i> <i class="filter-action pointer" ng-class="{'icon-check': filterSrv.list[id].active,'icon-check-empty': !filterSrv.list[id].active}" bs-tooltip="'Toggle'" ng-click="toggle(id)"></i>
......
...@@ -40,7 +40,7 @@ angular.module('kibana.filtering', []) ...@@ -40,7 +40,7 @@ angular.module('kibana.filtering', [])
} }
$scope.show_key = function(key) { $scope.show_key = function(key) {
return !_.contains(['type','id','alias','mandate','active'],key) return !_.contains(['type','id','alias','mandate','active','editing'],key)
} }
}); });
\ No newline at end of file
...@@ -107,7 +107,13 @@ angular.module('kibana.table', []) ...@@ -107,7 +107,13 @@ angular.module('kibana.table', [])
} }
$scope.build_search = function(field,value,negate) { $scope.build_search = function(field,value,negate) {
var query = field+":"+angular.toJson(value) var query;
// This needs to be abstracted somewhere
if(_.isArray(value)) {
query = field+":(" + _.map(value,function(v){return "\""+v+"\""}).join(",") + ")";
} else {
query = field+":"+angular.toJson(value);
}
filterSrv.set({type:'querystring',query:query,mandate:(negate ? 'mustNot':'must')}) filterSrv.set({type:'querystring',query:query,mandate:(negate ? 'mustNot':'must')})
$scope.panel.offset = 0; $scope.panel.offset = 0;
dashboard.refresh(); dashboard.refresh();
...@@ -216,7 +222,7 @@ angular.module('kibana.table', []) ...@@ -216,7 +222,7 @@ angular.module('kibana.table', [])
$scope.modal = { $scope.modal = {
title: "Table Inspector", title: "Table Inspector",
body : "<h5>Last Elasticsearch Query</h5><pre>"+ body : "<h5>Last Elasticsearch Query</h5><pre>"+
'curl -XGET '+config.elasticsearch+'/'+$scope.index+"/_search?pretty -d'\n"+ 'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+
angular.toJson(JSON.parse(request.toString()),true)+ angular.toJson(JSON.parse(request.toString()),true)+
"'</pre>", "'</pre>",
} }
......
/*jshint globalstrict:true */
/*global angular:true */
/* /*
## Hits ## Trends
A variety of representations of the hits a query matches Shows how queries are moving from a specified time ago
### Parameters ### Parameters
* query :: An array of queries. No labels here, just an array of strings. Maybe
there should be labels. Probably.
* style :: A hash of css styles * style :: A hash of css styles
* arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical'
* ago :: Date math formatted time to look back * ago :: Date math formatted time to look back
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment