Bladeren bron

Added the ability to toggle filters

Rashid Khan 12 jaren geleden
bovenliggende
commit
1d4af12f57

+ 37 - 46
dashboards/default.json

@@ -2,7 +2,12 @@
   "title": "Logstash Search",
   "services": {
     "query": {
-      "idQueue": [],
+      "idQueue": [
+        1,
+        2,
+        3,
+        4
+      ],
       "list": {
         "0": {
           "query": "*",
@@ -16,14 +21,18 @@
       ]
     },
     "filter": {
-      "idQueue": [],
+      "idQueue": [
+        1,
+        2
+      ],
       "list": {
         "0": {
-          "from": "2013-07-15T03:54:27.219Z",
-          "to": "2013-07-15T04:09:27.219Z",
+          "from": "2013-07-15T16:50:45.363Z",
+          "to": "2013-07-15T17:50:45.363Z",
           "field": "@timestamp",
           "type": "time",
           "mandate": "must",
+          "active": true,
           "alias": "",
           "id": 0
         }
@@ -63,7 +72,7 @@
             "7d",
             "30d"
           ],
-          "timespan": "15m",
+          "timespan": "1h",
           "timefield": "@timestamp",
           "timeformat": "",
           "refresh": {
@@ -126,57 +135,40 @@
       ]
     },
     {
-      "title": "Graph",
-      "height": "350px",
+      "title": "Filters",
+      "height": "50px",
       "editable": true,
-      "collapse": false,
+      "collapse": true,
       "collapsable": true,
       "panels": [
         {
           "loading": false,
-          "span": 9,
+          "error": false,
+          "span": 12,
           "editable": true,
           "group": [
             "default"
           ],
-          "type": "histogram",
-          "status": "Stable",
-          "query": [
-            {
-              "query": "*",
-              "label": "Query"
-            }
-          ],
-          "mode": "count",
-          "time_field": "@timestamp",
-          "value_field": null,
-          "auto_int": true,
-          "resolution": 100,
-          "interval": "10s",
-          "fill": 3,
-          "linewidth": 3,
-          "timezone": "browser",
-          "spyable": true,
-          "zoomlinks": true,
-          "bars": true,
-          "stack": true,
-          "points": false,
-          "lines": false,
-          "legend": true,
-          "x-axis": true,
-          "y-axis": true,
-          "percentage": false,
-          "interactive": true
-        },
+          "type": "filtering",
+          "status": "Experimental"
+        }
+      ]
+    },
+    {
+      "title": "Graph",
+      "height": "350px",
+      "editable": true,
+      "collapse": false,
+      "collapsable": true,
+      "panels": [
         {
           "loading": false,
-          "error": false,
-          "span": 3,
+          "span": 12,
           "editable": true,
           "group": [
             "default"
           ],
-          "type": "filtering",
+          "type": "histogram",
           "status": "Stable",
           "query": [
             {
@@ -189,22 +181,21 @@
           "value_field": null,
           "auto_int": true,
           "resolution": 100,
-          "interval": "5m",
+          "interval": "30s",
           "fill": 3,
           "linewidth": 3,
           "timezone": "browser",
           "spyable": true,
           "zoomlinks": true,
           "bars": true,
-          "stack": true,
+          "stack": false,
           "points": false,
           "lines": false,
           "legend": true,
           "x-axis": true,
           "y-axis": true,
           "percentage": false,
-          "interactive": true,
-          "title": "Filters"
+          "interactive": true
         }
       ]
     },
@@ -273,6 +264,6 @@
   "index": {
     "interval": "day",
     "pattern": "[logstash-]YYYY.MM.DD",
-    "default": "MISSING_INDEX"
+    "default": "logstash-*"
   }
 }

+ 54 - 43
js/services.js

@@ -300,6 +300,7 @@ angular.module('kibana.services', [])
   // If an id is passed, the filter at that id is updated
   this.set = function(filter,id) {
     _.defaults(filter,{mandate:'must'})
+    filter.active = true;
     if(!_.isUndefined(id)) {
       if(!_.isUndefined(self.list[id])) {
         _.extend(self.list[id],filter);
@@ -328,16 +329,18 @@ angular.module('kibana.services', [])
     // A default match all filter, just in case there are no other filters
     var bool = ejs.BoolFilter().must(ejs.MatchAllFilter());
     _.each(ids,function(id) {
-      switch(self.list[id].mandate) 
-      {
-      case 'mustNot':
-        bool = bool.mustNot(self.getEjsObj(id));
-        break;
-      case 'should':
-        bool = bool.should(self.getEjsObj(id));
-        break;
-      default:
-        bool = bool.must(self.getEjsObj(id));
+      if(self.list[id].active) {
+        switch(self.list[id].mandate) 
+        {
+        case 'mustNot':
+          bool = bool.mustNot(self.getEjsObj(id));
+          break;
+        case 'should':
+          bool = bool.should(self.getEjsObj(id));
+          break;
+        default:
+          bool = bool.must(self.getEjsObj(id));
+        }
       }
     })
     return bool;
@@ -348,6 +351,9 @@ angular.module('kibana.services', [])
   }
 
   this.toEjsObj = function (filter) {
+    if(!filter.active) {
+      return false
+    }
     switch(filter.type)
     {
     case 'time':
@@ -377,8 +383,8 @@ angular.module('kibana.services', [])
     }
   }
 
-  this.getByType = function(type) {
-    return _.pick(self.list,self.idsByType(type))
+  this.getByType = function(type,inactive) {
+    return _.pick(self.list,self.idsByType(type,inactive))
   }
 
   this.removeByType = function(type) {
@@ -389,13 +395,13 @@ angular.module('kibana.services', [])
     return ids;
   }
 
-  this.idsByType = function(type) {
-    return _.pluck(_.where(self.list,{type:type}),'id')
+  this.idsByType = function(type,inactive) {
+    return _.pluck(_.where(self.list,{type:type,active:(inactive ? false:true)}),'id')
   }
 
   // This special function looks for all time filters, and returns a time range according to the mode
   this.timeRange = function(mode) {
-    var _t = _.where(self.list,{type:'time'})
+    var _t = _.where(self.list,{type:'time',active:true})
     if(_t.length == 0) {
       return false;
     }
@@ -526,11 +532,43 @@ angular.module('kibana.services', [])
         $rootScope.$broadcast('refresh')
       }
     } else {
-      self.indices = [self.current.index.pattern]
+      self.indices = [self.current.index.default]
       $rootScope.$broadcast('refresh')
     }
   }
 
+  this.dash_load = function(dashboard) {
+    timer.cancel_all();
+
+    if(dashboard.index.interval === 'none') {
+      self.indices = [dashboard.index.default]
+    }
+
+    self.current = dashboard;
+
+    // Ok, now that we've setup the current dashboard, we can inject our services
+    query = $injector.get('query');
+    filterSrv = $injector.get('filterSrv')
+
+    if(dashboard.index.interval !== 'none' && filterSrv.idsByType('time').length == 0) {
+      self.refresh();
+    }
+
+    return true;
+  }
+
+  this.gist_id = function(string) {
+    if(self.is_gist(string))
+      return string.match(gist_pattern)[0].replace(/.*\//, '');
+  }
+
+  this.is_gist = function(string) {
+    if(!_.isUndefined(string) && string != '' && !_.isNull(string.match(gist_pattern)))
+      return string.match(gist_pattern).length > 0 ? true : false;
+    else
+      return false
+  }
+
   this.to_file = function() {
     var blob = new Blob([angular.toJson(self.current,true)], {type: "application/json;charset=utf-8"});
     // from filesaver.js
@@ -699,33 +737,6 @@ angular.module('kibana.services', [])
     });
   }
 
-  this.dash_load = function(dashboard) {
-    timer.cancel_all();
-
-    if(dashboard.index.interval === 'none') {
-      self.indices = [dashboard.index.pattern]
-    }
-
-    self.current = dashboard;
-
-    // Ok, now that we've setup the current dashboard, we can inject our services
-    query = $injector.get('query');
-    filterSrv = $injector.get('filterSrv')
-    return true;
-  }
-
-  this.gist_id = function(string) {
-    if(self.is_gist(string))
-      return string.match(gist_pattern)[0].replace(/.*\//, '');
-  }
-
-  this.is_gist = function(string) {
-    if(!_.isUndefined(string) && string != '' && !_.isNull(string.match(gist_pattern)))
-      return string.match(gist_pattern).length > 0 ? true : false;
-    else
-      return false
-  }
-
 })
 .service('keylistener', function($rootScope) {
   var keys = [];

+ 17 - 8
panels/filtering/module.html

@@ -1,7 +1,11 @@
 <kibana-panel ng-controller='filtering' ng-init="init()">
   <style>
+    .filtering-container {
+      margin-top: 3px;
+    }
     .filter-panel-filter {
       display:inline-block;
+      vertical-align: top;
       margin-left: 10px;
       width: 200px;
       padding: 5px;
@@ -17,20 +21,25 @@
     .filter-should {
       border-bottom: #EF843C 3px solid;
     }
-    .filter-remove {
+    .filter-action {
       float:right;
       margin-bottom: 0px !important;
+      margin-left: 3px;
     }
 
   </style>
 
-  <div ng-repeat="id in filterSrv.ids" class="small filter-panel-filter">
-    <div class="filter-{{filterSrv.list[id].mandate}}">
-      {{filterSrv.list[id].type}} ({{filterSrv.list[id].mandate}}) 
-      <i class="filter-remove pointer icon-remove" ng-click="remove(id)"></i>
+  <div class='filtering-container'>
+    <div ng-repeat="id in filterSrv.ids" class="small filter-panel-filter">
+      <div class="filter-{{filterSrv.list[id].mandate}}">
+        <strong>{{filterSrv.list[id].type}}</strong> {{filterSrv.list[id].mandate}}
+        <i class="filter-action pointer icon-remove" bs-tooltip="'Remove'" ng-click="remove(id)"></i>
+        <i class="filter-action pointer" ng-class="{'icon-check': filterSrv.list[id].active,'icon-check-empty': !filterSrv.list[id].active}" bs-tooltip="'Toggle'" ng-click="toggle(id)"></i>
+
+      </div>
+      <ul class="unstyled">
+        <li ng-repeat="(key,value) in filterSrv.list[id]" ng-show="show_key(key)"><strong>{{key}}</strong> : {{value}}</li>
+      </ul>
     </div>
-    <ul class="unstyled">
-      <li ng-repeat="(key,value) in stripped(filterSrv.list[id])"><strong>{{key}}</strong> : {{value}}</li>
-    </ul>
   </div>
 </kibana-panel>

+ 7 - 3
panels/filtering/module.js

@@ -26,6 +26,11 @@ angular.module('kibana.filtering', [])
     dashboard.refresh();
   }
 
+  $scope.toggle = function(id) {
+    filterSrv.list[id].active = !filterSrv.list[id].active;
+    dashboard.refresh();
+  }
+
   $scope.refresh = function(query) {
     $rootScope.$broadcast('refresh')
   }
@@ -34,9 +39,8 @@ angular.module('kibana.filtering', [])
     $rootScope.$broadcast('render')
   }
 
-  $scope.stripped = function(filter) {
-    var filter = _.omit(filter,'type','id','alias','mandate')
-    return filter
+  $scope.show_key = function(key) {
+    return !_.contains(['type','id','alias','mandate','active'],key)
   }
 
 });

+ 13 - 3
panels/timepicker/module.html

@@ -1,5 +1,5 @@
 <kibana-panel ng-controller='timepicker' ng-init="init()">
-  <div class="row-fluid" ng-switch="panel.mode">
+  <div class="row-fluid" ng-switch="panel.mode" ng-show="filterSrv.idsByType('time').length > 0">
     <div ng-switch-when="absolute">
       <div class="span5">
         <form class="nomargin">
@@ -47,17 +47,27 @@
       </div>
     </div>
   </div>
+  <div class="row-fluid" ng-show="filterSrv.idsByType('time').length < 1">
+    <div>
+      <div class="span11">
+        <h4>No time filter present</h4>
+      </div>
+    </div>
+  </div>
   <div class="row-fluid nomargin">
-    <div class="span12 small">
+    <div class="span12 small" ng-show="filterSrv.idsByType('time').length > 0">
       <a ng-click="set_mode('relative')" ng-class="{'strong': (panel.mode == 'relative')}">Relative</a> | 
       <a ng-click="set_mode('absolute')" ng-class="{'strong': (panel.mode == 'absolute')}">Absolute</a> | 
       <a ng-click="set_mode('since')"    ng-class="{'strong': (panel.mode == 'since')}">Since</a>
-      <span ng-hide="panel.mode == 'absolute'"> | 
+      <span ng-hide="panel.mode == 'absolute' || panel.mode == 'none'"> | 
         <input type="checkbox" ng-model="panel.refresh.enable" ng-change='refresh();'> Auto-refresh 
         <span ng-class="{'ng-cloak': !panel.refresh.enable}">
           every <a data-title="<small>Auto-refresh Settings</small>" data-placement="bottom" bs-popover="'panels/timepicker/refreshctrl.html'">{{panel.refresh.interval}}s</a>.
         </span>
       </span>
     </div>
+    <div class="span12 small" ng-show="filterSrv.idsByType('time').length < 1">
+      <a class='btn btn-small' ng-click="time_apply()">Create a time filter</a> 
+    </div>
   </div>
 </kibana-panel>

+ 20 - 13
panels/timepicker/module.js

@@ -44,7 +44,7 @@ angular.module('kibana.timepicker', [])
     // Private refresh interval that we can use for view display without causing
     // unnecessary refreshes during changes
     $scope.refresh_interval = $scope.panel.refresh.interval
-
+    $scope.filterSrv = filterSrv;
 
     // Init a private time object with Date() objects depending on mode
     switch($scope.panel.mode) {
@@ -68,7 +68,12 @@ angular.module('kibana.timepicker', [])
         break;
     }
     $scope.time.field = $scope.panel.timefield;
-    $scope.time_apply();
+    // These 3 statements basicly do everything time_apply() does
+    set_timepicker($scope.time.from,$scope.time.to)
+    update_panel()
+    set_time_filter($scope.time)
+    dashboard.refresh();
+
 
     // Start refresh timer if enabled
     if ($scope.panel.refresh.enable)
@@ -76,17 +81,19 @@ angular.module('kibana.timepicker', [])
 
     // In case some other panel broadcasts a time, set us to an absolute range
     $scope.$on('refresh', function() {
-      var time = filterSrv.timeRange('min')
-
-      if($scope.time.from.diff(moment.utc(time.from)) != 0 
-        || $scope.time.to.diff(moment.utc(time.to)) != 0)
-      {
-        $scope.panel.mode = 'absolute';
-
-        // These 3 statements basicly do everything time_apply() does
-        set_timepicker(moment(time.from),moment(time.to))
-        $scope.time = $scope.time_calc();
-        update_panel()
+      if(filterSrv.idsByType('time').length > 0) {
+        var time = filterSrv.timeRange('min')
+
+        if($scope.time.from.diff(moment.utc(time.from)) != 0 
+          || $scope.time.to.diff(moment.utc(time.to)) != 0)
+        {
+          $scope.set_mode('absolute');
+
+          // These 3 statements basicly do everything time_apply() does
+          set_timepicker(moment(time.from),moment(time.to))
+          $scope.time = $scope.time_calc();
+          update_panel()
+        }
       }
     });
   }

+ 4 - 4
partials/dasheditor.html

@@ -36,12 +36,12 @@
       <div class="span3">
         <h6>Timestamping</h6><select class="input-small" ng-model="dashboard.current.index.interval" ng-options='f for f in ["none","hour","day","week","month","year"]'></select>
       </div>
-      <div class="span5">
-        <h6>Index <span ng-show="dashboard.current.index.interval != 'none'">pattern <small>Absolutes in []</small></span></h6>
+      <div class="span5" ng-show="dashboard.current.index.interval != 'none'">
+        <h6>Index pattern <small>Absolutes in []</small></h6>
         <input type="text" class="input-medium" ng-model="dashboard.current.index.pattern">
       </div>
       <div class="span4">
-        <h6>Failover Index <small>If index not found</small></h6>
+        <h6>Default Index <small ng-show="dashboard.current.index.interval != 'none'">If index not found</small></h6>
         <input type="text" class="input-medium" ng-model="dashboard.current.index.default">
       </div>
     </div>
@@ -87,5 +87,5 @@
   </div>
 </div>
 <div class="modal-footer">
-  <button type="button" class="btn btn-success" ng-click="dismiss();reset_panel();">Close</button>
+  <button type="button" class="btn btn-success" ng-click="dismiss();reset_panel();dashboard.refresh()">Close</button>
 </div>