diff --git a/src/kibana/components/agg_response/point_series/_ordered_date_axis.js b/src/kibana/components/agg_response/point_series/_ordered_date_axis.js index 3fbd64517cfd..d5ddfc2ae9db 100644 --- a/src/kibana/components/agg_response/point_series/_ordered_date_axis.js +++ b/src/kibana/components/agg_response/point_series/_ordered_date_axis.js @@ -3,8 +3,8 @@ define(function (require) { var moment = require('moment'); return function orderedDateAxis(vis, chart) { - var aspects = chart.aspects; - var buckets = aspects.x.agg.buckets; + var xAgg = chart.aspects.x.agg; + var buckets = xAgg.buckets; var format = buckets.getScaledDateFormat(); chart.xAxisFormatter = function (val) { @@ -16,10 +16,13 @@ define(function (require) { interval: buckets.getInterval(), }; + var axisOnTimeField = xAgg.fieldIsTimeField(); var bounds = buckets.getBounds(); - if (bounds) { + if (bounds && axisOnTimeField) { chart.ordered.min = bounds.min; chart.ordered.max = bounds.max; + } else { + chart.ordered.endzones = false; } }; }; diff --git a/src/kibana/components/agg_types/buckets/_interval_options.js b/src/kibana/components/agg_types/buckets/_interval_options.js index 2e2fd220113c..fcc38469b49d 100644 --- a/src/kibana/components/agg_types/buckets/_interval_options.js +++ b/src/kibana/components/agg_types/buckets/_interval_options.js @@ -10,8 +10,10 @@ define(function (require) { { display: 'Auto', val: 'auto', - enabled: function (aggConfig) { - return !!aggConfig.vis.indexPattern.timeFieldName; + enabled: function (agg) { + // not only do we need a time field, but the selected field needs + // to be the time field. (see #3028) + return agg.fieldIsTimeField(); } }, { diff --git a/src/kibana/components/agg_types/buckets/date_histogram.js b/src/kibana/components/agg_types/buckets/date_histogram.js index c0b933b82510..0786dc16d060 100644 --- a/src/kibana/components/agg_types/buckets/date_histogram.js +++ b/src/kibana/components/agg_types/buckets/date_histogram.js @@ -8,6 +8,12 @@ define(function (require) { var tzOffset = moment().format('Z'); + function setBounds(agg, force) { + if (agg.buckets._alreadySet && !force) return; + agg.buckets._alreadySet = true; + agg.buckets.setBounds(agg.fieldIsTimeField() && timefilter.getActiveBounds()); + } + require('filters/field_type'); return new BucketAggType({ @@ -32,7 +38,8 @@ define(function (require) { buckets = new TimeBuckets(); buckets.setInterval(_.get(this, ['params', 'interval'])); - buckets.setBounds(timefilter.getActiveBounds()); + setBounds(this); + return buckets; } } @@ -44,6 +51,9 @@ define(function (require) { filterFieldTypes: 'date', default: function (agg) { return agg.vis.indexPattern.timeFieldName; + }, + onChange: function (agg) { + setBounds(agg, true); } }, @@ -54,15 +64,10 @@ define(function (require) { options: Private(require('components/agg_types/buckets/_interval_options')), editor: require('text!components/agg_types/controls/interval.html'), onRequest: function (agg) { - // flag that prevents us from clobbering on subsequest calls to write() - agg.buckets._sentToEs = true; - agg.buckets.setBounds(timefilter.getActiveBounds()); + setBounds(agg, true); }, write: function (agg, output) { - if (!agg.buckets._sentToEs) { - agg.buckets.setBounds(timefilter.getActiveBounds()); - } - + setBounds(agg); agg.buckets.setInterval(agg.params.interval); var interval = agg.buckets.getInterval(); diff --git a/src/kibana/components/agg_types/controls/field.html b/src/kibana/components/agg_types/controls/field.html index 5d5a3269510c..6661fbaf46d0 100644 --- a/src/kibana/components/agg_types/controls/field.html +++ b/src/kibana/components/agg_types/controls/field.html @@ -22,7 +22,8 @@ name="field" required ng-model="agg.params.field" - ng-options="field as field.displayName group by field.type for field in indexedFields"> + ng-options="field as field.displayName group by field.type for field in indexedFields" + ng-change="aggParam.onChange(agg)"> \ No newline at end of file diff --git a/src/kibana/components/time_buckets/time_buckets.js b/src/kibana/components/time_buckets/time_buckets.js index 4492045a65ea..3960e4f29e97 100644 --- a/src/kibana/components/time_buckets/time_buckets.js +++ b/src/kibana/components/time_buckets/time_buckets.js @@ -292,10 +292,10 @@ define(function (require) { } function cacheBreaker(prop) { - var breaker = breakers[prop]; - var setup = breaker.setup; - var changes = breaker.changes; - var deps = breaker.deps; + var resource = resources[breakers[prop]]; + var setup = resource.setup; + var changes = resource.changes; + var deps = resource.deps; var fn = self[prop]; return { @@ -304,7 +304,7 @@ define(function (require) { var ret = fn.apply(self, arguments); if (changes.call(self, prev)) { - cache = _.omit(cache, deps); + cache = {}; } return ret; @@ -330,8 +330,13 @@ define(function (require) { }; var breakers = { - setBounds: { - deps: ['getBounds', 'hasBounds', 'getDuration', 'getInterval', 'getScaledDateFormat'], + setBounds: 'bounds', + clearBounds: 'bounds', + setInterval: 'interval' + }; + + var resources = { + bounds: { setup: function () { return [self._lb, self._ub]; }, @@ -339,8 +344,7 @@ define(function (require) { return !sameMoment(prev[0], self._lb) || !sameMoment(prev[1], self._ub); } }, - setInterval: { - deps: ['getInterval', 'getScaledDateFormat'], + interval: { setup: function () { return self._i; }, diff --git a/src/kibana/components/vis/_agg_config.js b/src/kibana/components/vis/_agg_config.js index ad0168fe28b5..6762510b8ac1 100644 --- a/src/kibana/components/vis/_agg_config.js +++ b/src/kibana/components/vis/_agg_config.js @@ -282,6 +282,11 @@ define(function (require) { return field ? (field.displayName || this.fieldName()) : ''; }; + AggConfig.prototype.fieldIsTimeField = function () { + var timeFieldName = this.vis.indexPattern.timeFieldName; + return timeFieldName && this.fieldName() === timeFieldName; + }; + return AggConfig; }; }); diff --git a/src/kibana/components/vislib/visualizations/_point_series_chart.js b/src/kibana/components/vislib/visualizations/_point_series_chart.js index a243f6f2faf2..115f9e7ce6ad 100644 --- a/src/kibana/components/vislib/visualizations/_point_series_chart.js +++ b/src/kibana/components/vislib/visualizations/_point_series_chart.js @@ -53,7 +53,7 @@ define(function (require) { var yScale = xAxis.yScale; var ordered = xAxis.ordered; - if (!ordered || ordered.min == null || ordered.max == null) return; + if (!ordered || ordered.endzones === false) return; var attr = this.handler._attr; var height = attr.height; diff --git a/test/unit/specs/components/agg_response/point_series/_ordered_date_axis.js b/test/unit/specs/components/agg_response/point_series/_ordered_date_axis.js index d36d2fb44f6a..af62f16bda38 100644 --- a/test/unit/specs/components/agg_response/point_series/_ordered_date_axis.js +++ b/test/unit/specs/components/agg_response/point_series/_ordered_date_axis.js @@ -14,6 +14,7 @@ define(function (require) { aspects: { x: { agg: { + fieldIsTimeField: _.constant(true), buckets: { getScaledDateFormat: _.constant('hh:mm:ss'), getInterval: _.constant(moment.duration(15, 'm')), diff --git a/test/unit/specs/components/agg_types/buckets/_date_histogram.js b/test/unit/specs/components/agg_types/buckets/_date_histogram.js index 1061c38afae0..331972c41468 100644 --- a/test/unit/specs/components/agg_types/buckets/_date_histogram.js +++ b/test/unit/specs/components/agg_types/buckets/_date_histogram.js @@ -5,19 +5,27 @@ define(function (require) { 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) { @@ -31,24 +39,24 @@ define(function (require) { describe('interval', function () { it('accepts a valid interval', function () { - var output = paramWriter.write({ interval: 'day' }); + var output = writeInterval('day'); expect(output.params).to.have.property('interval', '1d'); }); it('ignores invalid intervals', function () { - var output = paramWriter.write({ interval: 'foo' }); + var output = writeInterval('foo'); expect(output.params).to.have.property('interval', '0ms'); }); it('automatically picks an interval', function () { setTimeBounds(15, 'minutes'); - var output = paramWriter.write({ interval: 'auto' }); + 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, 'minutes'); - var output = paramWriter.write({ interval: 'second' }); + var output = writeInterval('second'); expect(output.params.interval).to.be('10s'); expect(output.metricScaleText).to.be('second'); expect(output.metricScale).to.be(0.1); @@ -56,7 +64,7 @@ define(function (require) { it('does not scale down the interval', function () { setTimeBounds(1, 'minutes'); - var output = paramWriter.write({ interval: 'hour' }); + var output = writeInterval('hour'); expect(output.params.interval).to.be('1h'); expect(output.metricScaleText).to.be(undefined); expect(output.metricScale).to.be(undefined); @@ -82,7 +90,7 @@ define(function (require) { var histoConfig = new AggConfig(vis, { type: aggTypes.byName.date_histogram, schema: 'segment', - params: { interval: 'second' } + params: { interval: 'second', field: timeField } }); vis.aggs.push(histoConfig);