Browse Source

Linted, moved shared functions to kbn object

Rashid Khan 12 years ago
parent
commit
5a3028f784

+ 58 - 0
Gruntfile.js

@@ -0,0 +1,58 @@
+'use strict';
+
+module.exports = function (grunt) {
+
+  var post = ['src/client.js','src/post.js'];
+
+  // Project configuration.
+  grunt.initConfig({
+    pkg: grunt.file.readJSON('package.json'),
+    meta: {
+      banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
+        '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+        '<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
+        ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
+        ' Licensed <%= pkg.license %> */\n\n'
+    },
+    jshint: {
+      files: ['Gruntfile.js', 'js/*.js', 'panels/*/*.js' ],
+      options: {
+        bitwise: true,
+        curly: true,
+        eqeqeq: true,
+        immed: true,
+        indent: 2,
+        latedef: true,
+        newcap: true,
+        noarg: true,
+        sub: true,
+        undef: true,
+        boss: true,
+        eqnull: true,
+        globalstrict: true,
+        devel: true,
+        node: true,
+        globals: {
+          '$LAB': false,
+          '_': false,
+          '$': false,
+          'kbn' : false,
+          window: false,
+          document: false,
+          exports: true,
+          module: false,
+          config: false,
+          moment: false
+        }
+      }
+    }
+  });
+
+  // load plugins
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+
+
+  // Default task.
+  grunt.registerTask('default', ['jshint']);
+
+};

+ 251 - 368
common/lib/shared.js

@@ -1,412 +1,295 @@
-function get_object_fields(obj) {
-  var field_array = [];
-  obj = flatten_json(obj._source)
-  for (field in obj) {
-    field_array.push(field);
-  }
-  return field_array.sort();
-}
-
-function get_all_fields(data) {
-  var fields = [];
-  _.each(data,function(hit) {
-    fields = _.uniq(fields.concat(_.keys(hit)))
-  })
-  // Remove stupid angular key
-  fields = _.without(fields,'$$hashKey')
-  return fields;
-}
-
-function has_field(obj,field) {
-  var obj_fields = get_object_fields(obj);
-  if (_.inArray(obj_fields,field) < 0) {
-    return false;
-  } else {
-    return true;
-  }
-}
+// Wrap this all up in a 'kbn' object so I don't have a billion globals
+(function() {
 
 
-function get_related_fields(docs,field) {
-  var field_array = []
-  _.each(docs, function(doc) {
-    var keys = _.keys(doc)
-    if(_.contains(keys,field))
-      field_array = field_array.concat(keys)
-  })
-  var counts = _.countBy(_.without(field_array,field),function(field){return field;});
-  return counts;
-}
+  // Save a reference to this
+  var self = this;
 
 
-function recurse_field_dots(object,field) {
-  var value = null;
-  if (typeof object[field] != 'undefined')
-    value = object[field];
-  else if (nested = field.match(/(.*?)\.(.*)/))
-    if(typeof object[nested[1]] != 'undefined')
-      value = (typeof object[nested[1]][nested[2]] != 'undefined') ?
-        object[nested[1]][nested[2]] : recurse_field_dots(
-          object[nested[1]],nested[2]);
+  // Save a reference to the old versionof this
+  var wasKbn = self.kbn;
 
 
-  return value;
-}
+  // Create a safe refernce to the kbn object, for use below
+  var kbn = function(obj) { return new wrapper(obj); };
 
 
-// Probably useless now, leaving for cases where you might not want
-// a flat dot notated data structure
-function get_field_value(object,field,opt) {
-  var value = recurse_field_dots(object['_source'],field);
+  // Create a global object for accessing these functions
+  self.kbn = kbn;
 
 
-  if(value === null)
-    return ''
-  if(_.isArray(value))
-    if (opt == 'raw') {
-      return value;
-    }
-    else {
-        var complex = false;
-        _.each(value, function(el, index) {
-            if (typeof(el) == 'object') {
-                complex = true;
-            }
-        })
-        if (complex) {
-            return JSON.stringify(value, null, 4);
-        }
-        return value.toString();
+  kbn.get_object_fields = function(obj) {
+    var field_array = [];
+    obj = kbn.flatten_json(obj._source)
+    for (field in obj) {
+      field_array.push(field);
     }
     }
-  if(typeof value === 'object' && value != null)
-    // Leaving this out for now
-    //return opt == 'raw' ? value : JSON.stringify(value,null,4)
-    return JSON.stringify(value,null,4)
-
-  return (value != null) ? value.toString() : '';
-}
-
-function top_field_values(docs,field,count) {
-  var counts = _.countBy(_.pluck(docs,field),function(field){
-    return _.isUndefined(field) ? '' : field;
-  });
-  return _.pairs(counts).sort(function(a, b) {
-    return a[1] - b[1]
-  }).reverse().slice(0,count)
-}
+    return field_array.sort();
+  }
 
 
-function add_to_query(original,field,value,negate) {
-  var not = negate ? "-" : "";
-  if(value !== '')
-    var query = field + ":" + "\"" + addslashes(value.toString()) + "\"";
-  else
-    var query = "_missing_:" + field;
-  var glue = original != "" ? " AND " : "";
-  return original + glue + not + query;
-}
- /**
-   * Calculate a graph interval
-   *
-   * from::           Date object containing the start time
-   * to::             Date object containing the finish time
-   * size::           Calculate to approximately this many bars
-   * user_interval::  User specified histogram interval
-   *
-   */
-function calculate_interval(from,to,size,user_interval) {
-  if(_.isObject(from))
-    from = from.valueOf();
-  if(_.isObject(to))
-    to = to.valueOf();
-  return user_interval == 0 ? round_interval((to - from)/size) : user_interval;
-}
+  kbn.get_all_fields = function(data) {
+    var fields = [];
+    _.each(data,function(hit) {
+      fields = _.uniq(fields.concat(_.keys(hit)))
+    })
+    // Remove stupid angular key
+    fields = _.without(fields,'$$hashKey')
+    return fields;
+  }
 
 
-function get_bar_count(from,to,interval) {
-  return (to - from)/interval;
-}
+  kbn.has_field = function(obj,field) {
+    var obj_fields = get_object_fields(obj);
+    if (_.inArray(obj_fields,field) < 0) {
+      return false;
+    } else {
+      return true;
+    }
+  }
 
 
-function round_interval (interval) {
-  switch (true) {
-    // 0.5s
-    case (interval <= 500):         return 100;       // 0.1s
-    // 5s
-    case (interval <= 5000):        return 1000;      // 1s
-    // 7.5s
-    case (interval <= 7500):        return 5000;      // 5s
-    // 15s
-    case (interval <= 15000):       return 10000;     // 10s
-    // 45s
-    case (interval <= 45000):       return 30000;     // 30s
-    // 3m
-    case (interval <= 180000):      return 60000;     // 1m
-    // 9m
-    case (interval <= 450000):      return 300000;    // 5m
-    // 20m
-    case (interval <= 1200000):     return 600000;    // 10m
-    // 45m
-    case (interval <= 2700000):     return 1800000;   // 30m
-    // 2h
-    case (interval <= 7200000):     return 3600000;   // 1h
-    // 6h
-    case (interval <= 21600000):    return 10800000;  // 3h
-    // 24h
-    case (interval <= 86400000):    return 43200000;  // 12h
-    // 48h
-    case (interval <= 172800000):   return 86400000;  // 24h
-    // 1w
-    case (interval <= 604800000):   return 86400000;  // 24h
-    // 3w
-    case (interval <= 1814400000):  return 604800000; // 1w
-    // 2y
-    case (interval < 3628800000): return 2592000000; // 30d
-    default:                        return 31536000000; // 1y
+  kbn.get_related_fields = function(docs,field) {
+    var field_array = []
+    _.each(docs, function(doc) {
+      var keys = _.keys(doc)
+      if(_.contains(keys,field))
+        field_array = field_array.concat(keys)
+    })
+    var counts = _.countBy(_.without(field_array,field),function(field){return field;});
+    return counts;
   }
   }
-}
 
 
-function secondsToHms(seconds){
-    var numyears = Math.floor(seconds / 31536000);
-    if(numyears){
-        return numyears + 'y';
-    }
-    var numdays = Math.floor((seconds % 31536000) / 86400);
-    if(numdays){
-        return numdays + 'd';
-    }
-    var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
-    if(numhours){
-        return numhours + 'h';
-    }
-    var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
-    if(numminutes){
-        return numminutes + 'm';
-    }
-    var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
-    if(numseconds){
-        return numseconds + 's';
-    }
-    return 'less then a second'; //'just now' //or other string you like;
-}
+  kbn.recurse_field_dots = function(object,field) {
+    var value = null;
+    if (typeof object[field] != 'undefined')
+      value = object[field];
+    else if (nested = field.match(/(.*?)\.(.*)/))
+      if(typeof object[nested[1]] != 'undefined')
+        value = (typeof object[nested[1]][nested[2]] != 'undefined') ?
+          object[nested[1]][nested[2]] : recurse_field_dots(
+            object[nested[1]],nested[2]);
+
+    return value;
+  }
 
 
-function to_percent(number,outof) {
-  return Math.round((number/outof)*10000)/100 + "%";
-}
+  // Probably useless now, leaving for cases where you might not want
+  // a flat dot notated data structure
+  kbn.get_field_value = function(object,field,opt) {
+    var value = kbn.recurse_field_dots(object['_source'],field);
 
 
-function addslashes(str) {
-  str = str.replace(/\\/g, '\\\\');
-  str = str.replace(/\'/g, '\\\'');
-  str = str.replace(/\"/g, '\\"');
-  str = str.replace(/\0/g, '\\0');
-  return str;
-}
+    if(value === null)
+      return ''
+    if(_.isArray(value))
+      if (opt == 'raw') {
+        return value;
+      }
+      else {
+          var complex = false;
+          _.each(value, function(el, index) {
+              if (typeof(el) == 'object') {
+                  complex = true;
+              }
+          })
+          if (complex) {
+              return JSON.stringify(value, null, 4);
+          }
+          return value.toString();
+      }
+    if(typeof value === 'object' && value != null)
+      // Leaving this out for now
+      //return opt == 'raw' ? value : JSON.stringify(value,null,4)
+      return JSON.stringify(value,null,4)
 
 
-// Create an ISO8601 compliant timestamp for ES
-//function ISODateString(unixtime) {
-  //var d = new Date(parseInt(unixtime));
-function ISODateString(d) {
-  if(is_int(d)) {
-    d = new Date(parseInt(d));
+    return (value != null) ? value.toString() : '';
   }
   }
 
 
-  function pad(n) {
-    return n < 10 ? '0' + n : n
+  kbn.top_field_values = function(docs,field,count) {
+    var counts = _.countBy(_.pluck(docs,field),function(field){
+      return _.isUndefined(field) ? '' : field;
+    });
+    return _.pairs(counts).sort(function(a, b) {
+      return a[1] - b[1]
+    }).reverse().slice(0,count)
   }
   }
-  return d.getFullYear() + '-' +
-    pad(d.getMonth() + 1) + '-' +
-    pad(d.getDate()) + 'T' +
-    pad(d.getHours()) + ':' +
-    pad(d.getMinutes()) + ':' +
-    pad(d.getSeconds());
-}
 
 
-function pickDateString(d) {
-  return dateFormat(d,'yyyy-mm-dd HH:MM:ss')
-}
+   /**
+     * Calculate a graph interval
+     *
+     * from::           Date object containing the start time
+     * to::             Date object containing the finish time
+     * size::           Calculate to approximately this many bars
+     * user_interval::  User specified histogram interval
+     *
+     */
+  kbn.calculate_interval = function(from,to,size,user_interval) {
+    if(_.isObject(from))
+      from = from.valueOf();
+    if(_.isObject(to))
+      to = to.valueOf();
+    return user_interval == 0 ? kbn.round_interval((to - from)/size) : user_interval;
+  }
 
 
-function prettyDateString(d) {
-  d = new Date(parseInt(d));
-  d = utc_date_obj(d);
-  return dateFormat(d,window.time_format);
-}
+  kbn.round_interval = function(interval) {
+    switch (true) {
+      // 0.5s
+      case (interval <= 500):         return 100;       // 0.1s
+      // 5s
+      case (interval <= 5000):        return 1000;      // 1s
+      // 7.5s
+      case (interval <= 7500):        return 5000;      // 5s
+      // 15s
+      case (interval <= 15000):       return 10000;     // 10s
+      // 45s
+      case (interval <= 45000):       return 30000;     // 30s
+      // 3m
+      case (interval <= 180000):      return 60000;     // 1m
+      // 9m
+      case (interval <= 450000):      return 300000;    // 5m
+      // 20m
+      case (interval <= 1200000):     return 600000;    // 10m
+      // 45m
+      case (interval <= 2700000):     return 1800000;   // 30m
+      // 2h
+      case (interval <= 7200000):     return 3600000;   // 1h
+      // 6h
+      case (interval <= 21600000):    return 10800000;  // 3h
+      // 24h
+      case (interval <= 86400000):    return 43200000;  // 12h
+      // 48h
+      case (interval <= 172800000):   return 86400000;  // 24h
+      // 1w
+      case (interval <= 604800000):   return 86400000;  // 24h
+      // 3w
+      case (interval <= 1814400000):  return 604800000; // 1w
+      // 2y
+      case (interval < 3628800000): return 2592000000; // 30d
+      default:                        return 31536000000; // 1y
+    }
+  }
 
 
-function utc_date_obj(d) {
-  return new Date(
-    d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(),  
-    d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(),
-    d.getUTCMilliseconds());
-}
+  kbn.secondsToHms = function(seconds){
+      var numyears = Math.floor(seconds / 31536000);
+      if(numyears){
+          return numyears + 'y';
+      }
+      var numdays = Math.floor((seconds % 31536000) / 86400);
+      if(numdays){
+          return numdays + 'd';
+      }
+      var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
+      if(numhours){
+          return numhours + 'h';
+      }
+      var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
+      if(numminutes){
+          return numminutes + 'm';
+      }
+      var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
+      if(numseconds){
+          return numseconds + 's';
+      }
+      return 'less then a second'; //'just now' //or other string you like;
+  }
 
 
-function local_date_obj(d) {
-  return new Date(Date.UTC(
-    d.getFullYear(), d.getMonth(), d.getDate(),  
-    d.getHours(), d.getMinutes(), d.getSeconds()));
-}
+  kbn.to_percent = function(number,outof) {
+    return Math.round((number/outof)*10000)/100 + "%";
+  }
 
 
-function is_int(value) {
-  if ((parseFloat(value) == parseInt(value)) && !isNaN(value)) {
-    return true;
-  } else {
-    return false;
+  kbn.addslashes = function(str) {
+    str = str.replace(/\\/g, '\\\\');
+    str = str.replace(/\'/g, '\\\'');
+    str = str.replace(/\"/g, '\\"');
+    str = str.replace(/\0/g, '\\0');
+    return str;
   }
   }
-}
 
 
-function interval_to_seconds(string) {
-  var matches = string.match(/(\d+)([Mwdhmsy])/);
-  switch (matches[2]) {
-    case 'y': return matches[1]*31536000;;
-    case 'M': return matches[1]*2592000;;
-    case 'w': return matches[1]*604800;;
-    case 'd': return matches[1]*86400;;
-    case 'h': return matches[1]*3600;;
-    case 'm': return matches[1]*60;;
-    case 's': return matches[1];
-  } 
-}
+  // histogram & trends
+  kbn.interval_to_seconds = function(string) {
+    var matches = string.match(/(\d+)([Mwdhmsy])/);
+    switch (matches[2]) {
+      case 'y': return matches[1]*31536000;;
+      case 'M': return matches[1]*2592000;;
+      case 'w': return matches[1]*604800;;
+      case 'd': return matches[1]*86400;;
+      case 'h': return matches[1]*3600;;
+      case 'm': return matches[1]*60;;
+      case 's': return matches[1];
+    } 
+  }
 
 
-function time_ago(string) {
-  return new Date(new Date().getTime() - (interval_to_seconds(string)*1000))
-}
+  // This should go away, moment.js can do this
+  kbn.time_ago = function(string) {
+    return new Date(new Date().getTime() - (kbn.interval_to_seconds(string)*1000))
+  }
 
 
-function flatten_json(object,root,array) {
-  if (typeof array === 'undefined')
-    var array = {};
-  if (typeof root === 'undefined')
-    var root = '';
-  for(var index in object) {
-    var obj = object[index]
-    var rootname = root.length == 0 ? index : root + '.' + index;
-    if(typeof obj == 'object' ) {
-      if(_.isArray(obj)) {
-        if(obj.length > 0 && typeof obj[0] === 'object') {
-          var strval = '';
-          for (var objidx = 0, objlen = obj.length; objidx < objlen; objidx++) {
-            if (objidx > 0) {
-              strval = strval + ', ';
+  // LOL. hahahahaha. DIE.
+  kbn.flatten_json = function(object,root,array) {
+    if (typeof array === 'undefined')
+      var array = {};
+    if (typeof root === 'undefined')
+      var root = '';
+    for(var index in object) {
+      var obj = object[index]
+      var rootname = root.length == 0 ? index : root + '.' + index;
+      if(typeof obj == 'object' ) {
+        if(_.isArray(obj)) {
+          if(obj.length > 0 && typeof obj[0] === 'object') {
+            var strval = '';
+            for (var objidx = 0, objlen = obj.length; objidx < objlen; objidx++) {
+              if (objidx > 0) {
+                strval = strval + ', ';
+              }
+              
+              strval = strval + JSON.stringify(obj[objidx]);
             }
             }
-            
-            strval = strval + JSON.stringify(obj[objidx]);
+            array[rootname] = strval;
+          } else if(obj.length === 1 && _.isNumber(obj[0])) {
+            array[rootname] = parseFloat(obj[0]);
+          } else {
+            array[rootname] = typeof obj === 'undefined' ? null : obj;
           }
           }
-          array[rootname] = strval;
-        } else if(obj.length === 1 && _.isNumber(obj[0])) {
-          array[rootname] = parseFloat(obj[0]);
         } else {
         } else {
-          array[rootname] = typeof obj === 'undefined' ? null : obj;
+          kbn.flatten_json(obj,rootname,array)
         }
         }
       } else {
       } else {
-        flatten_json(obj,rootname,array)
+        array[rootname] = typeof obj === 'undefined' ? null : obj;
       }
       }
-    } else {
-      array[rootname] = typeof obj === 'undefined' ? null : obj;
     }
     }
+    return kbn.sortObj(array);
   }
   }
-  return sortObj(array);
-}
-
-function xmlEnt(value) {
-  if(_.isString(value)) {
-  var stg1 = value.replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;')
-    .replace(/\r\n/g, '<br/>')
-    .replace(/\r/g, '<br/>')
-    .replace(/\n/g, '<br/>')
-    .replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')
-    .replace(/  /g, '&nbsp;&nbsp;')
-    .replace(/&lt;del&gt;/g, '<del>')
-    .replace(/&lt;\/del&gt;/g, '</del>');
-  return stg1
-  } else {
-    return value
-  }
-}
-
-function sortObj(arr) {
-  // Setup Arrays
-  var sortedKeys = new Array();
-  var sortedObj = {};
-
-  // Separate keys and sort them
-  for (var i in arr) {
-    sortedKeys.push(i);
-  }
-  sortedKeys.sort();
 
 
-  // Reconstruct sorted obj based on keys
-  for (var i in sortedKeys) {
-    sortedObj[sortedKeys[i]] = arr[sortedKeys[i]];
-  }
-  return sortedObj;
-}
-
-// WTF. Has to be a better way to do this. Hi Tyler.
-function int_to_tz(offset) {
-  var hour = offset / 1000 / 3600
-  var str = ""
-  if (hour == 0) {
-    str = "+0000"
-  }
-  if (hour < 0) {
-    if (hour > -10)
-      str = "-0" + (hour * -100)
-    else
-      str = "-" + (hour * -100)
-  }
-  if (hour > 0) {
-    if (hour < 10)
-      str = "+0" + (hour * 100)
-    else
-      str = "+" + (hour * 100)
+  kbn.xmlEnt = function(value) {
+    if(_.isString(value)) {
+      var stg1 = value.replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/\r\n/g, '<br/>')
+        .replace(/\r/g, '<br/>')
+        .replace(/\n/g, '<br/>')
+        .replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')
+        .replace(/  /g, '&nbsp;&nbsp;')
+        .replace(/&lt;del&gt;/g, '<del>')
+        .replace(/&lt;\/del&gt;/g, '</del>');
+      return stg1;
+    } else {
+      return value;
+    }
   }
   }
-  str = str.substring(0,3) + ":" + str.substring(3);
-  return str
-}
 
 
-// Sets #hash, thus refreshing results
-function setHash(json) {
-  window.location.hash = encodeURIComponent(Base64.encode(JSON.stringify(json)));
-}
+  kbn.sortObj = function(arr) {
+    // Setup Arrays
+    var sortedKeys = new Array();
+    var sortedObj = {};
 
 
-// Add commas to numbers
-function addCommas(nStr) {
-  nStr += '';
-  var x = nStr.split('.');
-  var x1 = x[0];
-  var x2 = x.length > 1 ? '.' + x[1] : '';
-  var rgx = /(\d+)(\d{3})/;
-  while (rgx.test(x1)) {
-    x1 = x1.replace(rgx, '$1' + ',' + '$2');
-  }
-  return x1 + x2;
-}
-
-// Split up log spaceless strings
-// Str = string to split
-// num = number of letters between <wbr> tags
-function wbr(str, num) {
-  str = htmlEntities(str);
-  return str.replace(
-    RegExp("(@?\\w{" + num + "}|[:;,])([\\w\"'])([\\w@]*)", "g"),
-    function (all, text, char, trailer) {
-      if (/@KIBANA_\w+_(START|END)@/.test(all)) {
-        return text + char + trailer;
-      } else {
-        return text + "<del>&#8203;</del>" + char + trailer;
-      }
+    // Separate keys and sort them
+    for (var i in arr) {
+      sortedKeys.push(i);
     }
     }
-  );
-}
+    sortedKeys.sort();
 
 
-function htmlEntities(str) {
-    return String(str).replace(
-      /&/g, '&amp;').replace(
-      /</g, '&lt;').replace(
-      />/g, '&gt;').replace(
-      /"/g, '&quot;');
-}
-
-function bucket_round(start,num,dir) {
-  var resto = start%num;
-  if (resto <= (num/2) || dir === 'down') {
-    // Down
-    return start-resto;
-  } else {
-    // Up
-    return start+num-resto;
+    // Reconstruct sorted obj based on keys
+    for (var i in sortedKeys) {
+      sortedObj[sortedKeys[i]] = arr[sortedKeys[i]];
+    }
+    return sortedObj;
   }
   }
-}
+}).call(this);
+
+/*
+  UNDERSCORE.js Mixins
+*/
 
 
 _.mixin({
 _.mixin({
     move: function (array, fromIndex, toIndex) {
     move: function (array, fromIndex, toIndex) {

+ 1 - 1
js/directives.js

@@ -77,6 +77,6 @@ angular.module('kibana.directives', [])
         fn(scope, {$event:event});
         fn(scope, {$event:event});
       });
       });
     });
     });
