Merge pull request #3949 from spalger/fix/3944

[aggTypes/dateHistogram] on field changes clear the interval if needed
This commit is contained in:
Lukas Olson 2015-05-28 09:24:52 -07:00
commit c657b4f93d
7 changed files with 282 additions and 159 deletions

View file

@ -60,6 +60,10 @@ define(function (require) {
return agg.vis.indexPattern.timeFieldName;
},
onChange: function (agg) {
if (_.get(agg, 'params.interval.val') === 'auto' && !agg.fieldIsTimeField()) {
delete agg.params.interval;
}
setBounds(agg, true);
}
},

View file

@ -159,13 +159,6 @@ define(function (require) {
initialSet: fields
});
}
// bind a property from our scope a child scope, with one-way binding
function setupBoundProp($child, get, set) {
var getter = _.partial($parse(get), $scope);
var setter = _.partial($parse(set).assign, $child);
$scope.$watch(getter, setter);
}
}
};
});

View file

@ -1,151 +0,0 @@
define(function (require) {
return ['Date Histogram Agg', function () {
var _ = require('lodash');
var moment = require('moment');
describe('params', function () {
var paramWriter;
var writeInterval;
var aggTypes;
var AggConfig;
var setTimeBounds;
var timeField;
beforeEach(module('kibana'));
beforeEach(inject(function (Private, $injector) {
var AggParamWriter = Private(require('test_utils/agg_param_writer'));
var indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
var timefilter = $injector.get('timefilter');
timeField = indexPattern.timeFieldName;
aggTypes = Private(require('components/agg_types/index'));
AggConfig = Private(require('components/vis/_agg_config'));
paramWriter = new AggParamWriter({ aggType: 'date_histogram' });
writeInterval = function (interval) {
return paramWriter.write({ interval: interval, field: timeField });
};
var now = moment();
setTimeBounds = function (n, units) {
timefilter.enabled = true;
timefilter.getBounds = _.constant({
min: now.clone().subtract(n, units),
max: now.clone()
});
};
}));
describe('interval', function () {
it('accepts a valid interval', function () {
var output = writeInterval('d');
expect(output.params).to.have.property('interval', '1d');
});
it('ignores invalid intervals', function () {
var output = writeInterval('foo');
expect(output.params).to.have.property('interval', '0ms');
});
it('automatically picks an interval', function () {
setTimeBounds(15, 'm');
var output = writeInterval('auto');
expect(output.params.interval).to.be('30s');
});
it('scales up the interval if it will make too many buckets', function () {
setTimeBounds(30, 'm');
var output = writeInterval('s');
expect(output.params.interval).to.be('10s');
expect(output.metricScaleText).to.be('second');
expect(output.metricScale).to.be(0.1);
});
it('does not scale down the interval', function () {
setTimeBounds(1, 'm');
var output = writeInterval('h');
expect(output.params.interval).to.be('1h');
expect(output.metricScaleText).to.be(undefined);
expect(output.metricScale).to.be(undefined);
});
describe('only scales when all metrics are sum or count', function () {
var tests = [
[ false, 'avg', 'count', 'sum' ],
[ true, 'count', 'sum' ],
[ false, 'count', 'cardinality' ]
];
tests.forEach(function (test) {
var should = test.shift();
var typeNames = test.slice();
it(typeNames.join(', ') + ' should ' + (should ? '' : 'not') + ' scale', function () {
setTimeBounds(1, 'y');
var vis = paramWriter.vis;
vis.aggs.splice(0);
var histoConfig = new AggConfig(vis, {
type: aggTypes.byName.date_histogram,
schema: 'segment',
params: { interval: 's', field: timeField }
});
vis.aggs.push(histoConfig);
typeNames.forEach(function (type) {
vis.aggs.push(new AggConfig(vis, {
type: aggTypes.byName[type],
schema: 'metric'
}));
});
var output = histoConfig.write();
expect(_.has(output, 'metricScale')).to.be(should);
});
});
});
});
describe('extended_bounds', function () {
it('should write a long value if a moment passed in', function () {
var then = moment(0);
var now = moment(500);
var output = paramWriter.write({
extended_bounds: {
min: then,
max: now
}
});
expect(typeof output.params.extended_bounds.min).to.be('number');
expect(typeof output.params.extended_bounds.max).to.be('number');
expect(output.params.extended_bounds.min).to.be(then.valueOf());
expect(output.params.extended_bounds.max).to.be(now.valueOf());
});
it('should write a long if a long is passed', function () {
var then = 0;
var now = 500;
var output = paramWriter.write({
extended_bounds: {
min: then,
max: now
}
});
expect(typeof output.params.extended_bounds.min).to.be('number');
expect(typeof output.params.extended_bounds.max).to.be('number');
expect(output.params.extended_bounds.min).to.be(then.valueOf());
expect(output.params.extended_bounds.max).to.be(now.valueOf());
});
});
});
}];
});

