Explorar el Código

Working on new query editor for influxdb 0.9, #1525

Torkel Ödegaard hace 10 años
padre
commit
11c8e80ea9

+ 1 - 1
public/app/directives/all.js

@@ -12,7 +12,7 @@ define([
   './bootstrap-tagsinput',
   './bodyClass',
   './variableValueSelect',
-  './graphiteSegment',
+  './metric.segment',
   './grafanaVersionCheck',
   './dropdown.typeahead',
   './topnav',

+ 10 - 3
public/app/directives/graphiteSegment.js → public/app/directives/metric.segment.js

@@ -9,7 +9,7 @@ function (angular, app, _, $) {
 
   angular
     .module('grafana.directives')
-    .directive('graphiteSegment', function($compile, $sce) {
+    .directive('metricSegment', function($compile, $sce) {
       var inputTemplate = '<input type="text" data-provide="typeahead" ' +
                             ' class="tight-form-clear-input input-medium"' +
                             ' spellcheck="false" style="display:none"></input>';
@@ -17,6 +17,12 @@ function (angular, app, _, $) {
       var buttonTemplate = '<a class="tight-form-item" tabindex="1" focus-me="segment.focus" ng-bind-html="segment.html"></a>';
 
       return {
+        scope: {
+          segment: "=",
+          getAltSegments: "&",
+          onValueChanged: "&"
+        },
+
         link: function($scope, elem) {
           var $input = $(inputTemplate);
           var $button = $(buttonTemplate);
@@ -46,7 +52,7 @@ function (angular, app, _, $) {
                 segment.expandable = true;
                 segment.fake = false;
               }
-              $scope.segmentValueChanged(segment, $scope.$index);
+              $scope.onValueChanged();
             });
           };
 
@@ -69,7 +75,8 @@ function (angular, app, _, $) {
             if (options) { return options; }
 
             $scope.$apply(function() {
-              $scope.getAltSegments($scope.$index).then(function() {
+              $scope.getAltSegments().then(function(altSegments) {
+                $scope.altSegments = altSegments;
                 options = _.map($scope.altSegments, function(alt) { return alt.value; });
 
                 // add custom values

+ 3 - 1
public/app/plugins/datasource/graphite/partials/query.editor.html

@@ -74,7 +74,9 @@
               ng-show="showTextEditor" />
 
       <ul class="tight-form-list" role="menu" ng-hide="showTextEditor">
-        <li ng-repeat="segment in segments" role="menuitem" graphite-segment></li>
+				<li ng-repeat="segment in segments" role="menuitem">
+					<metric-segment segment="segment" get-alt-segments="getAltSegments($index)" on-value-changed="segmentValueChanged(segment, $index)"></metric-segment>
+				</li>
 				<li ng-repeat="func in functions">
           <span graphite-func-editor class="tight-form-item tight-form-func">
           </span>

+ 7 - 10
public/app/plugins/datasource/graphite/queryCtrl.js

@@ -152,23 +152,18 @@ function (angular, _, config, gfunc, Parser) {
     }
 
     $scope.getAltSegments = function (index) {
-      $scope.altSegments = [];
-
       var query = index === 0 ?  '*' : getSegmentPathUpTo(index) + '.*';
 
-      return $scope.datasource.metricFindQuery(query)
-        .then(function(segments) {
-          $scope.altSegments = _.map(segments, function(segment) {
+      return $scope.datasource.metricFindQuery(query).then(function(segments) {
+          var altSegments = _.map(segments, function(segment) {
             return new MetricSegment({ value: segment.text, expandable: segment.expandable });
           });
 
-          if ($scope.altSegments.length === 0) {
-            return;
-          }
+          if (altSegments.length === 0) { return altSegments; }
 
           // add template variables
           _.each(templateSrv.variables, function(variable) {
-            $scope.altSegments.unshift(new MetricSegment({
+            altSegments.unshift(new MetricSegment({
               type: 'template',
               value: '$' + variable.name,
               expandable: true,
@@ -176,10 +171,12 @@ function (angular, _, config, gfunc, Parser) {
           });
 
           // add wildcard option
-          $scope.altSegments.unshift(new MetricSegment('*'));
+          altSegments.unshift(new MetricSegment('*'));
+          return altSegments;
         })
         .then(null, function(err) {
           $scope.parserError = err.message || 'Failed to issue metric query';
+          return [];
         });
     };
 

+ 1 - 1
public/app/plugins/datasource/influxdb/funcEditor.js

@@ -108,7 +108,7 @@ function (angular, _, $) {
           function addElementsAndCompile() {
             $funcLink.appendTo(elem);
 
-            var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + $scope.target.column + '</a>');
+            var $paramLink = $('<a ng-click="" class="graphite-func-param-link">value</a>');
             var $input = $(paramTemplate);
 
             $paramLink.appendTo(elem);

+ 45 - 14
public/app/plugins/datasource/influxdb/partials/query.editor.html

@@ -62,23 +62,54 @@
 				</li>
 			</ul>
 
-			<input  type="text"
-			        class="tight-form-clear-input span10"
-              ng-model="target.query"
-              focus-me="target.rawQuery"
-              spellcheck='false'
-              ng-model-onblur ng-change="targetTextChanged()"
-              ng-show="target.rawQuery" />
+			<input  type="text" class="tight-form-clear-input span10" ng-model="target.query" focus-me="target.rawQuery"
+              spellcheck='false' ng-model-onblur ng-change="targetTextChanged()" ng-show="target.rawQuery" />
 
       <ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
-        <li ng-repeat="segment in segments" role="menuitem" graphite-segment></li>
-				<li ng-repeat="func in functions">
-          <span graphite-func-editor class="tight-form-item tight-form-func">
-          </span>
-        </li>
-        <li class="dropdown" graphite-add-func>
-        </li>
+				<li class="tight-form-item query-keyword">
+					SELECT
+				</li>
+				<li class="dropdown tight-form-item">
+					<a gf-dropdown="functionMenu" class="dropdown-toggle" data-toggle="dropdown">
+						{{target.function}}<span>(value)</span>
+					</a>
+				</li>
+				<li class="tight-form-item query-keyword">
+					FROM
+				</li>
+				<li>
+					<metric-segment segment="measurementSegment" get-alt-segments="getMeasurements()" on-value-changed="measurementChanged()"></metric-segment>
+				</li>
+				<li class="tight-form-item query-keyword">
+					WHERE
+				</li>
+				<li>
+					<input type="text" class="input-medium tight-form-input" ng-model="target.condition"
+					  bs-tooltip="'Add a where clause'" data-placement="right" spellcheck='false' placeholder="column ~= value" ng-blur="get_data()">
+				</li>
+				<li class="tight-form-item">
+					<span class="query-keyword">GROUP BY</span>
+					time($interval), <i class="fa fa-plus"></i>
+				</li>
+
+				<li class="dropdown">
+					<a class="tight-form-item pointer" data-toggle="dropdown" bs-tooltip="'Insert missing values, important when stacking'" data-placement="right">
+						<span ng-show="target.fill">
+							fill ({{target.fill}})
+						</span>
+						<span ng-show="!target.fill">
+							no fill
+						</span>
+					</a>
+					<ul class="dropdown-menu">
+						<li><a ng-click="target.fill = ''">no fill</a></li>
+						<li><a ng-click="target.fill = 'null'">fill (null)</a></li>
+						<li><a ng-click="target.fill = '0'">fill (0)</a></li>
+					</ul>
+				</li>
+
       </ul>
+
       <div class="clearfix"></div>
     </div>
 </div>

+ 54 - 93
public/app/plugins/datasource/influxdb/queryCtrl.js

@@ -7,19 +7,39 @@ function (angular, _) {
 
   var module = angular.module('grafana.controllers');
 
-  module.controller('InfluxQueryCtrl', function($scope, $timeout, $sce, templateSrv, $q) {
+  module.controller('InfluxQueryCtrl', function($scope, $timeout, $sce, templateSrv) {
+
+    $scope.functionList = [
+      'count', 'mean', 'sum', 'min',
+      'max', 'mode', 'distinct', 'median',
+      'derivative', 'stddev', 'first', 'last',
+      'difference'
+    ];
+
+    $scope.functionMenu = _.map($scope.functionList, function(func) {
+      return { text: func, click: "changeFunction('" + func + "');" };
+    });
 
     $scope.init = function() {
-      $scope.segments = $scope.target.segments || [];
+      var target = $scope.target;
+      target.function = target.function || 'mean';
 
-      $scope.functionsSelect = [
-        'count', 'mean', 'sum', 'min',
-        'max', 'mode', 'distinct', 'median',
-        'derivative', 'stddev', 'first', 'last',
-        'difference'
-      ];
+      if (!target.measurement) {
+        $scope.measurementSegment = MetricSegment.newSelectMeasurement();
+      } else {
+        $scope.measurementSegment = new MetricSegment(target.measurement);
+      }
+    };
 
-      checkOtherSegments(0);
+    $scope.changeFunction = function(func) {
+      $scope.target.function = func;
+      $scope.$parent.get_data();
+    };
+
+    $scope.measurementChanged = function() {
+      $scope.target.measurement = $scope.measurementSegment.value;
+      console.log('measurement updated', $scope.target.measurement);
+      $scope.$parent.get_data();
     };
 
     $scope.toggleQueryMode = function () {
@@ -35,103 +55,44 @@ function (angular, _) {
       $scope.panel.targets.push(clone);
     };
 
-    $scope.getAltSegments = function (index) {
-      $scope.altSegments = [];
-
-      var measurement = $scope.segments[0].value;
-      var queryType, query;
-      if (index === 0) {
-        queryType = 'MEASUREMENTS';
-        query = 'SHOW MEASUREMENTS';
-      } else if (index % 2 === 1) {
-        queryType = 'TAG_KEYS';
-        query = 'SHOW TAG KEYS FROM "' + measurement + '"';
-      } else {
-        queryType = 'TAG_VALUES';
-        query = 'SHOW TAG VALUES FROM "' + measurement + '" WITH KEY = ' + $scope.segments[$scope.segments.length - 2].value;
-      }
-
-      console.log('getAltSegments: query' , query);
-
-      return $scope.datasource.metricFindQuery(query, queryType).then(function(results) {
+    $scope.getMeasurements = function () {
+      // var measurement = $scope.segments[0].value;
+      // var queryType, query;
+      // if (index === 0) {
+      //   queryType = 'MEASUREMENTS';
+      //   query = 'SHOW MEASUREMENTS';
+      // } else if (index % 2 === 1) {
+      //   queryType = 'TAG_KEYS';
+      //   query = 'SHOW TAG KEYS FROM "' + measurement + '"';
+      // } else {
+      //   queryType = 'TAG_VALUES';
+      //   query = 'SHOW TAG VALUES FROM "' + measurement + '" WITH KEY = ' + $scope.segments[$scope.segments.length - 2].value;
+      // }
+      //
+      // console.log('getAltSegments: query' , query);
+      //
+      console.log('get measurements');
+      return $scope.datasource.metricFindQuery('SHOW MEASUREMENTS', 'MEASUREMENTS').then(function(results) {
         console.log('get alt segments: response', results);
-        $scope.altSegments = _.map(results, function(segment) {
+        var measurements = _.map(results, function(segment) {
           return new MetricSegment({ value: segment.text, expandable: segment.expandable });
         });
 
         _.each(templateSrv.variables, function(variable) {
-          $scope.altSegments.unshift(new MetricSegment({
+          measurements.unshift(new MetricSegment({
             type: 'template',
             value: '$' + variable.name,
             expandable: true,
           }));
         });
+
+        return measurements;
       }, function(err) {
         $scope.parserError = err.message || 'Failed to issue metric query';
+        return [];
       });
     };
 
-    $scope.segmentValueChanged = function (segment, segmentIndex) {
-      delete $scope.parserError;
-
-      if (segment.expandable) {
-        return checkOtherSegments(segmentIndex + 1).then(function () {
-          setSegmentFocus(segmentIndex + 1);
-          $scope.targetChanged();
-        });
-      }
-      else {
-        $scope.segments = $scope.segments.splice(0, segmentIndex + 1);
-      }
-
-      setSegmentFocus(segmentIndex + 1);
-      $scope.targetChanged();
-    };
-
-    $scope.targetChanged = function() {
-      if ($scope.parserError) {
-        return;
-      }
-
-      $scope.target.measurement = '';
-      $scope.target.tags = {};
-      $scope.target.measurement = $scope.segments[0].value;
-
-      for (var i = 1; i+1 < $scope.segments.length; i += 2) {
-        var key = $scope.segments[i].value;
-        $scope.target.tags[key] = $scope.segments[i+1].value;
-      }
-
-      $scope.$parent.get_data();
-    };
-
-    function checkOtherSegments(fromIndex) {
-      if (fromIndex === 0) {
-        $scope.segments.push(MetricSegment.newSelectMetric());
-        return;
-      }
-
-      if ($scope.segments.length === 0) {
-        throw('should always have a scope segment?');
-      }
-
-      if (_.last($scope.segments).fake) {
-        return $q.when([]);
-      } else if ($scope.segments.length % 2 === 1) {
-        $scope.segments.push(MetricSegment.newSelectTag());
-        return $q.when([]);
-      } else {
-        $scope.segments.push(MetricSegment.newSelectTagValue());
-        return $q.when([]);
-      }
-    }
-
-    function setSegmentFocus(segmentIndex) {
-      _.each($scope.segments, function(segment, index) {
-        segment.focus = segmentIndex === index;
-      });
-    }
-
     function MetricSegment(options) {
       if (options === '*' || options.value === '*') {
         this.value = '*';
@@ -153,8 +114,8 @@ function (angular, _) {
       this.html = $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
     }
 
-    MetricSegment.newSelectMetric = function() {
-      return new MetricSegment({value: 'select metric', fake: true});
+    MetricSegment.newSelectMeasurement = function() {
+      return new MetricSegment({value: 'select measurement', fake: true});
     };
 
     MetricSegment.newSelectTag = function() {

+ 7 - 0
public/css/less/grafana.less

@@ -337,3 +337,10 @@
     text-overflow: ellipsis;
   }
 }
+
+.query-keyword {
+  font-weight: bold;
+  color: @blue;
+}
+
+

+ 4 - 2
public/test/specs/graphiteTargetCtrl-specs.js

@@ -141,13 +141,15 @@ define([
         ctx.scope.target.target = 'test.count';
         ctx.scope.datasource.metricFindQuery.returns(ctx.$q.when([]));
         ctx.scope.init();
-        ctx.scope.getAltSegments(1);
+        ctx.scope.getAltSegments(1).then(function(results) {
+          ctx.altSegments = results;
+        });
         ctx.scope.$digest();
         ctx.scope.$parent = { get_data: sinon.spy() };
       });
 
       it('should have no segments', function() {
-        expect(ctx.scope.altSegments.length).to.be(0);
+        expect(ctx.altSegments.length).to.be(0);
       });
 
     });