-  }
+  };
 }]);
 }]);
 
 

+ 3 - 2
js/services.js

@@ -243,7 +243,8 @@ angular.module('kibana.services', [])
         query: '*',
         query: '*',
         alias: '',
         alias: '',
         color: colorAt(_id),
         color: colorAt(_id),
-        id: _id
+        id: _id,
+        type: 'lucene'
       };
       };
       _.defaults(query,_query);
       _.defaults(query,_query);
       self.list[_id] = query;
       self.list[_id] = query;
@@ -386,7 +387,7 @@ angular.module('kibana.services', [])
         .from(filter.from)
         .from(filter.from)
         .to(filter.to);
         .to(filter.to);
     case 'querystring':
     case 'querystring':
-      return ejs.QueryFilter(ejs.QueryStringQuery(filter.query));
+      return ejs.QueryFilter(ejs.QueryStringQuery(filter.query)).cache(true);
     case 'terms':
     case 'terms':
       return ejs.TermsFilter(filter.field,filter.value);
       return ejs.TermsFilter(filter.field,filter.value);
     case 'exists':
     case 'exists':

+ 14 - 0
package.json

@@ -0,0 +1,14 @@
+{
+  "author": {
+    "name": "Rashid Khan",
+    "company": "Elasticsearch BV"
+  },
+  "name": "kibana",
+  "version": "3.0.0m3pre",
+  "devDependencies": {
+    "grunt": "~0.4.0",
+    "grunt-contrib": "~0.7.0",
+    "grunt-contrib-jshint": "~0.6.0"
+  },
+  "license": "Apache License"
+}

+ 34 - 28
panels/derivequeries/module.js

@@ -1,3 +1,5 @@
+/*jshint globalstrict:true */
+/*global angular:true */
 /*
 /*
 
 
   ## Derivequeries
   ## Derivequeries
@@ -14,6 +16,8 @@
 
 
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.derivequeries', [])
 angular.module('kibana.derivequeries', [])
 .controller('derivequeries', function($scope, $rootScope, query, fields, dashboard, filterSrv) {
 .controller('derivequeries', function($scope, $rootScope, query, fields, dashboard, filterSrv) {
 
 
@@ -33,19 +37,19 @@ angular.module('kibana.derivequeries', [])
     exclude : [],
     exclude : [],
     history : [],
     history : [],
     remember: 10 // max: 100, angular strap can't take a variable for items param
     remember: 10 // max: 100, angular strap can't take a variable for items param
-  }
+  };
   _.defaults($scope.panel,_d);
   _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
-    $scope.panel.fields = fields.list
-  }
+    $scope.panel.fields = fields.list;
+  };
 
 
   $scope.get_data = function() {
   $scope.get_data = function() {
     update_history($scope.panel.query);
     update_history($scope.panel.query);
     
     
     // 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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     }
     }
 
 
     $scope.panel.loading = true;
     $scope.panel.loading = true;
@@ -53,15 +57,15 @@ angular.module('kibana.derivequeries', [])
 
 
     // Terms mode
     // Terms mode
     request = request
     request = request
-      .facet(ejs.TermsFacet('query')
+      .facet($scope.ejs.TermsFacet('query')
         .field($scope.panel.field)
         .field($scope.panel.field)
-        .size($scope.panel['size'])
+        .size($scope.panel.size)
         .exclude($scope.panel.exclude)
         .exclude($scope.panel.exclude)
-        .facetFilter(ejs.QueryFilter(
-          ejs.FilteredQuery(
-            ejs.QueryStringQuery($scope.panel.query || '*'),
+        .facetFilter($scope.ejs.QueryFilter(
+          $scope.ejs.FilteredQuery(
+            $scope.ejs.QueryStringQuery($scope.panel.query || '*'),
             filterSrv.getBoolFilter(filterSrv.ids)
             filterSrv.getBoolFilter(filterSrv.ids)
-            )))).size(0)
+            )))).size(0);
 
 
     $scope.populate_modal(request);
     $scope.populate_modal(request);
 
 
@@ -70,19 +74,20 @@ angular.module('kibana.derivequeries', [])
     // Populate scope when we have results
     // Populate scope when we have results
     results.then(function(results) {
     results.then(function(results) {
       $scope.panel.loading = false;
       $scope.panel.loading = false;
-      var data = [];
+      var suffix,
+          data = [];
       if ($scope.panel.query === '' || $scope.panel.mode === 'terms only') {
       if ($scope.panel.query === '' || $scope.panel.mode === 'terms only') {
-        var suffix = '';
+        suffix = '';
       } else if ($scope.panel.mode === 'AND') {
       } else if ($scope.panel.mode === 'AND') {
-        var suffix = ' AND (' + $scope.panel.query + ')';
+        suffix = ' AND (' + $scope.panel.query + ')';
       } else if ($scope.panel.mode === 'OR') {
       } else if ($scope.panel.mode === 'OR') {
-        var suffix = ' OR (' + $scope.panel.query + ')';
+        suffix = ' OR (' + $scope.panel.query + ')';
       }
       }
       var ids = [];
       var ids = [];
       _.each(results.facets.query.terms, function(v) {
       _.each(results.facets.query.terms, function(v) {
         var _q = $scope.panel.field+':"'+v.term+'"'+suffix;
         var _q = $scope.panel.field+':"'+v.term+'"'+suffix;
         // if it isn't in the list, remove it
         // if it isn't in the list, remove it
-        var _iq = query.findQuery(_q)
+        var _iq = query.findQuery(_q);
         if(!_iq) {
         if(!_iq) {
           ids.push(query.set({query:_q}));
           ids.push(query.set({query:_q}));
         } else {
         } else {
@@ -90,22 +95,23 @@ angular.module('kibana.derivequeries', [])
         }
         }
       });
       });
       _.each(_.difference($scope.panel.ids,ids),function(id){
       _.each(_.difference($scope.panel.ids,ids),function(id){
-        query.remove(id)
-      })
+        query.remove(id);
+      });
       $scope.panel.ids = ids;
       $scope.panel.ids = ids;
       dashboard.refresh();
       dashboard.refresh();
     });
     });
-  }
+  };
 
 
   $scope.set_refresh = function (state) { 
   $scope.set_refresh = function (state) { 
     $scope.refresh = state; 
     $scope.refresh = state; 
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
-    if($scope.refresh)
+    if($scope.refresh) {
       $scope.get_data();
       $scope.get_data();
+    }
     $scope.refresh =  false;
     $scope.refresh =  false;
-  }
+  };
 
 
   $scope.populate_modal = function(request) {
   $scope.populate_modal = function(request) {
     $scope.modal = {
     $scope.modal = {
@@ -114,18 +120,18 @@ angular.module('kibana.derivequeries', [])
           '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>", 
-    } 
-  }
+    }; 
+  };
 
 
   var update_history = function(query) {
   var update_history = function(query) {
     query = _.isArray(query) ? query : [query];
     query = _.isArray(query) ? query : [query];
     if($scope.panel.remember > 0) {
     if($scope.panel.remember > 0) {
-      $scope.panel.history = _.union(query.reverse(),$scope.panel.history)
-      var _length = $scope.panel.history.length
+      $scope.panel.history = _.union(query.reverse(),$scope.panel.history);
+      var _length = $scope.panel.history.length;
       if(_length > $scope.panel.remember) {
       if(_length > $scope.panel.remember) {
-        $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember)
+        $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember);
       }
       }
     }
     }
-  }
+  };
 
 
 });
 });

+ 33 - 27
panels/fields/module.js

@@ -1,3 +1,6 @@
+/*jshint globalstrict:true */
+/*global angular:true */
+
 /*
 /*
 
 
   ## Fields
   ## Fields
@@ -17,6 +20,9 @@
   * fields :: an object containing the sort order, existing fields and selected fields
   * fields :: an object containing the sort order, existing fields and selected fields
 
 
 */
 */
+
+'use strict';
+
 angular.module('kibana.fields', [])
 angular.module('kibana.fields', [])
 .controller('fields', function($scope, eventBus, $timeout, dashboard, query, filterSrv) {
 .controller('fields', function($scope, eventBus, $timeout, dashboard, query, filterSrv) {
 
 
@@ -27,7 +33,7 @@ angular.module('kibana.fields', [])
     style   : {},
     style   : {},
     arrange : 'vertical',
     arrange : 'vertical',
     micropanel_position : 'right', 
     micropanel_position : 'right', 
-  }
+  };
   _.defaults($scope.panel,_d);
   _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
@@ -35,7 +41,7 @@ angular.module('kibana.fields', [])
     $scope.fields = [];
     $scope.fields = [];
     eventBus.register($scope,'fields', function(event, fields) {
     eventBus.register($scope,'fields', function(event, fields) {
       $scope.panel.sort = _.clone(fields.sort);
       $scope.panel.sort = _.clone(fields.sort);
-      $scope.fields     = fields.all,
+      $scope.fields     = fields.all;
       $scope.active     = _.clone(fields.active);
       $scope.active     = _.clone(fields.active);
     });
     });
     eventBus.register($scope,'table_documents', function(event, docs) {
     eventBus.register($scope,'table_documents', function(event, docs) {
@@ -46,57 +52,57 @@ angular.module('kibana.fields', [])
     eventBus.register($scope,"get_fields", function(event,id) {
     eventBus.register($scope,"get_fields", function(event,id) {
       eventBus.broadcast($scope.$id,$scope.panel.group,"selected_fields",$scope.active);
       eventBus.broadcast($scope.$id,$scope.panel.group,"selected_fields",$scope.active);
     });
     });
-  }
+  };
 
 
   $scope.reload_list = function () {
   $scope.reload_list = function () {
     var temp = _.clone($scope.fields);
     var temp = _.clone($scope.fields);
-    $scope.fields = []    
+    $scope.fields = [];    
     $timeout(function(){
     $timeout(function(){
       $scope.fields = temp;
       $scope.fields = temp;
-    },10)
+    },10);
     
     
-  }
+  };
 
 
   $scope.toggle_micropanel = function(field) {
   $scope.toggle_micropanel = function(field) {
     $scope.micropanel = {
     $scope.micropanel = {
       field: field,
       field: field,
-      values : top_field_values($scope.docs,field,10),
-      related : get_related_fields($scope.docs,field),
-      count: _.countBy($scope.docs,function(doc){
-        return _.contains(_.keys(doc),field)})['true'],
-    }
-  }
+      values : kbn.top_field_values($scope.docs,field,10),
+      related : kbn.get_related_fields($scope.docs,field),
+      count: _.countBy($scope.docs,function(doc){return _.contains(_.keys(doc),field);})['true']
+    };
+  };
 
 
   $scope.toggle_sort = function() {
   $scope.toggle_sort = function() {
-    $scope.panel.sort[1] = $scope.panel.sort[1] == 'asc' ? 'desc' : 'asc';
-  }
+    $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc';
+  };
 
 
   $scope.toggle_field = function(field) {
   $scope.toggle_field = function(field) {
-    if (_.indexOf($scope.active,field) > -1) 
-      $scope.active = _.without($scope.active,field)
-    else
-      $scope.active.push(field)
-    eventBus.broadcast($scope.$id,$scope.panel.group,"selected_fields",$scope.active)
-  }
+    if (_.indexOf($scope.active,field) > -1) {
+      $scope.active = _.without($scope.active,field);
+    } else {
+      $scope.active.push(field);
+    }
+    eventBus.broadcast($scope.$id,$scope.panel.group,"selected_fields",$scope.active);
+  };
 
 
   $scope.build_search = function(field,value,mandate) {
   $scope.build_search = function(field,value,mandate) {
     var query;
     var query;
     if(_.isArray(value)) {
     if(_.isArray(value)) {
-      query = field+":(" + _.map(value,function(v){return "\""+v+"\""}).join(",") + ")";
+      query = field+":(" + _.map(value,function(v){return "\""+v+"\"";}).join(",") + ")";
     } else {
     } else {
       query = field+":"+angular.toJson(value);
       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();
-  }
+  };
 
 
   $scope.fieldExists = function(field,mandate) {
   $scope.fieldExists = function(field,mandate) {
-    filterSrv.set({type:'exists',field:field,mandate:mandate})
+    filterSrv.set({type:'exists',field:field,mandate:mandate});
     dashboard.refresh();
     dashboard.refresh();
-  }
+  };
 
 
   $scope.is_active = function(field) {
   $scope.is_active = function(field) {
     return _.indexOf($scope.active,field) > -1 ? ['label','label-info'] : '';    
     return _.indexOf($scope.active,field) > -1 ? ['label','label-info'] : '';    
-  }
+  };
 
 
-})
+});

+ 15 - 11
panels/filtering/module.js

@@ -1,3 +1,5 @@
+/*jshint globalstrict:true */
+/*global angular:true */
 /*
 /*
 
 
   ## filtering
   ## filtering
@@ -8,39 +10,41 @@
 
 
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.filtering', [])
 angular.module('kibana.filtering', [])
 .controller('filtering', function($scope, filterSrv, $rootScope, dashboard) {
 .controller('filtering', function($scope, filterSrv, $rootScope, dashboard) {
 
 
   // Set and populate defaults
   // Set and populate defaults
   var _d = {
   var _d = {
     status  : "Experimental"
     status  : "Experimental"
-  }
+  };
   _.defaults($scope.panel,_d);
   _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
-    $scope.filterSrv = filterSrv
-  }
+    $scope.filterSrv = filterSrv;
+  };
 
 
   $scope.remove = function(id) {
   $scope.remove = function(id) {
     filterSrv.remove(id);
     filterSrv.remove(id);
     dashboard.refresh();
     dashboard.refresh();
-  }
+  };
 
 
   $scope.toggle = function(id) {
   $scope.toggle = function(id) {
     filterSrv.list[id].active = !filterSrv.list[id].active;
     filterSrv.list[id].active = !filterSrv.list[id].active;
     dashboard.refresh();
     dashboard.refresh();
-  }
+  };
 
 
   $scope.refresh = function(query) {
   $scope.refresh = function(query) {
-    $rootScope.$broadcast('refresh')
-  }
+    $rootScope.$broadcast('refresh');
+  };
 
 
   $scope.render = function(query) {
   $scope.render = function(query) {
-    $rootScope.$broadcast('render')
-  }
+    $rootScope.$broadcast('render');
+  };
 
 
   $scope.show_key = function(key) {
   $scope.show_key = function(key) {
-    return !_.contains(['type','id','alias','mandate','active','editing'],key)
-  }
+    return !_.contains(['type','id','alias','mandate','active','editing'],key);
+  };
 
 
 });
 });

+ 89 - 74
panels/histogram/module.js

@@ -1,3 +1,6 @@
+/*jshint globalstrict:true */
+/*global angular:true */
+
 /*
 /*
 
 
   ## Histogram
   ## Histogram
@@ -35,6 +38,8 @@
 
 
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.histogram', [])
 angular.module('kibana.histogram', [])
 .controller('histogram', function($scope, eventBus, query, dashboard, filterSrv) {
 .controller('histogram', function($scope, eventBus, query, dashboard, filterSrv) {
 
 
@@ -63,8 +68,8 @@ angular.module('kibana.histogram', [])
     'y-axis'    : true,
     'y-axis'    : true,
     percentage  : false,
     percentage  : false,
     interactive : true,
     interactive : true,
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
 
 
@@ -72,49 +77,51 @@ angular.module('kibana.histogram', [])
 
 
     $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) {
-    delete $scope.panel.error
+    delete $scope.panel.error;
 
 
     // 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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     }
     }
 
 
     var _range = $scope.range = filterSrv.timeRange('min');
     var _range = $scope.range = filterSrv.timeRange('min');
     
     
-    if ($scope.panel.auto_int)
-      $scope.panel.interval = secondsToHms(calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000);
-    
+    if ($scope.panel.auto_int) {
+      $scope.panel.interval = kbn.secondsToHms(
+        kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000);
+    }
+
     $scope.panel.loading = true;
     $scope.panel.loading = true;
-    var _segment = _.isUndefined(segment) ? 0 : segment
+    var _segment = _.isUndefined(segment) ? 0 : segment;
     var request = $scope.ejs.Request().indices(dashboard.indices[_segment]);
     var request = $scope.ejs.Request().indices(dashboard.indices[_segment]);
 
 
     // Build the query
     // Build the query
     _.each($scope.queries.ids, function(id) {
     _.each($scope.queries.ids, function(id) {
       var query = $scope.ejs.FilteredQuery(
       var query = $scope.ejs.FilteredQuery(
-        ejs.QueryStringQuery($scope.queries.list[id].query || '*'),
+        $scope.ejs.QueryStringQuery($scope.queries.list[id].query || '*'),
         filterSrv.getBoolFilter(filterSrv.ids)
         filterSrv.getBoolFilter(filterSrv.ids)
-      )
+      );
 
 
-      var facet = $scope.ejs.DateHistogramFacet(id)
+      var facet = $scope.ejs.DateHistogramFacet(id);
       
       
       if($scope.panel.mode === 'count') {
       if($scope.panel.mode === 'count') {
-        facet = facet.field($scope.panel.time_field)
+        facet = facet.field($scope.panel.time_field);
       } else {
       } else {
         if(_.isNull($scope.panel.value_field)) {
         if(_.isNull($scope.panel.value_field)) {
           $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified";
           $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified";
-          return
+          return;
         }
         }
-        facet = facet.keyField($scope.panel.time_field).valueField($scope.panel.value_field)
+        facet = facet.keyField($scope.panel.time_field).valueField($scope.panel.value_field);
       }
       }
-      facet = facet.interval($scope.panel.interval).facetFilter($scope.ejs.QueryFilter(query))
-      request = request.facet(facet).size(0)
+      facet = facet.interval($scope.panel.interval).facetFilter($scope.ejs.QueryFilter(query));
+      request = request.facet(facet).size(0);
     });
     });
 
 
     // Populate the inspector panel
     // Populate the inspector panel
@@ -127,7 +134,7 @@ angular.module('kibana.histogram', [])
     results.then(function(results) {
     results.then(function(results) {
 
 
       $scope.panel.loading = false;
       $scope.panel.loading = false;
-      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();
@@ -140,37 +147,39 @@ angular.module('kibana.histogram', [])
       }
       }
 
 
       // Convert facet ids to numbers
       // Convert facet ids to numbers
-      var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k);})
+      var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);});
 
 
       // Make sure we're still on the same query/queries
       // Make sure we're still on the same query/queries
       if($scope.query_id === query_id && 
       if($scope.query_id === query_id && 
-        _.intersection(facetIds,query.ids).length == query.ids.length
+        _.intersection(facetIds,query.ids).length === query.ids.length
         ) {
         ) {
 
 
         var i = 0;
         var i = 0;
+        var data, hits;
+
         _.each(query.ids, function(id) {
         _.each(query.ids, function(id) {
           var v = results.facets[id];
           var v = results.facets[id];
 
 
           // Null values at each end of the time range ensure we see entire range
           // Null values at each end of the time range ensure we see entire range
-          if(_.isUndefined($scope.data[i]) || _segment == 0) {
-            var data = []
+          if(_.isUndefined($scope.data[i]) || _segment === 0) {
+            data = [];
             if(filterSrv.idsByType('time').length > 0) {
             if(filterSrv.idsByType('time').length > 0) {
               data = [[_range.from.getTime(), null],[_range.to.getTime(), null]];
               data = [[_range.from.getTime(), null],[_range.to.getTime(), null]];
             }
             }
-            var hits = 0;
+            hits = 0;
           } else {
           } else {
-            var data = $scope.data[i].data
-            var hits = $scope.data[i].hits
+            data = $scope.data[i].data;
+            hits = $scope.data[i].hits;
           }
           }
 
 
           // Assemble segments
           // Assemble segments
           var segment_data = [];
           var segment_data = [];
           _.each(v.entries, function(v, k) {
           _.each(v.entries, function(v, k) {
-            segment_data.push([v['time'],v[$scope.panel.mode]])
-            hits += v['count']; // The series level hits counter
-            $scope.hits += v['count']; // Entire dataset level hits counter
+            segment_data.push([v.time,v[$scope.panel.mode]]);
+            hits += v.count; // The series level hits counter
+            $scope.hits += v.count; // Entire dataset level hits counter
           });
           });
-          data.splice.apply(data,[1,0].concat(segment_data)) // Join histogram data
+          data.splice.apply(data,[1,0].concat(segment_data)); // Join histogram data
 
 
           // Create the flot series object
           // Create the flot series object
           var series = { 
           var series = { 
@@ -181,22 +190,22 @@ angular.module('kibana.histogram', [])
             },
             },
           };
           };
 
 
-          $scope.data[i] = series.data
+          $scope.data[i] = series.data;
 
 
           i++;
           i++;
         });
         });
 
 
         // Tell the histogram directive to render.
         // Tell the histogram directive to render.
-        $scope.$emit('render')
+        $scope.$emit('render');
 
 
         // If we still have segments left, get them
         // If we still have segments left, get them
         if(_segment < dashboard.indices.length-1) {
         if(_segment < dashboard.indices.length-1) {
-          $scope.get_data(_segment+1,query_id)
+          $scope.get_data(_segment+1,query_id);
         }
         }
       
       
       }
       }
     });
     });
-  }
+  };
 
 
   // function $scope.zoom
   // function $scope.zoom
   // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
   // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
@@ -204,31 +213,31 @@ angular.module('kibana.histogram', [])
     var _now = Date.now();
     var _now = Date.now();
     var _range = filterSrv.timeRange('min');
     var _range = filterSrv.timeRange('min');
     var _timespan = (_range.to.valueOf() - _range.from.valueOf());
     var _timespan = (_range.to.valueOf() - _range.from.valueOf());
-    var _center = _range.to.valueOf() - _timespan/2
+    var _center = _range.to.valueOf() - _timespan/2;
 
 
-    var _to = (_center + (_timespan*factor)/2)
-    var _from = (_center - (_timespan*factor)/2)
+    var _to = (_center + (_timespan*factor)/2);
+    var _from = (_center - (_timespan*factor)/2);
 
 
     // If we're not already looking into the future, don't.
     // If we're not already looking into the future, don't.
     if(_to > Date.now() && _range.to < Date.now()) {
     if(_to > Date.now() && _range.to < Date.now()) {
-      var _offset = _to - Date.now()
-      _from = _from - _offset
+      var _offset = _to - Date.now();
+      _from = _from - _offset;
       _to = Date.now();
       _to = Date.now();
     }
     }
 
 
     if(factor > 1) {
     if(factor > 1) {
-      filterSrv.removeByType('time')
+      filterSrv.removeByType('time');
     }
     }
     filterSrv.set({
     filterSrv.set({
       type:'time',
       type:'time',
       from:moment.utc(_from),
       from:moment.utc(_from),
       to:moment.utc(_to),
       to:moment.utc(_to),
       field:$scope.panel.time_field
       field:$scope.panel.time_field
-    })
+    });
     
     
     dashboard.refresh();
     dashboard.refresh();
 
 
-  }
+  };
 
 
   // 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) {
@@ -238,19 +247,20 @@ angular.module('kibana.histogram', [])
           '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>", 
-    } 
-  }
+    }; 
+  };
 
 
   $scope.set_refresh = function (state) { 
   $scope.set_refresh = function (state) { 
     $scope.refresh = state; 
     $scope.refresh = state; 
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
-    if($scope.refresh)
+    if($scope.refresh) {
       $scope.get_data();
       $scope.get_data();
+    }
     $scope.refresh =  false;
     $scope.refresh =  false;
     $scope.$emit('render');
     $scope.$emit('render');
-  }
+  };
 
 
 })
 })
 .directive('histogramChart', function(dashboard, eventBus, filterSrv, $rootScope) {
 .directive('histogramChart', function(dashboard, eventBus, filterSrv, $rootScope) {
@@ -274,19 +284,19 @@ angular.module('kibana.histogram', [])
         // Populate from the query service
         // Populate from the query service
         try {
         try {
           _.each(scope.data,function(series) {
           _.each(scope.data,function(series) {
-            series.label = series.info.alias,
-            series.color = series.info.color
-          })
-        } catch(e) {return}
+            series.label = series.info.alias;
+            series.color = series.info.color;
+          });
+        } catch(e) {return;}
 
 
         // Set barwidth based on specified interval
         // Set barwidth based on specified interval
-        var barwidth = interval_to_seconds(scope.panel.interval)*1000
+        var barwidth = kbn.interval_to_seconds(scope.panel.interval)*1000;
 
 
         var scripts = $LAB.script("common/lib/panels/jquery.flot.js").wait()
         var scripts = $LAB.script("common/lib/panels/jquery.flot.js").wait()
           .script("common/lib/panels/jquery.flot.time.js")
           .script("common/lib/panels/jquery.flot.time.js")
           .script("common/lib/panels/jquery.flot.stack.js")
           .script("common/lib/panels/jquery.flot.stack.js")
           .script("common/lib/panels/jquery.flot.selection.js")
           .script("common/lib/panels/jquery.flot.selection.js")
-          .script("common/lib/panels/timezone.js")
+          .script("common/lib/panels/timezone.js");
                     
                     
         // Populate element. Note that jvectormap appends, does not replace.
         // Populate element. Note that jvectormap appends, does not replace.
         scripts.wait(function(){
         scripts.wait(function(){
@@ -331,33 +341,38 @@ angular.module('kibana.histogram', [])
                 hoverable: true,
                 hoverable: true,
               },
               },
               colors: ['#86B22D','#BF6730','#1D7373','#BFB930','#BF3030','#77207D']
               colors: ['#86B22D','#BF6730','#1D7373','#BFB930','#BF3030','#77207D']
-            }
+            };
 
 
-            if(scope.panel.interactive)
+            if(scope.panel.interactive) {
               options.selection = { mode: "x", color: '#aaa' };
               options.selection = { mode: "x", color: '#aaa' };
+            }
 
 
-            scope.plot = $.plot(elem, scope.data, options)
+            scope.plot = $.plot(elem, scope.data, options);
             
             
-            // Work around for missing legend at initialization
-            if(!scope.$$phase)
-              scope.$apply()
+            // Work around for missing legend at initialization.
+            if(!scope.$$phase) {
+              scope.$apply();
+            }
 
 
           } catch(e) {
           } catch(e) {
-            elem.text(e)
+            elem.text(e);
           }
           }
-        })
+        });
       }
       }
 
 
       function time_format(interval) {
       function time_format(interval) {
-        var _int = interval_to_seconds(interval)
-        if(_int >= 2628000)
-          return "%m/%y"
-        if(_int >= 86400)
-          return "%m/%d/%y"
-        if(_int >= 60)
-          return "%H:%M<br>%m/%d"
-        else
-          return "%H:%M:%S"
+        var _int = kbn.interval_to_seconds(interval);
+        if(_int >= 2628000) {
+          return "%m/%y";
+        }
+        if(_int >= 86400) {
+          return "%m/%d/%y";
+        }
+        if(_int >= 60) {
+          return "%H:%M<br>%m/%d";
+        }
+        
+        return "%H:%M:%S";
       }
       }
 
 
       function tt(x, y, contents) {
       function tt(x, y, contents) {
@@ -396,9 +411,9 @@ angular.module('kibana.histogram', [])
           from  : moment.utc(ranges.xaxis.from),
           from  : moment.utc(ranges.xaxis.from),
           to    : moment.utc(ranges.xaxis.to),
           to    : moment.utc(ranges.xaxis.to),
           field : scope.panel.time_field
           field : scope.panel.time_field
-        })
+        });
         dashboard.refresh();
         dashboard.refresh();
       });
       });
     }
     }
   };
   };
-})
+});

+ 49 - 39
panels/hits/module.js

@@ -1,3 +1,6 @@
+/*jshint globalstrict:true */
+/*global angular:true */
+
 /*
 /*
 
 
   ## Hits
   ## Hits
@@ -15,6 +18,9 @@
   * lables :: Only 'pie' charts. Labels on the pie?
   * lables :: Only 'pie' charts. Labels on the pie?
 
 
 */
 */
+
+'use strict';
+
 angular.module('kibana.hits', [])
 angular.module('kibana.hits', [])
 .controller('hits', function($scope, query, dashboard, filterSrv) {
 .controller('hits', function($scope, query, dashboard, filterSrv) {
 
 
@@ -30,41 +36,41 @@ angular.module('kibana.hits', [])
     donut   : false,
     donut   : false,
     tilt    : false,
     tilt    : false,
     labels  : true
     labels  : true
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   $scope.init = function () {
   $scope.init = function () {
     $scope.hits = 0;
     $scope.hits = 0;
    
    
     $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) {
-    delete $scope.panel.error
+    delete $scope.panel.error;
     $scope.panel.loading = true;
     $scope.panel.loading = true;
 
 
     // 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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     }
     }
 
 
-    var _segment = _.isUndefined(segment) ? 0 : segment
+    var _segment = _.isUndefined(segment) ? 0 : segment;
     var request = $scope.ejs.Request().indices(dashboard.indices[_segment]);
     var request = $scope.ejs.Request().indices(dashboard.indices[_segment]);
     
     
     // Build the question part of the query
     // Build the question part of the query
     _.each(query.ids, function(id) {
     _.each(query.ids, function(id) {
       var _q = $scope.ejs.FilteredQuery(
       var _q = $scope.ejs.FilteredQuery(
-        ejs.QueryStringQuery(query.list[id].query || '*'),
+        $scope.ejs.QueryStringQuery(query.list[id].query || '*'),
         filterSrv.getBoolFilter(filterSrv.ids));
         filterSrv.getBoolFilter(filterSrv.ids));
     
     
       request = request
       request = request
         .facet($scope.ejs.QueryFacet(id)
         .facet($scope.ejs.QueryFacet(id)
           .query(_q)
           .query(_q)
-        ).size(0)
+        ).size(0);
     });
     });
 
 
     // TODO: Spy for hits panel
     // TODO: Spy for hits panel
@@ -76,7 +82,7 @@ angular.module('kibana.hits', [])
     // Populate scope when we have results
     // Populate scope when we have results
     results.then(function(results) {
     results.then(function(results) {
       $scope.panel.loading = false;
       $scope.panel.loading = false;
-      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();
@@ -89,18 +95,18 @@ angular.module('kibana.hits', [])
       }
       }
 
 
       // Convert facet ids to numbers
       // Convert facet ids to numbers
-      var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k);})
+      var facetIds = _.map(_.keys(results.facets),function(k){return parseInt(k, 10);});
 
 
       // Make sure we're still on the same query/queries
       // Make sure we're still on the same query/queries
       if($scope.query_id === query_id && 
       if($scope.query_id === query_id && 
-        _.intersection(facetIds,query.ids).length == query.ids.length
+        _.intersection(facetIds,query.ids).length === query.ids.length
         ) {
         ) {
         var i = 0;
         var i = 0;
         _.each(query.ids, function(id) {
         _.each(query.ids, function(id) {
-          var v = results.facets[id]
-          var hits = _.isUndefined($scope.data[i]) || _segment == 0 ? 
-            v.count : $scope.data[i].hits+v.count
-          $scope.hits += v.count
+          var v = results.facets[id];
+          var hits = _.isUndefined($scope.data[i]) || _segment === 0 ? 
+            v.count : $scope.data[i].hits+v.count;
+          $scope.hits += v.count;
 
 
           // Create series
           // Create series
           $scope.data[i] = { 
           $scope.data[i] = { 
@@ -113,23 +119,25 @@ angular.module('kibana.hits', [])
           i++;
           i++;
         });
         });
         $scope.$emit('render');
         $scope.$emit('render');
-        if(_segment < dashboard.indices.length-1) 
-          $scope.get_data(_segment+1,query_id)
+        if(_segment < dashboard.indices.length-1) {
+          $scope.get_data(_segment+1,query_id);
+        }
         
         
       }
       }
     });
     });
-  }
+  };
 
 
   $scope.set_refresh = function (state) { 
   $scope.set_refresh = function (state) { 
     $scope.refresh = state; 
     $scope.refresh = state; 
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
-    if($scope.refresh)
+    if($scope.refresh) {
       $scope.get_data();
       $scope.get_data();
+    }
     $scope.refresh =  false;
     $scope.refresh =  false;
     $scope.$emit('render');
     $scope.$emit('render');
-  }
+  };
 
 
   function set_time(time) {
   function set_time(time) {
     $scope.time = time;
     $scope.time = time;
@@ -156,20 +164,20 @@ angular.module('kibana.hits', [])
 
 
         try {
         try {
           _.each(scope.data,function(series) {
           _.each(scope.data,function(series) {
-            series.label = series.info.alias,
-            series.color = series.info.color
-          })
-        } catch(e) {return}
+            series.label = series.info.alias;
+            series.color = series.info.color;
+          });
+        } catch(e) {return;}
 
 
         var scripts = $LAB.script("common/lib/panels/jquery.flot.js").wait()
         var scripts = $LAB.script("common/lib/panels/jquery.flot.js").wait()
-                          .script("common/lib/panels/jquery.flot.pie.js")
+                          .script("common/lib/panels/jquery.flot.pie.js");
 
 
         // Populate element.
         // Populate element.
         scripts.wait(function(){
         scripts.wait(function(){
           // Populate element
           // Populate element
           try {
           try {
             // Add plot to scope so we can build out own legend 
             // Add plot to scope so we can build out own legend 
-            if(scope.panel.chart === 'bar')
+            if(scope.panel.chart === 'bar') {
               scope.plot = $.plot(elem, scope.data, {
               scope.plot = $.plot(elem, scope.data, {
                 legend: { show: false },
                 legend: { show: false },
                 series: {
                 series: {
@@ -186,8 +194,9 @@ angular.module('kibana.hits', [])
                   hoverable: true,
                   hoverable: true,
                 },
                 },
                 colors: query.colors
                 colors: query.colors
-              })
-            if(scope.panel.chart === 'pie')
+              });
+            }
+            if(scope.panel.chart === 'pie') {
               scope.plot = $.plot(elem, scope.data, {
               scope.plot = $.plot(elem, scope.data, {
                 legend: { show: false },
                 legend: { show: false },
                 series: {
                 series: {
@@ -218,19 +227,20 @@ angular.module('kibana.hits', [])
                 grid:   { hoverable: true, clickable: true },
                 grid:   { hoverable: true, clickable: true },
                 colors: query.colors
                 colors: query.colors
               });
               });
-
+            }
             // Compensate for the height of the  legend. Gross
             // Compensate for the height of the  legend. Gross
             elem.height(
             elem.height(
-              (scope.panel.height || scope.row.height).replace('px','') - $("#"+scope.$id+"-legend").height())
+              (scope.panel.height || scope.row.height).replace('px','') - $("#"+scope.$id+"-legend").height());
 
 
             // Work around for missing legend at initialization
             // Work around for missing legend at initialization
-            if(!scope.$$phase)
-              scope.$apply()
+            if(!scope.$$phase) {
+              scope.$apply();
+            }
 
 
           } catch(e) {
           } catch(e) {
-            elem.text(e)
+            elem.text(e);
           }
           }
-        })
+        });
       }
       }
 
 
       function tt(x, y, contents) {
       function tt(x, y, contents) {
@@ -256,7 +266,7 @@ angular.module('kibana.hits', [])
             item.datapoint[1] : item.datapoint[1][0][1];
             item.datapoint[1] : item.datapoint[1][0][1];
           tt(pos.pageX, pos.pageY,
           tt(pos.pageX, pos.pageY,
             "<div style='vertical-align:middle;border-radius:10px;display:inline-block;background:"+
             "<div style='vertical-align:middle;border-radius:10px;display:inline-block;background:"+
-            item.series.color+";height:20px;width:20px'></div> "+value.toFixed(0))
+            item.series.color+";height:20px;width:20px'></div> "+value.toFixed(0));
         } else {
         } else {
           $("#pie-tooltip").remove();
           $("#pie-tooltip").remove();
         }
         }
@@ -264,4 +274,4 @@ angular.module('kibana.hits', [])
 
 
     }
     }
   };
   };
-})
+});

+ 36 - 28
panels/map/module.js

@@ -1,3 +1,6 @@
+/*jshint globalstrict:true */
+/*global angular:true */
+
 /*
 /*
 
 
   ## Map
   ## Map
@@ -22,6 +25,8 @@
 
 
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.map', [])
 angular.module('kibana.map', [])
 .controller('map', function($scope, $rootScope, query, dashboard, filterSrv) {
 .controller('map', function($scope, $rootScope, query, dashboard, filterSrv) {
 
 
@@ -36,37 +41,39 @@ angular.module('kibana.map', [])
     spyable : true,
     spyable : true,
     group   : "default",
     group   : "default",
     index_limit : 0
     index_limit : 0
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
-    $scope.$on('refresh',function(){$scope.get_data()})
+    $scope.$on('refresh',function(){$scope.get_data();});
     $scope.get_data();
     $scope.get_data();
-  }
+  };
 
 
   $scope.get_data = function() {
   $scope.get_data = function() {
     
     
     // 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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     }
     }
-
     $scope.panel.loading = true;
     $scope.panel.loading = true;
-    var request = $scope.ejs.Request().indices(dashboard.indices);
 
 
-    var boolQuery = ejs.BoolQuery();
+
+    var request;
+    request = $scope.ejs.Request().indices(dashboard.indices);
+
+    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 || '*'));
+    });
 
 
     // Then the insert into facet and make the request
     // Then the insert into facet and make the request
-    var request = request
-      .facet(ejs.TermsFacet('map')
+    request = request
+      .facet($scope.ejs.TermsFacet('map')
         .field($scope.panel.field)
         .field($scope.panel.field)
-        .size($scope.panel['size'])
+        .size($scope.panel.size)
         .exclude($scope.panel.exclude)
         .exclude($scope.panel.exclude)
-        .facetFilter(ejs.QueryFilter(
-          ejs.FilteredQuery(
+        .facetFilter($scope.ejs.QueryFilter(
+          $scope.ejs.FilteredQuery(
             boolQuery,
             boolQuery,
             filterSrv.getBoolFilter(filterSrv.ids)
             filterSrv.getBoolFilter(filterSrv.ids)
             )))).size(0);
             )))).size(0);
@@ -83,9 +90,9 @@ angular.module('kibana.map', [])
       _.each(results.facets.map.terms, function(v) {
       _.each(results.facets.map.terms, function(v) {
         $scope.data[v.term.toUpperCase()] = v.count;
         $scope.data[v.term.toUpperCase()] = v.count;
       });
       });
-      $scope.$emit('render')
+      $scope.$emit('render');
     });
     });
-  }
+  };
 
 
   // 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) {
@@ -95,13 +102,13 @@ angular.module('kibana.map', [])
           '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>", 
-    } 
-  }
+    }; 
+  };
 
 
   $scope.build_search = function(field,value) {
   $scope.build_search = function(field,value) {
-    filterSrv.set({type:'querystring',mandate:'must',query:field+":"+value})
+    filterSrv.set({type:'querystring',mandate:'must',query:field+":"+value});
     dashboard.refresh();
     dashboard.refresh();
-  }
+  };
 
 
 })
 })
 .directive('map', function() {
 .directive('map', function() {
@@ -109,7 +116,7 @@ angular.module('kibana.map', [])
     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('render',function(){
       scope.$on('render',function(){
@@ -124,7 +131,7 @@ angular.module('kibana.map', [])
       function render_panel() {
       function render_panel() {
         // Using LABjs, wait until all scripts are loaded before rendering panel
         // Using LABjs, wait until all scripts are loaded before rendering panel
         var scripts = $LAB.script("panels/map/lib/jquery.jvectormap.min.js").wait()
         var scripts = $LAB.script("panels/map/lib/jquery.jvectormap.min.js").wait()
-          .script("panels/map/lib/map."+scope.panel.map+".js")
+          .script("panels/map/lib/map."+scope.panel.map+".js");
                     
                     
         // Populate element. Note that jvectormap appends, does not replace.
         // Populate element. Note that jvectormap appends, does not replace.
         scripts.wait(function(){
         scripts.wait(function(){
@@ -143,7 +150,7 @@ angular.module('kibana.map', [])
               }]
               }]
             },
             },
             onRegionLabelShow: function(event, label, code){
             onRegionLabelShow: function(event, label, code){
-              elem.children('.map-legend').show()
+              elem.children('.map-legend').show();
               var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
               var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
               elem.children('.map-legend').text(label.text() + ": " + count);
               elem.children('.map-legend').text(label.text() + ": " + count);
             },
             },
@@ -152,13 +159,14 @@ angular.module('kibana.map', [])
             },
             },
             onRegionClick: function(event, code) {
             onRegionClick: function(event, code) {
               var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
               var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code];
-              if (count != 0) 
-                scope.build_search(scope.panel.field,code)
+              if (count !== 0) {
+                scope.build_search(scope.panel.field,code);
+              }
             }
             }
           });
           });
           elem.prepend('<span class="map-legend"></span>');
           elem.prepend('<span class="map-legend"></span>');
           $('.map-legend').hide();
           $('.map-legend').hide();
-        })
+        });
       }
       }
     }
     }
   };
   };

+ 53 - 48
panels/pie/module.js

@@ -1,3 +1,5 @@
+/*jshint globalstrict:true */
+/*global angular:true */
 /*
 /*
 
 
   ## Pie
   ## Pie
@@ -22,9 +24,10 @@
   * default_field ::  LOL wat? A dumb fail over field if for some reason the query object 
   * default_field ::  LOL wat? A dumb fail over field if for some reason the query object 
                       doesn't have a field
                       doesn't have a field
   * spyable :: Show the 'eye' icon that displays the last ES query for this panel
   * spyable :: Show the 'eye' icon that displays the last ES query for this panel
-
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.pie', [])
 angular.module('kibana.pie', [])
 .controller('pie', function($scope, $rootScope, query, dashboard, filterSrv) {
 .controller('pie', function($scope, $rootScope, query, dashboard, filterSrv) {
 
 
@@ -42,13 +45,13 @@ angular.module('kibana.pie', [])
     group   : "default",
     group   : "default",
     default_field : 'DEFAULT',
     default_field : 'DEFAULT',
     spyable : true,
     spyable : true,
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
-    $scope.$on('refresh',function(){$scope.get_data()})
+    $scope.$on('refresh',function(){$scope.get_data();});
     $scope.get_data();
     $scope.get_data();
-  }
+  };
 
 
   $scope.set_mode = function(mode) {
   $scope.set_mode = function(mode) {
     switch(mode)
     switch(mode)
@@ -60,51 +63,54 @@ angular.module('kibana.pie', [])
       $scope.panel.query = {goal:100};
       $scope.panel.query = {goal:100};
       break;
       break;
     }
     }
-  }
+  };
 
 
   $scope.set_refresh = function (state) { 
   $scope.set_refresh = function (state) { 
     $scope.refresh = state; 
     $scope.refresh = state; 
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
-    if($scope.refresh)
+    if($scope.refresh) {
       $scope.get_data();
       $scope.get_data();
+    }
     $scope.refresh =  false;
     $scope.refresh =  false;
     $scope.$emit('render');
     $scope.$emit('render');
-  }
+  };
 
 
   $scope.get_data = function() {
   $scope.get_data = function() {
     
     
     // 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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     } 
     } 
 
 
     $scope.panel.loading = true;
     $scope.panel.loading = true;
     var request = $scope.ejs.Request().indices(dashboard.indices);
     var request = $scope.ejs.Request().indices(dashboard.indices);
 
 
     // This could probably be changed to a BoolFilter 
     // This could probably be changed to a BoolFilter 
-    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 results;
 
 
     // Terms mode
     // Terms mode
-    if ($scope.panel.mode == "terms") {
+    if ($scope.panel.mode === "terms") {
       request = request
       request = request
-        .facet(ejs.TermsFacet('pie')
+        .facet($scope.ejs.TermsFacet('pie')
           .field($scope.panel.query.field || $scope.panel.default_field)
           .field($scope.panel.query.field || $scope.panel.default_field)
-          .size($scope.panel['size'])
+          .size($scope.panel.size)
           .exclude($scope.panel.exclude)
           .exclude($scope.panel.exclude)
-          .facetFilter(ejs.QueryFilter(
-            ejs.FilteredQuery(
+          .facetFilter($scope.ejs.QueryFilter(
+            $scope.ejs.FilteredQuery(
               boolQuery,
               boolQuery,
               filterSrv.getBoolFilter(filterSrv.ids)
               filterSrv.getBoolFilter(filterSrv.ids)
-              )))).size(0)
+              )))).size(0);
 
 
       $scope.populate_modal(request);
       $scope.populate_modal(request);
 
 
-      var results = request.doSearch();
+      results = request.doSearch();
 
 
       // Populate scope when we have results
       // Populate scope when we have results
       results.then(function(results) {
       results.then(function(results) {
@@ -115,12 +121,7 @@ angular.module('kibana.pie', [])
         _.each(results.facets.pie.terms, function(v) {
         _.each(results.facets.pie.terms, function(v) {
           var slice = { label : v.term, data : v.count }; 
           var slice = { label : v.term, data : v.count }; 
           $scope.data.push();
           $scope.data.push();
-          if(!(_.isUndefined($scope.panel.colors)) 
-            && _.isArray($scope.panel.colors)
-            && $scope.panel.colors.length > 0) {
-            slice.color = $scope.panel.colors[k%$scope.panel.colors.length];
-          } 
-          $scope.data.push(slice)
+          $scope.data.push(slice);
           k = k + 1;
           k = k + 1;
         });
         });
         $scope.$emit('render');
         $scope.$emit('render');
@@ -130,11 +131,11 @@ angular.module('kibana.pie', [])
       request = request
       request = request
         .query(boolQuery)
         .query(boolQuery)
         .filter(filterSrv.getBoolFilter(filterSrv.ids))
         .filter(filterSrv.getBoolFilter(filterSrv.ids))
-        .size(0)
+        .size(0);
       
       
       $scope.populate_modal(request);
       $scope.populate_modal(request);
  
  
-      var results = request.doSearch();
+      results = request.doSearch();
 
 
       results.then(function(results) {
       results.then(function(results) {
         $scope.panel.loading = false;
         $scope.panel.loading = false;
@@ -142,11 +143,12 @@ angular.module('kibana.pie', [])
         var remaining = $scope.panel.query.goal - complete;
         var remaining = $scope.panel.query.goal - complete;
         $scope.data = [
         $scope.data = [
           { label : 'Complete', data : complete, color: '#BF6730' },
           { label : 'Complete', data : complete, color: '#BF6730' },
-          { data : remaining, color: '#e2d0c4'}]
+          { data : remaining, color: '#e2d0c4' }
+        ];
         $scope.$emit('render');
         $scope.$emit('render');
       });
       });
     }
     }
-  }
+  };
 
 
   // 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) {
@@ -156,8 +158,8 @@ angular.module('kibana.pie', [])
           '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('pie', function(query, filterSrv, dashboard) {
 .directive('pie', function(query, filterSrv, dashboard) {
@@ -165,7 +167,7 @@ angular.module('kibana.pie', [])
     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('render',function(){
       scope.$on('render',function(){
@@ -180,23 +182,25 @@ angular.module('kibana.pie', [])
       // Function for rendering panel
       // Function for rendering panel
       function render_panel() {
       function render_panel() {
         var scripts = $LAB.script("common/lib/panels/jquery.flot.js").wait()
         var scripts = $LAB.script("common/lib/panels/jquery.flot.js").wait()
-                        .script("common/lib/panels/jquery.flot.pie.js")
-
-        if(scope.panel.mode === 'goal')
-          var label = { 
+                          .script("common/lib/panels/jquery.flot.pie.js");
+    
+        var label;
+        if(scope.panel.mode === 'goal') {
+          label = { 
             show: scope.panel.labels,
             show: scope.panel.labels,
             radius: 0,
             radius: 0,
             formatter: function(label, series){
             formatter: function(label, series){
-              var font = parseInt(scope.row.height.replace('px',''))/8 + String('px')
-              if(!(_.isUndefined(label)))
+              var font = parseInt(scope.row.height.replace('px',''),10)/8 + String('px');
+              if(!(_.isUndefined(label))) {
                 return '<div style="font-size:'+font+';font-weight:bold;text-align:center;padding:2px;color:#fff;">'+
                 return '<div style="font-size:'+font+';font-weight:bold;text-align:center;padding:2px;color:#fff;">'+
                 Math.round(series.percent)+'%</div>';
                 Math.round(series.percent)+'%</div>';
-              else
-                return ''
+              } else {
+                return '';
+              }
             },
             },
-          }
-        else 
-          var label = { 
+          };
+        } else { 
+          label = { 
             show: scope.panel.labels,
             show: scope.panel.labels,
             radius: 2/3,
             radius: 2/3,
             formatter: function(label, series){
             formatter: function(label, series){
@@ -204,7 +208,8 @@ angular.module('kibana.pie', [])
                 label+'<br/>'+Math.round(series.percent)+'%</div>';
                 label+'<br/>'+Math.round(series.percent)+'%</div>';
             },
             },
             threshold: 0.1 
             threshold: 0.1 
-          }
+          };
+        }
 
 
         var pie = {
         var pie = {
           series: {
           series: {
@@ -263,7 +268,7 @@ angular.module('kibana.pie', [])
           return;
           return;
         }
         }
         if(scope.panel.mode === 'terms') {
         if(scope.panel.mode === 'terms') {
-          filterSrv.set({type:'terms',field:scope.panel.query.field,value:object.series.label})
+          filterSrv.set({type:'terms',field:scope.panel.query.field,value:object.series.label});
           dashboard.refresh();
           dashboard.refresh();
         }
         }
       });
       });
@@ -280,4 +285,4 @@ angular.module('kibana.pie', [])
 
 
     }
     }
   };
   };
-})
+});

+ 20 - 16
panels/query/module.js

@@ -1,3 +1,5 @@
+/*jshint globalstrict:true */
+/*global angular:true */
 /*
 /*
 
 
   ## query
   ## query
@@ -11,6 +13,8 @@
               one element
               one element
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.query', [])
 angular.module('kibana.query', [])
 .controller('query', function($scope, query, $rootScope) {
 .controller('query', function($scope, query, $rootScope) {
 
 
@@ -22,39 +26,39 @@ angular.module('kibana.query', [])
     group   : "default",
     group   : "default",
     history : [],
     history : [],
     remember: 10 // max: 100, angular strap can't take a variable for items param
     remember: 10 // max: 100, angular strap can't take a variable for items param
-  }
+  };
   _.defaults($scope.panel,_d);
   _.defaults($scope.panel,_d);
 
 
   $scope.queries = query;
   $scope.queries = query;
 
 
   $scope.init = function() {
   $scope.init = function() {
-  }
+  };
 
 
   $scope.refresh = function(query) {
   $scope.refresh = function(query) {
-    $rootScope.$broadcast('refresh')
-  }
+    $rootScope.$broadcast('refresh');
+  };
 
 
   $scope.render = function(query) {
   $scope.render = function(query) {
-    $rootScope.$broadcast('render')
-  }
+    $rootScope.$broadcast('render');
+  };
 
 
   $scope.add_query = function() {
   $scope.add_query = function() {
-    if (_.isArray($scope.panel.query))
-      $scope.panel.query.push("")
-    else {
-      $scope.panel.query = new Array($scope.panel.query)
-      $scope.panel.query.push("")
+    if (_.isArray($scope.panel.query)) {
+      $scope.panel.query.push("");
+    } else {
+      $scope.panel.query = new Array($scope.panel.query);
+      $scope.panel.query.push("");
     }
     }
-  }
+  };
 
 
   var update_history = function(query) {
   var update_history = function(query) {
     if($scope.panel.remember > 0) {
     if($scope.panel.remember > 0) {
-      $scope.panel.history = _.union(query.reverse(),$scope.panel.history)
-      var _length = $scope.panel.history.length
+      $scope.panel.history = _.union(query.reverse(),$scope.panel.history);
+      var _length = $scope.panel.history.length;
       if(_length > $scope.panel.remember) {
       if(_length > $scope.panel.remember) {
-        $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember)
+        $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember);
       }
       }
     }
     }
-  }
+  };
 
 
 });
 });

+ 75 - 70
panels/table/module.js

@@ -1,3 +1,5 @@
+/*jshint globalstrict:true */
+/*global angular:true */
 /*
 /*
 
 
   ## Table
   ## Table
@@ -22,12 +24,11 @@
   * table_documents :: An array containing all of the documents in the table. 
   * table_documents :: An array containing all of the documents in the table. 
                        Only used by the fields panel so far. 
                        Only used by the fields panel so far. 
   #### Receives
   #### Receives
-  * time :: An object containing the time range to use and the index(es) to query
-  * query :: An Array of queries, even if its only one
-  * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
   * selected_fields :: An array of fields to show
   * selected_fields :: An array of fields to show
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.table', [])
 angular.module('kibana.table', [])
 .controller('table', function($rootScope, $scope, eventBus, fields, query, dashboard, filterSrv) {
 .controller('table', function($rootScope, $scope, eventBus, fields, query, dashboard, filterSrv) {
 
 
@@ -48,104 +49,107 @@ angular.module('kibana.table', [])
     header  : true,
     header  : true,
     paging  : true, 
     paging  : true, 
     spyable: true
     spyable: true
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   $scope.init = function () {
   $scope.init = function () {
 
 
-    $scope.set_listeners($scope.panel.group)
+    $scope.set_listeners($scope.panel.group);
 
 
     $scope.get_data();
     $scope.get_data();
-  }
+  };
 
 
   $scope.set_listeners = function(group) {
   $scope.set_listeners = function(group) {
-    $scope.$on('refresh',function(){$scope.get_data()})
+    $scope.$on('refresh',function(){$scope.get_data();});
     eventBus.register($scope,'sort', function(event,sort){
     eventBus.register($scope,'sort', function(event,sort){
       $scope.panel.sort = _.clone(sort);
       $scope.panel.sort = _.clone(sort);
       $scope.get_data();
       $scope.get_data();
     });
     });
     eventBus.register($scope,'selected_fields', function(event, fields) {
     eventBus.register($scope,'selected_fields', function(event, fields) {
-      $scope.panel.fields = _.clone(fields)
+      $scope.panel.fields = _.clone(fields);
     });
     });
     eventBus.register($scope,'table_documents', function(event, docs) {
     eventBus.register($scope,'table_documents', function(event, docs) {
-        query.list[query.ids[0]].query = docs.query;
-        $scope.data = docs.docs;
+      query.list[query.ids[0]].query = docs.query;
+      $scope.data = docs.docs;
     });
     });
-  }
+  };
 
 
   $scope.set_sort = function(field) {
   $scope.set_sort = function(field) {
-    if($scope.panel.sort[0] === field)
-      $scope.panel.sort[1] = $scope.panel.sort[1] == 'asc' ? 'desc' : 'asc';
-    else
+    if($scope.panel.sort[0] === field) {
+      $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc';
+    } else {
       $scope.panel.sort[0] = field;
       $scope.panel.sort[0] = field;
+    }
     $scope.get_data();
     $scope.get_data();
-  }
+  };
 
 
   $scope.toggle_field = function(field) {
   $scope.toggle_field = function(field) {
-    if (_.indexOf($scope.panel.fields,field) > -1) 
-      $scope.panel.fields = _.without($scope.panel.fields,field)
-    else
-      $scope.panel.fields.push(field)
+    if (_.indexOf($scope.panel.fields,field) > -1) {
+      $scope.panel.fields = _.without($scope.panel.fields,field);
+    } else {
+      $scope.panel.fields.push(field);
+    }
     broadcast_results();
     broadcast_results();
-  }
+  };
 
 
   $scope.toggle_highlight = function(field) {
   $scope.toggle_highlight = function(field) {
-    if (_.indexOf($scope.panel.highlight,field) > -1) 
-      $scope.panel.highlight = _.without($scope.panel.highlight,field)
-    else
-      $scope.panel.highlight.push(field)
-  }  
+    if (_.indexOf($scope.panel.highlight,field) > -1) {
+      $scope.panel.highlight = _.without($scope.panel.highlight,field);
+    } else {
+      $scope.panel.highlight.push(field);
+    }
+  };  
 
 
   $scope.toggle_details = function(row) {
   $scope.toggle_details = function(row) {
     row.kibana = row.kibana || {};
     row.kibana = row.kibana || {};
     row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
     row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
-  }
+  };
 
 
   $scope.page = function(page) {
   $scope.page = function(page) {
-    $scope.panel.offset = page*$scope.panel.size
+    $scope.panel.offset = page*$scope.panel.size;
     $scope.get_data();
     $scope.get_data();
-  }
+  };
 
 
   $scope.build_search = function(field,value,negate) {
   $scope.build_search = function(field,value,negate) {
-    var query;
+    var query = field+":";
     // This needs to be abstracted somewhere
     // This needs to be abstracted somewhere
     if(_.isArray(value)) {
     if(_.isArray(value)) {
-      query = field+":(" + _.map(value,function(v){return angular.toJson(v)}).join(" AND ") + ")";
+      query = query+"(" + _.map(value,function(v){return angular.toJson(v);}).join(" AND ") + ")";
     } else {
     } else {
-      query = field+":"+angular.toJson(value);
+      query = query+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();
-  }
+  };
 
 
   $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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     }
     }
     
     
     $scope.panel.loading = true;
     $scope.panel.loading = true;
 
 
-    var _segment = _.isUndefined(segment) ? 0 : segment
+    var _segment = _.isUndefined(segment) ? 0 : segment;
     $scope.segment = _segment;
     $scope.segment = _segment;
 
 
-    var request = $scope.ejs.Request().indices(dashboard.indices[_segment])
+    var request = $scope.ejs.Request().indices(dashboard.indices[_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 || '*'));
+    });
 
 
     request = request.query(
     request = request.query(
-      ejs.FilteredQuery(
+      $scope.ejs.FilteredQuery(
         boolQuery,
         boolQuery,
         filterSrv.getBoolFilter(filterSrv.ids)
         filterSrv.getBoolFilter(filterSrv.ids)
       ))
       ))
       .highlight(
       .highlight(
-        ejs.Highlight($scope.panel.highlight)
+        $scope.ejs.Highlight($scope.panel.highlight)
         .fragmentSize(2147483647) // Max size of a 32bit unsigned int
         .fragmentSize(2147483647) // Max size of a 32bit unsigned int
         .preTags('@start-highlight@')
         .preTags('@start-highlight@')
         .postTags('@end-highlight@')
         .postTags('@end-highlight@')
@@ -153,9 +157,9 @@ angular.module('kibana.table', [])
       .size($scope.panel.size*$scope.panel.pages)
       .size($scope.panel.size*$scope.panel.pages)
       .sort($scope.panel.sort[0],$scope.panel.sort[1]);
       .sort($scope.panel.sort[0],$scope.panel.sort[1]);
 
 
-    $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) {
@@ -164,7 +168,7 @@ angular.module('kibana.table', [])
       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
@@ -177,46 +181,46 @@ angular.module('kibana.table', [])
       if($scope.query_id === query_id) {
       if($scope.query_id === query_id) {
         $scope.data= $scope.data.concat(_.map(results.hits.hits, function(hit) {
         $scope.data= $scope.data.concat(_.map(results.hits.hits, function(hit) {
           return {
           return {
-            _source   : flatten_json(hit['_source']),
-            highlight : flatten_json(hit['highlight']||{})
-          }
+            _source   : kbn.flatten_json(hit._source),
+            highlight : kbn.flatten_json(hit.highlight||{})
+          };
         }));
         }));
         
         
         $scope.hits += results.hits.total;
         $scope.hits += results.hits.total;
 
 
         // Sort the data
         // Sort the data
         $scope.data = _.sortBy($scope.data, function(v){
         $scope.data = _.sortBy($scope.data, function(v){
-          return v._source[$scope.panel.sort[0]]
+          return v._source[$scope.panel.sort[0]];
         });
         });
         
         
         // Reverse if needed
         // Reverse if needed
-        if($scope.panel.sort[1] == 'desc')
+        if($scope.panel.sort[1] === 'desc') {
           $scope.data.reverse();
           $scope.data.reverse();
-        
+        }
+
         // 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.panel.pages)
+        $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages);
 
 
       } else {
       } else {
         return;
         return;
       }
       }
       
       
       // This breaks, use $scope.data for this
       // This breaks, use $scope.data for this
-      $scope.all_fields = get_all_fields(_.pluck($scope.data,'_source'));
+      $scope.all_fields = kbn.get_all_fields(_.pluck($scope.data,'_source'));
       broadcast_results();
       broadcast_results();
 
 
       // If we're not sorting in reverse chrono order, query every index for
       // If we're not sorting in reverse chrono order, query every index for
       // size*pages results
       // size*pages results
       // Otherwise, only get size*pages results then stop querying
       // Otherwise, only get size*pages results then stop querying
-      if($scope.data.length < $scope.panel.size*$scope.panel.pages
-        //($scope.data.length < $scope.panel.size*$scope.panel.pages
-         // || !(($scope.panel.sort[0] === $scope.time.field) && $scope.panel.sort[1] === 'desc'))
-        && _segment+1 < dashboard.indices.length
-      ) {
-        $scope.get_data(_segment+1,$scope.query_id)
+      //($scope.data.length < $scope.panel.size*$scope.panel.pages
+     // || !(($scope.panel.sort[0] === $scope.time.field) && $scope.panel.sort[1] === 'desc'))
+      if($scope.data.length < $scope.panel.size*$scope.panel.pages &&
+        _segment+1 < dashboard.indices.length ) {
+        $scope.get_data(_segment+1,$scope.query_id);
       }
       }
 
 
     });
     });
-  }
+  };
 
 
   $scope.populate_modal = function(request) {
   $scope.populate_modal = function(request) {
     $scope.modal = {
     $scope.modal = {
@@ -225,15 +229,15 @@ angular.module('kibana.table', [])
           '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>", 
-    } 
-  }
+    }; 
+  };
 
 
   $scope.without_kibana = function (row) {
   $scope.without_kibana = function (row) {
     return { 
     return { 
       _source   : row._source,
       _source   : row._source,
       highlight : row.highlight
       highlight : row.highlight
-    }
-  } 
+    };
+  }; 
 
 
   // Broadcast a list of all fields. Note that receivers of field array 
   // Broadcast a list of all fields. Note that receivers of field array 
   // events should be able to receive from multiple sources, merge, dedupe 
   // events should be able to receive from multiple sources, merge, dedupe 
@@ -254,13 +258,14 @@ angular.module('kibana.table', [])
 
 
   $scope.set_refresh = function (state) { 
   $scope.set_refresh = function (state) { 
     $scope.refresh = state; 
     $scope.refresh = state; 
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
-    if($scope.refresh)
+    if($scope.refresh) {
       $scope.get_data();
       $scope.get_data();
+    }
     $scope.refresh =  false;
     $scope.refresh =  false;
-  }
+  };
 
 
 
 
 })
 })
@@ -273,8 +278,8 @@ angular.module('kibana.table', [])
         replace(/>/g, '&gt;').
         replace(/>/g, '&gt;').
         replace(/\r?\n/g, '<br/>').
         replace(/\r?\n/g, '<br/>').
         replace(/@start-highlight@/g, '<code class="highlight">').
         replace(/@start-highlight@/g, '<code class="highlight">').
-        replace(/@end-highlight@/g, '</code>')
+        replace(/@end-highlight@/g, '</code>');
     }
     }
     return '';
     return '';
-  }
+  };
 });
 });

+ 13 - 8
panels/text/module.js

@@ -1,3 +1,6 @@
+/*jshint globalstrict:true */
+/*global angular:true */
+/*global Showdown:false */
 /*
 /*
 
 
   ## Text
   ## Text
@@ -11,6 +14,8 @@
   
   
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.text', [])
 angular.module('kibana.text', [])
 .controller('text', function($scope, $rootScope) {
 .controller('text', function($scope, $rootScope) {
 
 
@@ -21,12 +26,12 @@ angular.module('kibana.text', [])
     mode    : "markdown",
     mode    : "markdown",
     content : "",
     content : "",
     style: {},
     style: {},
-  }
+  };
   _.defaults($scope.panel,_d);
   _.defaults($scope.panel,_d);
 
 
   $scope.init = function() {
   $scope.init = function() {
     $scope.ready = false;
     $scope.ready = false;
-  }
+  };
   
   
 }).directive('markdown', function() {
 }).directive('markdown', function() {
   return {
   return {
@@ -34,10 +39,10 @@ angular.module('kibana.text', [])
     link: function(scope, element, attrs) {
     link: function(scope, element, attrs) {
       scope.$on('render', function() {
       scope.$on('render', function() {
         render_panel();
         render_panel();
-      })
+      });
 
 
       function render_panel() {
       function render_panel() {
-        var scripts = $LAB.script("panels/text/lib/showdown.js")
+        var scripts = $LAB.script("panels/text/lib/showdown.js");
         scripts.wait(function(){
         scripts.wait(function(){
           scope.ready = true;
           scope.ready = true;
           var converter = new Showdown.converter();
           var converter = new Showdown.converter();
@@ -48,18 +53,18 @@ angular.module('kibana.text', [])
           element.html(htmlText);
           element.html(htmlText);
           // For whatever reason, this fixes chrome. I don't like it, I think
           // For whatever reason, this fixes chrome. I don't like it, I think
           // it makes things slow?
           // it makes things slow?
-          scope.$apply()
+          scope.$apply();
         });
         });
       }
       }
 
 
       render_panel();
       render_panel();
     }
     }
-  }
+  };
 })
 })
 .filter('newlines', function(){
 .filter('newlines', function(){
   return function (input) {
   return function (input) {
     return input.replace(/\n/g, '<br/>');
     return input.replace(/\n/g, '<br/>');
-  }
+  };
 })
 })
 .filter('striphtml', function () {
 .filter('striphtml', function () {
   return function(text) {
   return function(text) {
@@ -67,5 +72,5 @@ angular.module('kibana.text', [])
       .replace(/&/g, '&amp;')
       .replace(/&/g, '&amp;')
       .replace(/>/g, '&gt;')
       .replace(/>/g, '&gt;')
       .replace(/</g, '&lt;');
       .replace(/</g, '&lt;');
-  }
+  };
 });
 });

+ 84 - 78
panels/timepicker/module.js

@@ -1,3 +1,5 @@
+/*jshint globalstrict:true */
+/*global angular:true */
 /*
 /*
 
 
   ## Timepicker
   ## Timepicker
@@ -17,6 +19,8 @@
     * min :: The lowest interval a user may set
     * min :: The lowest interval a user may set
 */
 */
 
 
