continued large refactoring of filterSrv, timeSrv and templating

This commit is contained in:
Torkel Ödegaard 2014-08-27 17:58:49 +02:00
parent 1929490deb
commit 9ee4fcb36c
19 changed files with 261 additions and 218 deletions

View File

@ -41,8 +41,6 @@ function (angular, $, config, _) {
};
$scope.setupDashboard = function(event, dashboardData) {
timer.cancel_all();
$rootScope.performance.dashboardLoadStart = new Date().getTime();
$rootScope.performance.panelsInitialized = 0;
$rootScope.performance.panelsRendered= 0;
@ -67,11 +65,6 @@ function (angular, $, config, _) {
window.document.title = config.window_title_prefix + $scope.dashboard.title;
// start auto refresh
if($scope.dashboard.refresh) {
$scope.dashboard.set_interval($scope.dashboard.refresh);
}
dashboardKeybindings.shortcuts($scope);
$scope.emitAppEvent("dashboard-loaded", $scope.dashboard);

View File

@ -8,7 +8,7 @@ function (angular, app, _) {
var module = angular.module('grafana.controllers');
module.controller('SubmenuCtrl', function($scope, $q, $rootScope, datasourceSrv) {
module.controller('SubmenuCtrl', function($scope, $q, $rootScope, templateValuesSrv) {
var _d = {
enable: true
};
@ -18,62 +18,7 @@ function (angular, app, _) {
$scope.init = function() {
$scope.panel = $scope.pulldown;
$scope.row = $scope.pulldown;
};
$scope.filterOptionSelected = function(templateParameter, option, recursive) {
templateParameter.current = option;
$scope.filter.updateTemplateData();
return $scope.applyFilterToOtherFilters(templateParameter)
.then(function() {
// only refresh in the outermost call
if (!recursive) {
$scope.dashboard.emit_refresh();
}
});
};
$scope.applyFilterToOtherFilters = function(updatedTemplatedParam) {
var promises = _.map($scope.filter.templateParameters, function(templateParam) {
if (templateParam === updatedTemplatedParam) {
return;
}
if (templateParam.query.indexOf('[[' + updatedTemplatedParam.name + ']]') !== -1) {
return $scope.applyFilter(templateParam);
}
});
return $q.all(promises);
};
$scope.applyFilter = function(templateParam) {
return datasourceSrv.default.metricFindQuery($scope.filter, templateParam.query)
.then(function (results) {
templateParam.options = _.map(results, function(node) {
return { text: node.text, value: node.text };
});
if (templateParam.includeAll) {
var allExpr = '{';
_.each(templateParam.options, function(option) {
allExpr += option.text + ',';
});
allExpr = allExpr.substring(0, allExpr.length - 1) + '}';
templateParam.options.unshift({text: 'All', value: allExpr});
}
// if parameter has current value
// if it exists in options array keep value
if (templateParam.current) {
var currentExists = _.findWhere(templateParam.options, { value: templateParam.current.value });
if (currentExists) {
return $scope.filterOptionSelected(templateParam, templateParam.current, true);
}
}
return $scope.filterOptionSelected(templateParam, templateParam.options[0], true);
});
$scope.templateParameters = $scope.dashboard.templating.list;
};
$scope.disableAnnotation = function (annotation) {
@ -81,6 +26,10 @@ function (angular, app, _) {
$rootScope.$broadcast('refresh');
};
$scope.filterOptionSelected = function(param, option) {
templateValuesSrv.filterOptionSelected(param, option);
};
$scope.init();
});

View File

@ -12,7 +12,7 @@ function (angular, app, _, require) {
var converter;
module.controller('text', function($scope, filterSrv, $sce, panelSrv) {
module.controller('text', function($scope, templateSrv, $sce, panelSrv) {
$scope.panelMeta = {
description : "A static text panel that can use plain text, markdown, or (sanitized) HTML"
@ -75,7 +75,7 @@ function (angular, app, _, require) {
$scope.updateContent = function(html) {
try {
$scope.content = $sce.trustAsHtml(filterSrv.applyTemplateToTarget(html));
$scope.content = $sce.trustAsHtml(templateSrv.replace(html));
} catch(e) {
console.log('Text panel error: ', e);
$scope.content = $sce.trustAsHtml(html);

View File

@ -32,10 +32,10 @@
<a href="#">Auto-Refresh</a>
<ul class="dropdown-menu">
<li>
<a ng-click="dashboard.set_interval(false)">Off</a>
<a ng-click="timeSrv.set_interval(false)">Off</a>
</li>
<li bindonce ng-repeat="interval in panel.refresh_intervals track by $index">
<a ng-click="dashboard.set_interval(interval)" bo-text="'Every ' + interval"></a>
<a ng-click="timeSrv.set_interval(interval)" bo-text="'Every ' + interval"></a>
</li>
</ul>
</li>
@ -44,7 +44,7 @@
</li>
<li ng-show="!dashboard.refresh" class="grafana-menu-refresh">
<a ng-click="dashboard.emit_refresh()"><i class="icon-refresh"></i></a>
<a ng-click="timeSrv.refreshDashboard()"><i class="icon-refresh"></i></a>
</li>
</ul>

View File

@ -25,7 +25,7 @@ function (angular, app, _, moment, kbn) {
var module = angular.module('grafana.panels.timepicker', []);
app.useModule(module);
module.controller('timepicker', function($scope, timeSrv) {
module.controller('timepicker', function($scope, $rootScope, timeSrv) {
$scope.panelMeta = {
status : "Stable",
@ -50,6 +50,8 @@ function (angular, app, _, moment, kbn) {
millisecond: /^[0-9]*$/
};
$scope.timeSrv = timeSrv;
$scope.$on('refresh', function() {
$scope.init();
});

View File

@ -18,7 +18,7 @@
</ul>
<ul class="grafana-segment-list">
<li ng-repeat-start="param in filter.templateParameters" class="grafana-target-segment template-param-name">
<li ng-repeat-start="param in templateParameters" class="grafana-target-segment template-param-name">
{{param.name}}:
</li>

View File

@ -3,6 +3,7 @@ define([
'./datasourceSrv',
'./timeSrv',
'./templateSrv',
'./templateValuesSrv',
'./panelSrv',
'./timer',
'./panelMove',

View File

@ -11,7 +11,7 @@ function (angular, $, kbn, _, moment) {
var module = angular.module('grafana.services');
module.factory('dashboardSrv', function(timer, $rootScope, $timeout) {
module.factory('dashboardSrv', function($rootScope) {
function DashboardModel (data) {
@ -115,28 +115,6 @@ function (angular, $, kbn, _, moment) {
$rootScope.$broadcast('refresh');
};
p.start_scheduled_refresh = function (after_ms) {
this.cancel_scheduled_refresh();
this.refresh_timer = timer.register($timeout(function () {
this.start_scheduled_refresh(after_ms);
this.emit_refresh();
}.bind(this), after_ms));
};
p.cancel_scheduled_refresh = function () {
timer.cancel(this.refresh_timer);
};
p.set_interval = function (interval) {
this.refresh = interval;
if (interval) {
var _i = kbn.interval_to_ms(interval);
this.start_scheduled_refresh(_i);
} else {
this.cancel_scheduled_refresh();
}
};
p.updateSchema = function(old) {
var oldVersion = this.version;
var panelUpgrades = [];

View File

@ -11,7 +11,7 @@ function (angular, _, $, config, kbn, moment) {
var module = angular.module('grafana.services');
module.factory('GraphiteDatasource', function($q, $http, timeSrv) {
module.factory('GraphiteDatasource', function($q, $http, templateSrv) {
function GraphiteDatasource(datasource) {
this.type = 'graphite';
@ -63,7 +63,7 @@ function (angular, _, $, config, kbn, moment) {
GraphiteDatasource.prototype.annotationQuery = function(annotation, rangeUnparsed) {
// Graphite metric as annotation
if (annotation.target) {
var target = timeSrv.applyTemplateToTarget(annotation.target);
var target = templateSrv.replace(annotation.target);
var graphiteQuery = {
range: rangeUnparsed,
targets: [{ target: target }],
@ -71,7 +71,7 @@ function (angular, _, $, config, kbn, moment) {
maxDataPoints: 100
};
return this.query(timeSrv, graphiteQuery)
return this.query(graphiteQuery)
.then(function(result) {
var list = [];
@ -95,7 +95,7 @@ function (angular, _, $, config, kbn, moment) {
}
// Graphite event as annotation
else {
var tags = timeSrv.applyTemplateToTarget(annotation.tags);
var tags = templateSrv.replace(annotation.tags);
return this.events({ range: rangeUnparsed, tags: tags })
.then(function(results) {
var list = [];
@ -169,7 +169,7 @@ function (angular, _, $, config, kbn, moment) {
GraphiteDatasource.prototype.metricFindQuery = function(query) {
var interpolated;
try {
interpolated = encodeURIComponent(timeSrv.applyTemplateToTarget(query));
interpolated = encodeURIComponent(templateSrv.replace(query));
}
catch(err) {
return $q.reject(err);
@ -226,7 +226,7 @@ function (angular, _, $, config, kbn, moment) {
if (key === "targets") {
_.each(value, function (value) {
if (value.target && !value.hide) {
var targetValue = timeSrv.applyTemplateToTarget(value.target);
var targetValue = templateSrv.replace(value.target);
clean_options.push("target=" + encodeURIComponent(targetValue));
}
}, this);

View File

@ -9,7 +9,7 @@ function (angular, _, kbn, InfluxSeries) {
var module = angular.module('grafana.services');
module.factory('InfluxDatasource', function($q, $http, timeSrv) {
module.factory('InfluxDatasource', function($q, $http, templateSrv) {
function InfluxDatasource(datasource) {
this.type = 'influxDB';
@ -73,7 +73,7 @@ function (angular, _, kbn, InfluxSeries) {
}
query = queryElements.join(" ");
query = timeSrv.applyTemplateToTarget(query);
query = templateSrv.replace(query);
}
else {
@ -100,7 +100,7 @@ function (angular, _, kbn, InfluxSeries) {
}
query = _.template(template, templateData, this.templateSettings);
query = timeSrv.applyTemplateToTarget(query);
query = templateSrv.replace(query);
if (target.groupby_field_add) {
groupByField = target.groupby_field;
@ -110,7 +110,7 @@ function (angular, _, kbn, InfluxSeries) {
}
if (target.alias) {
alias = filterSrv.applyTemplateToTarget(target.alias);
alias = templateSrv.replace(target.alias);
}
var handleResponse = _.partial(handleInfluxQueryResponse, alias, groupByField);
@ -164,7 +164,7 @@ function (angular, _, kbn, InfluxSeries) {
InfluxDatasource.prototype.metricFindQuery = function (filterSrv, query) {
var interpolated;
try {
interpolated = filterSrv.applyTemplateToTarget(query);
interpolated = templateSrv.replace(query);
}
catch (err) {
return $q.reject(err);

View File

@ -129,13 +129,6 @@ function (angular, _) {
$scope.get_data();
}
}
if ($rootScope.profilingEnabled) {
$rootScope.performance.panelsInitialized++;
if ($rootScope.performance.panelsInitialized === $scope.dashboard.rows.length) {
$rootScope.performance.allPanelsInitialized = new Date().getTime();
}
}
};
});

View File

@ -4,16 +4,48 @@ define([
'kbn',
'store'
],
function (angular) {
function (angular, _) {
'use strict';
var module = angular.module('grafana.services');
module.service('templateSrv', function() {
module.service('templateSrv', function($q, $routeParams) {
this.init = function(dashboard) {
this.dashboard = dashboard;
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
this.templateParameters = dashboard.templating.list;
this.updateTemplateData(true);
};
this.updateTemplateData = function(initial) {
var _templateData = {};
_.each(this.templateParameters, function(templateParameter) {
if (initial) {
var urlValue = $routeParams[ templateParameter.name ];
if (urlValue) {
templateParameter.current = { text: urlValue, value: urlValue };
}
}
if (!templateParameter.current || !templateParameter.current.value) {
return;
}
_templateData[templateParameter.name] = templateParameter.current.value;
});
this._templateData = _templateData;
};
this.addTemplateParameter = function(templateParameter) {
this.templateParameters.push(templateParameter);
this.updateTemplateData();
};
this.replace = function(target) {
if (!target || target.indexOf('[[') === -1) {
return target;
}
return _.template(target, this._templateData, this.templateSettings);
};
});

View File

@ -0,0 +1,72 @@
define([
'angular',
'lodash',
'kbn',
'store'
],
function (angular, _) {
'use strict';
var module = angular.module('grafana.services');
module.service('templateValuesSrv', function($q, $rootScope, datasourceSrv, $routeParams, templateSrv) {
var self = this;
this.filterOptionSelected = function(templateParameter, option, recursive) {
templateParameter.current = option;
templateSrv.updateTemplateData();
return this.applyFilterToOtherFilters(templateParameter)
.then(function() {
if (!recursive) {
$rootScope.$broadcast('refresh');
}
});
};
this.applyFilterToOtherFilters = function(updatedTemplatedParam) {
var promises = _.map(self.templateParameters, function(templateParam) {
if (templateParam === updatedTemplatedParam) {
return;
}
if (templateParam.query.indexOf('[[' + updatedTemplatedParam.name + ']]') !== -1) {
return self.applyFilter(templateParam);
}
});
return $q.all(promises);
};
this.applyFilter = function(templateParam) {
return datasourceSrv.default.metricFindQuery(templateParam.query)
.then(function (results) {
templateParam.options = _.map(results, function(node) {
return { text: node.text, value: node.text };
});
if (templateParam.includeAll) {
var allExpr = '{';
_.each(templateParam.options, function(option) {
allExpr += option.text + ',';
});
allExpr = allExpr.substring(0, allExpr.length - 1) + '}';
templateParam.options.unshift({text: 'All', value: allExpr});
}
// if parameter has current value
// if it exists in options array keep value
if (templateParam.current) {
var currentExists = _.findWhere(templateParam.options, { value: templateParam.current.value });
if (currentExists) {
return self.filterOptionSelected(templateParam, templateParam.current, true);
}
}
return self.filterOptionSelected(templateParam, templateParam.options[0], true);
});
};
});
});

View File

@ -8,82 +8,82 @@ define([
var module = angular.module('grafana.services');
module.service('timeSrv', function($rootScope, $timeout, $routeParams) {
module.service('timeSrv', function($rootScope, $timeout, timer) {
var self = this;
this.init = function(dashboard) {
this.dashboard = dashboard;
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
this.time = dashboard.time;
this.templateParameters = dashboard.templating.list;
this.updateTemplateData(true);
timer.cancel_all();
this.dashboard = dashboard;
this.time = dashboard.time;
if(this.dashboard.refresh) {
this.set_interval(this.dashboard.refresh);
}
};
this.updateTemplateData = function(initial) {
var _templateData = {};
_.each(this.templateParameters, function(templateParameter) {
if (initial) {
var urlValue = $routeParams[ templateParameter.name ];
if (urlValue) {
templateParameter.current = { text: urlValue, value: urlValue };
}
}
if (!templateParameter.current || !templateParameter.current.value) {
return;
}
_templateData[templateParameter.name] = templateParameter.current.value;
});
this._templateData = _templateData;
};
this.set_interval = function (interval) {
this.dashboard.refresh = interval;
if (interval) {
var _i = kbn.interval_to_ms(interval);
this.start_scheduled_refresh(_i);
} else {
this.cancel_scheduled_refresh();
}
};
this.addTemplateParameter = function(templateParameter) {
this.templateParameters.push(templateParameter);
this.updateTemplateData();
};
this.refreshDashboard = function() {
$rootScope.$broadcast('refresh');
};
this.applyTemplateToTarget = function(target) {
if (!target || target.indexOf('[[') === -1) {
return target;
}
this.start_scheduled_refresh = function (after_ms) {
self.cancel_scheduled_refresh();
self.refresh_timer = timer.register($timeout(function () {
self.start_scheduled_refresh(after_ms);
self.refreshDashboard();
}, after_ms));
};
return _.template(target, this._templateData, this.templateSettings);
};
this.cancel_scheduled_refresh = function () {
timer.cancel(this.refresh_timer);
};
this.setTime = function(time) {
_.extend(this.time, time);
this.setTime = function(time) {
_.extend(this.time, time);
// disable refresh if we have an absolute time
if (time.to !== 'now') {
this.old_refresh = this.dashboard.refresh;
this.dashboard.set_interval(false);
}
else if (this.old_refresh && this.old_refresh !== this.dashboard.refresh) {
this.dashboard.set_interval(this.old_refresh);
this.old_refresh = null;
}
// disable refresh if we have an absolute time
if (time.to !== 'now') {
this.old_refresh = this.dashboard.refresh;
this.set_interval(false);
}
else if (this.old_refresh && this.old_refresh !== this.dashboard.refresh) {
this.set_interval(this.old_refresh);
this.old_refresh = null;
}
$timeout(this.dashboard.emit_refresh, 0);
};
$timeout(this.refreshDashboard, 0);
};
this.timeRange = function(parse) {
var _t = this.time;
if(_.isUndefined(_t) || _.isUndefined(_t.from)) {
return false;
}
if(parse === false) {
return {
from: _t.from,
to: _t.to
};
} else {
var _from = _t.from;
var _to = _t.to || new Date();
this.timeRange = function(parse) {
var _t = this.time;
if(_.isUndefined(_t) || _.isUndefined(_t.from)) {
return false;
}
if(parse === false) {
return {
from: _t.from,
to: _t.to
};
} else {
var _from = _t.from;
var _to = _t.to || new Date();
return {
from : kbn.parseDate(_from),
to : kbn.parseDate(_to)
};
}
};
return {
from: kbn.parseDate(_from),
to: kbn.parseDate(_to)
};
}
};
});

View File

@ -5,9 +5,6 @@ define([],
return {
create: function() {
return {
emit_refresh: function() {},
set_interval: function(value) { this.refresh = value; },
title: "",
tags: [],
style: "dark",
@ -18,11 +15,11 @@ define([],
rows: [],
pulldowns: [ { type: 'templating' }, { type: 'annotations' } ],
nav: [ { type: 'timepicker' } ],
time: {},
time: {from: '1h', to: 'now'},
templating: {
list: []
},
refresh: true
refresh: '10s',
};
}
};

View File

@ -73,7 +73,7 @@ define([
};
};
this.applyTemplateToTarget = function(target) {
this.replace = function(target) {
return target;
};
}

View File

@ -0,0 +1,55 @@
define([
'mocks/dashboard-mock',
'lodash',
'services/templateSrv'
], function(dashboardMock) {
'use strict';
describe('templateSrv', function() {
var _templateSrv;
var _dashboard;
beforeEach(module('grafana.services'));
beforeEach(module(function() {
_dashboard = dashboardMock.create();
}));
beforeEach(inject(function(templateSrv) {
_templateSrv = templateSrv;
}));
beforeEach(function() {
_templateSrv.init(_dashboard);
});
describe('init', function() {
beforeEach(function() {
_templateSrv.addTemplateParameter({ name: 'test', current: { value: 'oogle' } });
});
it('should initialize template data', function() {
var target = _templateSrv.replace('this.[[test]].filters');
expect(target).to.be('this.oogle.filters');
});
});
describe('updateTemplateData', function() {
beforeEach(function() {
_templateSrv.addTemplateParameter({
name: 'test',
value: 'muuu',
current: { value: 'muuuu' }
});
_templateSrv.updateTemplateData();
});
it('should set current value and update template data', function() {
var target = _templateSrv.replace('this.[[test]].filters');
expect(target).to.be('this.muuuu.filters');
});
});
});
});

View File

@ -10,45 +10,15 @@ define([
var _dashboard;
beforeEach(module('grafana.services'));
beforeEach(module(function() {
_dashboard = dashboardMock.create();
}));
beforeEach(inject(function(timeSrv) {
_timeSrv = timeSrv;
_dashboard = dashboardMock.create();
}));
beforeEach(function() {
_timeSrv.init(_dashboard);
});
describe('init', function() {
beforeEach(function() {
_timeSrv.addTemplateParameter({ name: 'test', current: { value: 'oogle' } });
});
it('should initialize template data', function() {
var target = _timeSrv.applyTemplateToTarget('this.[[test]].filters');
expect(target).to.be('this.oogle.filters');
});
});
describe('updateTemplateData', function() {
beforeEach(function() {
_timeSrv.addTemplateParameter({
name: 'test',
value: 'muuu',
current: { value: 'muuuu' }
});
_timeSrv.updateTemplateData();
});
it('should set current value and update template data', function() {
var target = _timeSrv.applyTemplateToTarget('this.[[test]].filters');
expect(target).to.be('this.muuuu.filters');
});
});
describe('timeRange', function() {
it('should return unparsed when parse is false', function() {
_timeSrv.setTime({from: 'now', to: 'now-1h' });
@ -67,18 +37,18 @@ define([
describe('setTime', function() {
it('should return disable refresh for absolute times', function() {
_dashboard.refresh = true;
_dashboard.refresh = false;
_timeSrv.setTime({from: '2011-01-01', to: '2015-01-01' });
expect(_dashboard.refresh).to.be(false);
});
it('should restore refresh after relative time range is set', function() {
_dashboard.refresh = true;
_dashboard.refresh = '10s';
_timeSrv.setTime({from: '2011-01-01', to: '2015-01-01' });
expect(_dashboard.refresh).to.be(false);
_timeSrv.setTime({from: '2011-01-01', to: 'now' });
expect(_dashboard.refresh).to.be(true);
expect(_dashboard.refresh).to.be('10s');
});
});

View File

@ -126,6 +126,7 @@ require([
'specs/grafanaGraph-specs',
'specs/seriesOverridesCtrl-specs',
'specs/timeSrv-specs',
'specs/templateSrv-specs',
'specs/kbn-format-specs',
'specs/dashboardSrv-specs',
'specs/dashboardViewStateSrv-specs',