Przeglądaj źródła

Improvement to InfluxDB query editor and function/value column selection, more space efficient, Closes #473

Torkel Ödegaard 11 lat temu
rodzic
commit
af1855601b

+ 2 - 0
CHANGELOG.md

@@ -9,6 +9,8 @@ vNext
 - improved asset (css/js) build pipeline, added revision to css and js. Will remove issues related
 - improved asset (css/js) build pipeline, added revision to css and js. Will remove issues related
   to the browser cache when upgrading grafana and improve load performance (Fixes #418)
   to the browser cache when upgrading grafana and improve load performance (Fixes #418)
 - Partial support for url encoded metrics when using Graphite datasource (PR #327) - thx @axe-felix
 - Partial support for url encoded metrics when using Graphite datasource (PR #327) - thx @axe-felix
+- Improvement to InfluxDB query editor and function/value column selection (Issue #473)
+- Initial support for filtering (templated queries) for InfluxDB (PR #375) - thx @mavimo
 
 
 # Fixes
 # Fixes
 - Filter option loading when having muliple nested filters now works better.
 - Filter option loading when having muliple nested filters now works better.

+ 7 - 3
src/app/controllers/influxTargetCtrl.js

@@ -11,9 +11,8 @@ function (angular) {
   module.controller('InfluxTargetCtrl', function($scope, $timeout) {
   module.controller('InfluxTargetCtrl', function($scope, $timeout) {
 
 
     $scope.init = function() {
     $scope.init = function() {
-      if (!$scope.target.function) {
-        $scope.target.function = 'mean';
-      }
+      $scope.target.function = $scope.target.function || 'mean';
+      $scope.target.column = $scope.target.column || 'value';
 
 
       $scope.rawQuery = false;
       $scope.rawQuery = false;
 
 
@@ -44,6 +43,11 @@ function (angular) {
       }
       }
     };
     };
 
 
+    $scope.changeFunction = function(func) {
+      $scope.target.function = func;
+      $scope.get_data();
+    };
+
     // called outside of digest
     // called outside of digest
     $scope.listColumns = function(query, callback) {
     $scope.listColumns = function(query, callback) {
       if (!$scope.columnList) {
       if (!$scope.columnList) {

+ 2 - 1
src/app/directives/all.js

@@ -15,5 +15,6 @@ define([
   './bodyClass',
   './bodyClass',
   './addGraphiteFunc',
   './addGraphiteFunc',
   './graphiteFuncEditor',
   './graphiteFuncEditor',
-  './grafanaVersionCheck'
+  './grafanaVersionCheck',
+  './influxdbFuncEditor'
 ], function () {});
 ], function () {});

+ 137 - 0
src/app/directives/influxdbFuncEditor.js

@@ -0,0 +1,137 @@
+define([
+  'angular',
+  'underscore',
+  'jquery',
+],
+function (angular, _, $) {
+  'use strict';
+
+  angular
+    .module('kibana.directives')
+    .directive('influxdbFuncEditor', function($compile) {
+
+      var funcSpanTemplate = '<a gf-dropdown="functionMenu" class="dropdown-toggle" ' +
+                             'data-toggle="dropdown">{{target.function}}</a><span>(</span>';
+
+      var paramTemplate = '<input type="text" style="display:none"' +
+                          ' class="input-mini grafana-function-param-input"></input>';
+
+      return {
+        restrict: 'A',
+        link: function postLink($scope, elem) {
+          var $funcLink = $(funcSpanTemplate);
+
+          $scope.functionMenu = _.map($scope.functions, function(func) {
+            return {
+              text: func,
+              click: "changeFunction('" + func + "');"
+            };
+          });
+
+          function clickFuncParam() {
+            /*jshint validthis:true */
+
+            var $link = $(this);
+            var $input = $link.next();
+
+            $input.val($scope.target.column);
+            $input.css('width', ($link.width() + 16) + 'px');
+
+            $link.hide();
+            $input.show();
+            $input.focus();
+            $input.select();
+
+            var typeahead = $input.data('typeahead');
+            if (typeahead) {
+              $input.val('');
+              typeahead.lookup();
+            }
+          }
+
+          function inputBlur() {
+            /*jshint validthis:true */
+
+            var $input = $(this);
+            var $link = $input.prev();
+
+            if ($input.val() !== '') {
+              $link.text($input.val());
+
+              $scope.target.column = $input.val();
+              $scope.$apply($scope.get_data);
+            }
+
+            $input.hide();
+            $link.show();
+          }
+
+          function inputKeyPress(e) {
+            /*jshint validthis:true */
+
+            if(e.which === 13) {
+              inputBlur.call(this);
+            }
+          }
+
+          function inputKeyDown() {
+            /*jshint validthis:true */
+            this.style.width = (3 + this.value.length) * 8 + 'px';
+          }
+
+          function addTypeahead($input) {
+            $input.attr('data-provide', 'typeahead');
+
+            $input.typeahead({
+              source: function () {
+                return $scope.listColumns.apply(null, arguments);
+              },
+              minLength: 0,
+              items: 20,
+              updater: function (value) {
+                setTimeout(function() {
+                  inputBlur.call($input[0]);
+                }, 0);
+                return value;
+              }
+            });
+
+            var typeahead = $input.data('typeahead');
+            typeahead.lookup = function () {
+              var items;
+              this.query = this.$element.val() || '';
+              items = this.source(this.query, $.proxy(this.process, this));
+              return items ? this.process(items) : items;
+            };
+          }
+
+          function addElementsAndCompile() {
+            $funcLink.appendTo(elem);
+
+            var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + $scope.target.column + '</a>');
+            var $input = $(paramTemplate);
+
+            $paramLink.appendTo(elem);
+            $input.appendTo(elem);
+
+            $input.blur(_.partial(inputBlur));
+            $input.keyup(inputKeyDown);
+            $input.keypress(_.partial(inputKeyPress));
+            $paramLink.click(_.partial(clickFuncParam));
+
+            addTypeahead($input);
+
+            $('<span>)</span>').appendTo(elem);
+
+            $compile(elem.contents())($scope);
+          }
+
+          addElementsAndCompile();
+
+        }
+      };
+
+    });
+
+
+});

+ 7 - 26
src/app/partials/influxdb/editor.html

@@ -53,13 +53,9 @@
                ng-show="target.rawQuery">
                ng-show="target.rawQuery">
 
 
         <ul class="grafana-segment-list" role="menu" ng-hide="target.rawQuery">
         <ul class="grafana-segment-list" role="menu" ng-hide="target.rawQuery">
-          <li class="grafana-target-segment">
-            from series
-          </li>
-
           <li>
           <li>
             <input type="text"
             <input type="text"
-                   class="input-small grafana-target-segment-input"
+                   class="input-large grafana-target-segment-input"
                    ng-model="target.series"
                    ng-model="target.series"
                    spellcheck='false'
                    spellcheck='false'
                    bs-typeahead="listSeries"
                    bs-typeahead="listSeries"
@@ -72,26 +68,11 @@
             select
             select
           </li>
           </li>
 
 
-          <li>
-            <input type="text"
-                   class="input-small grafana-target-segment-input"
-                   ng-model="target.column"
-                   placeholder="value column"
-                   spellcheck='false'
-                   bs-typeahead="listColumns"
-                   data-min-length=0
-                   ng-blur="get_data()">
+          <li class="dropdown">
+            <span influxdb-func-editor class="grafana-target-segment grafana-target-function">
+            </span>
           </li>
           </li>
 
 
-          <li class="grafana-target-segment">
-            function
-          </li>
-          <li>
-            <select class="input-small grafana-target-segment-input"
-                    ng-change="get_data()"
-                    ng-model="target.function"
-                    ng-options="f for f in functions" ></select>
-          </li>
           <li>
           <li>
             <a class="grafana-target-segment"
             <a class="grafana-target-segment"
                ng-click="target.condiction_filter = !target.condiction_filter; get_data();"
                ng-click="target.condiction_filter = !target.condiction_filter; get_data();"
@@ -139,16 +120,16 @@
           </li>
           </li>
 
 
           <li class="grafana-target-segment">
           <li class="grafana-target-segment">
-            alias as
+            as
           </li>
           </li>
 
 
           <li>
           <li>
             <input type="text"
             <input type="text"
-                   class="input-small grafana-target-segment-input"
+                   class="input-medium grafana-target-segment-input"
                    ng-model="target.alias"
                    ng-model="target.alias"
                    spellcheck='false'
                    spellcheck='false'
                    placeholder="alias"
                    placeholder="alias"
-                   ng-blur="seriesBlur()">
+                   ng-blur="get_data()">
           </li>
           </li>
         </ul>
         </ul>
 
 

+ 10 - 2
src/app/services/influxdb/influxdbDatasource.js

@@ -26,6 +26,7 @@ function (angular, _, kbn) {
     InfluxDatasource.prototype.query = function(filterSrv, options) {
     InfluxDatasource.prototype.query = function(filterSrv, options) {
       var promises = _.map(options.targets, function(target) {
       var promises = _.map(options.targets, function(target) {
         var query;
         var query;
+        var alias = '';
 
 
         if (target.hide || !((target.series && target.column) || target.query)) {
         if (target.hide || !((target.series && target.column) || target.query)) {
           return [];
           return [];
@@ -80,10 +81,15 @@ function (angular, _, kbn) {
 
 
           query = _.template(template, templateData, this.templateSettings);
           query = _.template(template, templateData, this.templateSettings);
           query = filterSrv.applyTemplateToTarget(query);
           query = filterSrv.applyTemplateToTarget(query);
+
+          if (target.alias) {
+            alias = filterSrv.applyTemplateToTarget(target.alias);
+          }
+
           target.query = query;
           target.query = query;
         }
         }
 
 
-        return this.doInfluxRequest(query, target.alias).then(handleInfluxQueryResponse);
+        return this.doInfluxRequest(query, alias).then(handleInfluxQueryResponse);
 
 
       }, this);
       }, this);
 
 
@@ -185,9 +191,11 @@ function (angular, _, kbn) {
 
 
           var target = data.alias || series.name + "." + column;
           var target = data.alias || series.name + "." + column;
           var datapoints = [];
           var datapoints = [];
+          var value;
 
 
           for(var i = 0; i < series.points.length; i++) {
           for(var i = 0; i < series.points.length; i++) {
-            datapoints[i] = [series.points[i][index], series.points[i][timeCol]];
+            value = isNaN(series.points[i][index]) ? null : series.points[i][index];
+            datapoints[i] = [value, series.points[i][timeCol]];
           }
           }
 
 
           output.push({ target:target, datapoints:datapoints });
           output.push({ target:target, datapoints:datapoints });