diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js
index 00c0cb3e127..4b7281c55e2 100644
--- a/public/app/core/utils/kbn.js
+++ b/public/app/core/utils/kbn.js
@@ -10,7 +10,7 @@ function($, _, moment) {
kbn.valueFormats = {};
kbn.regexEscape = function(value) {
- return value.replace(/[\\^$*+?.()|[\]{}]/g, '\\\\$&');
+ return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&')
};
///// HELPER FUNCTIONS /////
diff --git a/public/app/features/templating/all.ts b/public/app/features/templating/all.ts
index 208212c4034..d72a76f5a65 100644
--- a/public/app/features/templating/all.ts
+++ b/public/app/features/templating/all.ts
@@ -5,9 +5,13 @@ import './editorCtrl';
import {VariableSrv} from './variable_srv';
import {IntervalVariable} from './interval_variable';
import {QueryVariable} from './query_variable';
+import {DatasourceVariable} from './datasource_variable';
+import {CustomVariable} from './custom_variable';
export {
VariableSrv,
IntervalVariable,
QueryVariable,
+ DatasourceVariable,
+ CustomVariable,
}
diff --git a/public/app/features/templating/custom_variable.ts b/public/app/features/templating/custom_variable.ts
new file mode 100644
index 00000000000..99dd278f899
--- /dev/null
+++ b/public/app/features/templating/custom_variable.ts
@@ -0,0 +1,41 @@
+///
+
+import _ from 'lodash';
+import kbn from 'app/core/utils/kbn';
+import {Variable} from './variable';
+import {VariableSrv, variableConstructorMap} from './variable_srv';
+
+export class CustomVariable implements Variable {
+ query: string;
+ options: any;
+ includeAll: boolean;
+
+ /** @ngInject */
+ constructor(private model, private timeSrv, private templateSrv) {
+ _.extend(this, model);
+ }
+
+ setValue(option) {
+ }
+
+ updateOptions() {
+ // extract options in comma separated string
+ this.options = _.map(this.query.split(/[,]+/), function(text) {
+ return { text: text.trim(), value: text.trim() };
+ });
+
+ if (this.includeAll) {
+ this.addAllOption();
+ }
+ }
+
+ addAllOption() {
+ this.options.unshift({text: 'All', value: "$__all"});
+ }
+
+ dependsOn(variableName) {
+ return false;
+ }
+}
+
+variableConstructorMap['custom'] = CustomVariable;
diff --git a/public/app/features/templating/datasource_variable.ts b/public/app/features/templating/datasource_variable.ts
new file mode 100644
index 00000000000..bd13c43f6e4
--- /dev/null
+++ b/public/app/features/templating/datasource_variable.ts
@@ -0,0 +1,56 @@
+///
+
+import _ from 'lodash';
+import kbn from 'app/core/utils/kbn';
+import {Variable} from './variable';
+import {VariableSrv, variableConstructorMap} from './variable_srv';
+
+export class DatasourceVariable implements Variable {
+ regex: any;
+ query: string;
+ options: any;
+
+ /** @ngInject */
+ constructor(private model, private datasourceSrv) {
+ _.extend(this, model);
+ }
+
+ setValue(option) {
+ }
+
+ updateOptions() {
+ var options = [];
+ var sources = this.datasourceSrv.getMetricSources({skipVariables: true});
+ var regex;
+
+ if (this.regex) {
+ regex = kbn.stringToJsRegex(this.regex);
+ }
+
+ for (var i = 0; i < sources.length; i++) {
+ var source = sources[i];
+ // must match on type
+ if (source.meta.id !== this.query) {
+ continue;
+ }
+
+ if (regex && !regex.exec(source.name)) {
+ continue;
+ }
+
+ options.push({text: source.name, value: source.name});
+ }
+
+ if (options.length === 0) {
+ options.push({text: 'No data sources found', value: ''});
+ }
+
+ this.options = options;
+ }
+
+ dependsOn(variableName) {
+ return false;
+ }
+}
+
+variableConstructorMap['datasource'] = DatasourceVariable;
diff --git a/public/app/features/templating/interval_variable.ts b/public/app/features/templating/interval_variable.ts
index e7177982e07..681b088ed0b 100644
--- a/public/app/features/templating/interval_variable.ts
+++ b/public/app/features/templating/interval_variable.ts
@@ -43,6 +43,10 @@ export class IntervalVariable implements Variable {
this.updateAutoValue();
}
}
+
+ dependsOn(variableName) {
+ return false;
+ }
}
variableConstructorMap['interval'] = IntervalVariable;
diff --git a/public/app/features/templating/query_variable.ts b/public/app/features/templating/query_variable.ts
index 2bcd89460d3..784b401a52a 100644
--- a/public/app/features/templating/query_variable.ts
+++ b/public/app/features/templating/query_variable.ts
@@ -2,7 +2,7 @@
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
-import {Variable} from './variable';
+import {Variable, containsVariable} from './variable';
import {VariableSrv, variableConstructorMap} from './variable_srv';
function getNoneOption() {
@@ -17,8 +17,9 @@ export class QueryVariable implements Variable {
options: any;
current: any;
includeAll: boolean;
+ refresh: number;
- constructor(private model, private datasourceSrv, private templateSrv, private variableSrv) {
+ constructor(private model, private datasourceSrv, private templateSrv, private variableSrv, private $q) {
_.extend(this, model);
}
@@ -33,6 +34,23 @@ export class QueryVariable implements Variable {
return this.variableSrv.variableUpdated(this);
}
+ setValueFromUrl(urlValue) {
+ var promise = this.$q.when();
+
+ if (this.refresh) {
+ promise = this.updateOptions();
+ }
+
+ return promise.then(() => {
+ var option = _.find(this.options, op => {
+ return op.text === urlValue || op.value === urlValue;
+ });
+
+ option = option || { text: urlValue, value: urlValue };
+ return this.setValue(option);
+ });
+ }
+
updateOptions() {
return this.datasourceSrv.get(this.datasource)
.then(this.updateOptionsFromMetricFindQuery.bind(this))
@@ -102,24 +120,30 @@ export class QueryVariable implements Variable {
var sortType = Math.ceil(sortOrder / 2);
var reverseSort = (sortOrder % 2 === 0);
+
if (sortType === 1) {
options = _.sortBy(options, 'text');
} else if (sortType === 2) {
options = _.sortBy(options, function(opt) {
- var matches = opt.text.match(new RegExp(".*?(\d+).*"));
- if (!matches) {
- return 0;
- } else {
- return parseInt(matches[1], 10);
- }
+ var matches = opt.text.match(/.*?(\d+).*/);
+if (!matches) {
+ return 0;
+} else {
+ return parseInt(matches[1], 10);
+}
});
}
+
if (reverseSort) {
options = options.reverse();
}
return options;
}
+
+ dependsOn(variableName) {
+ return containsVariable(this.query, variableName) || containsVariable(this.datasource, variableName);
+ }
}
variableConstructorMap['query'] = QueryVariable;
diff --git a/public/app/features/templating/specs/variable_specs.ts b/public/app/features/templating/specs/variable_specs.ts
new file mode 100644
index 00000000000..a87cd744aaa
--- /dev/null
+++ b/public/app/features/templating/specs/variable_specs.ts
@@ -0,0 +1,36 @@
+import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
+
+import {containsVariable} from '../variable';
+
+describe('containsVariable', function() {
+
+ describe('when checking if a string contains a variable', function() {
+
+ it('should find it with $var syntax', function() {
+ var contains = containsVariable('this.$test.filters', 'test');
+ expect(contains).to.be(true);
+ });
+
+ it('should not find it if only part matches with $var syntax', function() {
+ var contains = containsVariable('this.$ServerDomain.filters', 'Server');
+ expect(contains).to.be(false);
+ });
+
+ it('should find it with [[var]] syntax', function() {
+ var contains = containsVariable('this.[[test]].filters', 'test');
+ expect(contains).to.be(true);
+ });
+
+ it('should find it when part of segment', function() {
+ var contains = containsVariable('metrics.$env.$group-*', 'group');
+ expect(contains).to.be(true);
+ });
+
+ it('should find it its the only thing', function() {
+ var contains = containsVariable('$env', 'env');
+ expect(contains).to.be(true);
+ });
+ });
+
+});
+
diff --git a/public/app/features/templating/specs/variable_srv_specs.ts b/public/app/features/templating/specs/variable_srv_specs.ts
index c5a1ea6f536..f6a7224da42 100644
--- a/public/app/features/templating/specs/variable_srv_specs.ts
+++ b/public/app/features/templating/specs/variable_srv_specs.ts
@@ -4,7 +4,7 @@ import moment from 'moment';
import helpers from 'test/specs/helpers';
import '../all';
-describe.only('VariableSrv', function() {
+describe('VariableSrv', function() {
var ctx = new helpers.ControllerTestContext();
beforeEach(angularMocks.module('grafana.core'));
@@ -15,11 +15,58 @@ describe.only('VariableSrv', function() {
beforeEach(angularMocks.inject(($rootScope, $q, $location, $injector) => {
ctx.$q = $q;
ctx.$rootScope = $rootScope;
+ ctx.$location = $location;
ctx.variableSrv = $injector.get('variableSrv');
ctx.variableSrv.init({templating: {list: []}});
ctx.$rootScope.$digest();
}));
+ function describeInitSceneario(desc, fn) {
+ describe(desc, function() {
+ var scenario: any = {
+ urlParams: {},
+ setup: setupFn => {
+ scenario.setupFn = setupFn;
+ }
+ };
+
+ beforeEach(function() {
+ scenario.setupFn();
+ var ds: any = {};
+ ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
+ ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds));
+ ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
+
+ ctx.$location.search = sinon.stub().returns(scenario.urlParams);
+
+ ctx.dashboard = {templating: {list: scenario.variables}};
+ ctx.variableSrv.init(ctx.dashboard);
+ ctx.$rootScope.$digest();
+
+ scenario.variables = ctx.variableSrv.variables;
+ });
+
+ fn(scenario);
+ });
+ }
+
+ describeInitSceneario('when setting simple variable via url', scenario => {
+ scenario.setup(() => {
+ scenario.variables = [{
+ name: 'apps',
+ type: 'query',
+ current: {text: "test", value: "test"},
+ options: [{text: "test", value: "test"}]
+ }];
+ scenario.urlParams["var-apps"] = "new";
+ });
+
+ it('should update current value', () => {
+ expect(scenario.variables[0].current.value).to.be("new");
+ expect(scenario.variables[0].current.text).to.be("new");
+ });
+ });
+
function describeUpdateVariable(desc, fn) {
describe(desc, function() {
var scenario: any = {};
@@ -32,6 +79,8 @@ describe.only('VariableSrv', function() {
var ds: any = {};
ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds));
+ ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
+
scenario.variable = ctx.variableSrv.addVariable(scenario.variableModel);
ctx.variableSrv.updateOptions(scenario.variable);
@@ -274,6 +323,114 @@ describe.only('VariableSrv', function() {
});
});
+ describeUpdateVariable('without sort', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 0};
+ scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
+ });
+
+ it('should return options without sort', function() {
+ expect(scenario.variable.options[0].text).to.be('bbb2');
+ expect(scenario.variable.options[1].text).to.be('aaa10');
+ expect(scenario.variable.options[2].text).to.be('ccc3');
+ });
+ });
+
+ describeUpdateVariable('with alphabetical sort (asc)', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 1};
+ scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
+ });
+
+ it('should return options with alphabetical sort', function() {
+ expect(scenario.variable.options[0].text).to.be('aaa10');
+ expect(scenario.variable.options[1].text).to.be('bbb2');
+ expect(scenario.variable.options[2].text).to.be('ccc3');
+ });
+ });
+
+ describeUpdateVariable('with alphabetical sort (desc)', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 2};
+ scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
+ });
+
+ it('should return options with alphabetical sort', function() {
+ expect(scenario.variable.options[0].text).to.be('ccc3');
+ expect(scenario.variable.options[1].text).to.be('bbb2');
+ expect(scenario.variable.options[2].text).to.be('aaa10');
+ });
+ });
+
+ describeUpdateVariable('with numerical sort (asc)', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 3};
+ scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
+ });
+
+ it('should return options with numerical sort', function() {
+ expect(scenario.variable.options[0].text).to.be('bbb2');
+ expect(scenario.variable.options[1].text).to.be('ccc3');
+ expect(scenario.variable.options[2].text).to.be('aaa10');
+ });
+ });
+
+ describeUpdateVariable('with numerical sort (desc)', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {type: 'query', query: 'apps.*', name: 'test', sort: 4};
+ scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
+ });
+
+ it('should return options with numerical sort', function() {
+ expect(scenario.variable.options[0].text).to.be('aaa10');
+ expect(scenario.variable.options[1].text).to.be('ccc3');
+ expect(scenario.variable.options[2].text).to.be('bbb2');
+ });
+ });
+
+ //
+ // datasource variable update
+ //
+ describeUpdateVariable('datasource variable with regex filter', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {
+ type: 'datasource',
+ query: 'graphite',
+ name: 'test',
+ current: {value: 'backend4_pee', text: 'backend4_pee'},
+ regex: '/pee$/'
+ };
+ scenario.metricSources = [
+ {name: 'backend1', meta: {id: 'influx'}},
+ {name: 'backend2_pee', meta: {id: 'graphite'}},
+ {name: 'backend3', meta: {id: 'graphite'}},
+ {name: 'backend4_pee', meta: {id: 'graphite'}},
+ ];
+ });
+
+ it('should set only contain graphite ds and filtered using regex', function() {
+ expect(scenario.variable.options.length).to.be(2);
+ expect(scenario.variable.options[0].value).to.be('backend2_pee');
+ expect(scenario.variable.options[1].value).to.be('backend4_pee');
+ });
+
+ it('should keep current value if available', function() {
+ expect(scenario.variable.current.value).to.be('backend4_pee');
+ });
+ });
+
+ //
+ // Custom variable update
+ //
+ describeUpdateVariable('update custom variable', function(scenario) {
+ scenario.setup(function() {
+ scenario.variableModel = {type: 'custom', query: 'hej, hop, asd', name: 'test'};
+ });
+
+ it('should update options array', function() {
+ expect(scenario.variable.options.length).to.be(3);
+ expect(scenario.variable.options[0].text).to.be('hej');
+ expect(scenario.variable.options[1].value).to.be('hop');
+ });
+ });
});
-
-
diff --git a/public/app/features/templating/templateSrv.js b/public/app/features/templating/templateSrv.js
index d6ed0b65877..7615aa7da0f 100644
--- a/public/app/features/templating/templateSrv.js
+++ b/public/app/features/templating/templateSrv.js
@@ -1,8 +1,9 @@
define([
'angular',
'lodash',
+ 'app/core/utils/kbn',
],
-function (angular, _) {
+function (angular, _, kbn) {
'use strict';
var module = angular.module('grafana.services');
@@ -32,10 +33,6 @@ function (angular, _) {
}
};
- function regexEscape(value) {
- return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
- }
-
function luceneEscape(value) {
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
}
@@ -61,10 +58,10 @@ function (angular, _) {
switch(format) {
case "regex": {
if (typeof value === 'string') {
- return regexEscape(value);
+ return kbn.regexEscape(value);
}
- var escapedValues = _.map(value, regexEscape);
+ var escapedValues = _.map(value, kbn.regexEscape);
return '(' + escapedValues.join('|') + ')';
}
case "lucene": {
@@ -95,17 +92,6 @@ function (angular, _) {
return match && (self._index[match[1] || match[2]] !== void 0);
};
- this.containsVariable = function(str, variableName) {
- if (!str) {
- return false;
- }
-
- variableName = regexEscape(variableName);
- var findVarRegex = new RegExp('\\$(' + variableName + ')(?:\\W|$)|\\[\\[(' + variableName + ')\\]\\]', 'g');
- var match = findVarRegex.exec(str);
- return match !== null;
- };
-
this.highlightVariablesAsHtml = function(str) {
if (!str || !_.isString(str)) { return str; }
diff --git a/public/app/features/templating/variable.ts b/public/app/features/templating/variable.ts
index fb8b08112d6..cbee8b0b9c1 100644
--- a/public/app/features/templating/variable.ts
+++ b/public/app/features/templating/variable.ts
@@ -1,5 +1,23 @@
+import kbn from 'app/core/utils/kbn';
+
+export function containsVariable(str, variableName) {
+ if (!str) {
+ return false;
+ }
+
+ variableName = kbn.regexEscape(variableName);
+ var findVarRegex = new RegExp('\\$(' + variableName + ')(?:\\W|$)|\\[\\[(' + variableName + ')\\]\\]', 'g');
+ var match = findVarRegex.exec(str);
+ return match !== null;
+}
+
export interface Variable {
setValue(option);
+ updateOptions();
+ dependsOn(variableName);
}
+
+
+
diff --git a/public/app/features/templating/variable_srv.ts b/public/app/features/templating/variable_srv.ts
index e7470bdfa98..f03cd8a576d 100644
--- a/public/app/features/templating/variable_srv.ts
+++ b/public/app/features/templating/variable_srv.ts
@@ -34,7 +34,52 @@ export class VariableSrv {
dashboard.templating.list.map(this.addVariable.bind(this));
this.templateSrv.init(this.variables);
- return this.$q.when();
+ var queryParams = this.$location.search();
+
+ for (let variable of this.variables) {
+ this.variableLock[variable.name] = this.$q.defer();
+ }
+
+ var promises = [];
+
+ for (let variable of this.variables) {
+ promises.push(this.processVariable(variable, queryParams));
+ }
+
+ return this.$q.all(this.variables.map(variable => {
+ return this.processVariable(variable, queryParams);
+ }));
+ }
+
+ processVariable(variable, queryParams) {
+ var dependencies = [];
+ var lock = this.variableLock[variable.name];
+
+ for (let otherVariable of this.variables) {
+ if (variable.dependsOn(otherVariable)) {
+ dependencies.push(this.variableLock[otherVariable.name].promise);
+ }
+ }
+
+ return this.$q.all(dependencies).then(() => {
+ var urlValue = queryParams['var-' + variable.name];
+ if (urlValue !== void 0) {
+ return variable.setValueFromUrl(urlValue).then(lock.resolve);
+ }
+
+ if (variable.refresh === 1 || variable.refresh === 2) {
+ return variable.updateOptions().then(() => {
+ // if (_.isEmpty(variable.current) && variable.options.length) {
+ // self.setVariableValue(variable, variable.options[0]);
+ // }
+ lock.resolve();
+ });
+ }
+
+ lock.resolve();
+ }).finally(() => {
+ delete this.variableLock[variable.name];
+ });
}
addVariable(model) {
@@ -60,14 +105,13 @@ export class VariableSrv {
return this.$q.when();
}
+ // cascade updates to variables that use this variable
var promises = _.map(this.variables, otherVariable => {
if (otherVariable === variable) {
return;
}
- if (this.templateSrv.containsVariable(otherVariable.regex, variable.name) ||
- this.templateSrv.containsVariable(otherVariable.query, variable.name) ||
- this.templateSrv.containsVariable(otherVariable.datasource, variable.name)) {
+ if (otherVariable.dependsOn(variable)) {
return this.updateOptions(otherVariable);
}
});
@@ -101,7 +145,7 @@ export class VariableSrv {
validateVariableSelectionState(variable) {
if (!variable.current) {
- if (!variable.options.length) { return Promise.resolve(); }
+ if (!variable.options.length) { return this.$q.when(); }
return variable.setValue(variable.options[0]);
}
@@ -129,6 +173,7 @@ export class VariableSrv {
}
}
}
+
}
coreModule.service('variableSrv', VariableSrv);
diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts
index af692bdd799..eedf9c1badd 100644
--- a/public/app/plugins/datasource/prometheus/datasource.ts
+++ b/public/app/plugins/datasource/prometheus/datasource.ts
@@ -3,7 +3,6 @@
import angular from 'angular';
import _ from 'lodash';
import moment from 'moment';
-import kbn from 'app/core/utils/kbn';
import * as dateMath from 'app/core/utils/datemath';
import PrometheusMetricFindQuery from './metric_find_query';
@@ -41,6 +40,10 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
return backendSrv.datasourceRequest(options);
};
+ function prometheusSpecialRegexEscape(value) {
+ return value.replace(/[\\^$*+?.()|[\]{}]/g, '\\\\$&');
+ }
+
this.interpolateQueryExpr = function(value, variable, defaultFormatFn) {
// if no multi or include all do not regexEscape
if (!variable.multi && !variable.includeAll) {
@@ -48,10 +51,10 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
}
if (typeof value === 'string') {
- return kbn.regexEscape(value);
+ return prometheusSpecialRegexEscape(value);
}
- var escapedValues = _.map(value, kbn.regexEscape);
+ var escapedValues = _.map(value, prometheusSpecialRegexEscape);
return escapedValues.join('|');
};
diff --git a/public/test/specs/templateSrv-specs.js b/public/test/specs/templateSrv-specs.js
index a592cc7a152..3dac01fbdf2 100644
--- a/public/test/specs/templateSrv-specs.js
+++ b/public/test/specs/templateSrv-specs.js
@@ -177,38 +177,6 @@ define([
var result = _templateSrv.highlightVariablesAsHtml('this $google ok');
expect(result).to.be('this $google ok');
});
-
- });
-
- describe('when checking if a string contains a variable', function() {
- beforeEach(function() {
- _templateSrv.init([{ name: 'test', current: { value: 'muuuu' } }]);
- });
-
- it('should find it with $var syntax', function() {
- var contains = _templateSrv.containsVariable('this.$test.filters', 'test');
- expect(contains).to.be(true);
- });
-
- it('should not find it if only part matches with $var syntax', function() {
- var contains = _templateSrv.containsVariable('this.$ServerDomain.filters', 'Server');
- expect(contains).to.be(false);
- });
-
- it('should find it with [[var]] syntax', function() {
- var contains = _templateSrv.containsVariable('this.[[test]].filters', 'test');
- expect(contains).to.be(true);
- });
-
- it('should find it when part of segment', function() {
- var contains = _templateSrv.containsVariable('metrics.$env.$group-*', 'group');
- expect(contains).to.be(true);
- });
-
- it('should find it its the only thing', function() {
- var contains = _templateSrv.containsVariable('$env', 'env');
- expect(contains).to.be(true);
- });
});
describe('updateTemplateData with simple value', function() {
diff --git a/public/test/specs/templateValuesSrv-specs.js b/public/test/specs/templateValuesSrv-specs.js
index 2ddb69a5b4a..1807157ae35 100644
--- a/public/test/specs/templateValuesSrv-specs.js
+++ b/public/test/specs/templateValuesSrv-specs.js
@@ -1,9 +1,8 @@
define([
'../mocks/dashboard-mock',
'./helpers',
- 'moment',
'app/features/templating/templateValuesSrv'
-], function(dashboardMock, helpers, moment) {
+], function(dashboardMock, helpers) {
'use strict';
describe('templateValuesSrv', function() {
@@ -13,20 +12,6 @@ define([
beforeEach(ctx.providePhase(['datasourceSrv', 'timeSrv', 'templateSrv', '$location']));
beforeEach(ctx.createService('templateValuesSrv'));
- describe('update interval variable options', function() {
- var variable = { type: 'interval', query: 'auto,1s,2h,5h,1d', name: 'test' };
-
- beforeEach(function() {
- ctx.service.updateOptions(variable);
- });
-
- it('should update options array', function() {
- expect(variable.options.length).to.be(5);
- expect(variable.options[1].text).to.be('1s');
- expect(variable.options[1].value).to.be('1s');
- });
- });
-
describe('when template variable is present in url', function() {
describe('and setting simple variable', function() {
var variable = {
@@ -99,375 +84,6 @@ define([
});
});
- function describeUpdateVariable(desc, fn) {
- describe(desc, function() {
- var scenario = {};
- scenario.setup = function(setupFn) {
- scenario.setupFn = setupFn;
- };
- beforeEach(function() {
- scenario.setupFn();
- var ds = {};
- ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
- ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds));
- ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
-
- ctx.service.updateOptions(scenario.variable);
- ctx.$rootScope.$digest();
- });
-
- fn(scenario);
- });
- }
-
- describeUpdateVariable('interval variable without auto', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'interval', query: '1s,2h,5h,1d', name: 'test' };
- });
-
- it('should update options array', function() {
- expect(scenario.variable.options.length).to.be(4);
- expect(scenario.variable.options[0].text).to.be('1s');
- expect(scenario.variable.options[0].value).to.be('1s');
- });
- });
-
- describeUpdateVariable('query variable with empty current object and refresh', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: '', name: 'test', current: {} };
- scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
- });
-
- it('should set current value to first option', function() {
- expect(scenario.variable.options.length).to.be(2);
- expect(scenario.variable.current.value).to.be('backend1');
- });
- });
-
- describeUpdateVariable('query variable with multi select and new options does not contain some selected values', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {
- type: 'query',
- query: '',
- name: 'test',
- current: {
- value: ['val1', 'val2', 'val3'],
- text: 'val1 + val2 + val3'
- }
- };
- scenario.queryResult = [{text: 'val2'}, {text: 'val3'}];
- });
-
- it('should update current value', function() {
- expect(scenario.variable.current.value).to.eql(['val2', 'val3']);
- expect(scenario.variable.current.text).to.eql('val2 + val3');
- });
- });
-
- describeUpdateVariable('query variable with multi select and new options does not contain any selected values', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {
- type: 'query',
- query: '',
- name: 'test',
- current: {
- value: ['val1', 'val2', 'val3'],
- text: 'val1 + val2 + val3'
- }
- };
- scenario.queryResult = [{text: 'val5'}, {text: 'val6'}];
- });
-
- it('should update current value with first one', function() {
- expect(scenario.variable.current.value).to.eql('val5');
- expect(scenario.variable.current.text).to.eql('val5');
- });
- });
-
- describeUpdateVariable('query variable with multi select and $__all selected', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {
- type: 'query',
- query: '',
- name: 'test',
- includeAll: true,
- current: {
- value: ['$__all'],
- text: 'All'
- }
- };
- scenario.queryResult = [{text: 'val5'}, {text: 'val6'}];
- });
-
- it('should keep current All value', function() {
- expect(scenario.variable.current.value).to.eql(['$__all']);
- expect(scenario.variable.current.text).to.eql('All');
- });
- });
-
- describeUpdateVariable('query variable with numeric results', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: '', name: 'test', current: {} };
- scenario.queryResult = [{text: 12, value: 12}];
- });
-
- it('should set current value to first option', function() {
- expect(scenario.variable.current.value).to.be('12');
- expect(scenario.variable.options[0].value).to.be('12');
- expect(scenario.variable.options[0].text).to.be('12');
- });
- });
-
- describeUpdateVariable('interval variable without auto', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'interval', query: '1s,2h,5h,1d', name: 'test' };
- });
-
- it('should update options array', function() {
- expect(scenario.variable.options.length).to.be(4);
- expect(scenario.variable.options[0].text).to.be('1s');
- expect(scenario.variable.options[0].value).to.be('1s');
- });
- });
-
- describeUpdateVariable('interval variable with auto', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'interval', query: '1s,2h,5h,1d', name: 'test', auto: true, auto_count: 10 };
-
- var range = {
- from: moment(new Date()).subtract(7, 'days').toDate(),
- to: new Date()
- };
-
- ctx.timeSrv.timeRange = sinon.stub().returns(range);
- ctx.templateSrv.setGrafanaVariable = sinon.spy();
- });
-
- it('should update options array', function() {
- expect(scenario.variable.options.length).to.be(5);
- expect(scenario.variable.options[0].text).to.be('auto');
- expect(scenario.variable.options[0].value).to.be('$__auto_interval');
- });
-
- it('should set $__auto_interval', function() {
- var call = ctx.templateSrv.setGrafanaVariable.getCall(0);
- expect(call.args[0]).to.be('$__auto_interval');
- expect(call.args[1]).to.be('12h');
- });
- });
-
- describeUpdateVariable('update custom variable', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'custom', query: 'hej, hop, asd', name: 'test'};
- });
-
- it('should update options array', function() {
- expect(scenario.variable.options.length).to.be(3);
- expect(scenario.variable.options[0].text).to.be('hej');
- expect(scenario.variable.options[1].value).to.be('hop');
- });
-
- it('should set $__auto_interval', function() {
- var call = ctx.templateSrv.setGrafanaVariable.getCall(0);
- expect(call.args[0]).to.be('$__auto_interval');
- expect(call.args[1]).to.be('12h');
- });
- });
-
- describeUpdateVariable('basic query variable', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
- scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
- });
-
- it('should update options array', function() {
- expect(scenario.variable.options.length).to.be(2);
- expect(scenario.variable.options[0].text).to.be('backend1');
- expect(scenario.variable.options[0].value).to.be('backend1');
- expect(scenario.variable.options[1].value).to.be('backend2');
- });
-
- it('should select first option as value', function() {
- expect(scenario.variable.current.value).to.be('backend1');
- });
- });
-
- describeUpdateVariable('and existing value still exists in options', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
- scenario.variable.current = { value: 'backend2', text: 'backend2'};
- scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
- });
-
- it('should keep variable value', function() {
- expect(scenario.variable.current.text).to.be('backend2');
- });
- });
-
- describeUpdateVariable('and regex pattern exists', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
- scenario.variable.regex = '/apps.*(backend_[0-9]+)/';
- scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
- });
-
- it('should extract and use match group', function() {
- expect(scenario.variable.options[0].value).to.be('backend_01');
- });
- });
-
- describeUpdateVariable('and regex pattern exists and no match', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
- scenario.variable.regex = '/apps.*(backendasd[0-9]+)/';
- scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
- });
-
- it('should not add non matching items, None option should be added instead', function() {
- expect(scenario.variable.options.length).to.be(1);
- expect(scenario.variable.options[0].isNone).to.be(true);
- });
- });
-
- describeUpdateVariable('regex pattern without slashes', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
- scenario.variable.regex = 'backend_01';
- scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
- });
-
- it('should return matches options', function() {
- expect(scenario.variable.options.length).to.be(1);
- });
- });
-
- describeUpdateVariable('regex pattern remove duplicates', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test' };
- scenario.variable.regex = 'backend_01';
- scenario.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_01.counters.req'}];
- });
-
- it('should return matches options', function() {
- expect(scenario.variable.options.length).to.be(1);
- });
- });
-
- describeUpdateVariable('with include All', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'query', query: 'apps.*', name: 'test', includeAll: true};
- scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}, { text: 'backend3'}];
- });
-
- it('should add All option', function() {
- expect(scenario.variable.options[0].text).to.be('All');
- expect(scenario.variable.options[0].value).to.be('$__all');
- });
- });
-
- describeUpdateVariable('with include all and custom value', function(scenario) {
- scenario.setup(function() {
- scenario.variable = { type: 'query', query: 'apps.*', name: 'test', includeAll: true, allValue: '*' };
- scenario.queryResult = [{text: 'backend1'}, {text: 'backend2'}, { text: 'backend3'}];
- });
-
- it('should add All option with custom value', function() {
- expect(scenario.variable.options[0].value).to.be('$__all');
- });
- });
-
- describeUpdateVariable('datasource variable with regex filter', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {
- type: 'datasource',
- query: 'graphite',
- name: 'test',
- current: {value: 'backend4_pee', text: 'backend4_pee'},
- regex: '/pee$/'
- };
- scenario.metricSources = [
- {name: 'backend1', meta: {id: 'influx'}},
- {name: 'backend2_pee', meta: {id: 'graphite'}},
- {name: 'backend3', meta: {id: 'graphite'}},
- {name: 'backend4_pee', meta: {id: 'graphite'}},
- ];
- });
-
- it('should set only contain graphite ds and filtered using regex', function() {
- expect(scenario.variable.options.length).to.be(2);
- expect(scenario.variable.options[0].value).to.be('backend2_pee');
- expect(scenario.variable.options[1].value).to.be('backend4_pee');
- });
-
- it('should keep current value if available', function() {
- expect(scenario.variable.current.value).to.be('backend4_pee');
- });
- });
-
- describeUpdateVariable('without sort', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'query', query: 'apps.*', name: 'test', sort: 0};
- scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
- });
-
- it('should return options without sort', function() {
- expect(scenario.variable.options[0].text).to.be('bbb2');
- expect(scenario.variable.options[1].text).to.be('aaa10');
- expect(scenario.variable.options[2].text).to.be('ccc3');
- });
- });
-
- describeUpdateVariable('with alphabetical sort (asc)', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'query', query: 'apps.*', name: 'test', sort: 1};
- scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
- });
-
- it('should return options with alphabetical sort', function() {
- expect(scenario.variable.options[0].text).to.be('aaa10');
- expect(scenario.variable.options[1].text).to.be('bbb2');
- expect(scenario.variable.options[2].text).to.be('ccc3');
- });
- });
-
- describeUpdateVariable('with alphabetical sort (desc)', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'query', query: 'apps.*', name: 'test', sort: 2};
- scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
- });
-
- it('should return options with alphabetical sort', function() {
- expect(scenario.variable.options[0].text).to.be('ccc3');
- expect(scenario.variable.options[1].text).to.be('bbb2');
- expect(scenario.variable.options[2].text).to.be('aaa10');
- });
- });
-
- describeUpdateVariable('with numerical sort (asc)', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'query', query: 'apps.*', name: 'test', sort: 3};
- scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
- });
-
- it('should return options with numerical sort', function() {
- expect(scenario.variable.options[0].text).to.be('bbb2');
- expect(scenario.variable.options[1].text).to.be('ccc3');
- expect(scenario.variable.options[2].text).to.be('aaa10');
- });
- });
-
- describeUpdateVariable('with numerical sort (desc)', function(scenario) {
- scenario.setup(function() {
- scenario.variable = {type: 'query', query: 'apps.*', name: 'test', sort: 4};
- scenario.queryResult = [{text: 'bbb2'}, {text: 'aaa10'}, { text: 'ccc3'}];
- });
-
- it('should return options with numerical sort', function() {
- expect(scenario.variable.options[0].text).to.be('aaa10');
- expect(scenario.variable.options[1].text).to.be('ccc3');
- expect(scenario.variable.options[2].text).to.be('bbb2');
- });
- });
});
});