Skip to content

Commit 4188c46

Browse files
committed
feat(templating): more work on new variable handling code, grafana#6048
1 parent 46ebae7 commit 4188c46

File tree

9 files changed

+192
-95
lines changed

9 files changed

+192
-95
lines changed

public/app/features/templating/custom_variable.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ export class CustomVariable implements Variable {
1111
includeAll: boolean;
1212

1313
/** @ngInject */
14-
constructor(private model, private timeSrv, private templateSrv) {
14+
constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
1515
_.extend(this, model);
1616
}
1717

1818
setValue(option) {
19+
this.variableSrv.setOptionAsCurrent(this, option);
1920
}
2021

2122
updateOptions() {
@@ -33,9 +34,13 @@ export class CustomVariable implements Variable {
3334
this.options.unshift({text: 'All', value: "$__all"});
3435
}
3536

36-
dependsOn(variableName) {
37+
dependsOn(variable) {
3738
return false;
3839
}
40+
41+
setValueFromUrl(urlValue) {
42+
return this.variableSrv.setOptionFromUrl(this, urlValue);
43+
}
3944
}
4045

4146
variableConstructorMap['custom'] = CustomVariable;

public/app/features/templating/datasource_variable.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ export class DatasourceVariable implements Variable {
1111
options: any;
1212

1313
/** @ngInject */
14-
constructor(private model, private datasourceSrv) {
14+
constructor(private model, private datasourceSrv, private variableSrv) {
1515
_.extend(this, model);
1616
}
1717

1818
setValue(option) {
19+
this.variableSrv.setOptionAsCurrent(this, option);
1920
}
2021

2122
updateOptions() {
@@ -48,9 +49,13 @@ export class DatasourceVariable implements Variable {
4849
this.options = options;
4950
}
5051

51-
dependsOn(variableName) {
52+
dependsOn(variable) {
5253
return false;
5354
}
55+
56+
setValueFromUrl(urlValue) {
57+
return this.variableSrv.setOptionFromUrl(this, urlValue);
58+
}
5459
}
5560

5661
variableConstructorMap['datasource'] = DatasourceVariable;

public/app/features/templating/interval_variable.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@ export class IntervalVariable implements Variable {
1313
query: string;
1414

1515
/** @ngInject */
16-
constructor(private model, private timeSrv, private templateSrv) {
16+
constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
1717
_.extend(this, model);
1818
}
1919

2020
setValue(option) {
21-
if (this.auto) {
22-
this.updateAutoValue();
23-
}
21+
this.updateAutoValue();
22+
this.variableSrv.setOptionAsCurrent(this, option);
2423
}
2524

2625
updateAutoValue() {
26+
if (!this.auto) {
27+
return;
28+
}
29+
2730
// add auto option if missing
2831
if (this.options.length && this.options[0].text !== 'auto') {
2932
this.options.unshift({ text: 'auto', value: '$__auto_interval' });
@@ -44,9 +47,14 @@ export class IntervalVariable implements Variable {
4447
}
4548
}
4649

47-
dependsOn(variableName) {
50+
dependsOn(variable) {
4851
return false;
4952
}
53+
54+
setValueFromUrl(urlValue) {
55+
this.updateAutoValue();
56+
return this.variableSrv.setOptionFromUrl(this, urlValue);
57+
}
5058
}
5159

5260
variableConstructorMap['interval'] = IntervalVariable;

public/app/features/templating/query_variable.ts

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,11 @@ export class QueryVariable implements Variable {
2424
}
2525

2626
setValue(option){
27-
this.current = _.cloneDeep(option);
28-
29-
if (_.isArray(this.current.text)) {
30-
this.current.text = this.current.text.join(' + ');
31-
}
32-
33-
this.variableSrv.selectOptionsForCurrentValue(this);
34-
return this.variableSrv.variableUpdated(this);
27+
this.variableSrv.setOptionAsCurrent(this, option);
3528
}
3629

3730
setValueFromUrl(urlValue) {
38-
var promise = this.$q.when();
39-
40-
if (this.refresh) {
41-
promise = this.updateOptions();
42-
}
43-
44-
return promise.then(() => {
45-
var option = _.find(this.options, op => {
46-
return op.text === urlValue || op.value === urlValue;
47-
});
48-
49-
option = option || { text: urlValue, value: urlValue };
50-
return this.setValue(option);
51-
});
31+
return this.variableSrv.setOptionFromUrl(this, urlValue);
5232
}
5333

5434
updateOptions() {
@@ -126,11 +106,11 @@ export class QueryVariable implements Variable {
126106
} else if (sortType === 2) {
127107
options = _.sortBy(options, function(opt) {
128108
var matches = opt.text.match(/.*?(\d+).*/);
129-
if (!matches) {
130-
return 0;
131-
} else {
132-
return parseInt(matches[1], 10);
133-
}
109+
if (!matches) {
110+
return 0;
111+
} else {
112+
return parseInt(matches[1], 10);
113+
}
134114
});
135115
}
136116

@@ -141,8 +121,8 @@ if (!matches) {
141121
return options;
142122
}
143123

144-
dependsOn(variableName) {
145-
return containsVariable(this.query, variableName) || containsVariable(this.datasource, variableName);
124+
dependsOn(variable) {
125+
return containsVariable(this.query, this.datasource, variable.name);
146126
}
147127
}
148128

public/app/features/templating/specs/variable_specs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ describe('containsVariable', function() {
3030
var contains = containsVariable('$env', 'env');
3131
expect(contains).to.be(true);
3232
});
33+
34+
it('should be able to pass in multiple test strings', function() {
35+
var contains = containsVariable('asd','asd2.$env', 'env');
36+
expect(contains).to.be(true);
37+
});
38+
3339
});
3440

3541
});
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
2+
3+
import _ from 'lodash';
4+
import helpers from 'test/specs/helpers';
5+
import '../all';
6+
7+
describe('VariableSrv init', function() {
8+
var ctx = new helpers.ControllerTestContext();
9+
10+
beforeEach(angularMocks.module('grafana.core'));
11+
beforeEach(angularMocks.module('grafana.controllers'));
12+
beforeEach(angularMocks.module('grafana.services'));
13+
14+
beforeEach(ctx.providePhase(['datasourceSrv', 'timeSrv', 'templateSrv', '$location']));
15+
beforeEach(angularMocks.inject(($rootScope, $q, $location, $injector) => {
16+
ctx.$q = $q;
17+
ctx.$rootScope = $rootScope;
18+
ctx.$location = $location;
19+
ctx.variableSrv = $injector.get('variableSrv');
20+
ctx.variableSrv.init({templating: {list: []}});
21+
ctx.$rootScope.$digest();
22+
}));
23+
24+
function describeInitScenario(desc, fn) {
25+
describe(desc, function() {
26+
var scenario: any = {
27+
urlParams: {},
28+
setup: setupFn => {
29+
scenario.setupFn = setupFn;
30+
}
31+
};
32+
33+
beforeEach(function() {
34+
scenario.setupFn();
35+
ctx.datasource = {};
36+
ctx.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
37+
38+
ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ctx.datasource));
39+
ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
40+
41+
ctx.$location.search = sinon.stub().returns(scenario.urlParams);
42+
43+
ctx.dashboard = {templating: {list: scenario.variables}};
44+
ctx.variableSrv.init(ctx.dashboard);
45+
ctx.$rootScope.$digest();
46+
47+
scenario.variables = ctx.variableSrv.variables;
48+
});
49+
50+
fn(scenario);
51+
});
52+
}
53+
54+
['query', 'interval', 'custom', 'datasource'].forEach(type => {
55+
describeInitScenario('when setting ' + type + ' variable via url', scenario => {
56+
scenario.setup(() => {
57+
scenario.variables = [{
58+
name: 'apps',
59+
type: type,
60+
current: {text: "test", value: "test"},
61+
options: [{text: "test", value: "test"}]
62+
}];
63+
scenario.urlParams["var-apps"] = "new";
64+
});
65+
66+
it('should update current value', () => {
67+
expect(scenario.variables[0].current.value).to.be("new");
68+
expect(scenario.variables[0].current.text).to.be("new");
69+
});
70+
});
71+
72+
});
73+
74+
describe('given dependent variables', () => {
75+
var variableList = [
76+
{
77+
name: 'app',
78+
type: 'query',
79+
query: '',
80+
current: {text: "app1", value: "app1"},
81+
options: [{text: "app1", value: "app1"}]
82+
},
83+
{
84+
name: 'server',
85+
type: 'query',
86+
refresh: 1,
87+
query: '$app.*',
88+
current: {text: "server1", value: "server1"},
89+
options: [{text: "server1", value: "server1"}]
90+
},
91+
];
92+
93+
describeInitScenario('when setting parent var from url', scenario => {
94+
scenario.setup(() => {
95+
scenario.variables = _.cloneDeep(variableList);
96+
scenario.urlParams["var-app"] = "google";
97+
scenario.queryResult = [{text: 'google-server1'}, {text: 'google-server2'}];
98+
});
99+
100+
it('should update child variable', () => {
101+
expect(scenario.variables[1].options.length).to.be(2);
102+
expect(scenario.variables[1].current.text).to.be("google-server1");
103+
});
104+
105+
it('should only update it once', () => {
106+
expect(ctx.datasource.metricFindQuery.callCount).to.be(1);
107+
});
108+
109+
});
110+
});
111+
112+
});
113+

public/app/features/templating/specs/variable_srv_specs.ts

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,52 +21,6 @@ describe('VariableSrv', function() {
2121
ctx.$rootScope.$digest();
2222
}));
2323

24-
function describeInitSceneario(desc, fn) {
25-
describe(desc, function() {
26-
var scenario: any = {
27-
urlParams: {},
28-
setup: setupFn => {
29-
scenario.setupFn = setupFn;
30-
}
31-
};
32-
33-
beforeEach(function() {
34-
scenario.setupFn();
35-
var ds: any = {};
36-
ds.metricFindQuery = sinon.stub().returns(ctx.$q.when(scenario.queryResult));
37-
ctx.datasourceSrv.get = sinon.stub().returns(ctx.$q.when(ds));
38-
ctx.datasourceSrv.getMetricSources = sinon.stub().returns(scenario.metricSources);
39-
40-
ctx.$location.search = sinon.stub().returns(scenario.urlParams);
41-
42-
ctx.dashboard = {templating: {list: scenario.variables}};
43-
ctx.variableSrv.init(ctx.dashboard);
44-
ctx.$rootScope.$digest();
45-
46-
scenario.variables = ctx.variableSrv.variables;
47-
});
48-
49-
fn(scenario);
50-
});
51-
}
52-
53-
describeInitSceneario('when setting simple variable via url', scenario => {
54-
scenario.setup(() => {
55-
scenario.variables = [{
56-
name: 'apps',
57-
type: 'query',
58-
current: {text: "test", value: "test"},
59-
options: [{text: "test", value: "test"}]
60-
}];
61-
scenario.urlParams["var-apps"] = "new";
62-
});
63-
64-
it('should update current value', () => {
65-
expect(scenario.variables[0].current.value).to.be("new");
66-
expect(scenario.variables[0].current.text).to.be("new");
67-
});
68-
});
69-
7024
function describeUpdateVariable(desc, fn) {
7125
describe(desc, function() {
7226
var scenario: any = {};

public/app/features/templating/variable.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
///<reference path="../../headers/common.d.ts" />
12

3+
import _ from 'lodash';
24
import kbn from 'app/core/utils/kbn';
35

4-
export function containsVariable(str, variableName) {
5-
if (!str) {
6-
return false;
6+
export function containsVariable(...args: any[]) {
7+
var variableName = args[args.length-1];
8+
var str = args[0] || '';
9+
10+
for (var i = 1; i < args.length-1; i++) {
11+
str += args[i] || '';
712
}
813

914
variableName = kbn.regexEscape(variableName);
@@ -15,7 +20,8 @@ export function containsVariable(str, variableName) {
1520
export interface Variable {
1621
setValue(option);
1722
updateOptions();
18-
dependsOn(variableName);
23+
dependsOn(variable);
24+
setValueFromUrl(urlValue);
1925
}
2026

2127

0 commit comments

Comments
 (0)