Pārlūkot izejas kodu

graphite-tags: refactor, use <gf-form-dropdown> instead of <metric-segment>

Alexander Zobnin 8 gadi atpakaļ
vecāks
revīzija
63d51d0db3

+ 19 - 5
public/app/plugins/datasource/graphite/partials/query.editor.html

@@ -10,13 +10,27 @@
         <label class="gf-form-label query-keyword">seriesByTag</label>
       </div>
 
-      <div ng-repeat="tagSegment in ctrl.tagSegments" role="menuitem" class="gf-form">
-        <metric-segment segment="tagSegment"
-          get-options="ctrl.getAltTagSegments($index)"
-          on-change="ctrl.tagSegmentChanged(tagSegment, $index)">
-        </metric-segment>
+      <div ng-repeat="tag in ctrl.tags" class="gf-form">
+        <gf-form-dropdown model="tag.key" lookup-text="false" allow-custom="false" label-mode="true" css-class="query-segment-key"
+          get-options="ctrl.getTags()"
+          on-change="ctrl.tagChanged(tag, $index)">
+        </gf-form-dropdown>
+        <gf-form-dropdown model="tag.operator" lookup-text="false" allow-custom="false" label-mode="true" css-class="query-segment-operator"
+          get-options="ctrl.getTagOperators()"
+          on-change="ctrl.tagChanged(tag, $index)">
+        </gf-form-dropdown>
+        <gf-form-dropdown model="tag.value" lookup-text="false" allow-custom="false" label-mode="true" css-class="query-segment-value"
+          get-options="ctrl.getTagValues(tag)"
+          on-change="ctrl.tagChanged(tag, $index)">
+        </gf-form-dropdown>
         <label class="gf-form-label query-keyword" ng-if="ctrl.showDelimiter($index)">,</label>
       </div>
+      <div ng-if="ctrl.seriesByTagUsed" ng-repeat="segment in ctrl.addTagSegments" role="menuitem" class="gf-form">
+        <metric-segment segment="segment"
+          get-options="ctrl.getTagsAsSegments()"
+          on-change="ctrl.addNewTag(segment)">
+        </metric-segment>
+      </div>
 
       <div ng-repeat="segment in ctrl.segments" role="menuitem" class="gf-form">
         <metric-segment segment="segment" get-options="ctrl.getAltSegments($index)" on-change="ctrl.segmentValueChanged(segment, $index)"></metric-segment>

+ 117 - 127
public/app/plugins/datasource/graphite/query_ctrl.ts

@@ -7,14 +7,17 @@ import {Parser} from './parser';
 import {QueryCtrl} from 'app/plugins/sdk';
 import appEvents from 'app/core/app_events';
 
