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" />
|
||||
|
||||
import _ from 'lodash';
|
||||
import {Variable} from './variable';
|
||||
import {Variable, assignModelProperties} from './variable';
|
||||
import {VariableSrv, variableConstructorMap} from './variable_srv';
|
||||
|
||||
export class ConstantVariable implements Variable {
|
||||
query: string;
|
||||
options: any[];
|
||||
|
||||
defaults = {
|
||||
type: 'constant',
|
||||
name: '',
|
||||
query: '',
|
||||
hide: 2,
|
||||
refresh: 0,
|
||||
};
|
||||
|
||||
/** @ngInject */
|
||||
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) {
|
||||
|
@ -13,7 +13,7 @@ function (angular, _) {
|
||||
type: 'query',
|
||||
datasource: null,
|
||||
refresh: 0,
|
||||
sort: 1,
|
||||
sort: 0,
|
||||
name: '',
|
||||
hide: 0,
|
||||
options: [],
|
||||
@ -37,7 +37,7 @@ function (angular, _) {
|
||||
];
|
||||
|
||||
$scope.sortOptions = [
|
||||
{value: 0, text: "Without Sort"},
|
||||
{value: 0, text: "Query sort"},
|
||||
{value: 1, text: "Alphabetical (asc)"},
|
||||
{value: 2, text: "Alphabetical (desc)"},
|
||||
{value: 3, text: "Numerical (asc)"},
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import _ from 'lodash';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import {Variable, containsVariable} from './variable';
|
||||
import {Variable, containsVariable, assignModelProperties} from './variable';
|
||||
import {VariableSrv, variableConstructorMap} from './variable_srv';
|
||||
|
||||
function getNoneOption() {
|
||||
@ -16,11 +16,36 @@ export class QueryVariable implements Variable {
|
||||
sort: any;
|
||||
options: any;
|
||||
current: any;
|
||||
includeAll: boolean;
|
||||
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) {
|
||||
_.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){
|
||||
|
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 {containsVariable} from '../variable';
|
||||
import {containsVariable, assignModelProperties} from '../variable';
|
||||
|
||||
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();
|
||||
dependsOn(variable);
|
||||
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[]) {
|
||||
|
@ -106,7 +106,7 @@ export class VariableSrv {
|
||||
|
||||
syncToDashboardModel() {
|
||||
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
|
||||
var promises = _.map(this.variables, otherVariable => {
|
||||
if (otherVariable === variable) {
|
||||
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);
|
||||
}
|
||||
if (otherVariable === variable) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!variable.current) {
|
||||
if (!variable.options.length) { return this.$q.when(); }
|
||||
return selected;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isArray(variable.current.value)) {
|
||||
var selected = this.selectOptionsForCurrentValue(variable);
|
||||
setOptionFromUrl(variable, urlValue) {
|
||||
var promise = this.$q.when();
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
if (variable.refresh) {
|
||||
promise = variable.updateOptions();
|
||||
}
|
||||
|
||||
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);
|
||||
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(' + ');
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
this.selectOptionsForCurrentValue(variable);
|
||||
return this.variableUpdated(variable);
|
||||
}
|
||||
}
|
||||
|
||||
coreModule.service('variableSrv', VariableSrv);
|
||||
|
Loading…
Reference in New Issue
Block a user