Kaynağa Gözat

Merge pull request #15118 from grafana/1909/from-to-template-variables

Time range from & to as template variables
Torkel Ödegaard 7 yıl önce
ebeveyn
işleme
67756c43a7

+ 5 - 0
docs/sources/reference/templating.md

@@ -245,6 +245,11 @@ summarize($myinterval, sum, false)
 
 Grafana has global built-in variables that can be used in expressions in the query editor.
 
+### Time range variables
+
+Grafana has two built in time range variables in `$__from` and `$__to`. They are currently always interpolated
+as epoch milliseconds.
+
 ### The $__interval Variable
 
 This $__interval variable is similar to the `auto` interval variable that is described above. It can be used as a parameter to group by time (for InfluxDB, MySQL, Postgres, MSSQL), Date histogram interval (for Elasticsearch) or as a *summarize* function parameter (for Graphite).

+ 3 - 2
public/app/features/dashboard/dashboard_model.ts

@@ -9,6 +9,7 @@ import sortByKeys from 'app/core/utils/sort_by_keys';
 
 import { PanelModel } from './panel_model';
 import { DashboardMigrator } from './dashboard_migration';
+import { TimeRange } from '@grafana/ui/src';
 
 export class DashboardModel {
   id: any;
@@ -200,8 +201,8 @@ export class DashboardModel {
     this.events.emit('view-mode-changed', panel);
   }
 
-  timeRangeUpdated() {
-    this.events.emit('time-range-updated');
+  timeRangeUpdated(timeRange: TimeRange) {
+    this.events.emit('time-range-updated', timeRange);
   }
 
   startRefresh() {

+ 1 - 1
public/app/features/dashboard/time_srv.ts

@@ -147,7 +147,7 @@ export class TimeSrv {
   }
 
   refreshDashboard() {
-    this.dashboard.timeRangeUpdated();
+    this.dashboard.timeRangeUpdated(this.timeRange());
   }
 
   private startNextRefreshTimer(afterMs) {

+ 1 - 1
public/app/features/templating/editor_ctrl.ts

@@ -135,7 +135,7 @@ export class VariableEditorCtrl {
         $scope.runQuery().then(() => {
           $scope.reset();
           $scope.mode = 'list';
-          templateSrv.updateTemplateData();
+          templateSrv.updateIndex();
         });
       }
     };

+ 2 - 2
public/app/features/templating/specs/template_srv.test.ts

@@ -348,7 +348,7 @@ describe('templateSrv', () => {
     });
   });
 
-  describe('updateTemplateData with simple value', () => {
+  describe('updateIndex with simple value', () => {
     beforeEach(() => {
       initTemplateSrv([{ type: 'query', name: 'test', current: { value: 'muuuu' } }]);
     });
@@ -476,7 +476,7 @@ describe('templateSrv', () => {
         }
       ]);
       _templateSrv.setGrafanaVariable('$__auto_interval_interval', '13m');
-      _templateSrv.updateTemplateData();
+      _templateSrv.updateIndex();
     });
 
     it('should replace with text except for grafanaVariables', () => {

+ 12 - 3
public/app/features/templating/specs/variable_srv.test.ts

@@ -8,7 +8,9 @@ describe('VariableSrv', function(this: any) {
   const ctx = {
     datasourceSrv: {},
     timeSrv: {
-      timeRange: () => {},
+      timeRange: () => {
+        return { from: '2018-01-29', to: '2019-01-29' };
+      },
     },
     $rootScope: {
       $on: () => {},
@@ -21,7 +23,7 @@ describe('VariableSrv', function(this: any) {
       init: vars => {
         this.variables = vars;
       },
-      updateTemplateData: () => {},
+      updateIndex: () => {},
       replace: str =>
         str.replace(this.regex, match => {
           return match;
@@ -45,7 +47,14 @@ describe('VariableSrv', function(this: any) {
         const ds: any = {};
         ds.metricFindQuery = () => Promise.resolve(scenario.queryResult);
 
-        ctx.variableSrv = new VariableSrv(ctx.$rootScope, $q, ctx.$location, ctx.$injector, ctx.templateSrv);
+        ctx.variableSrv = new VariableSrv(
+          ctx.$rootScope,
+          $q,
+          ctx.$location,
+          ctx.$injector,
+          ctx.templateSrv,
+          ctx.timeSrv
+        );
 
         ctx.variableSrv.timeSrv = ctx.timeSrv;
         ctx.datasourceSrv = {

+ 9 - 2
public/app/features/templating/specs/variable_srv_init.test.ts

@@ -11,13 +11,19 @@ describe('VariableSrv init', function(this: any) {
       this.variables = vars;
     },
     variableInitialized: () => {},
-    updateTemplateData: () => {},
+    updateIndex: () => {},
     replace: str =>
       str.replace(this.regex, match => {
         return match;
       }),
   };
 
+  const timeSrv = {
+    timeRange: () => {
+      return { from: '2018-01-29', to: '2019-01-29' };
+    },
+  };
+
   const $injector = {} as any;
   const $rootscope = {
     $on: () => {},
@@ -47,7 +53,8 @@ describe('VariableSrv init', function(this: any) {
           templateSrv,
         };
 
-        ctx.variableSrv = new VariableSrv($rootscope, $q, {}, $injector, templateSrv);
+        // @ts-ignore
+        ctx.variableSrv = new VariableSrv($rootscope, $q, {}, $injector, templateSrv, timeSrv);
 
         $injector.instantiate = (variable, model) => {
           return getVarMockConstructor(variable, model, ctx);

+ 36 - 7
public/app/features/templating/template_srv.ts

@@ -1,6 +1,7 @@
 import kbn from 'app/core/utils/kbn';
 import _ from 'lodash';
 import { variableRegex } from 'app/features/templating/variable';
+import { TimeRange } from '@grafana/ui/src';
 
 function luceneEscape(value) {
   return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, '\\$1');
@@ -13,6 +14,7 @@ export class TemplateSrv {
   private index = {};
   private grafanaVariables = {};
   private builtIns = {};
+  private timeRange: TimeRange = null;
 
   constructor() {
     this.builtIns['__interval'] = { text: '1s', value: '1s' };
@@ -20,12 +22,13 @@ export class TemplateSrv {
     this.variables = [];
   }
 
-  init(variables) {
+  init(variables, timeRange?: TimeRange) {
     this.variables = variables;
-    this.updateTemplateData();
+    this.timeRange = timeRange;
+    this.updateIndex();
   }
 
-  updateTemplateData() {
+  updateIndex() {
     const existsOrEmpty = value => value || value === '';
 
     this.index = this.variables.reduce((acc, currentValue) => {
@@ -34,6 +37,26 @@ export class TemplateSrv {
       }
       return acc;
     }, {});
+
+    if (this.timeRange) {
+      const from = this.timeRange.from.valueOf().toString();
+      const to = this.timeRange.to.valueOf().toString();
+
+      this.index = {
+        ...this.index,
+        ['__from']: {
+          current: { value: from, text: from },
+        },
+        ['__to']: {
+          current: { value: to, text: to },
+        },
+      };
+    }
+  }
+
+  updateTimeRange(timeRange: TimeRange) {
+    this.timeRange = timeRange;
+    this.updateIndex();
   }
 
   variableInitialized(variable) {
@@ -81,8 +104,14 @@ export class TemplateSrv {
   // also the sub-delims "!", "'", "(", ")" and "*" are encoded;
   // unicode handling uses UTF-8 as in ECMA-262.
   encodeURIComponentStrict(str) {
-    return encodeURIComponent(str).replace(/[!'()*]/g, (c) => {
-      return '%' + c.charCodeAt(0).toString(16).toUpperCase();
+    return encodeURIComponent(str).replace(/[!'()*]/g, c => {
+      return (
+        '%' +
+        c
+          .charCodeAt(0)
+          .toString(16)
+          .toUpperCase()
+      );
     });
   }
 
@@ -256,11 +285,11 @@ export class TemplateSrv {
 
       const value = this.grafanaVariables[variable.current.value];
 
-      return typeof(value) === 'string' ? value : variable.current.text;
+      return typeof value === 'string' ? value : variable.current.text;
     });
   }
 
-  fillVariableValuesForUrl(params, scopedVars) {
+  fillVariableValuesForUrl(params, scopedVars?) {
     _.each(this.variables, variable => {
       if (scopedVars && scopedVars[variable.name] !== void 0) {
         if (scopedVars[variable.name].skipUrlSync) {

+ 21 - 9
public/app/features/templating/variable_srv.ts

@@ -6,23 +6,34 @@ import _ from 'lodash';
 import coreModule from 'app/core/core_module';
 import { variableTypes } from './variable';
 import { Graph } from 'app/core/utils/dag';
+import { TemplateSrv } from 'app/features/templating/template_srv';
+import { TimeSrv } from 'app/features/dashboard/time_srv';
+import { DashboardModel } from 'app/features/dashboard/dashboard_model';
+
+// Types
+import { TimeRange } from '@grafana/ui/src';
 
 export class VariableSrv {
-  dashboard: any;
-  variables: any;
+  dashboard: DashboardModel;
+  variables: any[];
 
   /** @ngInject */
-  constructor(private $rootScope, private $q, private $location, private $injector, private templateSrv) {
+  constructor(private $rootScope,
+              private $q,
+              private $location,
+              private $injector,
+              private templateSrv: TemplateSrv,
+              private timeSrv: TimeSrv) {
     $rootScope.$on('template-variable-value-updated', this.updateUrlParamsWithCurrentVariables.bind(this), $rootScope);
   }
 
-  init(dashboard) {
+  init(dashboard: DashboardModel) {
     this.dashboard = dashboard;
     this.dashboard.events.on('time-range-updated', this.onTimeRangeUpdated.bind(this));
 
     // create working class models representing variables
     this.variables = dashboard.templating.list = dashboard.templating.list.map(this.createVariableFromModel.bind(this));
-    this.templateSrv.init(this.variables);
+    this.templateSrv.init(this.variables, this.timeSrv.timeRange());
 
     // init variables
     for (const variable of this.variables) {
@@ -37,11 +48,12 @@ export class VariableSrv {
         })
       )
       .then(() => {
-        this.templateSrv.updateTemplateData();
+        this.templateSrv.updateIndex();
       });
   }
 
-  onTimeRangeUpdated() {
+  onTimeRangeUpdated(timeRange: TimeRange) {
+    this.templateSrv.updateTimeRange(timeRange);
     const promises = this.variables.filter(variable => variable.refresh === 2).map(variable => {
       const previousOptions = variable.options.slice();
 
@@ -100,14 +112,14 @@ export class VariableSrv {
 
   addVariable(variable) {
     this.variables.push(variable);
-    this.templateSrv.updateTemplateData();
+    this.templateSrv.updateIndex();
     this.dashboard.updateSubmenuVisibility();
   }
 
   removeVariable(variable) {
     const index = _.indexOf(this.variables, variable);
     this.variables.splice(index, 1);
-    this.templateSrv.updateTemplateData();
+    this.templateSrv.updateIndex();
     this.dashboard.updateSubmenuVisibility();
   }
 

+ 1 - 1
public/test/specs/helpers.ts

@@ -182,7 +182,7 @@ export function TemplateSrvStub(this: any) {
     return [];
   };
   this.fillVariableValuesForUrl = () => {};
-  this.updateTemplateData = () => {};
+  this.updateIndex = () => {};
   this.variableExists = () => {
     return false;
   };