Pārlūkot izejas kodu

feat(graph): more work on graph panel and support for non time series

Torkel Ödegaard 9 gadi atpakaļ
vecāks
revīzija
5682520603

+ 1 - 0
public/app/core/directives/metric_segment.js

@@ -180,6 +180,7 @@ function (_, $, coreModule) {
               value: option ? option.text : value,
               selectMode: attrs.selectMode,
             };
+
             return uiSegmentSrv.newSegment(segment);
           };
 

+ 8 - 2
public/app/plugins/panel/graph/axes_editor.html

@@ -49,9 +49,15 @@
 		</div>
 
     <!-- Table mode -->
-		<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'custom'">
+		<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'field'">
 			<label class="gf-form-label width-5">Name</label>
-      <metric-segment-model property="ctrl.panel.xaxis.name" get-options="ctrl.getDataPropertyNames()" on-change="ctrl.xAxisOptionChanged()" custom="false" css-class="width-10" select-mode="true"></metric-segment-model>
+      <metric-segment-model property="ctrl.panel.xaxis.name" get-options="ctrl.getDataFieldNames(false)" on-change="ctrl.xAxisOptionChanged()" custom="false" css-class="width-10" select-mode="true"></metric-segment-model>
+		</div>
+
+    <!-- Series mode -->
+		<div class="gf-form" ng-if="ctrl.panel.xaxis.mode === 'field'">
+			<label class="gf-form-label width-5">Value</label>
+      <metric-segment-model property="ctrl.panel.xaxis.values[0]" get-options="ctrl.getDataFieldNames(true)" on-change="ctrl.xAxisOptionChanged()" custom="false" css-class="width-10" select-mode="true"></metric-segment-model>
 		</div>
 
 		<!-- Series mode -->

+ 6 - 28
public/app/plugins/panel/graph/axes_editor.ts

