diff --git a/js/app.js b/js/app.js index 5e0b15baf9a..980d11964a4 100644 --- a/js/app.js +++ b/js/app.js @@ -12,9 +12,9 @@ var modules = [ '$strap.directives', 'kibana.panels', 'ngSanitize', - ] +]; -var scripts = [] +var scripts = []; var labjs = $LAB .script("common/lib/jquery-1.8.0.min.js").wait() @@ -34,12 +34,12 @@ var labjs = $LAB .script("js/controllers.js") .script("js/filters.js") .script("js/directives.js") - .script("js/panels.js").wait() + .script("js/panels.js").wait(); _.each(config.modules, function(v) { - labjs = labjs.script('panels/'+v+'/module.js') - modules.push('kibana.'+v) -}) + labjs = labjs.script('panels/'+v+'/module.js'); + modules.push('kibana.'+v); +}); /* Application level module which depends on filters, controllers, and services */ labjs.wait(function(){ @@ -59,7 +59,7 @@ labjs.wait(function(){ }); }]); angular.element(document).ready(function() { - $('body').attr('ng-controller', 'DashCtrl') + $('body').attr('ng-controller', 'DashCtrl'); angular.bootstrap(document, ['kibana']); }); }); diff --git a/js/controllers.js b/js/controllers.js index a3ba095aa39..e4eea1640b4 100644 --- a/js/controllers.js +++ b/js/controllers.js @@ -11,7 +11,7 @@ angular.module('kibana.controllers', []) editable: true, rows: [], last: null - } + }; $scope.init = function() { @@ -22,16 +22,16 @@ angular.module('kibana.controllers', []) $scope.dashboard = dashboard; // Provide a global list of all see fields - $scope.fields = fields + $scope.fields = fields; $scope.reset_row(); $scope.clear_all_alerts(); var ejs = $scope.ejs = ejsResource(config.elasticsearch); - } + }; $scope.add_row = function(dash,row) { dash.rows.push(row); - } + }; $scope.reset_row = function() { $scope.row = { @@ -42,8 +42,8 @@ angular.module('kibana.controllers', []) }; $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) { var alert = { @@ -52,30 +52,34 @@ angular.module('kibana.controllers', []) severity: severity || 'info', }; $scope.global_alert.push(alert); - if (timeout > 0) + if (timeout > 0) { $timeout(function() { - $scope.global_alert = _.without($scope.global_alert,alert) + $scope.global_alert = _.without($scope.global_alert,alert); }, timeout); - } + } + }; $scope.clear_alert = function(alert) { $scope.global_alert = _.without($scope.global_alert,alert); - } + }; $scope.clear_all_alerts = function() { - $scope.global_alert = [] - } + $scope.global_alert = []; + }; $scope.edit_path = function(type) { - if(type) + if(type) { return 'panels/'+type+'/editor.html'; - } + } else { + return false; + } + }; // This is whoafully incomplete, but will do for now $scope.parse_error = function(data) { - var _error = data.match("nested: (.*?);") + var _error = data.match("nested: (.*?);"); return _.isNull(_error) ? data : _error[1]; - } + }; $scope.init(); @@ -89,31 +93,32 @@ angular.module('kibana.controllers', []) collapsable: true, editable: true, panels: [], - } - _.defaults($scope.row,_d) + }; + + _.defaults($scope.row,_d); $scope.init = function() { $scope.reset_panel(); - } + }; $scope.toggle_row = function(row) { row.collapse = row.collapse ? false : true; if (!row.collapse) { $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.$broadcast('render') - } + $scope.$broadcast('render'); + }; $scope.add_panel = function(row,panel) { $scope.row.panels.push(panel); - } + }; $scope.reset_panel = function() { $scope.panel = { @@ -121,7 +126,7 @@ angular.module('kibana.controllers', []) error : false, span : 3, editable: true, - group : ['default'], + group : ['default'] }; }; diff --git a/js/directives.js b/js/directives.js index c649d96155a..0acde7536a9 100644 --- a/js/directives.js +++ b/js/directives.js @@ -24,7 +24,7 @@ angular.module('kibana.directives', []) var template = '
'; elem.html($compile(angular.element(template))(scope)); } - }) + }); } }; }) @@ -39,11 +39,13 @@ angular.module('kibana.directives', []) } function join_array(text) { - if(_.isArray(text)) + if(_.isArray(text)) { return (text || '').join(','); - else - return text + } else { + return text; + } } + ngModel.$parsers.push(split_array); ngModel.$formatters.push(join_array); } @@ -54,8 +56,10 @@ angular.module('kibana.directives', []) restrict: 'A', require: 'ngModel', 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.bind('blur', function() { scope.$apply(function() { @@ -65,5 +69,4 @@ angular.module('kibana.directives', []) } }; }); -; diff --git a/js/filters.js b/js/filters.js index 3679ddec1e3..b17e7098d2e 100644 --- a/js/filters.js +++ b/js/filters.js @@ -6,5 +6,5 @@ angular.module('kibana.filters', []) .filter('stringSort', function() { return function(input) { return input.sort(); - } + }; }); \ No newline at end of file diff --git a/js/panels.js b/js/panels.js index d2af8ffebf1..ef98c7a189a 100644 --- a/js/panels.js +++ b/js/panels.js @@ -2,4 +2,4 @@ /*global angular:true */ 'use strict'; -angular.module('kibana.panels', []) +angular.module('kibana.panels', []); diff --git a/js/services.js b/js/services.js index d7a5afa8cce..5c2990cabdf 100644 --- a/js/services.js +++ b/js/services.js @@ -1,16 +1,18 @@ /*jshint globalstrict:true */ /*global angular:true */ +/*global Blob:false*/ 'use strict'; angular.module('kibana.services', []) .service('eventBus', function($rootScope) { // An array of registed types - var _types = [] + var _types = []; this.broadcast = function(from,to,type,data) { - if(_.isUndefined(data)) - var data = from + if(_.isUndefined(data)) { + data = from; + } var packet = { time: new Date(), @@ -18,38 +20,41 @@ angular.module('kibana.services', []) from: from, to: to, data: data - } + }; - if(_.contains(_types,'$kibana_debug')) + if(_.contains(_types,'$kibana_debug')) { $rootScope.$broadcast('$kibana_debug',packet); + } $rootScope.$broadcast(type,{ from: from, to: to, data: data }); - } + }; // 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 // is. this.register = function(scope,type,fn) { - _types = _.union(_types,[type]) + _types = _.union(_types,[type]); scope.$on(type,function(event,packet){ var _id = scope.$id; var _to = packet.to; var _from = packet.from; - var _type = packet.type - var _time = packet.time - var _group = (!(_.isUndefined(scope.panel))) ? scope.panel.group : ["NONE"] + var _type = packet.type; + var _time = packet.time; + var _group = (!(_.isUndefined(scope.panel))) ? scope.panel.group : ["NONE"]; - if(!(_.isArray(_to))) + if(!(_.isArray(_to))) { _to = [_to]; - if(!(_.isArray(_group))) + } + if(!(_.isArray(_group))) { _group = [_group]; - + } + // 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 // 3) Event is addressed to ALL 4) Receiver is in ALL group @@ -62,7 +67,7 @@ angular.module('kibana.services', []) fn(event,packet.data,{time:_time,to:_to,from:_from,type:_type}); } }); - } + }; }) /* Service: fields @@ -71,11 +76,11 @@ angular.module('kibana.services', []) .factory('fields', function($rootScope) { var fields = { list : [] - } + }; $rootScope.$on('fields', function(event,f) { - fields.list = _.union(f.data.all,fields.list) - }) + fields.list = _.union(f.data.all,fields.list); + }); return fields; @@ -93,8 +98,8 @@ angular.module('kibana.services', []) return all_indices().then(function(p) { var indices = _.intersection(possible,p); indices.reverse(); - return indices - }) + return indices; + }); }; // returns a promise containing an array of all indices in an elasticsearch @@ -110,7 +115,11 @@ angular.module('kibana.services', []) return something.then(function(p) { var indices = []; _.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; }); @@ -122,7 +131,7 @@ angular.module('kibana.services', []) // Update: I just read this again. I died a little more inside. // Update2: More death. function fake_utc(date) { - date = moment(date).clone().toDate() + date = moment(date).clone().toDate(); return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)); } @@ -136,20 +145,20 @@ angular.module('kibana.services', []) range.push(start.clone()); switch (interval) { case 'hour': - start.add('hours',1) - break + start.add('hours',1); + break; case 'day': - start.add('days',1) - break + start.add('days',1); + break; case 'week': - start.add('weeks',1) - break + start.add('weeks',1); + break; case 'month': - start.add('months',1) - break + start.add('months',1); + break; case 'year': - start.add('years',1) - break + start.add('years',1); + break; } } range.push(moment(end).clone()); @@ -169,19 +178,19 @@ angular.module('kibana.services', []) this.register = function(promise) { timers.push(promise); return promise; - } + }; this.cancel = function(promise) { - timers = _.without(timers,promise) - $timeout.cancel(promise) - } + timers = _.without(timers,promise); + $timeout.cancel(promise); + }; this.cancel_all = function() { _.each(timers, function(t){ $timeout.cancel(t); }); - timers = new Array(); - } + timers = []; + }; }) .service('query', function(dashboard) { @@ -214,10 +223,10 @@ angular.module('kibana.services', []) self.list = dashboard.current.services.query.list; self.ids = dashboard.current.services.query.ids; - if (self.ids.length == 0) { + if (self.ids.length === 0) { 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.set = function(query,id) { @@ -235,42 +244,44 @@ angular.module('kibana.services', []) alias: '', color: colorAt(_id), id: _id - } - _.defaults(query,_query) + }; + _.defaults(query,_query); self.list[_id] = query; - self.ids.push(_id) + self.ids.push(_id); return _id; } - } + }; this.remove = function(id) { if(!_.isUndefined(self.list[id])) { delete self.list[id]; // This must happen on the full path also since _.without returns a copy - self.ids = dashboard.current.services.query.ids = _.without(self.ids,id) - _q.idQueue.unshift(id) - _q.idQueue.sort(function(a,b){return a-b}); + self.ids = dashboard.current.services.query.ids = _.without(self.ids,id); + _q.idQueue.unshift(id); + _q.idQueue.sort(function(v,k){ + return v-k; + }); return true; } else { return false; } - } + }; this.findQuery = function(queryString) { - return _.findWhere(self.list,{query:queryString}) - } + return _.findWhere(self.list,{query:queryString}); + }; var nextId = function() { if(_q.idQueue.length > 0) { - return _q.idQueue.shift() + return _q.idQueue.shift(); } else { return self.ids.length; } - } + }; var colorAt = function(id) { - return self.colors[id % self.colors.length] - } + return self.colors[id % self.colors.length]; + }; self.init(); @@ -281,7 +292,7 @@ angular.module('kibana.services', []) _.defaults(dashboard.current.services.filter,{ idQueue : [], list : {}, - ids : [], + ids : [] }); // For convenience @@ -299,16 +310,16 @@ angular.module('kibana.services', []) _f = dashboard.current.services.filter; _.each(self.getByType('time',true),function(time) { - self.list[time.id].from = new Date(time.from) - self.list[time.id].to = new Date(time.to) - }) + self.list[time.id].from = new Date(time.from); + self.list[time.id].to = new Date(time.to); + }); - } + }; // This is used both for adding filters and modifying them. // If an id is passed, the filter at that id is updated this.set = function(filter,id) { - _.defaults(filter,{mandate:'must'}) + _.defaults(filter,{mandate:'must'}); filter.active = true; if(!_.isUndefined(id)) { if(!_.isUndefined(self.list[id])) { @@ -325,18 +336,19 @@ angular.module('kibana.services', []) var _filter = { alias: '', id: _id - } - _.defaults(filter,_filter) + }; + _.defaults(filter,_filter); self.list[_id] = filter; - self.ids.push(_id) + self.ids.push(_id); return _id; } } - } + }; this.getBoolFilter = function(ids) { // A default match all filter, just in case there are no other filters var bool = ejs.BoolFilter().must(ejs.MatchAllFilter()); + var either_bool = ejs.BoolFilter().must(ejs.MatchAllFilter()); _.each(ids,function(id) { if(self.list[id].active) { switch(self.list[id].mandate) @@ -344,75 +356,69 @@ angular.module('kibana.services', []) case 'mustNot': bool = bool.mustNot(self.getEjsObj(id)); break; - case 'should': - bool = bool.should(self.getEjsObj(id)); + case 'either': + either_bool = either_bool.should(self.getEjsObj(id)); break; default: bool = bool.must(self.getEjsObj(id)); } } - }) - return bool; - } + }); + return bool.must(either_bool); + }; this.getEjsObj = function(id) { - return self.toEjsObj(self.list[id]) - } + return self.toEjsObj(self.list[id]); + }; this.toEjsObj = function (filter) { if(!filter.active) { - return false + return false; } switch(filter.type) { case 'time': return ejs.RangeFilter(filter.field) .from(filter.from) - .to(filter.to) - break; + .to(filter.to); case 'range': return ejs.RangeFilter(filter.field) .from(filter.from) - .to(filter.to) - break; + .to(filter.to); case 'querystring': - return ejs.QueryFilter(ejs.QueryStringQuery(filter.query)) - break; + return ejs.QueryFilter(ejs.QueryStringQuery(filter.query)); case 'terms': - return ejs.TermsFilter(filter.field,filter.value) - break; + return ejs.TermsFilter(filter.field,filter.value); case 'exists': - return ejs.ExistsFilter(filter.field) - break; + return ejs.ExistsFilter(filter.field); case 'missing': - return ejs.MissingFilter(filter.field) - break; + return ejs.MissingFilter(filter.field); default: return false; } - } + }; 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) { - var ids = self.idsByType(type) + var ids = self.idsByType(type); _.each(ids,function(id) { - self.remove(id) - }) + self.remove(id); + }); return ids; - } + }; this.idsByType = function(type,inactive) { - var _require = inactive ? {type:type} : {type:type,active:true} - return _.pluck(_.where(self.list,_require),'id') - } + var _require = inactive ? {type:type} : {type:type,active:true}; + 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.timeRange = function(mode) { - var _t = _.where(self.list,{type:'time',active:true}) - if(_t.length == 0) { + var _t = _.where(self.list,{type:'time',active:true}); + if(_t.length === 0) { return false; } switch(mode) { @@ -420,41 +426,38 @@ angular.module('kibana.services', []) return { from: new Date(_.max(_.pluck(_t,'from'))), to: new Date(_.min(_.pluck(_t,'to'))) - } - break; + }; case "max": return { from: new Date(_.min(_.pluck(_t,'from'))), to: new Date(_.max(_.pluck(_t,'to'))) - } - break; + }; default: return false; } - - } + }; this.remove = function(id) { if(!_.isUndefined(self.list[id])) { delete self.list[id]; // This must happen on the full path also since _.without returns a copy - self.ids = dashboard.current.services.filter.ids = _.without(self.ids,id) - _f.idQueue.unshift(id) - _f.idQueue.sort(function(a,b){return a-b}); + self.ids = dashboard.current.services.filter.ids = _.without(self.ids,id); + _f.idQueue.unshift(id); + _f.idQueue.sort(function(v,k){return v-k;}); return true; } else { return false; } - } + }; var nextId = function() { if(_f.idQueue.length > 0) { - return _f.idQueue.shift() + return _f.idQueue.shift(); } else { return self.ids.length; } - } + }; // Now init self.init(); @@ -491,7 +494,7 @@ angular.module('kibana.services', []) self.current = {}; self.indices = []; route(); - }) + }); var route = function() { // Is there a dashboard type and id in the URL? @@ -499,29 +502,36 @@ angular.module('kibana.services', []) var _type = $routeParams.type; var _id = $routeParams.id; - if(_type === 'elasticsearch') - self.elasticsearch_load('dashboard',_id) - if(_type === 'temp') - self.elasticsearch_load('temp',_id) - if(_type === 'file') - self.file_load(_id) + switch(_type) { + case ('elasticsearch'): + self.elasticsearch_load('dashboard',_id); + break; + case ('temp'): + self.elasticsearch_load('temp',_id); + break; + case ('file'): + self.file_load(_id); + break; + default: + self.file_load('default.json'); + } // No dashboard in the URL } else { // Check if browser supports localstorage, and if there's a dashboard - if (Modernizr.localstorage && - !(_.isUndefined(localStorage['dashboard'])) && - localStorage['dashboard'] !== '' + if (window.Modernizr.localstorage && + !(_.isUndefined(window.localStorage['dashboard'])) && + window.localStorage['dashboard'] !== '' ) { - var dashboard = JSON.parse(localStorage['dashboard']); + var dashboard = JSON.parse(window.localStorage['dashboard']); _.defaults(dashboard,_dash); - self.dash_load(dashboard) + self.dash_load(dashboard); // No? Ok, grab default.json, its all we have now } 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 // here before telling the panels to refresh @@ -535,21 +545,21 @@ angular.module('kibana.services', []) if(p.length > 0) { self.indices = p; } else { - self.indices = [self.current.index.default] + self.indices = [self.current.index.default]; } - $rootScope.$broadcast('refresh') + $rootScope.$broadcast('refresh'); }); } else { // This is not optimal, we should be getting the entire index list here, or at least every // index that possibly matches the pattern - self.indices = [self.current.index.default] - $rootScope.$broadcast('refresh') + self.indices = [self.current.index.default]; + $rootScope.$broadcast('refresh'); } } else { - self.indices = [self.current.index.default] - $rootScope.$broadcast('refresh') + self.indices = [self.current.index.default]; + $rootScope.$broadcast('refresh'); } - } + }; this.dash_load = function(dashboard) { // Cancel all timers @@ -557,88 +567,89 @@ angular.module('kibana.services', []) // If not using time based indices, use the default index if(dashboard.index.interval === 'none') { - self.indices = [dashboard.index.default] + self.indices = [dashboard.index.default]; } self.current = _.clone(dashboard); // Ok, now that we've setup the current dashboard, we can inject our services query = $injector.get('query'); - filterSrv = $injector.get('filterSrv') + filterSrv = $injector.get('filterSrv'); // Make sure these re-init query.init(); filterSrv.init(); - if(dashboard.index.interval !== 'none' && filterSrv.idsByType('time').length == 0) { - //if(dashboard.index.interval !== 'none') { + if(dashboard.index.interval !== 'none' && filterSrv.idsByType('time').length === 0) { self.refresh(); } return true; - } + }; this.gist_id = function(string) { - if(self.is_gist(string)) + if(self.is_gist(string)) { return string.match(gist_pattern)[0].replace(/.*\//, ''); - } + } + }; 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; - else - return false - } + } else { + return false; + } + }; this.to_file = function() { var blob = new Blob([angular.toJson(self.current,true)], {type: "application/json;charset=utf-8"}); // from filesaver.js - saveAs(blob, self.current.title+"-"+new Date().getTime()); + window.saveAs(blob, self.current.title+"-"+new Date().getTime()); return true; - } + }; this.set_default = function(dashboard) { - if (Modernizr.localstorage) { - localStorage['dashboard'] = angular.toJson(dashboard || self.current); + if (window.Modernizr.localstorage) { + window.localStorage['dashboard'] = angular.toJson(dashboard || self.current); return true; } else { return false; } - } + }; this.purge_default = function() { - if (Modernizr.localstorage) { - localStorage['dashboard'] = ''; + if (window.Modernizr.localstorage) { + window.localStorage['dashboard'] = ''; return true; } else { return false; } - } + }; // TOFIX: Pretty sure this breaks when you're on a saved dashboard already this.share_link = function(title,type,id) { return { - location : location.href.replace(location.hash,""), + location : window.location.href.replace(window.location.hash,""), type : type, id : id, - link : location.href.replace(location.hash,"")+"#dashboard/"+type+"/"+id, + link : window.location.href.replace(window.location.hash,"")+"#dashboard/"+type+"/"+id, title : title }; - } + }; this.file_load = function(file) { return $http({ url: "dashboards/"+file, method: "GET", }).then(function(result) { - var _dashboard = result.data + var _dashboard = result.data; _.defaults(_dashboard,_dash); self.dash_load(_dashboard); return true; },function(result) { return false; }); - } + }; this.elasticsearch_load = function(type,id) { var request = ejs.Request().indices(config.kibana_index).types(type); @@ -649,19 +660,20 @@ angular.module('kibana.services', []) if(_.isUndefined(results)) { return false; } 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; } }); - } + }; this.elasticsearch_save = function(type,title,ttl) { // 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 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. @@ -670,10 +682,10 @@ angular.module('kibana.services', []) group: 'guest', title: save.title, dashboard: angular.toJson(save) - }) + }); - if (type === 'temp') - request = request.ttl(ttl) + request = type === 'temp' ? request.ttl(ttl) : request; + // TOFIX: Implement error handling here return request.doIndex( @@ -686,7 +698,7 @@ angular.module('kibana.services', []) return false; } ); - } + }; this.elasticsearch_delete = function(id) { return ejs.Document(config.kibana_index,'dashboard',id).doDelete( @@ -699,7 +711,7 @@ angular.module('kibana.services', []) return false; } ); - } + }; this.elasticsearch_list = function(query,count) { var request = ejs.Request().indices(config.kibana_index).types('dashboard'); @@ -715,11 +727,11 @@ angular.module('kibana.services', []) return false; } ); - } + }; // TOFIX: Gist functionality this.save_gist = function(title,dashboard) { - var save = _.clone(dashboard || self.current) + var save = _.clone(dashboard || self.current); save.title = title || self.current.title; return $http({ url: "https://api.github.com/gists", @@ -738,16 +750,16 @@ angular.module('kibana.services', []) }, function(data, status, headers, config) { return false; }); - } + }; this.gist_list = function(id) { return $http.jsonp("https://api.github.com/gists/"+id+"?callback=JSON_CALLBACK" ).then(function(response) { - var files = [] + var files = []; _.each(response.data.data.files,function(v,k) { try { - var file = JSON.parse(v.content) - files.push(file) + var file = JSON.parse(v.content); + files.push(file); } catch(e) { // Nothing? } @@ -756,20 +768,6 @@ angular.module('kibana.services', []) }, function(data, status, headers, config) { 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 diff --git a/panels/bettermap/module.js b/panels/bettermap/module.js index bb2da6b460d..f7775583c9c 100644 --- a/panels/bettermap/module.js +++ b/panels/bettermap/module.js @@ -1,3 +1,6 @@ +/*jshint globalstrict:true */ +/*global angular:true */ +/*global L:false*/ /* ## Better maps @@ -14,6 +17,8 @@ * spyable :: Show the 'eye' icon that reveals the last ES query */ +'use strict'; + angular.module('kibana.bettermap', []) .controller('bettermap', function($scope, query, dashboard, filterSrv) { @@ -26,61 +31,61 @@ angular.module('kibana.bettermap', []) tooltip : "_id", field : null, group : "default" - } - _.defaults($scope.panel,_d) + }; + _.defaults($scope.panel,_d); $scope.init = function() { $scope.$on('refresh',function(){ $scope.get_data(); - }) + }); $scope.get_data(); - } + }; $scope.get_data = function(segment,query_id) { $scope.panel.error = false; // Make sure we have everything for the request to complete - if(dashboard.indices.length == 0) { + if(dashboard.indices.length === 0) { return; } if(_.isUndefined($scope.panel.field)) { - $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format" - return + $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format"; + return; } // 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) { - $scope.panel.error = "Time field must be consistent amongst time filters" - } else if(timeField.length == 0) { + $scope.panel.error = "Time field must be consistent amongst time filters"; + } else if(timeField.length === 0) { timeField = null; } 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) { - boolQuery = boolQuery.should(ejs.QueryStringQuery((q.query || '*'))) - }) + boolQuery = boolQuery.should($scope.ejs.QueryStringQuery((q.query || '*'))); + }); var request = $scope.ejs.Request().indices(dashboard.indices[_segment]) - .query(ejs.FilteredQuery( + .query($scope.ejs.FilteredQuery( 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]) - .size($scope.panel.size) + .size($scope.panel.size); if(!_.isNull(timeField)) { 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 results.then(function(results) { @@ -89,7 +94,7 @@ angular.module('kibana.bettermap', []) if(_segment === 0) { $scope.hits = 0; $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 @@ -101,31 +106,32 @@ angular.module('kibana.bettermap', []) // Check that we're still on the same query, if not stop 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(){ $scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) { return { coordinates : new L.LatLng(hit.fields[$scope.panel.field][1],hit.fields[$scope.panel.field][0]), tooltip : hit.fields[$scope.panel.tooltip] - } + }; })); }); // 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 { return; } - $scope.$emit('draw') + $scope.$emit('draw'); // Get $size results then stop querying - if($scope.data.length < $scope.panel.size && _segment+1 < dashboard.indices.length) - $scope.get_data(_segment+1,$scope.query_id) + if($scope.data.length < $scope.panel.size && _segment+1 < dashboard.indices.length) { + $scope.get_data(_segment+1,$scope.query_id); + } }); - } + }; // I really don't like this function, too much dom manip. Break out into directive? $scope.populate_modal = function(request) { @@ -135,8 +141,8 @@ angular.module('kibana.bettermap', []) 'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+ angular.toJson(JSON.parse(request.toString()),true)+ "'", - } - } + }; + }; }) .directive('bettermap', function() { @@ -144,7 +150,7 @@ angular.module('kibana.bettermap', []) restrict: 'A', link: function(scope, elem, attrs) { - elem.html('
') + elem.html('
'); // Receive render events scope.$on('draw',function(){ @@ -154,9 +160,9 @@ angular.module('kibana.bettermap', []) scope.$on('render', function(){ if(!_.isUndefined(map)) { map.invalidateSize(); - var panes = map.getPanes() + var panes = map.getPanes(); } - }) + }); var map, markers, layerGroup, mcg; @@ -164,7 +170,7 @@ angular.module('kibana.bettermap', []) scope.panel.loading = false; 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 scripts.wait(function(){ @@ -185,16 +191,17 @@ angular.module('kibana.bettermap', []) } _.each(scope.data, function(p) { - if(!_.isUndefined(p.tooltip) && p.tooltip !== '') - layerGroup.addLayer(L.marker(p.coordinates).bindLabel(p.tooltip)) - else - layerGroup.addLayer(L.marker(p.coordinates)) - }) + if(!_.isUndefined(p.tooltip) && p.tooltip !== '') { + layerGroup.addLayer(L.marker(p.coordinates).bindLabel(p.tooltip)); + } else { + layerGroup.addLayer(L.marker(p.coordinates)); + } + }); - layerGroup.addTo(map) + layerGroup.addTo(map); map.fitBounds(_.pluck(scope.data,'coordinates')); - }) + }); } } }; diff --git a/panels/column/module.js b/panels/column/module.js index e563029d825..9edd9a34b6a 100644 --- a/panels/column/module.js +++ b/panels/column/module.js @@ -1,3 +1,5 @@ +/*jshint globalstrict:true */ +/*global angular:true */ /* ## Column @@ -8,26 +10,23 @@ ### Parameters * 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', []) -.controller('column', function($scope, $rootScope) { +.controller('column', function($scope, $rootScope, $timeout) { // Set and populate defaults var _d = { status: "Stable", - panels : [ - ] - } + panels : [] + }; _.defaults($scope.panel,_d); $scope.init = function(){ $scope.reset_panel(); - } + }; $scope.toggle_row = function(panel) { panel.collapse = panel.collapse ? false : true; @@ -36,15 +35,15 @@ angular.module('kibana.column', []) $scope.send_render(); }); } - } + }; $scope.send_render = function() { $scope.$broadcast('render'); - } + }; $scope.add_panel = function(panel) { $scope.panel.panels.push(panel); - } + }; $scope.reset_panel = function(type) { $scope.new_panel = { @@ -76,17 +75,17 @@ angular.module('kibana.column', []) $timeout(function() { // Create a reference to the new_panel as panel so that the existing // editors work with our isolate scope - scope.panel = scope.new_panel - var template = '
' + scope.panel = scope.new_panel; + var template = '
'; - if(!(_.isUndefined(scope.type)) && scope.type != "") + if(!(_.isUndefined(scope.type)) && scope.type !== "") { template = template+'
'; - //var new_elem = $compile(angular.element(template))(scope)) + } elem.html($compile(angular.element(template))(scope)); - }) - }) + }); + }); } - } + }; }).filter('withoutColumn', function() { return function() { return _.without(config.modules,'column'); diff --git a/panels/dashcontrol/module.js b/panels/dashcontrol/module.js index e2a159c17ac..6de4c89b8f3 100644 --- a/panels/dashcontrol/module.js +++ b/panels/dashcontrol/module.js @@ -1,3 +1,6 @@ +/*jshint globalstrict:true */ +/*global angular:true */ +/*global FileReader:false*/ /* ## Dashcontrol @@ -20,11 +23,8 @@ * temp :: Allow saving of temp dashboards * 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', []) .controller('dashcontrol', function($scope, $http, timer, dashboard) { @@ -49,7 +49,7 @@ angular.module('kibana.dashcontrol', []) elasticsearch_size: 20, temp: true, temp_ttl: '30d' - } + }; _.defaults($scope.panel,_d); // A hash of defaults for the dashboard object @@ -58,63 +58,63 @@ angular.module('kibana.dashcontrol', []) editable: true, rows: [], services: {} - } + }; $scope.init = function() { $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; $scope.gist = {}; $scope.elasticsearch = {}; - } + }; $scope.set_default = function() { 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 { - $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() { 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 { - $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) { dashboard.elasticsearch_save(type,($scope.elasticsearch.title || dashboard.current.title),ttl).then( function(result) { if(!_.isUndefined(result._id)) { $scope.alert('Dashboard Saved','This dashboard has been saved to Elasticsearch as "' + - result._id + '"','success',5000) + result._id + '"','success',5000); 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 { - $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) { dashboard.elasticsearch_delete(id).then( function(result) { if(!_.isUndefined(result)) { 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 - var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0] - $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete) + var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0]; + $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete); } 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 { - $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) { dashboard.elasticsearch_list(query,$scope.panel.elasticsearch_size).then( @@ -122,10 +122,10 @@ angular.module('kibana.dashcontrol', []) if(!_.isUndefined(result.hits)) { $scope.panel.error = false; $scope.hits = result.hits.total; - $scope.elasticsearch.dashboards = result.hits.hits + $scope.elasticsearch.dashboards = result.hits.hits; } - }) - } + }); + }; $scope.save_gist = function() { dashboard.save_gist($scope.gist.title).then( @@ -134,10 +134,10 @@ angular.module('kibana.dashcontrol', []) $scope.gist.last = link; $scope.alert('Gist saved','You will be able to access your exported dashboard file at '+link+' in a moment','success'); } 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) { dashboard.gist_list(id).then( @@ -145,10 +145,10 @@ angular.module('kibana.dashcontrol', []) if(files && files.length > 0) { $scope.gist.files = files; } 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){ return { @@ -159,14 +159,15 @@ angular.module('kibana.dashcontrol', []) // files is a FileList of File objects. List some properties. var output = []; + var readerOnload = function(theFile) { + return function(e) { + dashboard.dash_load(JSON.parse(e.target.result)); + scope.$apply(); + }; + }; for (var i = 0, f; f = files[i]; i++) { var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - dashboard.dash_load(JSON.parse(e.target.result)) - scope.$apply(); - }; - })(f); + reader.onload = (readerOnload)(f); reader.readAsText(f); } } @@ -179,15 +180,16 @@ angular.module('kibana.dashcontrol', []) alert('Sorry, the HTML5 File APIs are not fully supported in this browser.'); } } - } + }; }).filter('gistid', function() { - var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; - return function(input, scope) { - //return input+"boners" - if(!(_.isUndefined(input))) { - var output = input.match(gist_pattern); - if(!_.isNull(output) && !_.isUndefined(output)) - return output[0].replace(/.*\//, ''); - } + var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; + return function(input, scope) { + //return input+"boners" + if(!(_.isUndefined(input))) { + var output = input.match(gist_pattern); + if(!_.isNull(output) && !_.isUndefined(output)) { + return output[0].replace(/.*\//, ''); + } } -});; \ No newline at end of file + }; +}); \ No newline at end of file diff --git a/panels/fields/module.js b/panels/fields/module.js index e2a8a477c4c..a9ad74b744a 100644 --- a/panels/fields/module.js +++ b/panels/fields/module.js @@ -80,8 +80,12 @@ angular.module('kibana.fields', []) } $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}) dashboard.refresh(); } diff --git a/panels/filtering/module.html b/panels/filtering/module.html index 21ce51ffd47..204e02c787d 100644 --- a/panels/filtering/module.html +++ b/panels/filtering/module.html @@ -18,7 +18,7 @@ .filter-mustNot { border-bottom: #E24D42 3px solid; } - .filter-should { + .filter-either { border-bottom: #EF843C 3px solid; } .filter-action { @@ -26,13 +26,24 @@ margin-bottom: 0px !important; margin-left: 3px; } + .filter-mandate { + text-decoration: underline; + cursor: pointer; + }
- {{filterSrv.list[id].type}} {{filterSrv.list[id].mandate}} + {{filterSrv.list[id].type}} + {{filterSrv.list[id].mandate}} + + + + + + diff --git a/panels/filtering/module.js b/panels/filtering/module.js index 4c70615a617..dd78d7326d6 100644 --- a/panels/filtering/module.js +++ b/panels/filtering/module.js @@ -40,7 +40,7 @@ angular.module('kibana.filtering', []) } $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 diff --git a/panels/table/module.js b/panels/table/module.js index 943c1eae0c5..9aa43149da1 100644 --- a/panels/table/module.js +++ b/panels/table/module.js @@ -107,7 +107,13 @@ angular.module('kibana.table', []) } $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')}) $scope.panel.offset = 0; dashboard.refresh(); @@ -216,7 +222,7 @@ angular.module('kibana.table', []) $scope.modal = { title: "Table Inspector", body : "
Last Elasticsearch Query
"+
-          '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)+
         "'
", } diff --git a/panels/trends/module.js b/panels/trends/module.js index 87b8f734f4c..4b2ec418b81 100644 --- a/panels/trends/module.js +++ b/panels/trends/module.js @@ -1,12 +1,12 @@ +/*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 - * 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 * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' * ago :: Date math formatted time to look back