mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(templating): progress on variable system refactoring, #6048
This commit is contained in:
parent
5ded88fa4d
commit
8a796c5b4b
@ -1,16 +1,29 @@
|
|||||||
///<reference path="../../headers/common.d.ts" />
|
///<reference path="../../headers/common.d.ts" />
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {Variable} from './variable';
|
import {Variable, assignModelProperties} from './variable';
|
||||||
import {VariableSrv, variableConstructorMap} from './variable_srv';
|
import {VariableSrv, variableConstructorMap} from './variable_srv';
|
||||||
|
|
||||||
export class ConstantVariable implements Variable {
|
export class ConstantVariable implements Variable {
|
||||||
query: string;
|
query: string;
|
||||||
options: any[];
|
options: any[];
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
type: 'constant',
|
||||||
|
name: '',
|
||||||
|
query: '',
|
||||||
|
hide: 2,
|
||||||
|
refresh: 0,
|
||||||
|
};
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private model, private variableSrv) {
|
constructor(private model, private variableSrv) {
|
||||||
_.extend(this, model);
|
assignModelProperties(this, model, this.defaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
getModel() {
|
||||||
|
assignModelProperties(this.model, this, this.defaults);
|
||||||
|
return this.model;
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(option) {
|
setValue(option) {
|
||||||
|
@ -13,7 +13,7 @@ function (angular, _) {
|
|||||||
type: 'query',
|
type: 'query',
|
||||||
datasource: null,
|
datasource: null,
|
||||||
refresh: 0,
|
refresh: 0,
|
||||||
sort: 1,
|
sort: 0,
|
||||||
name: '',
|
name: '',
|
||||||
hide: 0,
|
hide: 0,
|
||||||
options: [],
|
options: [],
|
||||||
@ -37,7 +37,7 @@ function (angular, _) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
$scope.sortOptions = [
|
$scope.sortOptions = [
|
||||||
{value: 0, text: "Without Sort"},
|
{value: 0, text: "Query sort"},
|
||||||
{value: 1, text: "Alphabetical (asc)"},
|
{value: 1, text: "Alphabetical (asc)"},
|
||||||
{value: 2, text: "Alphabetical (desc)"},
|
{value: 2, text: "Alphabetical (desc)"},
|
||||||
{value: 3, text: "Numerical (asc)"},
|
{value: 3, text: "Numerical (asc)"},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import kbn from 'app/core/utils/kbn';
|
import kbn from 'app/core/utils/kbn';
|
||||||
import {Variable, containsVariable} from './variable';
|
import {Variable, containsVariable, assignModelProperties} from './variable';
|
||||||
import {VariableSrv, variableConstructorMap} from './variable_srv';
|
import {VariableSrv, variableConstructorMap} from './variable_srv';
|
||||||
|
|
||||||
function getNoneOption() {
|
function getNoneOption() {
|
||||||
@ -16,11 +16,36 @@ export class QueryVariable implements Variable {
|
|||||||
sort: any;
|
sort: any;
|
||||||
options: any;
|
options: any;
|
||||||
current: any;
|
current: any;
|
||||||
includeAll: boolean;
|
|
||||||
refresh: number;
|
refresh: number;
|
||||||
|
hide: number;
|
||||||
|
name: string;
|
||||||
|
multi: boolean;
|
||||||
|
includeAll: boolean;
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
type: 'query',
|
||||||
|
query: '',
|
||||||
|
regex: '',
|
||||||
|
sort: 1,
|
||||||
|
datasource: null,
|
||||||
|
refresh: 0,
|
||||||
|
hide: 0,
|
||||||
|
name: '',
|
||||||
|
multi: false,
|
||||||
|
includeAll: false,
|
||||||
|
options: [],
|
||||||
|
current: {text: '', value: ''},
|
||||||
|
};
|
||||||
|
|
||||||
constructor(private model, private datasourceSrv, private templateSrv, private variableSrv, private $q) {
|
constructor(private model, private datasourceSrv, private templateSrv, private variableSrv, private $q) {
|
||||||
_.extend(this, model);
|
// copy model properties to this instance
|
||||||
|
assignModelProperties(this, model, this.defaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
getModel() {
|
||||||
|
// copy back model properties to model
|
||||||
|
assignModelProperties(this.model, this, this.defaults);
|
||||||
|
return this.model;
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(option){
|
setValue(option){
|
||||||
|
39
public/app/features/templating/specs/query_variable_specs.ts
Normal file
39
public/app/features/templating/specs/query_variable_specs.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
|
||||||
|
|
||||||
|
import {QueryVariable} from '../query_variable';
|
||||||
|
|
||||||
|
describe('QueryVariable', function() {
|
||||||
|
|
||||||
|
describe('when creating from model', function() {
|
||||||
|
|
||||||
|
it('should set defaults', function() {
|
||||||
|
var variable = new QueryVariable({}, null, null, null, null);
|
||||||
|
expect(variable.datasource).to.be(null);
|
||||||
|
expect(variable.refresh).to.be(0);
|
||||||
|
expect(variable.sort).to.be(1);
|
||||||
|
expect(variable.name).to.be('');
|
||||||
|
expect(variable.hide).to.be(0);
|
||||||
|
expect(variable.options.length).to.be(0);
|
||||||
|
expect(variable.multi).to.be(false);
|
||||||
|
expect(variable.includeAll).to.be(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get model should copy changes back to model', () => {
|
||||||
|
var variable = new QueryVariable({}, null, null, null, null);
|
||||||
|
variable.options = [{text: 'test'}];
|
||||||
|
variable.datasource = 'google';
|
||||||
|
variable.regex = 'asd';
|
||||||
|
variable.sort = 50;
|
||||||
|
|
||||||
|
var model = variable.getModel();
|
||||||
|
expect(model.options.length).to.be(1);
|
||||||
|
expect(model.options[0].text).to.be('test');
|
||||||
|
expect(model.datasource).to.be('google');
|
||||||
|
expect(model.regex).to.be('asd');
|
||||||
|
expect(model.sort).to.be(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
|
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
|
||||||
|
|
||||||
import {containsVariable} from '../variable';
|
import {containsVariable, assignModelProperties} from '../variable';
|
||||||
|
|
||||||
describe('containsVariable', function() {
|
describe('containsVariable', function() {
|
||||||
|
|
||||||
@ -40,3 +40,20 @@ describe('containsVariable', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('assignModelProperties', function() {
|
||||||
|
|
||||||
|
it('only set properties defined in defaults', function() {
|
||||||
|
var target: any = {test: 'asd'};
|
||||||
|
assignModelProperties(target, {propA: 1, propB: 2}, {propB: 0});
|
||||||
|
expect(target.propB).to.be(2);
|
||||||
|
expect(target.test).to.be('asd');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('use default value if not found on source', function() {
|
||||||
|
var target: any = {test: 'asd'};
|
||||||
|
assignModelProperties(target, {propA: 1, propB: 2}, {propC: 10});
|
||||||
|
expect(target.propC).to.be(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
@ -8,6 +8,14 @@ export interface Variable {
|
|||||||
updateOptions();
|
updateOptions();
|
||||||
dependsOn(variable);
|
dependsOn(variable);
|
||||||
setValueFromUrl(urlValue);
|
setValueFromUrl(urlValue);
|
||||||
|
getModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function assignModelProperties(target, source, defaults) {
|
||||||
|
_.forEach(defaults, function(value, key) {
|
||||||
|
target[key] = source[key] === undefined ? value : source[key];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function containsVariable(...args: any[]) {
|
export function containsVariable(...args: any[]) {
|
||||||
|
@ -106,7 +106,7 @@ export class VariableSrv {
|
|||||||
|
|
||||||
syncToDashboardModel() {
|
syncToDashboardModel() {
|
||||||
this.dashboard.templating.list = this.variables.map(variable => {
|
this.dashboard.templating.list = this.variables.map(variable => {
|
||||||
return variable.model;
|
return variable.getModel();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,100 +122,100 @@ export class VariableSrv {
|
|||||||
|
|
||||||
// cascade updates to variables that use this variable
|
// cascade updates to variables that use this variable
|
||||||
var promises = _.map(this.variables, otherVariable => {
|
var promises = _.map(this.variables, otherVariable => {
|
||||||
if (otherVariable === variable) {
|
if (otherVariable === variable) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (otherVariable.dependsOn(variable)) {
|
|
||||||
return this.updateOptions(otherVariable);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.$q.all(promises);
|
|
||||||
}
|
|
||||||
|
|
||||||
selectOptionsForCurrentValue(variable) {
|
|
||||||
var i, y, value, option;
|
|
||||||
var selected: any = [];
|
|
||||||
|
|
||||||
for (i = 0; i < variable.options.length; i++) {
|
|
||||||
option = variable.options[i];
|
|
||||||
option.selected = false;
|
|
||||||
if (_.isArray(variable.current.value)) {
|
|
||||||
for (y = 0; y < variable.current.value.length; y++) {
|
|
||||||
value = variable.current.value[y];
|
|
||||||
if (option.value === value) {
|
|
||||||
option.selected = true;
|
|
||||||
selected.push(option);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (option.value === variable.current.value) {
|
|
||||||
option.selected = true;
|
|
||||||
selected.push(option);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return selected;
|
if (otherVariable.dependsOn(variable)) {
|
||||||
|
return this.updateOptions(otherVariable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.$q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectOptionsForCurrentValue(variable) {
|
||||||
|
var i, y, value, option;
|
||||||
|
var selected: any = [];
|
||||||
|
|
||||||
|
for (i = 0; i < variable.options.length; i++) {
|
||||||
|
option = variable.options[i];
|
||||||
|
option.selected = false;
|
||||||
|
if (_.isArray(variable.current.value)) {
|
||||||
|
for (y = 0; y < variable.current.value.length; y++) {
|
||||||
|
value = variable.current.value[y];
|
||||||
|
if (option.value === value) {
|
||||||
|
option.selected = true;
|
||||||
|
selected.push(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (option.value === variable.current.value) {
|
||||||
|
option.selected = true;
|
||||||
|
selected.push(option);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateVariableSelectionState(variable) {
|
return selected;
|
||||||
if (!variable.current) {
|
}
|
||||||
if (!variable.options.length) { return this.$q.when(); }
|
|
||||||
|
validateVariableSelectionState(variable) {
|
||||||
|
if (!variable.current) {
|
||||||
|
if (!variable.options.length) { return this.$q.when(); }
|
||||||
|
return variable.setValue(variable.options[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isArray(variable.current.value)) {
|
||||||
|
var selected = this.selectOptionsForCurrentValue(variable);
|
||||||
|
|
||||||
|
// if none pick first
|
||||||
|
if (selected.length === 0) {
|
||||||
|
selected = variable.options[0];
|
||||||
|
} else {
|
||||||
|
selected = {
|
||||||
|
value: _.map(selected, function(val) {return val.value;}),
|
||||||
|
text: _.map(selected, function(val) {return val.text;}).join(' + '),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return variable.setValue(selected);
|
||||||
|
} else {
|
||||||
|
var currentOption = _.find(variable.options, {text: variable.current.text});
|
||||||
|
if (currentOption) {
|
||||||
|
return variable.setValue(currentOption);
|
||||||
|
} else {
|
||||||
|
if (!variable.options.length) { return Promise.resolve(); }
|
||||||
return variable.setValue(variable.options[0]);
|
return variable.setValue(variable.options[0]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_.isArray(variable.current.value)) {
|
setOptionFromUrl(variable, urlValue) {
|
||||||
var selected = this.selectOptionsForCurrentValue(variable);
|
var promise = this.$q.when();
|
||||||
|
|
||||||
// if none pick first
|
if (variable.refresh) {
|
||||||
if (selected.length === 0) {
|
promise = variable.updateOptions();
|
||||||
selected = variable.options[0];
|
|
||||||
} else {
|
|
||||||
selected = {
|
|
||||||
value: _.map(selected, function(val) {return val.value;}),
|
|
||||||
text: _.map(selected, function(val) {return val.text;}).join(' + '),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return variable.setValue(selected);
|
|
||||||
} else {
|
|
||||||
var currentOption = _.find(variable.options, {text: variable.current.text});
|
|
||||||
if (currentOption) {
|
|
||||||
return variable.setValue(currentOption);
|
|
||||||
} else {
|
|
||||||
if (!variable.options.length) { return Promise.resolve(); }
|
|
||||||
return variable.setValue(variable.options[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptionFromUrl(variable, urlValue) {
|
return promise.then(() => {
|
||||||
var promise = this.$q.when();
|
var option = _.find(variable.options, op => {
|
||||||
|
return op.text === urlValue || op.value === urlValue;
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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(' + ');
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptionAsCurrent(variable, option) {
|
this.selectOptionsForCurrentValue(variable);
|
||||||
variable.current = _.cloneDeep(option);
|
return this.variableUpdated(variable);
|
||||||
|
}
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user