+'use strict';
+
 angular.module('kibana.timepicker', [])
 angular.module('kibana.timepicker', [])
 .controller('timepicker', function($scope, $rootScope, $timeout, timer, $http, dashboard, filterSrv) {
 .controller('timepicker', function($scope, $rootScope, $timeout, timer, $http, dashboard, filterSrv) {
 
 
@@ -34,8 +38,8 @@ angular.module('kibana.timepicker', [])
       interval: 30,
       interval: 30,
       min     : 3
       min     : 3
     }
     }
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   var _groups = _.isArray($scope.panel.group) ? 
   var _groups = _.isArray($scope.panel.group) ? 
     $scope.panel.group : [$scope.panel.group];
     $scope.panel.group : [$scope.panel.group];
@@ -43,91 +47,91 @@ angular.module('kibana.timepicker', [])
   $scope.init = function() {
   $scope.init = function() {
     // Private refresh interval that we can use for view display without causing
     // Private refresh interval that we can use for view display without causing
     // unnecessary refreshes during changes
     // unnecessary refreshes during changes
-    $scope.refresh_interval = $scope.panel.refresh.interval
+    $scope.refresh_interval = $scope.panel.refresh.interval;
     $scope.filterSrv = filterSrv;
     $scope.filterSrv = filterSrv;
 
 
     // Init a private time object with Date() objects depending on mode
     // Init a private time object with Date() objects depending on mode
     switch($scope.panel.mode) {
     switch($scope.panel.mode) {
-      case 'absolute':
-        $scope.time = {
-          from : moment($scope.panel.time.from,'MM/DD/YYYY HH:mm:ss') || moment(time_ago($scope.panel.timespan)),
-          to   : moment($scope.panel.time.to,'MM/DD/YYYY HH:mm:ss') || moment()
-        }
-        break;
-      case 'since':
-        $scope.time = {
-          from : moment($scope.panel.time.from,'MM/DD/YYYY HH:mm:ss') || moment(time_ago($scope.panel.timespan)),
-          to   : moment()
-        }
-        break;
-      case 'relative':
-        $scope.time = {
-          from : moment(time_ago($scope.panel.timespan)),
-          to   : moment()
-        }
-        break;
+    case 'absolute':
+      $scope.time = {
+        from : moment($scope.panel.time.from,'MM/DD/YYYY HH:mm:ss') || moment(kbn.time_ago($scope.panel.timespan)),
+        to   : moment($scope.panel.time.to,'MM/DD/YYYY HH:mm:ss') || moment()
+      };
+      break;
+    case 'since':
+      $scope.time = {
+        from : moment($scope.panel.time.from,'MM/DD/YYYY HH:mm:ss') || moment(kbn.time_ago($scope.panel.timespan)),
+        to   : moment()
+      };
+      break;
+    case 'relative':
+      $scope.time = {
+        from : moment(kbn.time_ago($scope.panel.timespan)),
+        to   : moment()
+      };
+      break;
     }
     }
     $scope.time.field = $scope.panel.timefield;
     $scope.time.field = $scope.panel.timefield;
     // These 3 statements basicly do everything time_apply() does
     // These 3 statements basicly do everything time_apply() does
-    set_timepicker($scope.time.from,$scope.time.to)
-    update_panel()
-    set_time_filter($scope.time)
+    set_timepicker($scope.time.from,$scope.time.to);
+    update_panel();
+    set_time_filter($scope.time);
     dashboard.refresh();
     dashboard.refresh();
 
 
 
 
     // Start refresh timer if enabled
     // Start refresh timer if enabled
-    if ($scope.panel.refresh.enable)
+    if ($scope.panel.refresh.enable) {
       $scope.set_interval($scope.panel.refresh.interval);
       $scope.set_interval($scope.panel.refresh.interval);
+    }
 
 
     // In case some other panel broadcasts a time, set us to an absolute range
     // In case some other panel broadcasts a time, set us to an absolute range
     $scope.$on('refresh', function() {
     $scope.$on('refresh', function() {
       if(filterSrv.idsByType('time').length > 0) {
       if(filterSrv.idsByType('time').length > 0) {
-        var time = filterSrv.timeRange('min')
+        var time = filterSrv.timeRange('min');
 
 
-        if($scope.time.from.diff(moment.utc(time.from),'seconds') !== 0 
-          || $scope.time.to.diff(moment.utc(time.to),'seconds') !== 0)
+        if($scope.time.from.diff(moment.utc(time.from),'seconds') !== 0 ||
+          $scope.time.to.diff(moment.utc(time.to),'seconds') !== 0)
         {
         {
-          console.log($scope.time.from+ " and "+ moment.utc(time.from))
-          console.log($scope.time.to+" and "+moment.utc(time.to))
+          console.log($scope.time.from+ " and "+ moment.utc(time.from));
+          console.log($scope.time.to+" and "+moment.utc(time.to));
 
 
           $scope.set_mode('absolute');
           $scope.set_mode('absolute');
 
 
           // These 3 statements basicly do everything time_apply() does
           // These 3 statements basicly do everything time_apply() does
-          set_timepicker(moment(time.from),moment(time.to))
+          set_timepicker(moment(time.from),moment(time.to));
           $scope.time = $scope.time_calc();
           $scope.time = $scope.time_calc();
-          update_panel()
+          update_panel();
         }
         }
       }
       }
     });
     });
-  }
+  };
 
 
   $scope.set_interval = function (refresh_interval) {
   $scope.set_interval = function (refresh_interval) {
-    $scope.panel.refresh.interval = refresh_interval
+    $scope.panel.refresh.interval = refresh_interval;
     if(_.isNumber($scope.panel.refresh.interval)) {
     if(_.isNumber($scope.panel.refresh.interval)) {
       if($scope.panel.refresh.interval < $scope.panel.refresh.min) {
       if($scope.panel.refresh.interval < $scope.panel.refresh.min) {
-        $scope.panel.refresh.interval = $scope.panel.refresh.min        
-        timer.cancel($scope.refresh_timer)
+        $scope.panel.refresh.interval = $scope.panel.refresh.min;        
+        timer.cancel($scope.refresh_timer);
         return;
         return;
       }
       }
-      timer.cancel($scope.refresh_timer)
-      $scope.refresh()
+      timer.cancel($scope.refresh_timer);
+      $scope.refresh();
     } else {
     } else {
-      timer.cancel($scope.refresh_timer)
+      timer.cancel($scope.refresh_timer);
     }
     }
-  }
+  };
 
 
   $scope.refresh = function() {
   $scope.refresh = function() {
     if ($scope.panel.refresh.enable) {
     if ($scope.panel.refresh.enable) {
-      timer.cancel($scope.refresh_timer)
+      timer.cancel($scope.refresh_timer);
       $scope.refresh_timer = timer.register($timeout(function() {
       $scope.refresh_timer = timer.register($timeout(function() {
         $scope.refresh();
         $scope.refresh();
         $scope.time_apply();
         $scope.time_apply();
-        },$scope.panel.refresh.interval*1000
-      ));
+      },$scope.panel.refresh.interval*1000));
     } else {
     } else {
-      timer.cancel($scope.refresh_timer)
+      timer.cancel($scope.refresh_timer);
     }
     }
-  }
+  };
 
 
   var update_panel = function() {
   var update_panel = function() {
     // Update panel's string representation of the time object.Don't update if
     // Update panel's string representation of the time object.Don't update if
@@ -141,92 +145,94 @@ angular.module('kibana.timepicker', [])
     } else {
     } else {
       delete $scope.panel.time;
       delete $scope.panel.time;
     }
     }
-  }
+  };
 
 
   $scope.set_mode = function(mode) {
   $scope.set_mode = function(mode) {
     $scope.panel.mode = mode;
     $scope.panel.mode = mode;
     $scope.panel.refresh.enable = mode === 'absolute' ? 
     $scope.panel.refresh.enable = mode === 'absolute' ? 
-      false : $scope.panel.refresh.enable
+      false : $scope.panel.refresh.enable;
 
 
     update_panel();
     update_panel();
-  }
+  };
 
 
   $scope.to_now = function() {
   $scope.to_now = function() {
     $scope.timepicker.to = {
     $scope.timepicker.to = {
       time : moment().format("HH:mm:ss"),
       time : moment().format("HH:mm:ss"),
       date : moment().format("MM/DD/YYYY")
       date : moment().format("MM/DD/YYYY")
-    }
-  }
+    };
+  };
 
 
   $scope.set_timespan = function(timespan) {
   $scope.set_timespan = function(timespan) {
     $scope.panel.timespan = timespan;
     $scope.panel.timespan = timespan;
     $scope.timepicker.from = {
     $scope.timepicker.from = {
-      time : moment(time_ago(timespan)).format("HH:mm:ss"),
-      date : moment(time_ago(timespan)).format("MM/DD/YYYY")
-    }
+      time : moment(kbn.time_ago(timespan)).format("HH:mm:ss"),
+      date : moment(kbn.time_ago(timespan)).format("MM/DD/YYYY")
+    };
     $scope.time_apply();
     $scope.time_apply();
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
     $scope.time_apply();
     $scope.time_apply();
-  }
+  };
 
 
   // 
   // 
   $scope.time_calc = function(){
   $scope.time_calc = function(){
+    var from,to;
     // If time picker is defined (usually is)
     // If time picker is defined (usually is)
     if(!(_.isUndefined($scope.timepicker))) {
     if(!(_.isUndefined($scope.timepicker))) {
-      var from = $scope.panel.mode === 'relative' ? moment(time_ago($scope.panel.timespan)) :
-        moment($scope.timepicker.from.date + " " + $scope.timepicker.from.time,'MM/DD/YYYY HH:mm:ss')
-      var to = $scope.panel.mode !== 'absolute' ? moment() :
-        moment($scope.timepicker.to.date + " " + $scope.timepicker.to.time,'MM/DD/YYYY HH:mm:ss')
+      from = $scope.panel.mode === 'relative' ? moment(kbn.time_ago($scope.panel.timespan)) :
+        moment($scope.timepicker.from.date + " " + $scope.timepicker.from.time,'MM/DD/YYYY HH:mm:ss');
+      to = $scope.panel.mode !== 'absolute' ? moment() :
+        moment($scope.timepicker.to.date + " " + $scope.timepicker.to.time,'MM/DD/YYYY HH:mm:ss');
     // Otherwise (probably initialization)
     // Otherwise (probably initialization)
     } else {
     } else {
-      var from = $scope.panel.mode === 'relative' ? moment(time_ago($scope.panel.timespan)) :
+      from = $scope.panel.mode === 'relative' ? moment(kbn.time_ago($scope.panel.timespan)) :
         $scope.time.from;
         $scope.time.from;
-      var to = $scope.panel.mode !== 'absolute' ? moment() :
+      to = $scope.panel.mode !== 'absolute' ? moment() :
         $scope.time.to;
         $scope.time.to;
     }
     }
 
 
-    if (from.valueOf() >= to.valueOf())
-      from = moment(to.valueOf() - 1000)
+    if (from.valueOf() >= to.valueOf()) {
+      from = moment(to.valueOf() - 1000);
+    }
 
 
     $timeout(function(){
     $timeout(function(){
-      set_timepicker(from,to)
+      set_timepicker(from,to);
     });
     });
 
 
     return {
     return {
       from : from,
       from : from,
       to   : to
       to   : to
     };
     };
-  }
+  };
 
 
   $scope.time_apply = function() { 
   $scope.time_apply = function() { 
     $scope.panel.error = "";   
     $scope.panel.error = "";   
     // Update internal time object
     // Update internal time object
 
 
     // Remove all other time filters
     // Remove all other time filters
-    filterSrv.removeByType('time')
+    filterSrv.removeByType('time');
 
 
     $scope.time = $scope.time_calc();
     $scope.time = $scope.time_calc();
-    $scope.time.field = $scope.panel.timefield
-    update_panel()
+    $scope.time.field = $scope.panel.timefield;
+    update_panel();
 
 
-    set_time_filter($scope.time)
+    set_time_filter($scope.time);
     dashboard.refresh();
     dashboard.refresh();
 
 
   };
   };
 
 
 
 
   function set_time_filter(time) {
   function set_time_filter(time) {
-    time.type = 'time'
+    time.type = 'time';
     // Check if there's a time filter we remember, if not, set one and remember it
     // Check if there's a time filter we remember, if not, set one and remember it
     if(!_.isUndefined($scope.panel.filter_id) && 
     if(!_.isUndefined($scope.panel.filter_id) && 
       !_.isUndefined(filterSrv.list[$scope.panel.filter_id]) && 
       !_.isUndefined(filterSrv.list[$scope.panel.filter_id]) && 
-      filterSrv.list[$scope.panel.filter_id].type == 'time') 
+      filterSrv.list[$scope.panel.filter_id].type === 'time') 
     {
     {
-      filterSrv.set(compile_time(time),$scope.panel.filter_id)
+      filterSrv.set(compile_time(time),$scope.panel.filter_id);
     } else {
     } else {
-      $scope.panel.filter_id = filterSrv.set(compile_time(time))
+      $scope.panel.filter_id = filterSrv.set(compile_time(time));
     }
     }
     return $scope.panel.filter_id;
     return $scope.panel.filter_id;
   }
   }
