Commit 4188c46f by Torkel Ödegaard

feat(templating): more work on new variable handling code, #6048

parent 46ebae73
...@@ -11,11 +11,12 @@ export class CustomVariable implements Variable { ...@@ -11,11 +11,12 @@ export class CustomVariable implements Variable {
includeAll: boolean; includeAll: boolean;
/** @ngInject */ /** @ngInject */
constructor(private model, private timeSrv, private templateSrv) { constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
_.extend(this, model); _.extend(this, model);
} }
setValue(option) { setValue(option) {
this.variableSrv.setOptionAsCurrent(this, option);
} }
updateOptions() { updateOptions() {
...@@ -33,9 +34,13 @@ export class CustomVariable implements Variable { ...@@ -33,9 +34,13 @@ export class CustomVariable implements Variable {
this.options.unshift({text: 'All', value: "$__all"}); this.options.unshift({text: 'All', value: "$__all"});
} }
dependsOn(variableName) { dependsOn(variable) {
return false; return false;
} }
setValueFromUrl(urlValue) {
return this.variableSrv.setOptionFromUrl(this, urlValue);
}
} }
variableConstructorMap['custom'] = CustomVariable; variableConstructorMap['custom'] = CustomVariable;
...@@ -11,11 +11,12 @@ export class DatasourceVariable implements Variable { ...@@ -11,11 +11,12 @@ export class DatasourceVariable implements Variable {
options: any; options: any;
/** @ngInject */ /** @ngInject */
constructor(private model, private datasourceSrv) { constructor(private model, private datasourceSrv, private variableSrv) {
_.extend(this, model); _.extend(this, model);
} }
setValue(option) { setValue(option) {
this.variableSrv.setOptionAsCurrent(this, option);
} }
updateOptions() { updateOptions() {
...@@ -48,9 +49,13 @@ export class DatasourceVariable implements Variable { ...@@ -48,9 +49,13 @@ export class DatasourceVariable implements Variable {
this.options = options; this.options = options;
} }
dependsOn(variableName) { dependsOn(variable) {
return false; return false;
} }
setValueFromUrl(urlValue) {
return this.variableSrv.setOptionFromUrl(this, urlValue);
}
} }
variableConstructorMap['datasource'] = DatasourceVariable; variableConstructorMap['datasource'] = DatasourceVariable;
...@@ -13,17 +13,20 @@ export class IntervalVariable implements Variable { ...@@ -13,17 +13,20 @@ export class IntervalVariable implements Variable {
query: string; query: string;
/** @ngInject */ /** @ngInject */
constructor(private model, private timeSrv, private templateSrv) { constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
_.extend(this, model); _.extend(this, model);
} }
setValue(option) { setValue(option) {
if (this.auto) { this.updateAutoValue();
this.updateAutoValue(); this.variableSrv.setOptionAsCurrent(this, option);
}
} }
updateAutoValue() { updateAutoValue() {
if (!this.auto) {
return;
}
// add auto option if missing // add auto option if missing
if (this.options.length && this.options[0].text !== 'auto') { if (this.options.length && this.options[0].text !== 'auto') {
this.options.unshift({ text: 'auto', value: '$__auto_interval' }); this.options.unshift({ text: 'auto', value: '$__auto_interval' });
...@@ -44,9 +47,14 @@ export class IntervalVariable implements Variable { ...@@ -44,9 +47,14 @@ export class IntervalVariable implements Variable {
} }
} }
dependsOn(variableName) { dependsOn(variable) {
return false; return false;
} }
setValueFromUrl(urlValue) {
this.updateAutoValue();
return this.variableSrv.setOptionFromUrl(this, urlValue);
}
} }
variableConstructorMap['interval'] = IntervalVariable; variableConstructorMap['interval'] = IntervalVariable;
...@@ -24,31 +24,11 @@ export class QueryVariable implements Variable { ...@@ -24,31 +24,11 @@ export class QueryVariable implements Variable {
} }
setValue(option){ setValue(option){
this.current = _.cloneDeep(option); this.variableSrv.setOptionAsCurrent(this, option);
if (_.isArray(this.current.text)) {
this.current.text = this.current.text.join(' + ');
}
this.variableSrv.selectOptionsForCurrentValue(this);
return this.variableSrv.variableUpdated(this);
} }
setValueFromUrl(urlValue) { setValueFromUrl(urlValue) {
var promise = this.$q.when(); return this.variableSrv.setOptionFromUrl(this, urlValue);
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() { updateOptions() {
...@@ -126,11 +106,11 @@ export class QueryVariable implements Variable { ...@@ -126,11 +106,11 @@ export class QueryVariable implements Variable {
} else if (sortType === 2) { } else if (sortType === 2) {
options = _.sortBy(options, function(opt) { options = _.sortBy(options, function(opt) {
var matches = opt.text.match(/.*?(\d+).*/); var matches = opt.text.match(/.*?(\d+).*/);
if (!matches) { if (!matches) {
return 0; return 0;
} else { } else {
return parseInt(matches[1], 10); return parseInt(matches[1], 10);
} }
}); });
} }
...@@ -141,8 +121,8 @@ if (!matches) { ...@@ -141,8 +121,8 @@ if (!matches) {
return options; return options;
} }
dependsOn(variableName) { dependsOn(variable) {
return containsVariable(this.query, variableName) || containsVariable(this.datasource, variableName); return containsVariable(this.query, this.datasource, variable.name);
} }
} }
......
...@@ -30,6 +30,12 @@ describe('containsVariable', function() { ...@@ -30,6 +30,12 @@ describe('containsVariable', function() {
var contains = containsVariable('$env', 'env'); var contains = containsVariable('$env', 'env');
expect(contains).to.be(true); expect(contains).to.be(true);
}); });
it('should be able to pass in multiple test strings', function() {
var contains = containsVariable('asd','asd2.$env', 'env');
expect(contains).to.be(true);
});
}); });
}); });
......
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
import _ from 'lodash';
import helpers from 'test/specs/helpers';
import '../all';
describe('VariableSrv init', function() {
var ctx = new helpers.ControllerTestContext();
beforeEach(angularMocks.module('grafana.core'));
beforeEach(angularMocks.module('grafana.controllers'));
beforeEach(angularMocks.module('grafana.services'));
beforeEach(ctx.providePhase(['datasourceSrv', 'timeSrv', 'templateSrv', '$location']));
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 describeInitScenario(desc, fn) {
describe(desc, function() {
var scenario: any = {
urlParams: {},
setup: setupFn => {
scenario.setupFn = setupFn;
}
};
beforeEach(function() {
scenario.setupFn();
ctx.datasource = {};
ctx.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ctx.datasource));
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);
});
}
['query', 'interval', 'custom', 'datasource'].forEach(type => {
describeInitScenario('when setting ' + type + ' variable via url', scenario => {
scenario.setup(() => {
scenario.variables = [{
name: 'apps',
type: type,
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");
});
});
});
describe('given dependent variables', () => {
var variableList = [
{
name: 'app',
type: 'query',
query: '',
current: {text: "app1", value: "app1"},
options: [{text: "app1", value: "app1"}]
},
{
name: 'server',
type: 'query',
refresh: 1,
query: '$app.*',
current: {text: "server1", value: "server1"},
options: [{text: "server1", value: "server1"}]
},
];
describeInitScenario('when setting parent var from url', scenario => {
scenario.setup(() => {
scenario.variables = _.cloneDeep(variableList);
scenario.urlParams["var-app"] = "google";
scenario.queryResult = [{text: 'google-server1'}, {text: 'google-server2'}];
});
it('should update child variable', () => {
expect(scenario.variables[1].options.length).to.be(2);
expect(scenario.variables[1].current.text).to.be("google-server1");
});
it('should only update it once', () => {
expect(ctx.datasource.metricFindQuery.callCount).to.be(1);
});
});
});
});
...@@ -21,52 +21,6 @@ describe('VariableSrv', function() { ...@@ -21,52 +21,6 @@ describe('VariableSrv', function() {
ctx.$rootScope.$digest(); 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) { function describeUpdateVariable(desc, fn) {
describe(desc, function() { describe(desc, function() {
var scenario: any = {}; var scenario: any = {};
......
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
export function containsVariable(str, variableName) { export function containsVariable(...args: any[]) {
if (!str) { var variableName = args[args.length-1];
return false; var str = args[0] || '';
for (var i = 1; i < args.length-1; i++) {
str += args[i] || '';
} }
variableName = kbn.regexEscape(variableName); variableName = kbn.regexEscape(variableName);
...@@ -15,7 +20,8 @@ export function containsVariable(str, variableName) { ...@@ -15,7 +20,8 @@ export function containsVariable(str, variableName) {
export interface Variable { export interface Variable {
setValue(option); setValue(option);
updateOptions(); updateOptions();
dependsOn(variableName); dependsOn(variable);
setValueFromUrl(urlValue);
} }
......
...@@ -40,12 +40,6 @@ export class VariableSrv { ...@@ -40,12 +40,6 @@ export class VariableSrv {
this.variableLock[variable.name] = this.$q.defer(); 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.$q.all(this.variables.map(variable => {
return this.processVariable(variable, queryParams); return this.processVariable(variable, queryParams);
})); }));
...@@ -66,7 +60,6 @@ export class VariableSrv { ...@@ -66,7 +60,6 @@ export class VariableSrv {
if (urlValue !== void 0) { if (urlValue !== void 0) {
return variable.setValueFromUrl(urlValue).then(lock.resolve); return variable.setValueFromUrl(urlValue).then(lock.resolve);
} }
if (variable.refresh === 1 || variable.refresh === 2) { if (variable.refresh === 1 || variable.refresh === 2) {
return variable.updateOptions().then(() => { return variable.updateOptions().then(() => {
// if (_.isEmpty(variable.current) && variable.options.length) { // if (_.isEmpty(variable.current) && variable.options.length) {
...@@ -174,6 +167,33 @@ export class VariableSrv { ...@@ -174,6 +167,33 @@ export class VariableSrv {
} }
} }
setOptionFromUrl(variable, urlValue) {
var promise = this.$q.when();
if (variable.refresh) {
promise = variable.updateOptions();
}
return promise.then(() => {
var option = _.find(variable.options, op => {
return op.text === urlValue || op.value === urlValue;
});
option = option || {text: urlValue, value: urlValue};
return variable.setValue(option);
});
}
setOptionAsCurrent(variable, option) {
variable.current = _.cloneDeep(option);
if (_.isArray(variable.current.text)) {
variable.current.text = variable.current.text.join(' + ');
}
this.selectOptionsForCurrentValue(variable);
return this.variableUpdated(variable);
}
} }
coreModule.service('variableSrv', VariableSrv); coreModule.service('variableSrv', VariableSrv);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment