feat(templating): progress on variable system refactoring, #6048

This commit is contained in:
Torkel Ödegaard
2016-09-19 18:06:36 +02:00
parent 945b5ee3cf
commit 9d6ecc6361
9 changed files with 124 additions and 145 deletions
@@ -87,6 +87,7 @@ export class DashboardCtrl {
}; };
$scope.templateVariableUpdated = function() { $scope.templateVariableUpdated = function() {
dynamicDashboardSrv.update($scope.dashboard);
}; };
$scope.updateSubmenuVisibility = function() { $scope.updateSubmenuVisibility = function() {
@@ -23,13 +23,15 @@ export class CustomVariable implements Variable {
multi: false, multi: false,
}; };
supportsMulti = true;
/** @ngInject */ /** @ngInject */
constructor(private model, private timeSrv, private templateSrv, private variableSrv) { constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
assignModelProperties(this, model, this.defaults); assignModelProperties(this, model, this.defaults);
} }
setValue(option) { setValue(option) {
this.variableSrv.setOptionAsCurrent(this, option); return this.variableSrv.setOptionAsCurrent(this, option);
} }
getModel() { getModel() {
@@ -47,7 +49,7 @@ export class CustomVariable implements Variable {
this.addAllOption(); this.addAllOption();
} }
return Promise.resolve(); return this.variableSrv.validateVariableSelectionState(this);
} }
addAllOption() { addAllOption() {
@@ -15,7 +15,7 @@ export class DatasourceVariable implements Variable {
name: '', name: '',
hide: 0, hide: 0,
label: '', label: '',
current: {text: '', value: ''} current: {text: '', value: ''},
regex: '', regex: '',
options: [], options: [],
query: '', query: '',
@@ -32,7 +32,7 @@ export class DatasourceVariable implements Variable {
} }
setValue(option) { setValue(option) {
this.variableSrv.setOptionAsCurrent(this, option); return this.variableSrv.setOptionAsCurrent(this, option);
} }
updateOptions() { updateOptions() {
@@ -63,6 +63,7 @@ export class DatasourceVariable implements Variable {
} }
this.options = options; this.options = options;
return this.variableSrv.validateVariableSelectionState(this);
} }
dependsOn(variable) { dependsOn(variable) {
+3 -35
View File
@@ -10,7 +10,7 @@ import appEvents from 'app/core/app_events';
export class VariableEditorCtrl { export class VariableEditorCtrl {
/** @ngInject */ /** @ngInject */
constructor(private $scope, private datasourceSrv, private variableSrv) { constructor(private $scope, private datasourceSrv, private variableSrv, templateSrv) {
$scope.variableTypes = [ $scope.variableTypes = [
{value: "query", text: "Query"}, {value: "query", text: "Query"},
{value: "adhoc", text: "Ad hoc filters"}, {value: "adhoc", text: "Ad hoc filters"},
@@ -27,7 +27,7 @@ export class VariableEditorCtrl {
]; ];
$scope.sortOptions = [ $scope.sortOptions = [
{value: 0, text: "Query sort"}, {value: 0, text: "Disabled"},
{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)"},
@@ -115,6 +115,7 @@ export class VariableEditorCtrl {
$scope.runQuery().then(function() { $scope.runQuery().then(function() {
$scope.reset(); $scope.reset();
$scope.mode = 'list'; $scope.mode = 'list';
templateSrv.updateTemplateData();
}); });
} }
}; };
@@ -124,18 +125,6 @@ export class VariableEditorCtrl {
$scope.current = variableSrv.createVariableFromModel({type: 'query'}); $scope.current = variableSrv.createVariableFromModel({type: 'query'});
}; };
$scope.showSelectionOptions = function() {
if ($scope.current) {
if ($scope.current.type === 'query') {
return true;
}
if ($scope.current.type === 'custom') {
return true;
}
}
return false;
};
$scope.typeChanged = function() { $scope.typeChanged = function() {
var old = $scope.current; var old = $scope.current;
$scope.current = variableSrv.createVariableFromModel({type: $scope.current.type}); $scope.current = variableSrv.createVariableFromModel({type: $scope.current.type});
@@ -147,27 +136,6 @@ export class VariableEditorCtrl {
if (oldIndex !== -1) { if (oldIndex !== -1) {
this.variables[oldIndex] = $scope.current; this.variables[oldIndex] = $scope.current;
} }
// if ($scope.current.type === 'interval') {
// $scope.current.query = '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d';
// $scope.current.refresh = 0;
// }
//
// if ($scope.current.type === 'query') {
// $scope.current.query = '';
// }
//
// if ($scope.current.type === 'constant') {
// $scope.current.query = '';
// $scope.current.refresh = 0;
// $scope.current.hide = 2;
// }
//
// if ($scope.current.type === 'datasource') {
// $scope.current.query = $scope.datasourceTypes[0].value;
// $scope.current.regex = '';
// $scope.current.refresh = 1;
// }
}; };
$scope.removeVariable = function(variable) { $scope.removeVariable = function(variable) {
@@ -11,12 +11,14 @@ export class IntervalVariable implements Variable {
options: any; options: any;
auto: boolean; auto: boolean;
query: string; query: string;
refresh: number;
defaults = { defaults = {
type: 'interval', type: 'interval',
name: '', name: '',
hide: 0, hide: 0,
label: '', label: '',
refresh: 2,
options: [], options: [],
current: {text: '', value: ''}, current: {text: '', value: ''},
query: '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d', query: '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d',
@@ -28,6 +30,7 @@ export class IntervalVariable implements Variable {
/** @ngInject */ /** @ngInject */
constructor(private model, private timeSrv, private templateSrv, private variableSrv) { constructor(private model, private timeSrv, private templateSrv, private variableSrv) {
assignModelProperties(this, model, this.defaults); assignModelProperties(this, model, this.defaults);
this.refresh = 2;
} }
getModel() { getModel() {
@@ -37,7 +40,7 @@ export class IntervalVariable implements Variable {
setValue(option) { setValue(option) {
this.updateAutoValue(); this.updateAutoValue();
this.variableSrv.setOptionAsCurrent(this, option); return this.variableSrv.setOptionAsCurrent(this, option);
} }
updateAutoValue() { updateAutoValue() {
@@ -61,6 +64,7 @@ export class IntervalVariable implements Variable {
}); });
this.updateAutoValue(); this.updateAutoValue();
return this.variableSrv.validateVariableSelectionState(this);
} }
dependsOn(variable) { dependsOn(variable) {
@@ -181,19 +181,8 @@
<select class="gf-form-input" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select> <select class="gf-form-input" ng-model="current.refresh" ng-options="f.value as f.text for f in refreshOptions"></select>
</div> </div>
</div> </div>
<div class="gf-form max-width-21"> </div>
<span class="gf-form-label width-7"> <div class="gf-form">
Sort
<info-popover mode="right-normal">
How to sort the values of this variable.
</info-popover>
</span>
<div class="gf-form-select-wrapper max-width-14">
<select class="gf-form-input" ng-model="current.sort" ng-options="f.value as f.text for f in sortOptions" ng-change="runQuery()"></select>
</div>
</div>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">Query</span> <span class="gf-form-label width-7">Query</span>
<input type="text" class="gf-form-input" ng-model='current.query' placeholder="metric name or tags query" ng-model-onblur ng-change="runQuery()"></input> <input type="text" class="gf-form-input" ng-model='current.query' placeholder="metric name or tags query" ng-model-onblur ng-change="runQuery()"></input>
</div> </div>
@@ -206,35 +195,46 @@
</span> </span>
<input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input> <input type="text" class="gf-form-input" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
</div> </div>
</div> <div class="gf-form max-width-21">
<span class="gf-form-label width-7">
Sort
<info-popover mode="right-normal">
How to sort the values of this variable.
</info-popover>
</span>
<div class="gf-form-select-wrapper max-width-14">
<select class="gf-form-input" ng-model="current.sort" ng-options="f.value as f.text for f in sortOptions" ng-change="runQuery()"></select>
</div>
</div>
</div>
<div ng-show="current.type === 'datasource'" class="gf-form-group"> <div ng-show="current.type === 'datasource'" class="gf-form-group">
<h5 class="section-heading">Data source options</h5> <h5 class="section-heading">Data source options</h5>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-12">Type</label> <label class="gf-form-label width-12">Type</label>
<div class="gf-form-select-wrapper max-width-18"> <div class="gf-form-select-wrapper max-width-18">
<select class="gf-form-input" ng-model="current.query" ng-options="f.value as f.text for f in datasourceTypes" ng-change="runQuery()"></select> <select class="gf-form-input" ng-model="current.query" ng-options="f.value as f.text for f in datasourceTypes" ng-change="runQuery()"></select>
</div> </div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-12"> <label class="gf-form-label width-12">
Instance name filter Instance name filter
<info-popover mode="right-normal"> <info-popover mode="right-normal">
Regex filter for which data source instances to choose from in Regex filter for which data source instances to choose from in
the variable value dropdown. Leave empty for all. the variable value dropdown. Leave empty for all.
<br><br> <br><br>
Example: <code>/^prod/</code> Example: <code>/^prod/</code>
</info-popover> </info-popover>
</label> </label>
<input type="text" class="gf-form-input max-width-18" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input> <input type="text" class="gf-form-input max-width-18" ng-model='current.regex' placeholder="/.*-(.*)-.*/" ng-model-onblur ng-change="runQuery()"></input>
</div> </div>
</div> </div>
<div ng-show="current.type === 'adhoc'" class="gf-form-group"> <div ng-show="current.type === 'adhoc'" class="gf-form-group">
<h5 class="section-heading">Options</h5> <h5 class="section-heading">Options</h5>
<div class="gf-form max-width-21"> <div class="gf-form max-width-21">
<span class="gf-form-label width-8">Data source</span> <span class="gf-form-label width-8">Data source</span>
@@ -242,58 +242,58 @@
<select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"></select> <select class="gf-form-input" ng-model="current.datasource" ng-options="f.value as f.name for f in datasources"></select>
</div> </div>
</div> </div>
</div> </div>
<div class="section gf-form-group" ng-show="showSelectionOptions()"> <div class="section gf-form-group" ng-show="current.supportsMulti">
<h5 class="section-heading">Selection Options</h5> <h5 class="section-heading">Selection Options</h5>
<div class="section"> <div class="section">
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label="Multi-value" label="Multi-value"
label-class="width-10" label-class="width-10"
tooltip="Enables multiple values to be selected at the same time" tooltip="Enables multiple values to be selected at the same time"
checked="current.multi" checked="current.multi"
on-change="runQuery()"> on-change="runQuery()">
</gf-form-switch> </gf-form-switch>
<gf-form-switch class="gf-form" <gf-form-switch class="gf-form"
label="Include All option" label="Include All option"
label-class="width-10" label-class="width-10"
checked="current.includeAll" checked="current.includeAll"
on-change="runQuery()"> on-change="runQuery()">
</gf-form-switch> </gf-form-switch>
</div> </div>
<div class="gf-form" ng-if="current.includeAll"> <div class="gf-form" ng-if="current.includeAll">
<span class="gf-form-label width-10">Custom all value</span> <span class="gf-form-label width-10">Custom all value</span>
<input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input> <input type="text" class="gf-form-input max-width-15" ng-model='current.allValue' placeholder="blank = auto"></input>
</div> </div>
</div> </div>
<div class="gf-form-group" ng-if="current.type === 'query'"> <div class="gf-form-group" ng-if="current.type === 'query'">
<h5>Value groups/tags (Experimental feature)</h5> <h5>Value groups/tags (Experimental feature)</h5>
<div class="gf-form"> <div class="gf-form">
<editor-checkbox text="Enable" model="current.useTags" change="runQuery()"></editor-checkbox> <editor-checkbox text="Enable" model="current.useTags" change="runQuery()"></editor-checkbox>
</div> </div>
<div class="gf-form last" ng-if="current.useTags"> <div class="gf-form last" ng-if="current.useTags">
<span class="gf-form-label width-10">Tags query</span> <span class="gf-form-label width-10">Tags query</span>
<input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query" ng-model-onblur></input> <input type="text" class="gf-form-input" ng-model='current.tagsQuery' placeholder="metric name or tags query" ng-model-onblur></input>
</div> </div>
<div class="gf-form" ng-if="current.useTags"> <div class="gf-form" ng-if="current.useTags">
<li class="gf-form-label width-10">Tag values query</li> <li class="gf-form-label width-10">Tag values query</li>
<input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*" ng-model-onblur></input> <input type="text" class="gf-form-input" ng-model='current.tagValuesQuery' placeholder="apps.$tag.*" ng-model-onblur></input>
</div> </div>
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<h5>Preview of values (shows max 20)</h5> <h5>Preview of values (shows max 20)</h5>
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form" ng-repeat="option in current.options | limitTo: 20"> <div class="gf-form" ng-repeat="option in current.options | limitTo: 20">
<span class="gf-form-label">{{option.text}}</span> <span class="gf-form-label">{{option.text}}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="gf-form-button-row p-y-0"> <div class="gf-form-button-row p-y-0">
<button type="button" class="btn btn-success" ng-show="mode === 'edit'" ng-click="update();">Update</button> <button type="button" class="btn btn-success" ng-show="mode === 'edit'" ng-click="update();">Update</button>
<button type="button" class="btn btn-success" ng-show="mode === 'new'" ng-click="add();">Add</button> <button type="button" class="btn btn-success" ng-show="mode === 'new'" ng-click="add();">Add</button>
</div> </div>
</div> </div>
@@ -37,6 +37,8 @@ export class QueryVariable implements Variable {
current: {text: '', value: ''}, current: {text: '', value: ''},
}; };
supportsMulti = true;
constructor(private model, private datasourceSrv, private templateSrv, private variableSrv, private $q) { constructor(private model, private datasourceSrv, private templateSrv, private variableSrv, private $q) {
// copy model properties to this instance // copy model properties to this instance
assignModelProperties(this, model, this.defaults); assignModelProperties(this, model, this.defaults);
@@ -49,7 +51,7 @@ export class QueryVariable implements Variable {
} }
setValue(option){ setValue(option){
this.variableSrv.setOptionAsCurrent(this, option); return this.variableSrv.setOptionAsCurrent(this, option);
} }
setValueFromUrl(urlValue) { setValueFromUrl(urlValue) {
@@ -59,9 +61,7 @@ export class QueryVariable implements Variable {
updateOptions() { updateOptions() {
return this.datasourceSrv.get(this.datasource) return this.datasourceSrv.get(this.datasource)
.then(this.updateOptionsFromMetricFindQuery.bind(this)) .then(this.updateOptionsFromMetricFindQuery.bind(this))
.then(() => { .then(this.variableSrv.validateVariableSelectionState.bind(this.variableSrv, this));
this.variableSrv.validateVariableSelectionState(this);
});
} }
updateOptionsFromMetricFindQuery(datasource) { updateOptionsFromMetricFindQuery(datasource) {
+16 -17
View File
@@ -15,7 +15,7 @@ export class VariableSrv {
/** @ngInject */ /** @ngInject */
constructor(private $rootScope, private $q, private $location, private $injector, private templateSrv) { constructor(private $rootScope, private $q, private $location, private $injector, private templateSrv) {
// update time variant variables // update time variant variables
// $rootScope.onAppEvent('refresh', this.onDashboardRefresh.bind(this), $rootScope); $rootScope.$on('refresh', this.onDashboardRefresh.bind(this), $rootScope);
} }
init(dashboard) { init(dashboard) {
@@ -41,22 +41,21 @@ export class VariableSrv {
} }
onDashboardRefresh() { onDashboardRefresh() {
// var promises = this.variables var promises = this.variables
// .filter(variable => variable.refresh === 2) .filter(variable => variable.refresh === 2)
// .map(variable => { .map(variable => {
// var previousOptions = variable.options.slice(); var previousOptions = variable.options.slice();
//
// return self.updateOptions(variable).then(function () { return variable.updateOptions()
// return self.variableUpdated(variable).then(function () { .then(this.variableUpdated.bind(this, variable))
// // check if current options changed due to refresh .then(() => {
// if (angular.toJson(previousOptions) !== angular.toJson(variable.options)) { if (angular.toJson(previousOptions) !== angular.toJson(variable.options)) {
// $rootScope.appEvent('template-variable-value-updated'); this.$rootScope.$emit('template-variable-value-updated');
// } }
// }); });
// }); });
// });
// return this.$q.all(promises);
// return this.$q.all(promises);
} }
processVariable(variable, queryParams) { processVariable(variable, queryParams) {
@@ -257,6 +257,10 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
esQuery = header + '\n' + esQuery + '\n'; esQuery = header + '\n' + esQuery + '\n';
return this._post('_msearch?search_type=count', esQuery).then(function(res) { return this._post('_msearch?search_type=count', esQuery).then(function(res) {
if (!res.responses[0].aggregations) {
return [];
}
var buckets = res.responses[0].aggregations["1"].buckets; var buckets = res.responses[0].aggregations["1"].buckets;
return _.map(buckets, function(bucket) { return _.map(buckets, function(bucket) {
return {text: bucket.key, value: bucket.key}; return {text: bucket.key, value: bucket.key};