Browse Source

feat(adhoc filters): good progress on ad hoc filters and sync from to url, #6038

Torkel Ödegaard 9 years ago
parent
commit
6e429b8575

+ 25 - 13
public/app/features/dashboard/ad_hoc_filters.ts

@@ -21,7 +21,7 @@ export class AdHocFiltersCtrl {
     if (this.variable.value && !_.isArray(this.variable.value)) {
     }
 
-    for (let tag of this.variable.tags) {
+    for (let tag of this.variable.filters) {
       if (this.segments.length > 0) {
         this.segments.push(this.uiSegmentSrv.newCondition('AND'));
       }
@@ -38,7 +38,11 @@ export class AdHocFiltersCtrl {
 
   getOptions(segment, index) {
     if (segment.type === 'operator') {
-      return this.$q.when(this.uiSegmentSrv.newOperators(['=', '!=', '<>', '<', '>', '=~', '!~']));
+      return this.$q.when(this.uiSegmentSrv.newOperators(['=', '!=', '<', '>', '=~', '!~']));
+    }
+
+    if (segment.type === 'condition') {
+      return this.$q.when([this.uiSegmentSrv.newSegment('AND')]);
     }
 
     return this.datasourceSrv.get(this.variable.datasource).then(ds => {
@@ -100,37 +104,45 @@ export class AdHocFiltersCtrl {
   }
 
   updateVariableModel() {
-    var tags = [];
-    var tagIndex = -1;
-    var tagOperator = "";
-
-    this.segments.forEach((segment, index) => {
-      if (segment.fake) {
+    var filters = [];
+    var filterIndex = -1;
+    var operator = "";
+    var hasFakes = false;
+
+    this.segments.forEach(segment => {
+      if (segment.type === 'value' && segment.fake) {
+        hasFakes = true;
         return;
       }
 
       switch (segment.type) {
         case 'key': {
-          tags.push({key: segment.value});
-          tagIndex += 1;
+          filters.push({key: segment.value});
+          filterIndex += 1;
           break;
         }
         case 'value': {
-          tags[tagIndex].value = segment.value;
+          filters[filterIndex].value = segment.value;
           break;
         }
         case 'operator': {
-          tags[tagIndex].operator = segment.value;
+          filters[filterIndex].operator = segment.value;
           break;
         }
         case 'condition': {
+          filters[filterIndex].condition = segment.value;
           break;
         }
       }
     });
 
+    if (hasFakes) {
+      return;
+    }
+
+    this.variable.setFilters(filters);
+    this.$rootScope.$emit('template-variable-value-updated');
     this.$rootScope.$broadcast('refresh');
-    this.variable.tags = tags;
   }
 }
 

+ 0 - 20
public/app/features/dashboard/viewStateSrv.js

@@ -34,10 +34,6 @@ function (angular, _, $) {
         $location.search(urlParams);
       });
 
-      $scope.onAppEvent('template-variable-value-updated', function() {
-        self.updateUrlParamsWithCurrentVariables();
-      });
-
       $scope.onAppEvent('$routeUpdate', function() {
         var urlState = self.getQueryStringState();
         if (self.needsSync(urlState)) {
@@ -57,22 +53,6 @@ function (angular, _, $) {
       this.expandRowForPanel();
     }
 
-    DashboardViewState.prototype.updateUrlParamsWithCurrentVariables = function() {
-      // update url
-      var params = $location.search();
-      // remove variable params
-      _.each(params, function(value, key) {
-        if (key.indexOf('var-') === 0) {
-          delete params[key];
-        }
-      });
-
-      // add new values
-      templateSrv.fillVariableValuesForUrl(params);
-      // update url
-      $location.search(params);
-    };
-
     DashboardViewState.prototype.expandRowForPanel = function() {
       if (!this.state.panelId) { return; }
 

+ 25 - 3
public/app/features/templating/adhoc_variable.ts

@@ -6,6 +6,7 @@ import {Variable, assignModelProperties, variableTypes} from './variable';
 import {VariableSrv} from './variable_srv';
 
 export class AdhocVariable implements Variable {
+  filters: any[];
 
   defaults = {
     type: 'adhoc',
@@ -13,9 +14,7 @@ export class AdhocVariable implements Variable {
     label: '',
     hide: 0,
     datasource: null,
-    options: [],
-    current: {},
-    tags: {},
+    filters: [],
   };
 
   /** @ngInject **/
@@ -41,8 +40,31 @@ export class AdhocVariable implements Variable {
   }
 
   setValueFromUrl(urlValue) {
+    if (!_.isArray(urlValue)) {
+      urlValue = [urlValue];
+    }
+
+    this.filters = urlValue.map(item => {
+      var values = item.split('|');
+      return {
+        key: values[0],
+        operator: values[1],
+        value: values[2],
+      };
+    });
+
     return Promise.resolve();
   }
+
+  getValueForUrl() {
+    return this.filters.map(filter => {
+      return filter.key + '|' + filter.operator + '|' + filter.value;
+    });
+  }
+
+  setFilters(filters: any[]) {
+    this.filters = filters;
+  }
 }
 
 variableTypes['adhoc'] = {

+ 7 - 0
public/app/features/templating/constant_variable.ts

@@ -7,6 +7,7 @@ import {VariableSrv} from './variable_srv';
 export class ConstantVariable implements Variable {
   query: string;
   options: any[];
+  current: any;
 
   defaults = {
     type: 'constant',
@@ -14,6 +15,7 @@ export class ConstantVariable implements Variable {
     hide: 2,
     label: '',
     query: '',
+    current: {},
   };
 
   /** @ngInject */
@@ -43,6 +45,11 @@ export class ConstantVariable implements Variable {
   setValueFromUrl(urlValue) {
     return this.variableSrv.setOptionFromUrl(this, urlValue);
   }
+
+  getValueForUrl() {
+    return this.current.value;
+  }
+
 }
 
 variableTypes['constant'] = {

+ 10 - 1
public/app/features/templating/custom_variable.ts

@@ -10,6 +10,7 @@ export class CustomVariable implements Variable {
   options: any;
   includeAll: boolean;
   multi: boolean;
+  current: any;
 
   defaults = {
     type: 'custom',
@@ -17,10 +18,11 @@ export class CustomVariable implements Variable {
     label: '',
     hide: 0,
     options: [],
-    current: {text: '', value: ''},
+    current: {},
     query: '',
     includeAll: false,
     multi: false,
+    allValue: null,
   };
 
   /** @ngInject **/
@@ -61,6 +63,13 @@ export class CustomVariable implements Variable {
   setValueFromUrl(urlValue) {
     return this.variableSrv.setOptionFromUrl(this, urlValue);
   }
+
+  getValueForUrl() {
+    if (this.current.text === 'All') {
+      return 'All';
+    }
+    return this.current.value;
+  }
 }
 
 variableTypes['custom'] = {

+ 6 - 1
public/app/features/templating/datasource_variable.ts

@@ -9,13 +9,14 @@ export class DatasourceVariable implements Variable {
   regex: any;
   query: string;
   options: any;
+  current: any;
 
  defaults = {
     type: 'datasource',
     name: '',
     hide: 0,
     label: '',
-    current: {text: '', value: ''},
+    current: {},
     regex: '',
     options: [],
     query: '',
@@ -73,6 +74,10 @@ export class DatasourceVariable implements Variable {
   setValueFromUrl(urlValue) {
     return this.variableSrv.setOptionFromUrl(this, urlValue);
   }
+
+  getValueForUrl() {
+    return this.current.value;
+  }
 }
 
 variableTypes['datasource'] = {

+ 6 - 1
public/app/features/templating/interval_variable.ts

@@ -12,6 +12,7 @@ export class IntervalVariable implements Variable {
   auto: boolean;
   query: string;
   refresh: number;
+  current: any;
 
   defaults = {
     type: 'interval',
@@ -20,7 +21,7 @@ export class IntervalVariable implements Variable {
     label: '',
     refresh: 2,
     options: [],
-    current: {text: '', value: ''},
+    current: {},
     query: '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d',
     auto: false,
     auto_min: '10s',
@@ -75,6 +76,10 @@ export class IntervalVariable implements Variable {
     this.updateAutoValue();
     return this.variableSrv.setOptionFromUrl(this, urlValue);
   }
+
+  getValueForUrl() {
+    return this.current.value;
+  }
 }
 
 variableTypes['interval'] = {

+ 11 - 1
public/app/features/templating/query_variable.ts

@@ -33,8 +33,11 @@ export class QueryVariable implements Variable {
     name: '',
     multi: false,
     includeAll: false,
+    allValue: null,
     options: [],
-    current: {text: '', value: ''},
+    current: {},
+    tagsQuery: null,
+    tagValuesQuery: null,
   };
 
   constructor(private model, private datasourceSrv, private templateSrv, private variableSrv, private $q)  {
@@ -56,6 +59,13 @@ export class QueryVariable implements Variable {
     return this.variableSrv.setOptionFromUrl(this, urlValue);
   }
 
+  getValueForUrl() {
+    if (this.current.text === 'All') {
+      return 'All';
+    }
+    return this.current.value;
+  }
+
   updateOptions() {
     return this.datasourceSrv.get(this.datasource)
     .then(this.updateOptionsFromMetricFindQuery.bind(this))

+ 237 - 0
public/app/features/templating/specs/template_srv_specs.ts

@@ -0,0 +1,237 @@
+import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
+
+import '../all';
+import {Emitter} from 'app/core/core';
+
+describe('templateSrv', function() {
+  var _templateSrv, _variableSrv;
+
+  beforeEach(angularMocks.module('grafana.core'));
+  beforeEach(angularMocks.module('grafana.services'));
+
+  beforeEach(angularMocks.inject(function(variableSrv, templateSrv) {
+    _templateSrv = templateSrv;
+    _variableSrv = variableSrv;
+  }));
+
+  function initTemplateSrv(variables) {
+    _variableSrv.init({
+      templating: {list: variables},
+      events: new Emitter(),
+    });
+  }
+
+  describe('init', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', 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('replace can pass scoped vars', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: {value: 'oogle' }}]);
+    });
+
+    it('should replace $test with scoped value', function() {
+      var target = _templateSrv.replace('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
+      expect(target).to.be('this.mupp.filters');
+    });
+
+    it('should replace $test with scoped text', function() {
+      var target = _templateSrv.replaceWithText('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
+      expect(target).to.be('this.asd.filters');
+    });
+  });
+
+  describe('replace can pass multi / all format', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: {value: ['value1', 'value2'] }}]);
+    });
+
+    it('should replace $test with globbed value', function() {
+      var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
+      expect(target).to.be('this.{value1,value2}.filters');
+    });
+
+    it('should replace $test with piped value', function() {
+      var target = _templateSrv.replace('this=$test', {}, 'pipe');
+      expect(target).to.be('this=value1|value2');
+    });
+
+    it('should replace $test with piped value', function() {
+      var target = _templateSrv.replace('this=$test', {}, 'pipe');
+      expect(target).to.be('this=value1|value2');
+    });
+  });
+
+  describe('variable with all option', function() {
+    beforeEach(function() {
+      initTemplateSrv([{
+        type: 'query',
+        name: 'test',
+        current: {value: '$__all' },
+        options: [
+          {value: '$__all'}, {value: 'value1'}, {value: 'value2'}
+        ]
+      }]);
+    });
+
+    it('should replace $test with formatted all value', function() {
+      var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
+      expect(target).to.be('this.{value1,value2}.filters');
+    });
+  });
+
+  describe('variable with all option and custom value', function() {
+    beforeEach(function() {
+      initTemplateSrv([{
+        type: 'query',
+        name: 'test',
+        current: {value: '$__all' },
+        allValue: '*',
+        options: [
+          {value: 'value1'}, {value: 'value2'}
+        ]
+      }]);
+    });
+
+    it('should replace $test with formatted all value', function() {
+      var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
+      expect(target).to.be('this.*.filters');
+    });
+
+    it('should not escape custom all value', function() {
+      var target = _templateSrv.replace('this.$test', {}, 'regex');
+      expect(target).to.be('this.*');
+    });
+  });
+
+  describe('lucene format', function() {
+    it('should properly escape $test with lucene escape sequences', function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: {value: 'value/4' }}]);
+      var target = _templateSrv.replace('this:$test', {}, 'lucene');
+      expect(target).to.be("this:value\\\/4");
+    });
+  });
+
+  describe('format variable to string values', function() {
+    it('single value should return value', function() {
+      var result = _templateSrv.formatValue('test');
+      expect(result).to.be('test');
+    });
+
+    it('multi value and glob format should render glob string', function() {
+      var result = _templateSrv.formatValue(['test','test2'], 'glob');
+      expect(result).to.be('{test,test2}');
+    });
+
+    it('multi value and lucene should render as lucene expr', function() {
+      var result = _templateSrv.formatValue(['test','test2'], 'lucene');
+      expect(result).to.be('("test" OR "test2")');
+    });
+
+    it('multi value and regex format should render regex string', function() {
+      var result = _templateSrv.formatValue(['test.','test2'], 'regex');
+      expect(result).to.be('(test\\.|test2)');
+    });
+
+    it('multi value and pipe should render pipe string', function() {
+      var result = _templateSrv.formatValue(['test','test2'], 'pipe');
+      expect(result).to.be('test|test2');
+    });
+
+    it('slash should be properly escaped in regex format', function() {
+      var result = _templateSrv.formatValue('Gi3/14', 'regex');
+      expect(result).to.be('Gi3\\/14');
+    });
+
+  });
+
+  describe('can check if variable exists', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: { value: 'oogle' } }]);
+    });
+
+    it('should return true if exists', function() {
+      var result = _templateSrv.variableExists('$test');
+      expect(result).to.be(true);
+    });
+  });
+
+  describe('can hightlight variables in string', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: { value: 'oogle' } }]);
+    });
+
+    it('should insert html', function() {
+      var result = _templateSrv.highlightVariablesAsHtml('$test');
+      expect(result).to.be('<span class="template-variable">$test</span>');
+    });
+
+    it('should insert html anywhere in string', function() {
+      var result = _templateSrv.highlightVariablesAsHtml('this $test ok');
+      expect(result).to.be('this <span class="template-variable">$test</span> ok');
+    });
+
+    it('should ignore if variables does not exist', function() {
+      var result = _templateSrv.highlightVariablesAsHtml('this $google ok');
+      expect(result).to.be('this $google ok');
+    });
+  });
+
+  describe('updateTemplateData with simple value', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: { value: 'muuuu' } }]);
+    });
+
+    it('should set current value and update template data', function() {
+      var target = _templateSrv.replace('this.[[test]].filters');
+      expect(target).to.be('this.muuuu.filters');
+    });
+  });
+
+  describe('fillVariableValuesForUrl with multi value', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: { value: ['val1', 'val2'] }}]);
+    });
+
+    it('should set multiple url params', function() {
+      var params = {};
+      _templateSrv.fillVariableValuesForUrl(params);
+      expect(params['var-test']).to.eql(['val1', 'val2']);
+    });
+  });
+
+  describe('fillVariableValuesForUrl with multi value and scopedVars', function() {
+    beforeEach(function() {
+      initTemplateSrv([{type: 'query', name: 'test', current: { value: ['val1', 'val2'] }}]);
+    });
+
+    it('should set scoped value as url params', function() {
+      var params = {};
+      _templateSrv.fillVariableValuesForUrl(params, {'test': {value: 'val1'}});
+      expect(params['var-test']).to.eql('val1');
+    });
+  });
+
+  describe('replaceWithText', function() {
+    beforeEach(function() {
+      initTemplateSrv([
+        {type: 'query', name: 'server', current: { value: '{asd,asd2}', text: 'All' } },
+        {type: 'interval', name: 'period', current: { value: '$__auto_interval', text: 'auto' } }
+      ]);
+      _templateSrv.setGrafanaVariable('$__auto_interval', '13m');
+      _templateSrv.updateTemplateData();
+    });
+
+    it('should replace with text except for grafanaVariables', function() {
+      var target = _templateSrv.replaceWithText('Server: $server, period: $period');
+      expect(target).to.be('Server: All, period: 13m');
+    });
+  });
+});