View file

@ -0,0 +1,6 @@
define(function (require) {
return ['Date Histogram Agg', function () {
describe(require('specs/components/agg_types/buckets/date_histogram/_editor'));
describe(require('specs/components/agg_types/buckets/date_histogram/_params'));
}];
});

View file

@ -0,0 +1,123 @@
define(function (require) {
return ['editor', function () {
var _ = require('lodash');
var $ = require('jquery');
var indexPattern;
var vis;
var agg;
var render;
var $scope;
beforeEach(module('kibana'));
beforeEach(inject(function (Private, $injector, $compile) {
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
var Vis = Private(require('components/vis/vis'));
/**
* Render the AggParams editor for the date histogram aggregation
*
* @param {object} params - the agg params to give to the date_histogram
* by default
* @return {object} - object pointing to the different inputs, keys
* are the aggParam name and the value is an object
* with $el, $scope, and a few helpers for getting
* data from them.
*/
render = function (params) {
vis = new Vis(indexPattern, {
type: 'histogram',
aggs:[
{ schema: 'metric', type: 'avg', params: { field: 'bytes' } },
{ schema: 'segment', type: 'date_histogram', params: params || {} }
]
});
var $el = $('<vis-editor-agg-params agg="agg" group-name="groupName"></vis-editor-agg-params>');
var $parentScope = $injector.get('$rootScope').$new();
agg = $parentScope.agg = vis.aggs.bySchemaName.segment[0];
$parentScope.groupName = 'buckets';
$compile($el)($parentScope);
$scope = $el.scope();
$scope.$digest();
var $inputs = $('vis-agg-param-editor', $el);
return _.transform($inputs.toArray(), function (inputs, e) {
var $el = $(e);
var $scope = $el.scope();
inputs[$scope.aggParam.name] = {
$el: $el,
$scope: $scope,
$input: function () {
return $el.find('[ng-model]').first();
},
modelValue: function () {
return this.$input().controller('ngModel').$modelValue;
}
};
}, {});
};
}));
describe('random field/interval', function () {
var params;
var field;
var interval;
beforeEach(inject(function (Private) {
field = _.sample(indexPattern.fields);
interval = _.sample(Private(require('components/agg_types/buckets/_interval_options')));
params = render({ field: field, interval: interval });
}));
it('renders the field editor', function () {
expect(agg.params.field).to.be(field);
expect(params).to.have.property('field');
expect(params.field).to.have.property('$el');
expect(params.field.modelValue()).to.be(field);
});
it('renders the interval editor', function () {
expect(agg.params.interval).to.be(interval);
expect(params).to.have.property('interval');
expect(params.interval).to.have.property('$el');
expect(params.interval.modelValue()).to.be(interval);
});
});
describe('interval "auto" and indexPattern timeField', function () {
var params;
beforeEach(function () {
params = render({ field: indexPattern.timeFieldName, interval: 'auto' });
});
it('clears the interval when the field is changed', function () {
expect(params.interval.modelValue().val).to.be('auto');
expect(params.field.modelValue().name).to.be(indexPattern.timeFieldName);
var field = _.find(indexPattern.fields, function (f) {
return f.type === 'date' && f.name !== indexPattern.timeFieldName;
});
params.field.$input()
.find('option')
.filter(function () {
return $(this).text().trim() === field.name;
})
.prop('selected', true);
params.field.$input().change();
expect(params.interval.modelValue()).to.be(undefined);
});
});
}];
});

View file

@ -0,0 +1,149 @@
define(function (require) {
return ['params', function () {
var _ = require('lodash');
var moment = require('moment');
var paramWriter;
var writeInterval;
var aggTypes;
var AggConfig;
var setTimeBounds;
var timeField;
beforeEach(module('kibana'));
beforeEach(inject(function (Private, $injector) {
var AggParamWriter = Private(require('test_utils/agg_param_writer'));
var indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
var timefilter = $injector.get('timefilter');
timeField = indexPattern.timeFieldName;
aggTypes = Private(require('components/agg_types/index'));
AggConfig = Private(require('components/vis/_agg_config'));
paramWriter = new AggParamWriter({ aggType: 'date_histogram' });
writeInterval = function (interval) {
return paramWriter.write({ interval: interval, field: timeField });
};
var now = moment();
setTimeBounds = function (n, units) {
timefilter.enabled = true;
timefilter.getBounds = _.constant({
min: now.clone().subtract(n, units),
max: now.clone()
});
};
}));
describe('interval', function () {
it('accepts a valid interval', function () {
var output = writeInterval('d');
expect(output.params).to.have.property('interval', '1d');
});
it('ignores invalid intervals', function () {
var output = writeInterval('foo');
expect(output.params).to.have.property('interval', '0ms');
});
it('automatically picks an interval', function () {
setTimeBounds(15, 'm');
var output = writeInterval('auto');
expect(output.params.interval).to.be('30s');
});
it('scales up the interval if it will make too many buckets', function () {
setTimeBounds(30, 'm');
var output = writeInterval('s');
expect(output.params.interval).to.be('10s');
expect(output.metricScaleText).to.be('second');
expect(output.metricScale).to.be(0.1);
});
it('does not scale down the interval', function () {
setTimeBounds(1, 'm');
var output = writeInterval('h');
expect(output.params.interval).to.be('1h');
expect(output.metricScaleText).to.be(undefined);
expect(output.metricScale).to.be(undefined);
});
describe('only scales when all metrics are sum or count', function () {
var tests = [
[ false, 'avg', 'count', 'sum' ],
[ true, 'count', 'sum' ],
[ false, 'count', 'cardinality' ]
];
tests.forEach(function (test) {
var should = test.shift();
var typeNames = test.slice();
it(typeNames.join(', ') + ' should ' + (should ? '' : 'not') + ' scale', function () {
setTimeBounds(1, 'y');
var vis = paramWriter.vis;
vis.aggs.splice(0);
var histoConfig = new AggConfig(vis, {
type: aggTypes.byName.date_histogram,
schema: 'segment',
params: { interval: 's', field: timeField }
});
vis.aggs.push(histoConfig);
typeNames.forEach(function (type) {
vis.aggs.push(new AggConfig(vis, {
type: aggTypes.byName[type],
schema: 'metric'
}));
});
var output = histoConfig.write();
expect(_.has(output, 'metricScale')).to.be(should);
});
});
});
});
describe('extended_bounds', function () {
it('should write a long value if a moment passed in', function () {
var then = moment(0);
var now = moment(500);
var output = paramWriter.write({
extended_bounds: {
min: then,
max: now
}
});
expect(typeof output.params.extended_bounds.min).to.be('number');
expect(typeof output.params.extended_bounds.max).to.be('number');
expect(output.params.extended_bounds.min).to.be(then.valueOf());
expect(output.params.extended_bounds.max).to.be(now.valueOf());
});
it('should write a long if a long is passed', function () {
var then = 0;
var now = 500;
var output = paramWriter.write({
extended_bounds: {
min: then,
max: now
}
});
expect(typeof output.params.extended_bounds.min).to.be('number');
expect(typeof output.params.extended_bounds.max).to.be('number');
expect(output.params.extended_bounds.min).to.be(then.valueOf());
expect(output.params.extended_bounds.max).to.be(now.valueOf());
});
});
}];
});

View file

@ -4,7 +4,6 @@ define(function (require) {
describe(require('specs/components/agg_types/_agg_params'));
describe(require('specs/components/agg_types/_bucket_count_between'));
describe(require('specs/components/agg_types/buckets/_histogram'));
describe(require('specs/components/agg_types/buckets/_date_histogram'));
describe('bucket aggs', function () {
var bucketAggs;