@@ -234,9 +240,9 @@ angular.module('kibana.timepicker', [])
   // Prefer to pass around Date() objects since interacting with
   // Prefer to pass around Date() objects since interacting with
   // moment objects in libraries that are expecting Date()s can be tricky
   // moment objects in libraries that are expecting Date()s can be tricky
   function compile_time(time) {
   function compile_time(time) {
-    time = _.clone(time)
-    time.from = time.from.toDate()
-    time.to   = time.to.toDate()
+    time = _.clone(time);
+    time.from = time.from.toDate();
+    time.to   = time.to.toDate();
     return time;
     return time;
   }
   }
 
 
@@ -251,7 +257,7 @@ angular.module('kibana.timepicker', [])
         time : to.format("HH:mm:ss"),
         time : to.format("HH:mm:ss"),
         date : to.format("MM/DD/YYYY")
         date : to.format("MM/DD/YYYY")
       } 
       } 
-    }
+    };
   }
   }
 
 
-})
+});

+ 101 - 96
panels/trends/module.js

@@ -18,6 +18,9 @@
   * query :: An Array of queries, even if its only one
   * query :: An Array of queries, even if its only one
 
 
 */
 */
+
+'use strict';
+
 angular.module('kibana.trends', [])
 angular.module('kibana.trends', [])
 .controller('trends', function($scope, kbnIndex, query, dashboard, filterSrv) {
 .controller('trends', function($scope, kbnIndex, query, dashboard, filterSrv) {
 
 
@@ -29,87 +32,87 @@ angular.module('kibana.trends', [])
     style   : { "font-size": '14pt'},
     style   : { "font-size": '14pt'},
     ago     : '1d',
     ago     : '1d',
     arrangement : 'vertical',
     arrangement : 'vertical',
-  }
-  _.defaults($scope.panel,_d)
+  };
+  _.defaults($scope.panel,_d);
 
 
   $scope.init = function () {
   $scope.init = function () {
     $scope.hits = 0;
     $scope.hits = 0;
 
 
-    $scope.$on('refresh',function(){$scope.get_data()})
+    $scope.$on('refresh',function(){$scope.get_data();});
 
 
     $scope.get_data();
     $scope.get_data();
-  }
+  };
 
 
   $scope.get_data = function(segment,query_id) {
   $scope.get_data = function(segment,query_id) {
-    delete $scope.panel.error
+    delete $scope.panel.error;
     $scope.panel.loading = true;
     $scope.panel.loading = true;
 
 
     // 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) {
-      return
+    if(dashboard.indices.length === 0) {
+      return;
     } else {
     } else {
       $scope.index = segment > 0 ? $scope.index : dashboard.indices;
       $scope.index = segment > 0 ? $scope.index : dashboard.indices;
     }
     }
 
 
     // Determine a time field
     // Determine a time field
-    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"
-      return
-    } else if(timeField.length == 0) {
-      $scope.panel.error = "A time filter must exist for this panel to function"
-      return
+      $scope.panel.error = "Time field must be consistent amongst time filters";
+      return;
+    } else if(timeField.length === 0) {
+      $scope.panel.error = "A time filter must exist for this panel to function";
+      return;
     } else {
     } else {
-      timeField = timeField[0]
+      timeField = timeField[0];
     }
     }
 
 
     $scope.time = filterSrv.timeRange('min');
     $scope.time = filterSrv.timeRange('min');
     $scope.old_time = {
     $scope.old_time = {
-      from : new Date($scope.time.from.getTime() - interval_to_seconds($scope.panel.ago)*1000),
-      to   : new Date($scope.time.to.getTime() - interval_to_seconds($scope.panel.ago)*1000)
-    }
+      from : new Date($scope.time.from.getTime() - kbn.interval_to_seconds($scope.panel.ago)*1000),
+      to   : new Date($scope.time.to.getTime() - kbn.interval_to_seconds($scope.panel.ago)*1000)
+    };
 
 
-    var _segment = _.isUndefined(segment) ? 0 : segment
+    var _segment = _.isUndefined(segment) ? 0 : segment;
     var request = $scope.ejs.Request();
     var request = $scope.ejs.Request();
-    var _ids_without_time = _.difference(filterSrv.ids,filterSrv.idsByType('time'))
+    var _ids_without_time = _.difference(filterSrv.ids,filterSrv.idsByType('time'));
 
 
 
 
     // Build the question part of the query
     // Build the question part of the query
     _.each(query.ids, function(id) {
     _.each(query.ids, function(id) {
       var q = $scope.ejs.FilteredQuery(
       var q = $scope.ejs.FilteredQuery(
-        ejs.QueryStringQuery(query.list[id].query || '*'),
+        $scope.ejs.QueryStringQuery(query.list[id].query || '*'),
         filterSrv.getBoolFilter(_ids_without_time).must(
         filterSrv.getBoolFilter(_ids_without_time).must(
-          ejs.RangeFilter(timeField)
+          $scope.ejs.RangeFilter(timeField)
           .from($scope.time.from)
           .from($scope.time.from)
           .to($scope.time.to)
           .to($scope.time.to)
-        ))
+        ));
 
 
       request = request
       request = request
         .facet($scope.ejs.QueryFacet(id)
         .facet($scope.ejs.QueryFacet(id)
           .query(q)
           .query(q)
-        ).size(0)
+        ).size(0);
     });
     });
 
 
     // And again for the old time period
     // And again for the old time period
     _.each(query.ids, function(id) {
     _.each(query.ids, function(id) {
       var q = $scope.ejs.FilteredQuery(
       var q = $scope.ejs.FilteredQuery(
-        ejs.QueryStringQuery(query.list[id].query || '*'),
+        $scope.ejs.QueryStringQuery(query.list[id].query || '*'),
         filterSrv.getBoolFilter(_ids_without_time).must(
         filterSrv.getBoolFilter(_ids_without_time).must(
-          ejs.RangeFilter(timeField)
+          $scope.ejs.RangeFilter(timeField)
           .from($scope.old_time.from)
           .from($scope.old_time.from)
           .to($scope.old_time.to)
           .to($scope.old_time.to)
-        ))
+        ));
       request = request
       request = request
         .facet($scope.ejs.QueryFacet("old_"+id)
         .facet($scope.ejs.QueryFacet("old_"+id)
           .query(q)
           .query(q)
-        ).size(0)
+        ).size(0);
     });
     });
 
 
     // TODO: Spy for trend panel
     // TODO: Spy for trend panel
     //$scope.populate_modal(request);
     //$scope.populate_modal(request);
 
 
     // If we're on the first segment we need to get our indices
     // If we're on the first segment we need to get our indices
-    if (_segment == 0) {
+    if (_segment === 0) {
       kbnIndex.indices(
       kbnIndex.indices(
         $scope.old_time.from,
         $scope.old_time.from,
         $scope.old_time.to,
         $scope.old_time.to,
@@ -117,90 +120,92 @@ angular.module('kibana.trends', [])
         dashboard.current.index.interval
         dashboard.current.index.interval
       ).then(function (p) {
       ).then(function (p) {
         $scope.index = _.union(p,$scope.index);
         $scope.index = _.union(p,$scope.index);
-        request = request.indices($scope.index[_segment])
+        request = request.indices($scope.index[_segment]);
         process_results(request.doSearch());
         process_results(request.doSearch());
 
 
       });
       });
     } else {
     } else {
-      process_results(request.indices($scope.index[_segment]).doSearch());
+      process_results(request.indices($scope.index[_segment]).doSearch(),_segment,query_id);
     }
     }
 
 
-    // Populate scope when we have results
-    function process_results(results) { 
-      results.then(function(results) {
-
-        $scope.panel.loading = false;
-        if(_segment == 0) {
-          $scope.hits = {};
-          $scope.data = [];
-          query_id = $scope.query_id = new Date().getTime();
-        }
-        
-        // Check for error and abort if found
-        if(!(_.isUndefined(results.error))) {
-          $scope.panel.error = $scope.parse_error(results.error);
-          return;
-        }
-
-        // Convert facet ids to numbers
-        var facetIds = _.map(_.keys(results.facets),function(k){if(!isNaN(k)){return parseInt(k)}})
-
-        // Make sure we're still on the same query/queries
-        if($scope.query_id === query_id && 
-          _.intersection(facetIds,query.ids).length == query.ids.length
-          ) {
-          var i = 0;
-          _.each(query.ids, function(id) {
-            var v = results.facets[id]
-            var n = results.facets[id].count
-            var o = results.facets['old_'+id].count
-
-            var hits = {
-              new : _.isUndefined($scope.data[i]) || _segment == 0 ? n : $scope.data[i].hits.new+n,        
-              old : _.isUndefined($scope.data[i]) || _segment == 0 ? o : $scope.data[i].hits.old+o
-            }
-            
-            $scope.hits.new += n;
-            $scope.hits.old += o;
-
-            var percent = percentage(hits.old,hits.new) == null ? 
-              '?' : Math.round(percentage(hits.old,hits.new)*100)/100
-            // Create series
-            $scope.data[i] = { 
-              info: query.list[id],
-              hits: {
-                new : hits.new,
-                old : hits.old
-              },
-              percent: percent
-            };
-
-            i++;
-          });
-          $scope.$emit('render');
-          if(_segment < $scope.index.length-1) 
-            $scope.get_data(_segment+1,query_id)
-          else
-            $scope.trends = $scope.data
+  };
+
+  // Populate scope when we have results
+  var process_results = function(results,_segment,query_id) { 
+    results.then(function(results) {
+
+      $scope.panel.loading = false;
+      if(_segment === 0) {
+        $scope.hits = {};
+        $scope.data = [];
+        query_id = $scope.query_id = new Date().getTime();
+      }
+      
+      // Check for error and abort if found
+      if(!(_.isUndefined(results.error))) {
+        $scope.panel.error = $scope.parse_error(results.error);
+        return;
+      }
+
+      // Convert facet ids to numbers
+      var facetIds = _.map(_.keys(results.facets),function(k){if(!isNaN(k)){return parseInt(k, 10);}});
+
+      // Make sure we're still on the same query/queries
+      if($scope.query_id === query_id && 
+        _.intersection(facetIds,query.ids).length === query.ids.length
+        ) {
+        var i = 0;
+        _.each(query.ids, function(id) {
+          var v = results.facets[id];
+          var n = results.facets[id].count;
+          var o = results.facets['old_'+id].count;
+
+          var hits = {
+            new : _.isUndefined($scope.data[i]) || _segment === 0 ? n : $scope.data[i].hits.new+n,        
+            old : _.isUndefined($scope.data[i]) || _segment === 0 ? o : $scope.data[i].hits.old+o
+          };
+          
+          $scope.hits.new += n;
+          $scope.hits.old += o;
+
+          var percent = percentage(hits.old,hits.new) == null ? 
+            '?' : Math.round(percentage(hits.old,hits.new)*100)/100;
+          // Create series
+          $scope.data[i] = { 
+            info: query.list[id],
+            hits: {
+              new : hits.new,
+              old : hits.old
+            },
+            percent: percent
+          };
+
+          i++;
+        });
+        $scope.$emit('render');
+        if(_segment < $scope.index.length-1) {
+          $scope.get_data(_segment+1,query_id);
+        } else {
+          $scope.trends = $scope.data;
         }
         }
-      });
-    }
-
-  }
+      }
+    });
+  };
 
 
   function percentage(x,y) {
   function percentage(x,y) {
-    return x == 0 ? null : 100*(y-x)/x
+    return x === 0 ? null : 100*(y-x)/x;
   }
   }
 
 
   $scope.set_refresh = function (state) { 
   $scope.set_refresh = function (state) { 
     $scope.refresh = state; 
     $scope.refresh = state; 
-  }
+  };
 
 
   $scope.close_edit = function() {
   $scope.close_edit = function() {
-    if($scope.refresh)
+    if($scope.refresh) {
       $scope.get_data();
       $scope.get_data();
+    }
     $scope.refresh =  false;
     $scope.refresh =  false;
     $scope.$emit('render');
     $scope.$emit('render');
-  }
+  };
 
 
-})
+});