Commit 7666e7bf by Erik Sundell

stackdriver: break out aggretation logic into its own directive and controller.…

stackdriver: break out aggretation logic into its own directive and controller. also adds tests for new dropdown population logic
parent b700c6b0
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label query-keyword width-9">Aggregation</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-12" ng-model="target.aggregation.crossSeriesReducer" ng-options="f.value as f.text for f in getAggOptions()"
ng-change="onAggregationChange(target.aggregation.crossSeriesReducer)"></select>
</div>
</div>
<div class="gf-form gf-form--grow">
<label class="gf-form-label gf-form-label--grow">
<a ng-click="target.showAggregationOptions = !target.showAggregationOptions">
<i class="fa fa-caret-down" ng-show="target.showAggregationOptions"></i>
<i class="fa fa-caret-right" ng-hide="target.showAggregationOptions"></i>
Advanced Options
</a>
</label>
</div>
</div>
<div class="gf-form-group" ng-if="target.showAggregationOptions">
<div class="gf-form offset-width-9">
<label class="gf-form-label query-keyword width-12">Aligner</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-14" ng-model="target.aggregation.perSeriesAligner" ng-options="f.value as f.text for f in getAlignOptions()"
ng-change="onAlignmentChange(target.aggregation.perSeriesAligner)"></select>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form offset-width-9">
<label class="gf-form-label query-keyword width-12">Alignment Period</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-14" ng-model="target.aggregation.alignmentPeriod" ng-options="f.value as f.text for f in alignmentPeriods"
ng-change="refresh()"></select>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
</div>
\ No newline at end of file
......@@ -31,48 +31,7 @@
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label query-keyword width-9">Aggregation</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-12" ng-model="ctrl.target.aggregation.crossSeriesReducer" ng-options="f.value as f.text for f in ctrl.getAggOptions()"
ng-change="ctrl.refresh()"></select>
</div>
</div>
<div class="gf-form gf-form--grow">
<label class="gf-form-label gf-form-label--grow">
<a ng-click="ctrl.target.showAggregationOptions = !ctrl.target.showAggregationOptions">
<i class="fa fa-caret-down" ng-show="ctrl.target.showAggregationOptions"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.target.showAggregationOptions"></i>
Advanced Options
</a>
</label>
</div>
</div>
<div class="gf-form-group" ng-if="ctrl.target.showAggregationOptions">
<div class="gf-form offset-width-9">
<label class="gf-form-label query-keyword width-12">Aligner</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-14" ng-model="ctrl.target.aggregation.perSeriesAligner" ng-options="f.value as f.text for f in ctrl.getAlignOptions()"
ng-change="ctrl.refresh()"></select>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form offset-width-9">
<label class="gf-form-label query-keyword width-12">Alignment Period</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input width-14" ng-model="ctrl.target.aggregation.alignmentPeriod" ng-options="f.value as f.text for f in ctrl.stackdriverConstants.alignmentPeriods"
ng-change="ctrl.refresh()"></select>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
</div>
<stackdriver-aggregation target="ctrl.target" refresh="ctrl.refresh()"></stackdriver-aggregation>
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label query-keyword width-9">Alias By</span>
......
import angular from 'angular';
import _ from 'lodash';
import * as options from './constants';
export class StackdriverAggregation {
constructor() {
return {
templateUrl: 'public/app/plugins/datasource/stackdriver/partials/query.aggregation.html',
controller: 'StackdriverAggregationCtrl',
restrict: 'E',
scope: {
target: '=',
refresh: '&',
},
};
}
}
export class StackdriverAggregationCtrl {
target: any;
alignOptions: any[];
aggOptions: any[];
refresh: () => void;
constructor(private $scope) {
this.aggOptions = options.aggOptions;
this.alignOptions = options.alignOptions;
$scope.alignmentPeriods = options.alignmentPeriods;
$scope.getAlignOptions = this.getAlignOptions;
$scope.getAggOptions = this.getAggOptions;
$scope.onAlignmentChange = this.onAlignmentChange;
$scope.onAggregationChange = this.onAggregationChange;
this.refresh = $scope.refresh;
}
onAlignmentChange(newVal) {
if (newVal === 'ALIGN_NONE') {
this.target.aggregation.crossSeriesReducer = 'REDUCE_NONE';
}
this.refresh();
}
onAggregationChange(newVal) {
if (newVal !== 'REDUCE_NONE') {
const newAlignmentOption = options.alignOptions.find(o => o.value !== 'ALIGN_NONE');
this.target.aggregation.perSeriesAligner = newAlignmentOption ? newAlignmentOption.value : '';
}
this.refresh();
}
getAlignOptions() {
return !this.target.valueType
? options.alignOptions
: options.alignOptions.filter(i => {
return (
i.valueTypes.indexOf(this.target.valueType) !== -1 && i.metricKinds.indexOf(this.target.metricKind) !== -1
);
});
}
getAggOptions() {
return !this.target.metricKind
? options.aggOptions
: options.aggOptions.filter(i => {
return (
i.valueTypes.indexOf(this.target.valueType) !== -1 && i.metricKinds.indexOf(this.target.metricKind) !== -1
);
});
}
}
angular.module('grafana.controllers').directive('stackdriverAggregation', StackdriverAggregation);
angular.module('grafana.controllers').controller('StackdriverAggregationCtrl', StackdriverAggregationCtrl);
import _ from 'lodash';
import { QueryCtrl } from 'app/plugins/sdk';
import appEvents from 'app/core/app_events';
import * as options from './constants';
import { FilterSegments, DefaultRemoveFilterValue } from './filter_segments';
import './query_aggregation_ctrl';
export interface QueryMeta {
rawQuery: string;
......@@ -55,8 +55,6 @@ export class StackdriverQueryCtrl extends QueryCtrl {
valueType: '',
};
alignOptions: any[];
aggOptions: any[];
groupBySegments: any[];
removeSegment: any;
showHelp: boolean;
......@@ -74,9 +72,6 @@ export class StackdriverQueryCtrl extends QueryCtrl {
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
this.stackdriverConstants = options;
this.aggOptions = options.aggOptions;
this.alignOptions = options.alignOptions;
this.getCurrentProject()
.then(this.getMetricTypes.bind(this))
......@@ -155,6 +150,9 @@ export class StackdriverQueryCtrl extends QueryCtrl {
this.metricLabels = data.results[this.target.refId].meta.metricLabels;
this.resourceLabels = data.results[this.target.refId].meta.resourceLabels;
this.target.valueType = data.results[this.target.refId].meta.valueType;
this.target.metricKind = data.results[this.target.refId].meta.metricKind;
resolve();
} catch (error) {
resolve();
......@@ -264,31 +262,6 @@ export class StackdriverQueryCtrl extends QueryCtrl {
}
}
getAlignOptions() {
return !this.target.valueType
? options.alignOptions
: options.alignOptions.filter(i => {
return (
i.valueTypes.indexOf(this.target.valueType) !== -1 && i.metricKinds.indexOf(this.target.metricKind) !== -1
);
});
}
getAggOptions() {
if (this.target.aggregation.perSeriesAligner === 'ALIGN_NONE') {
this.target.aggregation.crossSeriesReducer = options.aggOptions[0].value;
return options.aggOptions.slice(0, 1);
}
return !this.target.metricKind
? options.aggOptions
: options.aggOptions.filter(i => {
return (
i.valueTypes.indexOf(this.target.valueType) !== -1 && i.metricKinds.indexOf(this.target.metricKind) !== -1
);
});
}
onDataReceived(dataList) {
this.lastQueryError = null;
this.lastQueryMeta = null;
......@@ -297,8 +270,6 @@ export class StackdriverQueryCtrl extends QueryCtrl {
if (anySeriesFromQuery) {
this.lastQueryMeta = anySeriesFromQuery.meta;
this.lastQueryMeta.rawQueryString = decodeURIComponent(this.lastQueryMeta.rawQuery);
this.target.valueType = anySeriesFromQuery.meta.valueType;
this.target.metricKind = anySeriesFromQuery.meta.metricKind;
}
}
......
import { StackdriverAggregationCtrl } from '../query_aggregation_ctrl';
describe('StackdriverAggregationCtrl', () => {
let ctrl;
describe('aggregation and alignment options', () => {
beforeEach(() => {
ctrl = createCtrlWithFakes();
});
describe('when new query result is returned from the server', () => {
describe('and result is double and gauge', () => {
beforeEach(async () => {
ctrl.target.valueType = 'DOUBLE';
ctrl.target.metricKind = 'GAUGE';
});
it('should populate all aggregate options except two', () => {
const result = ctrl.getAggOptions();
expect(result.length).toBe(11);
expect(result.map(o => o.value)).toEqual(
expect.not.arrayContaining(['REDUCE_COUNT_TRUE', 'REDUCE_COUNT_FALSE'])
);
});
it('should populate all alignment options except two', () => {
const result = ctrl.getAlignOptions();
console.log(result.map(o => o.value));
expect(result.length).toBe(10);
expect(result.map(o => o.value)).toEqual(
expect.not.arrayContaining(['REDUCE_COUNT_TRUE', 'REDUCE_COUNT_FALSE'])
);
});
});
});
describe('when a user a user select ALIGN_NONE and a reducer is selected', () => {
beforeEach(async () => {
ctrl.target.aggregation.crossSeriesReducer = 'RANDOM_REDUCER';
ctrl.onAlignmentChange('ALIGN_NONE');
});
it('should set REDUCE_NONE as selected aggregation', () => {
expect(ctrl.target.aggregation.crossSeriesReducer).toBe('REDUCE_NONE');
});
});
describe('when a user a user select a reducer and no alignment is selected', () => {
beforeEach(async () => {
ctrl.target.aggregation.crossSeriesReducer = 'REDUCE_NONE';
ctrl.target.aggregation.perSeriesAligner = 'ALIGN_NONE';
ctrl.onAggregationChange('ALIGN_NONE');
});
it('should set an alignment', () => {
expect(ctrl.target.aggregation.perSeriesAligner).not.toBe('ALIGN_NONE');
});
});
});
});
function createCtrlWithFakes() {
StackdriverAggregationCtrl.prototype.target = createTarget();
return new StackdriverAggregationCtrl({ refresh: () => {} });
}
function createTarget(existingFilters?: string[]) {
return {
project: {
id: '',
name: '',
},
metricType: 'ametric',
refId: 'A',
aggregation: {
crossSeriesReducer: '',
alignmentPeriod: '',
perSeriesAligner: '',
groupBys: [],
},
filters: existingFilters || [],
aliasBy: '',
};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment