diff --git a/public/app/features/templating/adhoc_variable.ts b/public/app/features/templating/adhoc_variable.ts index ea942beaef3..5ebffb0b0e6 100644 --- a/public/app/features/templating/adhoc_variable.ts +++ b/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', }; diff --git a/public/app/features/templating/specs/adhoc_variable_specs.ts b/public/app/features/templating/specs/adhoc_variable_specs.ts new file mode 100644 index 00000000000..15856940540 --- /dev/null +++ b/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'); + }); + + }); + +}); + diff --git a/public/app/features/templating/templateSrv.js b/public/app/features/templating/templateSrv.js index bca814d29a4..e5ef5a0f6b7 100644 --- a/public/app/features/templating/templateSrv.js +++ b/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"); } diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index 81cffd18364..dd35f42f02e 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/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}; }); }; diff --git a/public/app/plugins/datasource/influxdb/influx_query.ts b/public/app/plugins/datasource/influxdb/influx_query.ts index fddb452767a..2f03f37a0a1 100644 --- a/public/app/plugins/datasource/influxdb/influx_query.ts +++ b/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(' '); + } } diff --git a/public/app/plugins/datasource/influxdb/specs/influx_query_specs.ts b/public/app/plugins/datasource/influxdb/specs/influx_query_specs.ts index 557c626a7cc..52beed1d080 100644 --- a/public/app/plugins/datasource/influxdb/specs/influx_query_specs.ts +++ b/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\''); + }); + }); + }); });