Commit 4e5dcafa by Torkel Ödegaard

working on auto interval template variable support

parent afc8380f
...@@ -69,7 +69,7 @@ function (angular, _) { ...@@ -69,7 +69,7 @@ function (angular, _) {
}; };
$scope.typeChanged = function () { $scope.typeChanged = function () {
if ($scope.current.type === 'time period') { if ($scope.current.type === 'interval') {
$scope.current.query = '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d'; $scope.current.query = '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d';
} }
}; };
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<label class="small">Span</label> <select class="input-mini" ng-model="panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select> <label class="small">Span</label> <select class="input-mini" ng-model="panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select>
</div> </div>
<div class="editor-option"> <div class="editor-option">
<label class="small">Height</label><input type="text" class="input-medium" ng-model='panel.height'></select> <label class="small">Height</label><input type="text" class="input-small" ng-model='panel.height'></select>
</div> </div>
</div> </div>
</div> </div>
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
</div> </div>
<div class="editor-option"> <div class="editor-option">
<label class="small">Type</label> <label class="small">Type</label>
<select class="input-medium" ng-model="current.type" ng-options="f for f in ['query', 'time period']" ng-change="typeChanged()"></select> <select class="input-medium" ng-model="current.type" ng-options="f for f in ['query', 'interval', 'custom']" ng-change="typeChanged()"></select>
</div> </div>
<div class="editor-option" ng-show="current.type === 'query'"> <div class="editor-option" ng-show="current.type === 'query'">
<label class="small">Datasource</label> <label class="small">Datasource</label>
...@@ -70,10 +70,22 @@ ...@@ -70,10 +70,22 @@
</div> </div>
</div> </div>
<div ng-show="current.type === 'time period'"> <div ng-show="current.type === 'interval'">
<div class="editor-row">
<div class="editor-option"> <div class="editor-option">
<label class="small">Values</label> <label class="small">Values</label>
<input type="text" class="input-xxlarge" ng-model='current.query' placeholder="name"></input> <input type="text" class="input-xxlarge" ng-model='current.query' ng-blur="runQuery()" placeholder="name"></input>
</div>
</div>
<div class="editor-row">
<div class="editor-option text-center">
<label class="small">Include auto interval</label>
<input type="checkbox" ng-model="current.auto" ng-checked="current.auto" ng-change="runQuery()">
</div>
<div class="editor-option" ng-show="current.auto">
<label class="small">Auto interval steps <tip>The number of times the time range should be divided to calculate the interval<tip></label>
<select class="input-mini" ng-model="current.auto_count" ng-options="f for f in [3,4,5,6,7,8,9,10,13,15,16,20,25,30,35,40,50,100,200]" ng-change="runQuery()"></select>
</div>
</div> </div>
</div> </div>
...@@ -101,7 +113,7 @@ ...@@ -101,7 +113,7 @@
</div> </div>
<div class="editor-option" ng-show="current.includeAll"> <div class="editor-option" ng-show="current.includeAll">
<label class="small">All format</label> <label class="small">All format</label>
<select class="input-medium" ng-model="current.allFormat" ng-change="runQuery()" ng-options="f for f in ['glob', 'wildcard', 'regex wildcard', 'regex all values', 'comma list', 'custom']" ng-change="typeChanged()"></select> <select class="input-medium" ng-model="current.allFormat" ng-change="runQuery()" ng-options="f for f in ['glob', 'wildcard', 'regex wildcard', 'regex all values', 'comma list', 'custom']"></select>
</div> </div>
<div class="editor-option" ng-show="current.includeAll"> <div class="editor-option" ng-show="current.includeAll">
<label class="small">All value</label> <label class="small">All value</label>
......
...@@ -10,15 +10,18 @@ function (angular, _) { ...@@ -10,15 +10,18 @@ function (angular, _) {
module.service('templateSrv', function($q, $routeParams) { module.service('templateSrv', function($q, $routeParams) {
var self = this; var self = this;
this._regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
this._templateData = {};
this._grafanaVariables = {};
this.init = function(variables) { this.init = function(variables) {
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
this.variables = variables; this.variables = variables;
this.regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
this.updateTemplateData(true); this.updateTemplateData(true);
}; };
this.updateTemplateData = function(initial) { this.updateTemplateData = function(initial) {
var _templateData = {}; var data = {};
_.each(this.variables, function(variable) { _.each(this.variables, function(variable) {
if (initial) { if (initial) {
var urlValue = $routeParams[ variable.name ]; var urlValue = $routeParams[ variable.name ];
...@@ -26,31 +29,32 @@ function (angular, _) { ...@@ -26,31 +29,32 @@ function (angular, _) {
variable.current = { text: urlValue, value: urlValue }; variable.current = { text: urlValue, value: urlValue };
} }
} }
if (!variable.current || !variable.current.value) { if (!variable.current || !variable.current.value) {
return; return;
} }
_templateData[variable.name] = variable.current.value; data[variable.name] = variable.current.value;
}); });
this._templateData = _templateData;
this._templateData = data;
}; };
this.setGrafanaVariable = function(name, value) { this.setGrafanaVariable = function (name, value) {
this._templateData[name] = value; this._grafanaVariables[name] = value;
}; };
this.variableExists = function(expression) { this.variableExists = function(expression) {
this.regex.lastIndex = 0; this._regex.lastIndex = 0;
var match = this.regex.exec(expression); var match = this._regex.exec(expression);
return match && (self._templateData[match[1] || match[2]] !== void 0); return match && (self._templateData[match[1] || match[2]] !== void 0);
}; };
this.highlightVariablesAsHtml = function(str) { this.highlightVariablesAsHtml = function(str) {
if (!str || !_.isString(str)) { return str; } if (!str || !_.isString(str)) { return str; }
this.regex.lastIndex = 0; this._regex.lastIndex = 0;
return str.replace(this.regex, function(match, g1, g2) { return str.replace(this._regex, function(match, g1, g2) {
if (self._templateData[g1 || g2]) { if (self._templateData[g1 || g2]) {
return '<span class="template-variable">' + match + '</span>'; return '<span class="template-variable">' + match + '</span>';
} }
...@@ -60,9 +64,14 @@ function (angular, _) { ...@@ -60,9 +64,14 @@ function (angular, _) {
this.replace = function(target) { this.replace = function(target) {
if (!target) { return; } if (!target) { return; }
this.regex.lastIndex = 0; var value;
return target.replace(this.regex, function(match, g1, g2) { this._regex.lastIndex = 0;
return self._templateData[g1 || g2] || match;
return target.replace(this._regex, function(match, g1, g2) {
value = self._templateData[g1 || g2];
if (!value) { return match; }
return self._grafanaVariables[value] || value;
}); });
}; };
......
...@@ -8,12 +8,18 @@ function (angular, _, kbn) { ...@@ -8,12 +8,18 @@ function (angular, _, kbn) {
var module = angular.module('grafana.services'); var module = angular.module('grafana.services');
module.service('templateValuesSrv', function($q, $rootScope, datasourceSrv, $routeParams, templateSrv) { module.service('templateValuesSrv', function($q, $rootScope, datasourceSrv, $routeParams, templateSrv, timeSrv) {
var self = this; var self = this;
$rootScope.onAppEvent('time-range-changed', function() {
var variable = _.findWhere(self.variables, { type: 'interval' });
if (variable) {
self.updateAutoInterval(variable);
}
});
this.init = function(dashboard) { this.init = function(dashboard) {
this.variables = dashboard.templating.list; this.variables = dashboard.templating.list;
templateSrv.init(this.variables); templateSrv.init(this.variables);
for (var i = 0; i < this.variables.length; i++) { for (var i = 0; i < this.variables.length; i++) {
...@@ -21,9 +27,24 @@ function (angular, _, kbn) { ...@@ -21,9 +27,24 @@ function (angular, _, kbn) {
if (param.refresh) { if (param.refresh) {
this.updateOptions(param); this.updateOptions(param);
} }
else if (param.type === 'interval') {
this.updateAutoInterval(param);
}
} }
}; };
this.updateAutoInterval = function(variable) {
if (!variable.auto) { return; }
// add auto option if missing
if (variable.options[0].text !== 'auto') {
variable.options.unshift({ text: 'auto', value: '$__auto_interval' });
}
var interval = kbn.calculateInterval(timeSrv.timeRange(), variable.auto_count);
templateSrv.setGrafanaVariable('$__auto_interval', interval);
};
this.setVariableValue = function(variable, option, recursive) { this.setVariableValue = function(variable, option, recursive) {
variable.current = option; variable.current = option;
...@@ -51,10 +72,12 @@ function (angular, _, kbn) { ...@@ -51,10 +72,12 @@ function (angular, _, kbn) {
}; };
this.updateOptions = function(variable) { this.updateOptions = function(variable) {
if (variable.type === 'time period') { if (variable.type === 'interval') {
variable.options = _.map(variable.query.split(','), function(text) { variable.options = _.map(variable.query.split(','), function(text) {
return { text: text, value: text }; return { text: text, value: text };
}); });
self.updateAutoInterval(variable);
self.setVariableValue(variable, variable.options[0]); self.setVariableValue(variable, variable.options[0]);
return $q.when([]); return $q.when([]);
} }
......
...@@ -61,6 +61,7 @@ define([ ...@@ -61,6 +61,7 @@ define([
this.old_refresh = null; this.old_refresh = null;
} }
$rootScope.emitAppEvent('time-range-changed', this.time);
$timeout(this.refreshDashboard, 0); $timeout(this.refreshDashboard, 0);
}; };
......
...@@ -49,20 +49,28 @@ define([ ...@@ -49,20 +49,28 @@ define([
function ServiceTestContext() { function ServiceTestContext() {
var self = this; var self = this;
self.templateSrv = new TemplateSrvStub(); self.templateSrv = new TemplateSrvStub();
self.timeSrv = new TimeSrvStub();
self.datasourceSrv = {};
this.providePhase = function() { this.providePhase = function(mocks) {
return module(function($provide) { return module(function($provide) {
$provide.value('templateSrv', self.templateSrv); _.each(mocks, function(key) {
$provide.value(key, self[key]);
});
}); });
}; };
this.createService = function(name) { this.createService = function(name) {
return inject([name, '$q', '$rootScope', '$httpBackend', function(service, $q, $rootScope, $httpBackend) { return inject(function($q, $rootScope, $httpBackend, $injector) {
self.service = service;
self.$q = $q; self.$q = $q;
self.$rootScope = $rootScope; self.$rootScope = $rootScope;
self.$httpBackend = $httpBackend; self.$httpBackend = $httpBackend;
}]);
self.$rootScope.onAppEvent = function() {};
self.$rootScope.emitAppEvent = function() {};
self.service = $injector.get(name);
});
}; };
} }
...@@ -95,6 +103,7 @@ define([ ...@@ -95,6 +103,7 @@ define([
this.replace = function(text) { this.replace = function(text) {
return _.template(text, this.data, this.templateSettings); return _.template(text, this.data, this.templateSettings);
}; };
this.updateTemplateData = function() { };
this.variableExists = function() { return false; }; this.variableExists = function() { return false; };
this.highlightVariablesAsHtml = function(str) { return str; }; this.highlightVariablesAsHtml = function(str) { return str; };
this.setGrafanaVariable = function(name, value) { this.setGrafanaVariable = function(name, value) {
......
define([ define([
'mocks/dashboard-mock', 'mocks/dashboard-mock',
'./helpers',
'lodash', 'lodash',
'services/timeSrv' 'services/timeSrv'
], function(dashboardMock, _) { ], function(dashboardMock, helpers, _) {
'use strict'; 'use strict';
describe('timeSrv', function() { describe('timeSrv', function() {
var _timeSrv; var ctx = new helpers.ServiceTestContext();
var _dashboard; var _dashboard;
beforeEach(module('grafana.services')); beforeEach(module('grafana.services'));
beforeEach(inject(function(timeSrv) { beforeEach(ctx.providePhase());
_timeSrv = timeSrv; beforeEach(ctx.createService('timeSrv'));
_dashboard = dashboardMock.create();
}));
beforeEach(function() { beforeEach(function() {
_timeSrv.init(_dashboard); _dashboard = dashboardMock.create();
ctx.service.init(_dashboard);
}); });
describe('timeRange', function() { describe('timeRange', function() {
it('should return unparsed when parse is false', function() { it('should return unparsed when parse is false', function() {
_timeSrv.setTime({from: 'now', to: 'now-1h' }); ctx.service.setTime({from: 'now', to: 'now-1h' });
var time = _timeSrv.timeRange(false); var time = ctx.service.timeRange(false);
expect(time.from).to.be('now'); expect(time.from).to.be('now');
expect(time.to).to.be('now-1h'); expect(time.to).to.be('now-1h');
}); });
it('should return parsed when parse is true', function() { it('should return parsed when parse is true', function() {
_timeSrv.setTime({from: 'now', to: 'now-1h' }); ctx.service.setTime({from: 'now', to: 'now-1h' });
var time = _timeSrv.timeRange(true); var time = ctx.service.timeRange(true);
expect(_.isDate(time.from)).to.be(true); expect(_.isDate(time.from)).to.be(true);
expect(_.isDate(time.to)).to.be(true); expect(_.isDate(time.to)).to.be(true);
}); });
...@@ -39,15 +39,15 @@ define([ ...@@ -39,15 +39,15 @@ define([
it('should return disable refresh for absolute times', function() { it('should return disable refresh for absolute times', function() {
_dashboard.refresh = false; _dashboard.refresh = false;
_timeSrv.setTime({from: '2011-01-01', to: '2015-01-01' }); ctx.service.setTime({from: '2011-01-01', to: '2015-01-01' });
expect(_dashboard.refresh).to.be(false); expect(_dashboard.refresh).to.be(false);
}); });
it('should restore refresh after relative time range is set', function() { it('should restore refresh after relative time range is set', function() {
_dashboard.refresh = '10s'; _dashboard.refresh = '10s';
_timeSrv.setTime({from: '2011-01-01', to: '2015-01-01' }); ctx.service.setTime({from: '2011-01-01', to: '2015-01-01' });
expect(_dashboard.refresh).to.be(false); expect(_dashboard.refresh).to.be(false);
_timeSrv.setTime({from: '2011-01-01', to: 'now' }); ctx.service.setTime({from: '2011-01-01', to: 'now' });
expect(_dashboard.refresh).to.be('10s'); expect(_dashboard.refresh).to.be('10s');
}); });
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment