Browse Source

feat(adhoc): adhoc filters progress

Torkel Ödegaard 9 years ago
parent
commit
dfe0f91105

+ 3 - 3
public/app/features/templating/adhoc_variable.ts

@@ -18,7 +18,7 @@ export class AdhocVariable implements Variable {
   };
 
   /** @ngInject **/
-  constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
+  constructor(private model) {
     assignModelProperties(this, model, this.defaults);
   }
 
@@ -68,7 +68,7 @@ export class AdhocVariable implements Variable {
 }
 
 variableTypes['adhoc'] = {
-  name: 'Ad hoc',
+  name: 'Ad hoc filters',
   ctor: AdhocVariable,
-  description: 'Ad hoc filters',
+  description: 'Add key/value filters on the fly',
 };

+ 40 - 0
public/app/features/templating/specs/adhoc_variable_specs.ts

@@ -0,0 +1,40 @@
+import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
+
+import {AdhocVariable} from '../adhoc_variable';
+
+describe('AdhocVariable', function() {
+
+  describe('when serializing to url', function() {
+
+    it('should set return key value and op seperated by pipe', function() {
+      var variable = new AdhocVariable({
+        filters: [
+          {key: 'key1', operator: '=', value: 'value1'},
+          {key: 'key2', operator: '!=', value: 'value2'},
+        ]
+      });
+      var urlValue = variable.getValueForUrl();
+      expect(urlValue).to.eql(["key1|=|value1", "key2|!=|value2"]);
+    });
+
+  });
+
+  describe('when deserializing from url', function() {
+
+    it('should restore filters', function() {
+      var variable = new AdhocVariable({});
+      variable.setValueFromUrl(["key1|=|value1", "key2|!=|value2"]);
+
+      expect(variable.filters[0].key).to.be('key1');
+      expect(variable.filters[0].operator).to.be('=');
+      expect(variable.filters[0].value).to.be('value1');
+
+      expect(variable.filters[1].key).to.be('key2');
+      expect(variable.filters[1].operator).to.be('!=');
+      expect(variable.filters[1].value).to.be('value2');
+    });
+
+  });
+
+});
+

+ 18 - 0
public/app/features/templating/templateSrv.js

@@ -15,6 +15,7 @@ function (angular, _, kbn) {
     this._index = {};
     this._texts = {};
     this._grafanaVariables = {};
+    this._adhocVariables = {};
 
     this.init = function(variables) {
       this.variables = variables;
@@ -23,16 +24,33 @@ function (angular, _, kbn) {
 
     this.updateTemplateData = function() {
       this._index = {};
+      this._filters = {};
 
       for (var i = 0; i < this.variables.length; i++) {
         var variable = this.variables[i];
+
+        // add adhoc filters to it's own index
+        if (variable.type === 'adhoc') {
+          this._adhocVariables[variable.datasource] = variable;
+          continue;
+        }
+
         if (!variable.current || !variable.current.isNone && !variable.current.value) {
           continue;
         }
+
         this._index[variable.name] = variable;
       }
     };
 
+    this.getAdhocFilters = function(datasourceName) {
+      var variable = this._adhocVariables[datasourceName];
+      if (variable) {
+        return variable.filters || [];
+      }
+      return []
+    };
+
     function luceneEscape(value) {
       return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
     }

+ 15 - 18
public/app/plugins/datasource/influxdb/datasource.ts

@@ -44,36 +44,23 @@ export default class InfluxDatasource {
 
   query(options) {
     var timeFilter = this.getTimeFilter(options);
-    var scopedVars = _.extend({}, options.scopedVars);
+    var scopedVars = options.scopedVars ? _.cloneDeep(options.scopedVars) : {};
     var targets = _.cloneDeep(options.targets);
     var queryTargets = [];
+    var queryModel;
     var i, y;
 
     var allQueries = _.map(targets, target => {
       if (target.hide) { return ""; }
 
-      if (!target.rawQuery) {
-        // apply add hoc filters
-        for (let variable of this.templateSrv.variables) {
-          if (variable.type === 'adhoc' && variable.datasource === this.name) {
-            for (let filter of variable.filters) {
-              if (filter.key !== undefined && filter.value !== undefined) {
-                target.tags.push({key: filter.key, value: filter.value, condition: filter.condition, operator: filter.operator});
-              }
-            }
-          }
-        }
-      }
-
       queryTargets.push(target);
 
       // build query
       scopedVars.interval = {value: target.interval || options.interval};
 
-      var queryModel = new InfluxQuery(target, this.templateSrv, scopedVars);
-      var query =  queryModel.render(true);
+      queryModel = new InfluxQuery(target, this.templateSrv, scopedVars);
+      return queryModel.render(true);
 
-      return query;
     }).reduce((acc, current) => {
       if (current !== "") {
         acc += ";" + current;
@@ -81,6 +68,16 @@ export default class InfluxDatasource {
       return acc;
     });
 
+    if (allQueries === '') {
+      return this.$q.when({data: []});
+    }
+
+    // add global adhoc filters to timeFilter
+    var adhocFilters = this.templateSrv.getAdhocFilters(this.name);
+    if (adhocFilters.length > 0 ) {
+      timeFilter += ' AND ' + queryModel.renderAdhocFilters(adhocFilters);
+    }
+
     // replace grafana variables
     scopedVars.timeFilter = {value: timeFilter};
 
@@ -120,7 +117,7 @@ export default class InfluxDatasource {
         }
       }
 
-      return { data: seriesList };
+      return {data: seriesList};
     });
   };
 

+ 7 - 0
public/app/plugins/datasource/influxdb/influx_query.ts

@@ -251,4 +251,11 @@ export default class InfluxQuery {
 
     return query;
   }
+
+  renderAdhocFilters(filters) {
+    var conditions = _.map(filters, (tag, index) => {
+      return this.renderTagCondition(tag, index, false);
+    });
+    return conditions.join(' ');
+  }
 }

+ 13 - 0
public/app/plugins/datasource/influxdb/specs/influx_query_specs.ts

@@ -237,6 +237,19 @@ describe('InfluxQuery', function() {
       expect(query.target.select[0][2].type).to.be('math');
     });
 
+    describe('when render adhoc filters', function() {
+      it('should generate correct query segment', function() {
+        var query = new InfluxQuery({measurement: 'cpu', }, templateSrv, {});
+
+        var queryText = query.renderAdhocFilters([
+          {key: 'key1', operator: '=', value: 'value1'},
+          {key: 'key2', operator: '!=', value: 'value2'},
+        ]);
+
+        expect(queryText).to.be('"key1" = \'value1\' AND "key2" != \'value2\'');
+      });
+    });
+
   });
 
 });