Browse Source

feat(query parts): refactoring query part component to support actions

Torkel Ödegaard 9 years ago
parent
commit
befca9bb2f

+ 20 - 27
public/app/core/components/query_part/query_part_editor.ts

@@ -5,33 +5,34 @@ import $ from 'jquery';
 import coreModule from 'app/core/core_module';
 
 var template = `
-<div class="tight-form-func-controls">
-  <span class="pointer fa fa-remove" ng-click="removeActionInternal()"></span>
-</div>
-
-<a ng-click="toggleControls()" class="query-part-name">{{part.def.type}}</a>
+<div class="dropdown cascade-open">
+<a ng-click="showActionsMenu()" class="query-part-name pointer dropdown-toggle" data-toggle="dropdown">{{part.def.type}}</a>
 <span>(</span><span class="query-part-parameters"></span><span>)</span>
+<ul class="dropdown-menu">
+  <li ng-repeat="action in partActions">
+    <a ng-click="triggerPartAction(action)">{{action.text}}</a>
+  </li>
+</ul>
 `;
 
   /** @ngInject */
 export function queryPartEditorDirective($compile, templateSrv) {
 
-  var paramTemplate = '<input type="text" style="display:none"' +
-    ' class="input-mini tight-form-func-param"></input>';
+  var paramTemplate = '<input type="text" class="hide input-mini tight-form-func-param"></input>';
+
   return {
     restrict: 'E',
     template: template,
     scope: {
       part: "=",
-      removeAction: "&",
-      partUpdated: "&",
-      getOptions: "&",
+      handleEvent: "&",
     },
     link: function postLink($scope, elem) {
       var part = $scope.part;
       var partDef = part.def;
       var $paramsContainer = elem.find('.query-part-parameters');
-      var $controlsContainer = elem.find('.tight-form-func-controls');
+
+      $scope.partActions = [];
 
       function clickFuncParam(paramIndex) {
         /*jshint validthis:true */
@@ -91,7 +92,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
           if (param.options) { return param.options; }
 
           $scope.$apply(function() {
-            $scope.getOptions().then(function(result) {
+            $scope.handleEvent({$event: {name: 'get-param-options'}}).then(function(result) {
               var dynamicOptions = _.map(result, function(op) { return op.value; });
               callback(dynamicOptions);
             });
@@ -124,24 +125,16 @@ export function queryPartEditorDirective($compile, templateSrv) {
         };
       }
 
-      $scope.toggleControls = function() {
-        var targetDiv = elem.closest('.tight-form');
-
-        if (elem.hasClass('show-function-controls')) {
-          elem.removeClass('show-function-controls');
-          targetDiv.removeClass('has-open-function');
-          $controlsContainer.hide();
-          return;
+      $scope.showActionsMenu = function() {
+        if ($scope.partActions.length === 0) {
+          $scope.handleEvent({$event: {name: 'get-part-actions'}}).then(res => {
+            $scope.partActions = res;
+          });
         }
-
-        elem.addClass('show-function-controls');
-        targetDiv.addClass('has-open-function');
-        $controlsContainer.show();
       };
 
-      $scope.removeActionInternal = function() {
-        $scope.toggleControls();
-        $scope.removeAction();
+      $scope.triggerPartAction = function(action) {
+        $scope.handleEvent({$event: {name: 'action-' + action.value}});
       };
 
       function addElementsAndCompile() {

+ 15 - 7
public/app/features/alerting/alert_def.ts

@@ -25,12 +25,6 @@ var alertQueryDef = new QueryPartDef({
   defaultParams: ['#A', '5m', 'now', 'avg']
 });
 
-var reducerAvgDef = new QueryPartDef({
-  type: 'avg',
-  params: [],
-  defaultParams: []
-});
-
 var conditionTypes = [
   {text: 'Query', value: 'query'},
 ];
@@ -43,6 +37,19 @@ var evalFunctions = [
   {text: 'HAS NO VALUE' , value: 'no_value'}
 ];
 
+var reducerTypes = [
+  {text: 'avg()', value: 'avg'},
+  {text: 'min()', value: 'min'},
+  {text: 'max()', value: 'max'},
+  {text: 'sum()' , value: 'sum'},
+  {text: 'count()', value: 'count'},
+];
+
+function createReducerPart(model) {
+  var def = new QueryPartDef({type: model.type, defaultParams: []});
+  return new QueryPart(model, def);
+}
+
 var severityLevels = [
   {text: 'Critical', value: 'critical'},
   {text: 'Warning', value: 'warning'},
@@ -50,9 +57,10 @@ var severityLevels = [
 
 export default {
   alertQueryDef: alertQueryDef,
-  reducerAvgDef: reducerAvgDef,
   getSeverityIconClass: getSeverityIconClass,
   conditionTypes: conditionTypes,
   evalFunctions: evalFunctions,
   severityLevels: severityLevels,
+  reducerTypes: reducerTypes,
+  createReducerPart: createReducerPart,
 };

+ 8 - 1
public/app/features/alerting/alert_tab_ctrl.ts

@@ -16,6 +16,7 @@ export class AlertTabCtrl {
   conditionModels: any;
   evalFunctions: any;
   severityLevels: any;
+  reducerTypes: any;
   addNotificationSegment;
   notifications;
   alertNotifications;
@@ -29,6 +30,7 @@ export class AlertTabCtrl {
     this.evalFunctions = alertDef.evalFunctions;
     this.conditionTypes = alertDef.conditionTypes;
     this.severityLevels = alertDef.severityLevels;
+    this.reducerTypes = alertDef.reducerTypes;
   }
 
   $onInit() {
@@ -148,7 +150,7 @@ export class AlertTabCtrl {
     var cm: any = {source: source, type: source.type};
 
     cm.queryPart = new QueryPart(source.query, alertDef.alertQueryDef);
-    cm.reducerPart = new QueryPart({params: []}, alertDef.reducerAvgDef);
+    cm.reducerPart = alertDef.createReducerPart(source.reducer);
     cm.evaluator = source.evaluator;
 
     return cm;
@@ -157,6 +159,11 @@ export class AlertTabCtrl {
   queryPartUpdated(conditionModel) {
   }
 
+  changeReducerType(conditionModel, value) {
+    conditionModel.source.reducer.type = value;
+    conditionModel.reducerPart = alertDef.createReducerPart(conditionModel.source.reducer);
+  }
+
   addCondition(type) {
     var condition = this.buildDefaultCondition();
     // add to persited model

+ 7 - 0
public/app/features/alerting/partials/alert_tab.html

@@ -55,6 +55,13 @@
 					<div class="gf-form">
 						<span class="gf-form-label">Reducer</span>
 						<query-part-editor class="gf-form-label query-part" part="conditionModel.reducerPart" part-updated="ctrl.reducerPartUpdated(conditionModel)">
+              <query-part-editor-actions>
+                <ul class="dropdown-menu">
+                  <li ng-repeat="reducer in ctrl.reducerTypes">
+                    <a ng-click="ctrl.changeReducerType(conditionModel, reducer.value)" ng-hide="reducer.value === conditionModel.reducerPart.def.type">{{reducer.text}}</a>
+                  </li>
+                </ul>
+              </query-part-editor-actions>
 						</query-part-editor>
 					</div>
 					<div class="gf-form">

+ 1 - 6
public/app/plugins/datasource/influxdb/partials/query.editor.html

@@ -35,12 +35,7 @@
 			</div>
 
 			<div class="gf-form" ng-repeat="part in selectParts">
-				<query-part-editor
-														class="gf-form-label query-part"
-														part="part"
-														remove-action="ctrl.removeSelectPart(selectParts, part)"
-														part-updated="ctrl.selectPartUpdated(selectParts, part)"
-														get-options="ctrl.getPartOptions(part)">
+				<query-part-editor class="gf-form-label query-part" part="part" handle-event="ctrl.handleSelectPartEvent(selectParts, part, $event)">
 				</query-part-editor>
 			</div>
 

+ 18 - 2
public/app/plugins/datasource/influxdb/query_ctrl.ts

@@ -117,8 +117,24 @@ export class InfluxQueryCtrl extends QueryCtrl {
   }
 
   removeSelectPart(selectParts, part) {
-    this.queryModel.removeSelectPart(selectParts, part);
-    this.panelCtrl.refresh();
+ }
+
+  handleSelectPartEvent(selectParts, part, evt) {
+    switch (evt.name) {
+      case "get-param-options": {
+        var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS');
+        return this.datasource.metricFindQuery(fieldsQuery)
+        .then(this.transformToSegments(true))
+        .catch(this.handleQueryError.bind(this));
+      }
+      case "action-remove-part": {
+        this.queryModel.removeSelectPart(selectParts, part);
+        this.panelCtrl.refresh();
+      }
+      case "get-part-actions": {
+        return this.$q.when([{text: 'Remove', value: 'remove-part'}]);
+      }
+    }
   }
 
   selectPartUpdated() {

+ 6 - 0
public/sass/components/_dropdown.scss

@@ -140,6 +140,12 @@
   & > .dropdown-menu {
     display: block;
   }
+
+  &.cascade-open {
+    .dropdown-menu {
+      display: block;
+    }
+  }
 }
 
 // Backdrop to catch body clicks on mobile, etc.