@@ -30,7 +30,7 @@ export class AxesEditorCtrl {
     this.xAxisModes = {
       'Time': 'time',
       'Series': 'series',
-      'Custom': 'custom'
+      'Data field': 'field',
     };
 
     this.xAxisStatOptions =  [
@@ -58,37 +58,15 @@ export class AxesEditorCtrl {
   }
 
   xAxisOptionChanged()  {
-    switch (this.panel.xaxis.mode) {
-      case 'time': {
-        this.panel.bars = false;
-        this.panel.lines = true;
-        this.panel.points = false;
-        this.panel.legend.show = true;
-        this.panel.tooltip.shared = true;
-        this.panel.xaxis.values = [];
-        this.panelCtrl.onDataReceived(this.panelCtrl.dataList);
-        break;
-      }
-      case 'series': {
-        this.panel.bars = true;
-        this.panel.lines = false;
-        this.panel.points = false;
-        this.panel.stack = false;
-        this.panel.legend.show = false;
-        this.panel.tooltip.shared = false;
-        this.panelCtrl.processor.validateXAxisSeriesValue();
-        this.panelCtrl.onDataReceived(this.panelCtrl.dataList);
-        break;
-      }
-    }
+    this.panelCtrl.processor.setPanelDefaultsForNewXAxisMode();
+    this.panelCtrl.onDataReceived(this.panelCtrl.dataList);
   }
 
-  getDataPropertyNames() {
-    var props = this.panelCtrl.processor.getDocProperties(this.panelCtrl.dataList);
+  getDataFieldNames(onlyNumbers) {
+    var props = this.panelCtrl.processor.getDataFieldNames(this.panelCtrl.dataList, onlyNumbers);
     var items = props.map(prop => {
-      return {text: prop};
+      return {text: prop, value: prop};
     });
-    console.log(items);
 
     return this.$q.when(items);
   }

+ 78 - 42
public/app/plugins/panel/graph/data_processor.ts

@@ -21,22 +21,60 @@ export class DataProcessor {
     var firstItem;
     if (options.dataList && options.dataList.length > 0) {
       firstItem = options.dataList[0];
-      if (firstItem.type === 'docs') {
-        this.panel.xaxis.mode = 'custom';
+      let autoDetectMode = this.getAutoDetectXAxisMode(firstItem);
+      if (this.panel.xaxis.mode !== autoDetectMode) {
+        this.panel.xaxis.mode = autoDetectMode;
+        this.setPanelDefaultsForNewXAxisMode();
       }
     }
 
     switch (this.panel.xaxis.mode) {
       case 'series':
-      case 'time': {
+        case 'time': {
         return options.dataList.map(this.timeSeriesHandler.bind(this));
       }
-      case 'custom': {
+      case 'field': {
         return this.customHandler(firstItem);
       }
     }
   }
 
+  getAutoDetectXAxisMode(firstItem) {
+    switch (firstItem.type) {
+      case 'docs': return 'field';
+      case 'table': return 'field';
+      default: {
+        if (this.panel.xaxis.mode === 'series') {
+          return 'series';
+        }
+        return 'time';
+      }
+    }
+  }
+
+  setPanelDefaultsForNewXAxisMode() {
+    switch (this.panel.xaxis.mode) {
+      case 'time': {
+        this.panel.bars = false;
+        this.panel.lines = true;
+        this.panel.points = false;
+        this.panel.legend.show = true;
+        this.panel.tooltip.shared = true;
+        this.panel.xaxis.values = [];
+        break;
+      }
+      case 'series': {
+        this.panel.bars = true;
+        this.panel.lines = false;
+        this.panel.points = false;
+        this.panel.stack = false;
+        this.panel.legend.show = false;
+        this.panel.tooltip.shared = false;
+        break;
+      }
+    }
+  }
+
   seriesHandler(seriesData, index, datapoints, alias) {
     var colorIndex = index % colors.length;
     var color = this.panel.aliasColors[alias] || colors[colorIndex];
@@ -71,21 +109,21 @@ export class DataProcessor {
       throw {message: 'No field name specified to use for x-axis, check your axes settings'};
     }
 
-  //   let valueField = this.panel.xaxis.esValueField;
-  //   let datapoints = _.map(seriesData.datapoints, (doc) => {
-  //     return [
-  //       pluckDeep(doc, valueField),  // Y value
-  //       pluckDeep(doc, xField)       // X value
-  //     ];
-  //   });
-  //
-  //   // Remove empty points
-  //   datapoints = _.filter(datapoints, (point) => {
-  //     return point[0] !== undefined;
-  //   });
-  //
-  //   var alias = valueField;
-  //   re
+    //   let valueField = this.panel.xaxis.esValueField;
+    //   let datapoints = _.map(seriesData.datapoints, (doc) => {
+    //     return [
+    //       pluckDeep(doc, valueField),  // Y value
+    //       pluckDeep(doc, xField)       // X value
+    //     ];
+    //   });
+    //
+    //   // Remove empty points
+    //   datapoints = _.filter(datapoints, (point) => {
+    //     return point[0] !== undefined;
+    //   });
+    //
+    //   var alias = valueField;
+    //   re
     return [];
   }
 
@@ -142,18 +180,37 @@ export class DataProcessor {
     }
   }
 
-  getDocProperties(dataList) {
+  getDataFieldNames(dataList, onlyNumbers) {
     if (dataList.length === 0) {
       return [];
     }
 
+    let fields = [];
     var firstItem = dataList[0];
     if (firstItem.type === 'docs'){
       if (firstItem.datapoints.length === 0) {
         return [];
       }
 
-      return this.getPropertiesFromDoc(firstItem.datapoints[0]);
+      let fieldParts = [];
+
+      function getPropertiesRecursive(obj) {
+        _.forEach(obj, (value, key) => {
+          if (_.isObject(value)) {
+            fieldParts.push(key);
+            getPropertiesRecursive(value);
+          } else {
+            if (!onlyNumbers || _.isNumber(value)) {
+              let field = fieldParts.concat(key).join('.');
+              fields.push(field);
+            }
+          }
+        });
+        fieldParts.pop();
+      }
+
+      getPropertiesRecursive(firstItem.datapoints[0]);
+      return fields;
     }
   }
 
@@ -174,27 +231,6 @@ export class DataProcessor {
     }
   }
 
-  getPropertiesFromDoc(doc) {
-    let props = [];
-    let propParts = [];
-
-    function getPropertiesRecursive(obj) {
-      _.forEach(obj, (value, key) => {
-        if (_.isObject(value)) {
-          propParts.push(key);
-          getPropertiesRecursive(value);
-        } else {
-          let field = propParts.concat(key).join('.');
-          props.push(field);
-        }
-      });
-      propParts.pop();
-    }
-
-    getPropertiesRecursive(doc);
-    return props;
-  }
-
   pluckDeep(obj: any, property: string) {
     let propertyParts = property.split('.');
     let value = obj;

+ 13 - 16
public/app/plugins/panel/graph/graph.js

@@ -258,29 +258,26 @@ function (angular, $, moment, _, kbn, GraphTooltip, thresholdManExports) {
             }
           }
 
-          if (panel.xaxis.mode === 'series') {
-            if (data.length) {
+          switch(panel.xaxis.mode) {
+            case 'series': {
               options.series.bars.barWidth = 0.7;
               options.series.bars.align = 'center';
+              addXSeriesAxis(options);
+              break;
             }
-
-            addXSeriesAxis(options);
-
-          } else if (panel.xaxis.mode === 'table' ||
-                     panel.xaxis.mode === 'elastic') {
-            if (data.length) {
+            case 'table': {
               options.series.bars.barWidth = 0.7;
               options.series.bars.align = 'center';
+              addXTableAxis(options);
+              break;
             }
-
-            addXTableAxis(options);
-
-          } else {
-            if (data.length && data[0].stats.timeStep) {
-              options.series.bars.barWidth = data[0].stats.timeStep / 1.5;
+            default: {
+              if (data.length && data[0].stats.timeStep) {
+                options.series.bars.barWidth = data[0].stats.timeStep / 1.5;
+              }
+              addTimeAxis(options);
+              break;
             }
-
-            addTimeAxis(options);
           }
 
           thresholdManager.addPlotOptions(options, panel);

+ 28 - 2
public/app/plugins/panel/graph/specs/data_processor_specs.ts

@@ -28,11 +28,37 @@ describe('Graph DataProcessor', function() {
       });
     });
 
-    it('Should automatically set xaxis mode to custom', () => {
-      expect(panel.xaxis.mode).to.be('custom');
+    it('Should automatically set xaxis mode to field', () => {
+      expect(panel.xaxis.mode).to.be('field');
     });
 
   });
 
+  describe('getDataFieldNames(', () => {
+    var dataList = [{
+      type: 'docs', datapoints: [
+        {
+          hostname: "server1",
+          valueField: 11,
+          nested: {
+            prop1: 'server2', value2: 23}
+        }
+      ]
+    }];
+
+    it('Should return all field names', () => {
+      var fields = processor.getDataFieldNames(dataList, false);
+      expect(fields).to.contain('hostname');
+      expect(fields).to.contain('valueField');
+      expect(fields).to.contain('nested.prop1');
+      expect(fields).to.contain('nested.value2');
+    });
+
+    it('Should return all number fields', () => {
+      var fields = processor.getDataFieldNames(dataList, true);
+      expect(fields).to.contain('valueField');
+      expect(fields).to.contain('nested.value2');
+    });
+  });
 });