refactor how template vars are updated. fixes #4283

Use promises to order the updates of variable options so that
parents are always updated before children.
This ensures that we only need to query the datasource once per
variable as variables that depend on other variables will only be
processed once their parent has been.
This commit also ensures that variable options are refreshed if
"refresh_on_load" is true even when query params are used to
set the variable seltion.
pull/4284/head
woodsaj 9 years ago
parent d2aaa2211e
commit 0cb57f52de
  1. 67
      public/app/features/templating/templateValuesSrv.js

@ -27,29 +27,72 @@ function (angular, _, kbn) {
var queryParams = $location.search();
var promises = [];
//use promises to delay processing variables that
//depend on other variables.
this.variableLock = {};
var self = this;
_.forEach(this.variables, function(variable) {
self.variableLock[variable.name] = $q.defer();
});
for (var i = 0; i < this.variables.length; i++) {
var variable = this.variables[i];
promises.push(this.processVariable(variable, queryParams));
}
return $q.all(promises);
};
this.processVariable = function(variable, queryParams) {
var dependencies = [];
var self = this;
// determine our dependencies.
if (variable.type === "query") {
_.forEach(this.variables, function(v) {
if (templateSrv.containsVariable(variable.query, v.name)) {
dependencies.push(self.variableLock[v.name].promise);
}
});
}
return $q.all(dependencies).then(function() {
var variableName = variable.name;
var urlValue = queryParams['var-' + variable.name];
if (urlValue !== void 0) {
promises.push(this.setVariableFromUrl(variable, urlValue));
return self.setVariableFromUrl(variable, urlValue).then(function() {
self.variableLock[variableName].resolve();
});
}
else if (variable.refresh) {
promises.push(this.updateOptions(variable));
return self.updateOptions(variable).then(function() {
self.variableLock[variableName].resolve();
});
}
else if (variable.type === 'interval') {
this.updateAutoInterval(variable);
self.updateAutoInterval(variable);
self.variableLock[variableName].resolve();
} else {
self.variableLock[variableName].resolve();
}
}
return $q.all(promises);
});
};
this.setVariableFromUrl = function(variable, urlValue) {
if (variable.refresh) {
var self = this;
//refresh the list of options before setting the value
return this.updateOptions(variable).then(function() {
var option = _.findWhere(variable.options, { text: urlValue });
option = option || { text: urlValue, value: urlValue };
self.updateAutoInterval(variable);
return self.setVariableValue(variable, option, true);
});
}
var option = _.findWhere(variable.options, { text: urlValue });
option = option || { text: urlValue, value: urlValue };
this.updateAutoInterval(variable);
return this.setVariableValue(variable, option);
return this.setVariableValue(variable, option, true);
};
this.updateAutoInterval = function(variable) {
@ -64,7 +107,7 @@ function (angular, _, kbn) {
templateSrv.setGrafanaVariable('$__auto_interval', interval);
};
this.setVariableValue = function(variable, option) {
this.setVariableValue = function(variable, option, firstLoad) {
variable.current = angular.copy(option);
if (_.isArray(variable.current.value)) {
@ -74,6 +117,11 @@ function (angular, _, kbn) {
self.selectOptionsForCurrentValue(variable);
templateSrv.updateTemplateData();
// on first load, variable loading is ordered to ensure
// that parents are updated before children.
if (firstLoad) {
return $q.when();
}
return self.updateOptionsInChildVariables(variable);
};
@ -119,8 +167,7 @@ function (angular, _, kbn) {
return datasourceSrv.get(variable.datasource)
.then(_.partial(this.updateOptionsFromMetricFindQuery, variable))
.then(_.partial(this.updateTags, variable))
.then(_.partial(this.validateVariableSelectionState, variable));
.then(_.partial(this.updateTags, variable));
};
this.selectOptionsForCurrentValue = function(variable) {

Loading…
Cancel
Save