+ 3 - 10
public/app/features/templating/templateSrv.js

@@ -180,18 +180,11 @@ function (angular, _, kbn) {
 
     this.fillVariableValuesForUrl = function(params, scopedVars) {
       _.each(this.variables, function(variable) {
-        var current = variable.current;
-        var value = current.value;
-
-        if (current.text === 'All') {
-          value = 'All';
-        }
-
         if (scopedVars && scopedVars[variable.name] !== void 0) {
-          value = scopedVars[variable.name].value;
+          params['var-' + variable.name] = scopedVars[variable.name].value;
+        } else {
+          params['var-' + variable.name] = variable.getValueForUrl();
         }
-
-        params['var-' + variable.name] = value;
       });
     };
 

+ 1 - 0
public/app/features/templating/variable.ts

@@ -8,6 +8,7 @@ export interface Variable {
   updateOptions();
   dependsOn(variable);
   setValueFromUrl(urlValue);
+  getValueForUrl();
   getModel();
 }
 

+ 18 - 0
public/app/features/templating/variable_srv.ts

@@ -14,6 +14,7 @@ export class VariableSrv {
   constructor(private $rootScope, private $q, private $location, private $injector, private templateSrv) {
     // update time variant variables
     $rootScope.$on('refresh', this.onDashboardRefresh.bind(this), $rootScope);
+    $rootScope.$on('template-variable-value-updated', this.updateUrlParamsWithCurrentVariables.bind(this), $rootScope);
   }
 
   init(dashboard) {
@@ -210,6 +211,23 @@ export class VariableSrv {
     this.selectOptionsForCurrentValue(variable);
     return this.variableUpdated(variable);
   }
+
+  updateUrlParamsWithCurrentVariables() {
+    // update url
+    var params = this.$location.search();
+
+    // remove variable params
+    _.each(params, function(value, key) {
+      if (key.indexOf('var-') === 0) {
+        delete params[key];
+      }
+    });
+
+    // add new values
+    this.templateSrv.fillVariableValuesForUrl(params);
+    // update url
+    this.$location.search(params);
+  }
 }
 
 coreModule.service('variableSrv', VariableSrv);

+ 3 - 3
public/app/plugins/datasource/influxdb/datasource.ts

@@ -56,9 +56,9 @@ export default class InfluxDatasource {
         // apply add hoc filters
         for (let variable of this.templateSrv.variables) {
           if (variable.type === 'adhoc' && variable.datasource === this.name) {
-            for (let tag of variable.tags) {
-              if (tag.key !== undefined && tag.value !== undefined) {
-                target.tags.push({key: tag.key, value: tag.value, condition: 'AND'});
+            for (let filter of variable.filters) {
+              if (filter.key !== undefined && filter.value !== undefined) {
+                target.tags.push({key: filter.key, value: filter.value, condition: filter.condition, operator: filter.operator});
               }
             }
           }

+ 0 - 235
public/test/specs/templateSrv-specs.js

@@ -1,235 +0,0 @@
-define([
-  '../mocks/dashboard-mock',
-  'lodash',
-  'app/features/templating/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;
-    }));
-
-    describe('init', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ 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('replace can pass scoped vars', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ name: 'test', current: { value: 'oogle' } }]);
-      });
-
-      it('should replace $test with scoped value', function() {
-        var target = _templateSrv.replace('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
-        expect(target).to.be('this.mupp.filters');
-      });
-
-      it('should replace $test with scoped text', function() {
-        var target = _templateSrv.replaceWithText('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
-        expect(target).to.be('this.asd.filters');
-      });
-    });
-
-    describe('replace can pass multi / all format', function() {
-      beforeEach(function() {
-        _templateSrv.init([{name: 'test', current: {value: ['value1', 'value2'] }}]);
-      });
-
-      it('should replace $test with globbed value', function() {
-        var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
-        expect(target).to.be('this.{value1,value2}.filters');
-      });
-
-      it('should replace $test with piped value', function() {
-        var target = _templateSrv.replace('this=$test', {}, 'pipe');
-        expect(target).to.be('this=value1|value2');
-      });
-
-      it('should replace $test with piped value', function() {
-        var target = _templateSrv.replace('this=$test', {}, 'pipe');
-        expect(target).to.be('this=value1|value2');
-      });
-    });
-
-    describe('variable with all option', function() {
-      beforeEach(function() {
-        _templateSrv.init([{
-          name: 'test',
-          current: {value: '$__all' },
-          options: [
-            {value: '$__all'}, {value: 'value1'}, {value: 'value2'}
-          ]
-        }]);
-      });
-
-      it('should replace $test with formatted all value', function() {
-        var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
-        expect(target).to.be('this.{value1,value2}.filters');
-      });
-    });
-
-    describe('variable with all option and custom value', function() {
-      beforeEach(function() {
-        _templateSrv.init([{
-          name: 'test',
-          current: {value: '$__all' },
-          allValue: '*',
-          options: [
-            {value: 'value1'}, {value: 'value2'}
-          ]
-        }]);
-      });
-
-      it('should replace $test with formatted all value', function() {
-        var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
-        expect(target).to.be('this.*.filters');
-      });
-
-      it('should not escape custom all value', function() {
-        var target = _templateSrv.replace('this.$test', {}, 'regex');
-        expect(target).to.be('this.*');
-      });
-    });
-
-    describe('lucene format', function() {
-      it('should properly escape $test with lucene escape sequences', function() {
-        _templateSrv.init([{name: 'test', current: {value: 'value/4' }}]);
-        var target = _templateSrv.replace('this:$test', {}, 'lucene');
-        expect(target).to.be("this:value\\\/4");
-      });
-    });
-
-    describe('format variable to string values', function() {
-      it('single value should return value', function() {
-        var result = _templateSrv.formatValue('test');
-        expect(result).to.be('test');
-      });
-
-      it('multi value and glob format should render glob string', function() {
-        var result = _templateSrv.formatValue(['test','test2'], 'glob');
-        expect(result).to.be('{test,test2}');
-      });
-
-      it('multi value and lucene should render as lucene expr', function() {
-        var result = _templateSrv.formatValue(['test','test2'], 'lucene');
-        expect(result).to.be('("test" OR "test2")');
-      });
-
-      it('multi value and regex format should render regex string', function() {
-        var result = _templateSrv.formatValue(['test.','test2'], 'regex');
-        expect(result).to.be('(test\\.|test2)');
-      });
-
-      it('multi value and pipe should render pipe string', function() {
-        var result = _templateSrv.formatValue(['test','test2'], 'pipe');
-        expect(result).to.be('test|test2');
-      });
-
-      it('slash should be properly escaped in regex format', function() {
-        var result = _templateSrv.formatValue('Gi3/14', 'regex');
-        expect(result).to.be('Gi3\\/14');
-      });
-
-    });
-
-    describe('can check if variable exists', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ name: 'test', current: { value: 'oogle' } }]);
-      });
-
-      it('should return true if exists', function() {
-        var result = _templateSrv.variableExists('$test');
-        expect(result).to.be(true);
-      });
-    });
-
-    describe('can hightlight variables in string', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ name: 'test', current: { value: 'oogle' } }]);
-      });
-
-      it('should insert html', function() {
-        var result = _templateSrv.highlightVariablesAsHtml('$test');
-        expect(result).to.be('<span class="template-variable">$test</span>');
-      });
-
-      it('should insert html anywhere in string', function() {
-        var result = _templateSrv.highlightVariablesAsHtml('this $test ok');
-        expect(result).to.be('this <span class="template-variable">$test</span> ok');
-      });
-
-      it('should ignore if variables does not exist', function() {
-        var result = _templateSrv.highlightVariablesAsHtml('this $google ok');
-        expect(result).to.be('this $google ok');
-      });
-    });
-
-    describe('updateTemplateData with simple value', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ name: 'test', current: { value: 'muuuu' } }]);
-      });
-
-      it('should set current value and update template data', function() {
-        var target = _templateSrv.replace('this.[[test]].filters');
-        expect(target).to.be('this.muuuu.filters');
-      });
-    });
-
-    describe('fillVariableValuesForUrl with multi value', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ name: 'test', current: { value: ['val1', 'val2'] }}]);
-      });
-
-      it('should set multiple url params', function() {
-        var params = {};
-        _templateSrv.fillVariableValuesForUrl(params);
-        expect(params['var-test']).to.eql(['val1', 'val2']);
-      });
-    });
-
-    describe('fillVariableValuesForUrl with multi value and scopedVars', function() {
-      beforeEach(function() {
-        _templateSrv.init([{ name: 'test', current: { value: ['val1', 'val2'] }}]);
-      });
-
-      it('should set multiple url params', function() {
-        var params = {};
-        _templateSrv.fillVariableValuesForUrl(params, {'test': {value: 'val1'}});
-        expect(params['var-test']).to.eql('val1');
-      });
-    });
-
-    describe('replaceWithText', function() {
-      beforeEach(function() {
-        _templateSrv.init([
-          { name: 'server', current: { value: '{asd,asd2}', text: 'All' } },
-          { name: 'period', current: { value: '$__auto_interval', text: 'auto' } }
-        ]);
-        _templateSrv.setGrafanaVariable('$__auto_interval', '13m');
-        _templateSrv.updateTemplateData();
-      });
-
-      it('should replace with text except for grafanaVariables', function() {
-        var target = _templateSrv.replaceWithText('Server: $server, period: $period');
-        expect(target).to.be('Server: All, period: 13m');
-      });
-    });
-
-  });
-
-});