+const GRAPHITE_TAG_OPERATORS = ['=', '!=', '=~', '!=~'];
+
 export class GraphiteQueryCtrl extends QueryCtrl {
   static templateUrl = 'partials/query.editor.html';
 
   functions: any[];
   segments: any[];
-  tagSegments: any[];
+  addTagSegments: any[];
+  tags: any[];
   seriesByTagUsed: boolean;
-  removeTagSegment: any;
+  removeTagValue: string;
 
   /** @ngInject **/
   constructor($scope, $injector, private uiSegmentSrv, private templateSrv) {
@@ -25,7 +28,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
       this.parseTarget();
     }
 
-    this.removeTagSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove tag --'});
+    this.removeTagValue = '-- remove tag --';
   }
 
   toggleEditorMode() {
@@ -120,40 +123,6 @@ export class GraphiteQueryCtrl extends QueryCtrl {
     return func.def.name !== 'seriesByTag';
   }
 
-  checkForSeriesByTag() {
-    let seriesByTagFunc = _.find(this.functions, (func) => func.def.name === 'seriesByTag');
-    if (seriesByTagFunc) {
-      this.seriesByTagUsed = true;
-      let tags = this.splitSeriesByTagParams(seriesByTagFunc);
-      this.tagSegments = [];
-      _.each(tags, (tag) => {
-        this.tagSegments.push(this.uiSegmentSrv.newKey(tag.key));
-        this.tagSegments.push(this.uiSegmentSrv.newOperator(tag.operator));
-        this.tagSegments.push(this.uiSegmentSrv.newKeyValue(tag.value));
-      });
-
-      this.fixTagSegments();
-    }
-  }
-
-  splitSeriesByTagParams(func) {
-    const tagPattern = /([^\!=~]+)([\!=~]+)([^\!=~]+)/;
-    return _.flatten(_.map(func.params, (param: string) => {
-      let matches = tagPattern.exec(param);
-      if (matches) {
-        let tag = matches.slice(1);
-        if (tag.length === 3) {
-          return {
-            key: tag[0],
-            operator: tag[1],
-            value: tag[2]
-          }
-        }
-      }
-      return [];
-    }));
-  }
-
   getSegmentPathUpTo(index) {
     var arr = this.segments.slice(0, index);
 
@@ -201,36 +170,6 @@ export class GraphiteQueryCtrl extends QueryCtrl {
     return func.render(target);
   }
 
-  getAltTagSegments(index) {
-    let paramPartIndex = getParamPartIndex(index);
-
-    if (paramPartIndex === 1) {
-      // Operator
-      let operators = ['=', '!=', '=~', '!=~'];
-      let segments = _.map(operators, (operator) => this.uiSegmentSrv.newOperator(operator));
-      return Promise.resolve(segments);
-    } else if (paramPartIndex === 0) {
-      // Tag
-      return this.datasource.getTags().then(segments => {
-        let altSegments = _.map(segments, segment => {
-          return this.uiSegmentSrv.newSegment({value: segment.text, expandable: false});
-        });
-        altSegments.splice(0, 0, _.cloneDeep(this.removeTagSegment));
-        return altSegments;
-      });
-    } else {
-      // Tag value
-      let relatedTagSegmentIndex = getRelatedTagSegmentIndex(index);
-      let tag = this.tagSegments[relatedTagSegmentIndex].value;
-      return this.datasource.getTagValues(tag).then(segments => {
-        let altSegments = _.map(segments, segment => {
-          return this.uiSegmentSrv.newSegment({value: segment.text, expandable: false});
-        });
-        return altSegments;
-      });
-    }
-  }
-
   getAltSegments(index) {
     var query = index === 0 ?  '*' : this.getSegmentPathUpTo(index) + '.*';
     var options = {range: this.panelCtrl.range, requestId: "get-alt-segments"};
@@ -279,52 +218,6 @@ export class GraphiteQueryCtrl extends QueryCtrl {
     this.targetChanged();
   }
 
-  tagSegmentChanged(tagSegment, segmentIndex) {
-    this.error = null;
-
-    if (tagSegment.value === this.removeTagSegment.value) {
-      this.removeTag(segmentIndex);
-      return;
-    }
-
-    if (tagSegment.type === 'plus-button') {
-      let newTag = {key: tagSegment.value, operator: '=', value: 'select tag value'};
-      this.tagSegments.splice(this.tagSegments.length - 1, 1);
-      this.addNewTag(newTag);
-    }
-
-    let paramIndex = getParamIndex(segmentIndex);
-    let newTagParam = this.renderTagParam(segmentIndex);
-    this.functions[this.getSeriesByTagFuncIndex()].params[paramIndex] = newTagParam;
-
-    this.targetChanged();
-    this.parseTarget();
-  }
-
-  getSeriesByTagFuncIndex() {
-    return _.findIndex(this.functions, (func) => func.def.name === 'seriesByTag');
-  }
-
-  addNewTag(tag) {
-    this.tagSegments.push(this.uiSegmentSrv.newKey(tag.key));
-    this.tagSegments.push(this.uiSegmentSrv.newOperator(tag.operator));
-    this.tagSegments.push(this.uiSegmentSrv.newKeyValue(tag.value));
-  }
-
-  removeTag(index) {
-    let paramIndex = getParamIndex(index);
-    this.tagSegments.splice(index, 3);
-    this.functions[this.getSeriesByTagFuncIndex()].params.splice(paramIndex, 1);
-
-    this.targetChanged();
-    this.parseTarget();
-  }
-
-  renderTagParam(segmentIndex) {
-    let tagIndex = getRelatedTagSegmentIndex(segmentIndex)
-    return _.map(this.tagSegments.slice(tagIndex, tagIndex + 3), (segment) => segment.value).join('');
-  }
-
   targetTextChanged() {
     this.updateModelTarget();
     this.refresh();
@@ -454,28 +347,125 @@ export class GraphiteQueryCtrl extends QueryCtrl {
     }
   }
 
-  fixTagSegments() {
-    var count = this.tagSegments.length;
-    var lastSegment = this.tagSegments[Math.max(count-1, 0)];
+  //////////////////////////////////
+  // Graphite seriesByTag support //
+  //////////////////////////////////
+
+  checkForSeriesByTag() {
+    let seriesByTagFunc = _.find(this.functions, (func) => func.def.name === 'seriesByTag');
+    if (seriesByTagFunc) {
+      this.seriesByTagUsed = true;
+      let tags = this.splitSeriesByTagParams(seriesByTagFunc);
+      this.tags = tags;
+      this.fixTagSegments();
+    }
+  }
+
+  splitSeriesByTagParams(func) {
+    const tagPattern = /([^\!=~]+)([\!=~]+)([^\!=~]+)/;
+    return _.flatten(_.map(func.params, (param: string) => {
+      let matches = tagPattern.exec(param);
+      if (matches) {
+        let tag = matches.slice(1);
+        if (tag.length === 3) {
+          return {
+            key: tag[0],
+            operator: tag[1],
+            value: tag[2]
+          }
+        }
+      }
+      return [];
+    }));
+  }
 
-    if (!lastSegment || lastSegment.type !== 'plus-button') {
-      this.tagSegments.push(this.uiSegmentSrv.newPlusButton());
+  getTags() {
+    return this.datasource.getTags().then((values) => {
+      let altTags = _.map(values, 'text');
+      altTags.splice(0, 0, this.removeTagValue);
+      return mapToDropdownOptions(altTags);
+    });
+  }
+
+  getTagsAsSegments() {
+    return this.datasource.getTags().then((values) => {
+      return _.map(values, (val) => {
+        return this.uiSegmentSrv.newSegment(val.text);
+      });
+    });
+  }
+
+  getTagOperators() {
+    return mapToDropdownOptions(GRAPHITE_TAG_OPERATORS);
+  }
+
+  getTagValues(tag) {
+    let tagKey = tag.key;
+    return this.datasource.getTagValues(tagKey).then((values) => {
+      let altValues = _.map(values, 'text');
+      return mapToDropdownOptions(altValues);
+    });
+  }
+
+  tagChanged(tag, tagIndex) {
+    this.error = null;
+
+    if (tag.key === this.removeTagValue) {
+      this.removeTag(tagIndex);
+      return;
     }
+
+    let newTagParam = renderTagString(tag);
+    this.getSeriesByTagFunc().params[tagIndex] = newTagParam;
+    this.targetChanged();
+    this.parseTarget();
   }
 
-  showDelimiter(index) {
-    return getParamPartIndex(index) === 2 && index !== this.tagSegments.length - 2;
+  getSeriesByTagFuncIndex() {
+    return _.findIndex(this.functions, (func) => func.def.name === 'seriesByTag');
   }
-}
 
-function getParamIndex(segmentIndex) {
-  return Math.floor(segmentIndex / 3);
+  getSeriesByTagFunc() {
+    let seriesByTagFuncIndex = this.getSeriesByTagFuncIndex();
+    if (seriesByTagFuncIndex >= 0) {
+      return this.functions[seriesByTagFuncIndex];
+    } else {
+      return undefined;
+    }
+  }
+
+  addNewTag(segment) {
+    let newTagKey = segment.value;
+    let newTag = {key: newTagKey, operator: '=', value: 'select tag value'};
+    let newTagParam = renderTagString(newTag);
+    this.getSeriesByTagFunc().params.push(newTagParam);
+    this.targetChanged();
+    this.parseTarget();
+  }
+
+  removeTag(index) {
+    this.getSeriesByTagFunc().params.splice(index, 1);
+
+    this.targetChanged();
+    this.parseTarget();
+  }
+
+  fixTagSegments() {
+    // Adding tag with the same name as just removed works incorrectly if single segment is used (instead of array)
+    this.addTagSegments = [this.uiSegmentSrv.newPlusButton()];
+  }
+
+  showDelimiter(index) {
+    return index !== this.tags.length - 1;
+  }
 }
 
-function getParamPartIndex(segmentIndex) {
-  return segmentIndex % 3;
+function renderTagString(tag) {
+  return tag.key + tag.operator + tag.value;
 }
 
-function getRelatedTagSegmentIndex(segmentIndex) {
-  return getParamIndex(segmentIndex) * 3;
+function mapToDropdownOptions(results) {
+  return _.map(results, (value) => {
+    return {text: value, value: value};
+  });
 }