From 0f4a9f1ed18093cc5d88a5ab56a6ef8bb77d878b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 15 Sep 2016 14:53:36 +0200 Subject: [PATCH] feat(templating): began refactoring variables into rich behavioral classes --- .../app/features/dashboard/dashboard_ctrl.ts | 4 +- .../app/features/dashboard/submenu/submenu.ts | 8 +- public/app/features/templating/editorCtrl.js | 6 +- .../templating/specs/variable_srv_specs.ts | 4 + public/app/features/templating/templateSrv.js | 1 + .../features/templating/templateValuesSrv.js | 3 +- .../app/features/templating/variable_srv.ts | 107 ++++++++++++++++++ public/test/specs/templateValuesSrv-specs.js | 32 +++--- 8 files changed, 138 insertions(+), 27 deletions(-) create mode 100644 public/app/features/templating/specs/variable_srv_specs.ts create mode 100644 public/app/features/templating/variable_srv.ts diff --git a/public/app/features/dashboard/dashboard_ctrl.ts b/public/app/features/dashboard/dashboard_ctrl.ts index 162331c4a98..4f70d56bd7f 100644 --- a/public/app/features/dashboard/dashboard_ctrl.ts +++ b/public/app/features/dashboard/dashboard_ctrl.ts @@ -15,7 +15,7 @@ export class DashboardCtrl { private $rootScope, dashboardKeybindings, timeSrv, - templateValuesSrv, + variableSrv, dashboardSrv, unsavedChangesSrv, dynamicDashboardSrv, @@ -46,7 +46,7 @@ export class DashboardCtrl { // template values service needs to initialize completely before // the rest of the dashboard can load - templateValuesSrv.init(dashboard) + variableSrv.init(dashboard) // template values failes are non fatal .catch($scope.onInitFailed.bind(this, 'Templating init failed', false)) // continue diff --git a/public/app/features/dashboard/submenu/submenu.ts b/public/app/features/dashboard/submenu/submenu.ts index 3b9b0b6b0d8..01405d8894c 100644 --- a/public/app/features/dashboard/submenu/submenu.ts +++ b/public/app/features/dashboard/submenu/submenu.ts @@ -10,11 +10,11 @@ export class SubmenuCtrl { /** @ngInject */ constructor(private $rootScope, - private templateValuesSrv, + private variableSrv, private templateSrv, private $location) { this.annotations = this.dashboard.templating.list; - this.variables = this.dashboard.templating.list; + this.variables = this.variableSrv.variables; } disableAnnotation(annotation) { @@ -23,11 +23,11 @@ export class SubmenuCtrl { } getValuesForTag(variable, tagKey) { - return this.templateValuesSrv.getValuesForTag(variable, tagKey); + return this.variableSrv.getValuesForTag(variable, tagKey); } variableUpdated(variable) { - this.templateValuesSrv.variableUpdated(variable).then(() => { + this.variableSrv.variableUpdated(variable).then(() => { this.$rootScope.$emit('template-variable-value-updated'); this.$rootScope.$broadcast('refresh'); }); diff --git a/public/app/features/templating/editorCtrl.js b/public/app/features/templating/editorCtrl.js index 8b3e7d3a169..7d60295168f 100644 --- a/public/app/features/templating/editorCtrl.js +++ b/public/app/features/templating/editorCtrl.js @@ -7,7 +7,7 @@ function (angular, _) { var module = angular.module('grafana.controllers'); - module.controller('TemplateEditorCtrl', function($scope, datasourceSrv, templateSrv, templateValuesSrv) { + module.controller('TemplateEditorCtrl', function($scope, datasourceSrv, variableSrv) { var replacementDefaults = { type: 'query', @@ -63,7 +63,7 @@ function (angular, _) { return value; }); - $scope.variables = templateSrv.variables; + $scope.variables = variableSrv.variables; $scope.reset(); $scope.$watch('mode', function(val) { @@ -113,7 +113,7 @@ function (angular, _) { }; $scope.runQuery = function() { - return templateValuesSrv.updateOptions($scope.current).then(null, function(err) { + return variableSrv.updateOptions($scope.current).then(null, function(err) { if (err.data && err.data.message) { err.message = err.data.message; } $scope.appEvent("alert-error", ['Templating', 'Template variables could not be initialized: ' + err.message]); }); diff --git a/public/app/features/templating/specs/variable_srv_specs.ts b/public/app/features/templating/specs/variable_srv_specs.ts new file mode 100644 index 00000000000..4d0c88e2e39 --- /dev/null +++ b/public/app/features/templating/specs/variable_srv_specs.ts @@ -0,0 +1,4 @@ +import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common'; + +describe('VariableSrv', function() { +}); diff --git a/public/app/features/templating/templateSrv.js b/public/app/features/templating/templateSrv.js index b8d6cbaee2d..130e2fed246 100644 --- a/public/app/features/templating/templateSrv.js +++ b/public/app/features/templating/templateSrv.js @@ -2,6 +2,7 @@ define([ 'angular', 'lodash', './editorCtrl', + './variable_srv', './templateValuesSrv', ], function (angular, _) { diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 3db7a3f5d9f..a3db47fe3a9 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -166,8 +166,7 @@ function (angular, _, $, kbn) { if (otherVariable === updatedVariable) { return; } - if ((otherVariable.type === "datasource" && - templateSrv.containsVariable(otherVariable.regex, updatedVariable.name)) || + if (templateSrv.containsVariable(otherVariable.regex, updatedVariable.name) || templateSrv.containsVariable(otherVariable.query, updatedVariable.name) || templateSrv.containsVariable(otherVariable.datasource, updatedVariable.name)) { return self.updateOptions(otherVariable); diff --git a/public/app/features/templating/variable_srv.ts b/public/app/features/templating/variable_srv.ts new file mode 100644 index 00000000000..d03559537dc --- /dev/null +++ b/public/app/features/templating/variable_srv.ts @@ -0,0 +1,107 @@ +/// + +import angular from 'angular'; +import _ from 'lodash'; +import $ from 'jquery'; +import coreModule from 'app/core/core_module'; +import appEvents from 'app/core/app_events'; + +interface Variable { +} + +class ConstantVariable implements Variable { + constructor(private model) { + } +} + +class CustomVariable implements Variable { + constructor(private model) { + } +} + +class IntervalVariable implements Variable { + constructor(private model) { + } +} + + +class QueryVariable implements Variable { + + constructor(private model, + private variableSrv: VariableSrv, + private datasourceSrv) { + _.extend(this, model); + } + + updateOptions() { + return this.datasourceSrv.get(this.datasource) + .then(_.partial(this.updateOptionsFromMetricFindQuery, variable)) + .then(_.partial(this.updateTags, variable)) + .then(_.partial(this.validateVariableSelectionState, variable)); + } +} + +class DatasourceVariable implements Variable { + constructor(private model) { + } +} + + +export class VariableSrv { + dashboard: any; + variables: any; + + variableLock: any; + + /** @ngInject */ + constructor( + private $q, + private $rootScope, + private datasourceSrv, + private $location, + private templateSrv, + private timeSrv) { + + } + + init(dashboard) { + this.variableLock = {}; + this.dashboard = dashboard; + + this.variables = dashboard.templating.list.map(item => { + return new QueryVariable(item, this); + }); + + this.templateSrv.init(this.variables); + return this.$q.when(); + } + + updateOptions(variable) { + return variable.updateOptions(); + } + + variableUpdated(variable) { + // if there is a variable lock ignore cascading update because we are in a boot up scenario + if (this.variableLock[variable.name]) { + return this.$q.when(); + } + + var promises = _.map(this.variables, otherVariable => { + if (otherVariable === variable) { + return; + } + + if (this.templateSrv.containsVariable(otherVariable.regex, variable.name) || + this.templateSrv.containsVariable(otherVariable.query, variable.name) || + this.templateSrv.containsVariable(otherVariable.datasource, variable.name)) { + return this.updateOptions(otherVariable); + } + }); + + return this.$q.all(promises); + } + + +} + +coreModule.service('variableSrv', VariableSrv); diff --git a/public/test/specs/templateValuesSrv-specs.js b/public/test/specs/templateValuesSrv-specs.js index 7e62c0f87e0..2ddb69a5b4a 100644 --- a/public/test/specs/templateValuesSrv-specs.js +++ b/public/test/specs/templateValuesSrv-specs.js @@ -50,22 +50,22 @@ define([ }); }); - describe('and setting adhoc variable', function() { - var variable = {name: 'filters', type: 'adhoc'}; - - beforeEach(function(done) { - var dashboard = { templating: { list: [variable] } }; - var urlParams = {}; - urlParams["var-filters"] = "hostname|gt|server2"; - ctx.$location.search = sinon.stub().returns(urlParams); - ctx.service.init(dashboard).then(function() { done(); }); - ctx.$rootScope.$digest(); - }); - - it('should update current value', function() { - expect(variable.tags[0]).to.eq({tag: 'hostname', value: 'server2'}); - }); - }); + // describe('and setting adhoc variable', function() { + // var variable = {name: 'filters', type: 'adhoc'}; + // + // beforeEach(function(done) { + // var dashboard = { templating: { list: [variable] } }; + // var urlParams = {}; + // urlParams["var-filters"] = "hostname|gt|server2"; + // ctx.$location.search = sinon.stub().returns(urlParams); + // ctx.service.init(dashboard).then(function() { done(); }); + // ctx.$rootScope.$digest(); + // }); + // + // it('should update current value', function() { + // expect(variable.tags[0]).to.eq({tag: 'hostname', value: 'server2'}); + // }); + // }); }); describe('when template variable is present in url multiple times', function() {