mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Merge pull request #3949 from spalger/fix/3944
[aggTypes/dateHistogram] on field changes clear the interval if needed
This commit is contained in:
commit
c657b4f93d
7 changed files with 282 additions and 159 deletions
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
|
@ -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'));
|
||||
}];
|
||||
});
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
}];
|
||||
});
|
|
@ -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());
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}];
|
||||
});
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue