From 38adb3f5c909c744a7e742fe325006e62a42bbc4 Mon Sep 17 00:00:00 2001 From: Gaurav Singhania Date: Wed, 15 Jul 2015 18:30:03 +0530 Subject: [PATCH 1/6] Using string formatter for range visualization. Closes #4432 & #4404 --- src/kibana/components/agg_types/_agg_type.js | 3 +++ .../specs/components/agg_types/_agg_type.js | 21 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/kibana/components/agg_types/_agg_type.js b/src/kibana/components/agg_types/_agg_type.js index 09c9221153d5..789ffc8fb95d 100644 --- a/src/kibana/components/agg_types/_agg_type.js +++ b/src/kibana/components/agg_types/_agg_type.js @@ -132,6 +132,9 @@ define(function (require) { * @return {FieldFromat} */ AggType.prototype.getFormat = function (agg) { + if (agg.type && agg.type.dslName === 'range') { + return fieldFormats.getDefaultInstance('string'); + } var field = agg.field(); return field ? field.format : fieldFormats.getDefaultInstance('string'); }; diff --git a/test/unit/specs/components/agg_types/_agg_type.js b/test/unit/specs/components/agg_types/_agg_type.js index d0671a52c823..58c3e1a0fa44 100644 --- a/test/unit/specs/components/agg_types/_agg_type.js +++ b/test/unit/specs/components/agg_types/_agg_type.js @@ -105,6 +105,25 @@ define(function (require) { expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('string')); }); + it('returns the string formatter for the range aggs', function () { + var aggType = new AggType({}); + + var vis = new Vis(indexPattern, { + type: 'histogram', + aggs: [ + { + type: 'range', + schema: 'segment', + } + ] + }); + + var aggConfig = vis.aggs.byTypeName.range[0]; + aggConfig.params = {field: {format: 'non_used_format'}}; + + expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('string')); + }); + it('can be overridden via config', function () { var someGetter = function () {}; @@ -171,4 +190,4 @@ define(function (require) { }); }]; -}); \ No newline at end of file +}); From f7921504785d3f2ce284878385c7b8d6cfa0a55e Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Aug 2015 12:50:18 -0700 Subject: [PATCH 2/6] convert range formatting to match date formatter --- src/ui/public/agg_types/AggType.js | 3 --- src/ui/public/agg_types/buckets/range.js | 11 +++++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/public/agg_types/AggType.js b/src/ui/public/agg_types/AggType.js index 19788daadd75..85231ddb3a85 100644 --- a/src/ui/public/agg_types/AggType.js +++ b/src/ui/public/agg_types/AggType.js @@ -132,9 +132,6 @@ define(function (require) { * @return {FieldFromat} */ AggType.prototype.getFormat = function (agg) { - if (agg.type && agg.type.dslName === 'range') { - return fieldFormats.getDefaultInstance('string'); - } var field = agg.field(); return field ? field.format : fieldFormats.getDefaultInstance('string'); }; diff --git a/src/ui/public/agg_types/buckets/range.js b/src/ui/public/agg_types/buckets/range.js index edc9faf39c2c..122f14fd3e9b 100644 --- a/src/ui/public/agg_types/buckets/range.js +++ b/src/ui/public/agg_types/buckets/range.js @@ -1,10 +1,9 @@ define(function (require) { return function RangeAggDefinition(Private) { var _ = require('lodash'); - var moment = require('moment'); - var angular = require('angular'); var BucketAggType = Private(require('ui/agg_types/buckets/_bucket_agg_type')); var createFilter = Private(require('ui/agg_types/buckets/create_filter/range')); + var fieldFormats = Private(require('ui/registry/field_formats')); return new BucketAggType({ name: 'range', @@ -13,6 +12,14 @@ define(function (require) { makeLabel: function (aggConfig) { return aggConfig.params.field.displayName + ' ranges'; }, + getKey: function (bucket, key, agg) { + let stringFormat = fieldFormats.getDefaultInstance('string'); + let format = _.get(agg.field(), 'format', stringFormat).getConverterFor('text'); + return `${format(bucket.from)} to ${format(bucket.to)}`; + }, + getFormat: function () { + return fieldFormats.getDefaultInstance('string'); + }, params: [ { name: 'field', From b43499d8489e0341cec9fb81f4439f2011b61777 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Aug 2015 22:41:16 -0700 Subject: [PATCH 3/6] remove extra test file that accidentally merged in f7921504785d3f2ce284878385c7b8d6cfa0a55e --- .../specs/components/agg_types/_agg_type.js | 193 ------------------ 1 file changed, 193 deletions(-) delete mode 100644 test/unit/specs/components/agg_types/_agg_type.js diff --git a/test/unit/specs/components/agg_types/_agg_type.js b/test/unit/specs/components/agg_types/_agg_type.js deleted file mode 100644 index 58c3e1a0fa44..000000000000 --- a/test/unit/specs/components/agg_types/_agg_type.js +++ /dev/null @@ -1,193 +0,0 @@ -define(function (require) { - return ['AggType Class', function () { - var _ = require('lodash'); - var sinon = require('test_utils/auto_release_sinon'); - var AggType; - var AggParams; - var AggConfig; - var indexPattern; - var fieldFormat; - var Vis; - - require('services/private'); - - beforeEach(module('kibana')); - beforeEach(inject(function (Private) { - var AggParamsPM = require('components/agg_types/_agg_params'); - AggParams = sinon.spy(Private(AggParamsPM)); - Private.stub(AggParamsPM, AggParams); - - Vis = Private(require('components/vis/vis')); - fieldFormat = Private(require('registry/field_formats')); - AggType = Private(require('components/agg_types/_agg_type')); - AggConfig = Private(require('components/vis/_agg_config')); - indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern')); - })); - - describe('constructor', function () { - - it('requires a config object as it\'s first param', function () { - expect(function () { - new AggType(null); - }).to.throwError(); - }); - - describe('application of config properties', function () { - var copiedConfigProps = [ - 'name', - 'title', - 'makeLabel', - 'ordered' - ]; - - describe('"' + copiedConfigProps.join('", "') + '"', function () { - it('assigns the config value to itself', function () { - var config = _.transform(copiedConfigProps, function (config, prop) { - config[prop] = {}; - }, {}); - - var aggType = new AggType(config); - - copiedConfigProps.forEach(function (prop) { - expect(aggType[prop]).to.be(config[prop]); - }); - }); - }); - - describe('makeLabel', function () { - it('makes a function when the makeLabel config is not specified', function () { - var someGetter = function () {}; - - var aggType = new AggType({ - makeLabel: someGetter - }); - - expect(aggType.makeLabel).to.be(someGetter); - - aggType = new AggType({ - name: 'pizza' - }); - - expect(aggType.makeLabel).to.be.a('function'); - expect(aggType.makeLabel()).to.be('pizza'); - }); - }); - - describe('getFormat', function () { - it('returns the formatter for the aggConfig', function () { - var aggType = new AggType({}); - - var vis = new Vis(indexPattern, { - type: 'histogram', - aggs: [ - { - type: 'date_histogram', - schema: 'segment' - } - ] - }); - - var aggConfig = vis.aggs.byTypeName.date_histogram[0]; - - expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('date')); - - vis = new Vis(indexPattern, { - type: 'metric', - aggs: [ - { - type: 'count', - schema: 'metric' - } - ] - }); - aggConfig = vis.aggs.byTypeName.count[0]; - - expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('string')); - }); - - it('returns the string formatter for the range aggs', function () { - var aggType = new AggType({}); - - var vis = new Vis(indexPattern, { - type: 'histogram', - aggs: [ - { - type: 'range', - schema: 'segment', - } - ] - }); - - var aggConfig = vis.aggs.byTypeName.range[0]; - aggConfig.params = {field: {format: 'non_used_format'}}; - - expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('string')); - }); - - it('can be overridden via config', function () { - var someGetter = function () {}; - - var aggType = new AggType({ - getFormat: someGetter - }); - - expect(aggType.getFormat).to.be(someGetter); - }); - }); - - describe('params', function () { - beforeEach(function () { - AggParams.reset(); - }); - - it('defaults to AggParams object with JSON param', function () { - var aggType = new AggType({ - name: 'smart agg' - }); - - expect(aggType.params).to.be.an(AggParams); - expect(aggType.params.length).to.be(1); - expect(aggType.params[0].name).to.be('json'); - }); - - it('passes the params arg directly to the AggParams constructor', function () { - var params = [ - {name: 'one'}, - {name: 'two'} - ]; - var paramLength = params.length + 1; // json is always appended - - var aggType = new AggType({ - name: 'bucketeer', - params: params - }); - - expect(aggType.params).to.be.an(AggParams); - expect(aggType.params.length).to.be(paramLength); - expect(AggParams.callCount).to.be(1); - expect(AggParams.firstCall.args[0]).to.be(params); - }); - }); - - describe('getResponseAggs', function () { - it('copies the value', function () { - var football = {}; - var aggType = new AggType({ - getResponseAggs: football - }); - - expect(aggType.getResponseAggs).to.be(football); - }); - - it('defaults to _.noop', function () { - var aggType = new AggType({}); - - expect(aggType.getResponseAggs).to.be(_.noop); - }); - }); - }); - - }); - - }]; -}); From 3589c101b30bce1ace67e8d462db834ebb55f4e8 Mon Sep 17 00:00:00 2001 From: spalger Date: Sat, 8 Aug 2015 12:33:49 -0700 Subject: [PATCH 4/6] extended formatting support for filterbar, fixed tests, support unbounded filters --- src/fixtures/agg_resp/range.js | 37 ++++++++++++ .../elasticsearch/lib/__tests__/routes.js | 12 ++-- src/ui/public/Vis/AggConfig.js | 18 +++--- .../hierarchical/_create_raw_data.js | 2 +- .../hierarchical/_extract_buckets.js | 4 +- .../hierarchical/_transform_aggregation.js | 2 +- .../hierarchical/build_hierarchical_data.js | 4 +- src/ui/public/agg_types/__tests__/AggType.js | 19 ------ .../agg_types/__tests__/buckets/_range.js | 58 +++++++++++++++++++ .../__tests__/buckets/create_filter/range.js | 2 +- src/ui/public/agg_types/__tests__/index.js | 1 + .../agg_types/buckets/create_filter/range.js | 8 +-- src/ui/public/agg_types/buckets/date_range.js | 7 +-- src/ui/public/agg_types/buckets/range.js | 23 ++++++-- src/ui/public/filter_bar/lib/mapRange.js | 44 +++++++------- .../_field_format/FieldFormat.js | 9 +++ src/ui/public/stringify/types/_Numeral.js | 2 + 17 files changed, 174 insertions(+), 78 deletions(-) create mode 100644 src/fixtures/agg_resp/range.js create mode 100644 src/ui/public/agg_types/__tests__/buckets/_range.js diff --git a/src/fixtures/agg_resp/range.js b/src/fixtures/agg_resp/range.js new file mode 100644 index 000000000000..c571d1e1d2ae --- /dev/null +++ b/src/fixtures/agg_resp/range.js @@ -0,0 +1,37 @@ +module.exports = { + "took": 35, + "timed_out": false, + "_shards": { + "total": 7, + "successful": 7, + "failed": 0 + }, + "hits": { + "total": 218512, + "max_score": 0, + "hits": [] + }, + "aggregations": { + "1": { + "buckets": { + "*-1024.0": { + "to": 1024, + "to_as_string": "1024.0", + "doc_count": 20904 + }, + "1024.0-2560.0": { + "from": 1024, + "from_as_string": "1024.0", + "to": 2560, + "to_as_string": "2560.0", + "doc_count": 23358 + }, + "2560.0-*": { + "from": 2560, + "from_as_string": "2560.0", + "doc_count": 174250 + } + } + } + } +}; diff --git a/src/plugins/elasticsearch/lib/__tests__/routes.js b/src/plugins/elasticsearch/lib/__tests__/routes.js index 93c34bf2ecd0..59857ba0dc02 100644 --- a/src/plugins/elasticsearch/lib/__tests__/routes.js +++ b/src/plugins/elasticsearch/lib/__tests__/routes.js @@ -38,6 +38,10 @@ describe('plugins/elasticsearch', function () { function testRoute(options) { + if (typeof options.payload === 'object') { + options.payload = JSON.stringify(options.payload); + } + var statusCode = options.statusCode || 200; describe(format('%s %s', options.method, options.url), function () { it('should should return ' + statusCode, function (done) { @@ -69,7 +73,7 @@ describe('plugins/elasticsearch', function () { testRoute({ method: 'POST', url: '/elasticsearch/.kibana', - payload: '{settings: {number_of_shards: 1, number_of_replicas: 1}}', + payload: {settings: { number_of_shards: 1, number_of_replicas: 1 }}, statusCode: 201 }); @@ -93,19 +97,19 @@ describe('plugins/elasticsearch', function () { testRoute({ method: 'POST', url: '/elasticsearch/.kibana/index-pattern/_search?fields=', - payload: '{query: {match_all: {}}, size: 2147483647}' + payload: {query: {match_all: {}}, size: 2147483647} }); testRoute({ method: 'POST', url: '/elasticsearch/.kibana/__kibanaQueryValidator/_validate/query?explain=true&ignore_unavailable=true', - payload: '{query: {query_string: {analyze_wildcard: true, query: "*"}}}' + payload: {query: {query_string: {analyze_wildcard: true, query: '*'}}} }); testRoute({ method: 'POST', url: '/elasticsearch/_mget?timeout=0&ignore_unavailable=true&preference=1429574531063', - payload: '{docs: [{_index: ".kibana", _type: "index-pattern", _id: "[logstash-]YYYY.MM.DD"}]}' + payload: {docs: [{_index: '.kibana', _type: 'index-pattern', _id: '[logstash-]YYYY.MM.DD'}]} }); testRoute({ diff --git a/src/ui/public/Vis/AggConfig.js b/src/ui/public/Vis/AggConfig.js index 652c9a81f42d..1310feda4c19 100644 --- a/src/ui/public/Vis/AggConfig.js +++ b/src/ui/public/Vis/AggConfig.js @@ -267,16 +267,18 @@ define(function (require) { return this.params.field; }; - AggConfig.prototype.fieldFormatter = function (contentType) { + AggConfig.prototype.fieldFormatter = function (contentType, defaultFormat) { + var format = this.type && this.type.getFormat(this); + if (format) return format.getConverterFor(contentType); + return this.fieldOwnFormatter(contentType, defaultFormat); + }; + + AggConfig.prototype.fieldOwnFormatter = function (contentType, defaultFormat) { var field = this.field(); var format = field && field.format; - var strFormat = fieldFormats.getDefaultInstance('string'); - - if (this.type) { - format = this.type.getFormat(this) || format; - } - - return (format || strFormat).getConverterFor(contentType); + if (!format) format = defaultFormat; + if (!format) format = fieldFormats.getDefaultInstance('string'); + return format.getConverterFor(contentType); }; AggConfig.prototype.fieldName = function () { diff --git a/src/ui/public/agg_response/hierarchical/_create_raw_data.js b/src/ui/public/agg_response/hierarchical/_create_raw_data.js index ba4478c13c46..9f4346a9fca5 100644 --- a/src/ui/public/agg_response/hierarchical/_create_raw_data.js +++ b/src/ui/public/agg_response/hierarchical/_create_raw_data.js @@ -59,7 +59,7 @@ define(function (require) { } // iterate through all the buckets - _.each(extractBuckets(data[agg.id]), function (bucket) { + _.each(extractBuckets(data[agg.id], agg), function (bucket) { var _record = _.flattenDeep([record, bucket.key]); _.each(metrics, function (metric) { diff --git a/src/ui/public/agg_response/hierarchical/_extract_buckets.js b/src/ui/public/agg_response/hierarchical/_extract_buckets.js index c227a31b8c07..e1866ea5d006 100644 --- a/src/ui/public/agg_response/hierarchical/_extract_buckets.js +++ b/src/ui/public/agg_response/hierarchical/_extract_buckets.js @@ -1,10 +1,10 @@ define(function (require) { var _ = require('lodash'); - return function (bucket) { + return function (bucket, agg) { if (bucket && _.isPlainObject(bucket.buckets)) { return _.map(bucket.buckets, function (value, key) { var item = _.cloneDeep(value); - item.key = key; + item.key = agg ? agg.getKey(value, key) : key; return item; }); diff --git a/src/ui/public/agg_response/hierarchical/_transform_aggregation.js b/src/ui/public/agg_response/hierarchical/_transform_aggregation.js index ee166a6f36f5..0a3342ce8d23 100644 --- a/src/ui/public/agg_response/hierarchical/_transform_aggregation.js +++ b/src/ui/public/agg_response/hierarchical/_transform_aggregation.js @@ -4,7 +4,7 @@ define(function (require) { return function transformAggregationProvider(Private) { var AggConfigResult = require('ui/Vis/AggConfigResult'); return function transformAggregation(agg, metric, aggData, parent) { - return _.map(extractBuckets(aggData), function (bucket) { + return _.map(extractBuckets(aggData, agg), function (bucket) { var aggConfigResult = new AggConfigResult( agg, parent && parent.aggConfigResult, diff --git a/src/ui/public/agg_response/hierarchical/build_hierarchical_data.js b/src/ui/public/agg_response/hierarchical/build_hierarchical_data.js index 3ba63852008f..bceb842dc6ea 100644 --- a/src/ui/public/agg_response/hierarchical/build_hierarchical_data.js +++ b/src/ui/public/agg_response/hierarchical/build_hierarchical_data.js @@ -65,11 +65,11 @@ define(function (require) { } // map the split aggregations into rows. - var rows = _.map(extractBuckets(aggData), function (bucket) { + var rows = _.map(extractBuckets(aggData, firstAgg), function (bucket) { var agg = firstAgg._next; var split = buildSplit(agg, metric, bucket[agg.id]); // Since splits display labels we need to set it. - split.label = firstAgg.fieldFormatter()(bucket.key); + split.label = firstAgg.fieldFormatter()(agg.getKey(bucket)); var displayName = firstAgg.fieldDisplayName(); if (!_.isEmpty(displayName)) split.label += ': ' + displayName; diff --git a/src/ui/public/agg_types/__tests__/AggType.js b/src/ui/public/agg_types/__tests__/AggType.js index 9756b9664054..2f3e37f31797 100644 --- a/src/ui/public/agg_types/__tests__/AggType.js +++ b/src/ui/public/agg_types/__tests__/AggType.js @@ -106,25 +106,6 @@ describe('AggType Class', function () { expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('string')); }); - it('returns the string formatter for the range aggs', function () { - var aggType = new AggType({}); - - var vis = new Vis(indexPattern, { - type: 'histogram', - aggs: [ - { - type: 'range', - schema: 'segment', - } - ] - }); - - var aggConfig = vis.aggs.byTypeName.range[0]; - aggConfig.params = {field: {format: 'non_used_format'}}; - - expect(aggType.getFormat(aggConfig)).to.be(fieldFormat.getDefaultInstance('string')); - }); - it('can be overridden via config', function () { var someGetter = function () {}; diff --git a/src/ui/public/agg_types/__tests__/buckets/_range.js b/src/ui/public/agg_types/__tests__/buckets/_range.js new file mode 100644 index 000000000000..f627194b0619 --- /dev/null +++ b/src/ui/public/agg_types/__tests__/buckets/_range.js @@ -0,0 +1,58 @@ +describe('Range Agg', function () { + var _ = require('lodash'); + var ngMock = require('ngMock'); + var expect = require('expect.js'); + var values = require('lodash').values; + + var resp = require('fixtures/agg_resp/range'); + var buckets = values(resp.aggregations[1].buckets); + + var range; + var Vis; + var indexPattern; + + beforeEach(ngMock.module('kibana')); + beforeEach(ngMock.inject(function (Private) { + range = Private(require('ui/agg_types/index')).byName.range; + Vis = Private(require('ui/Vis')); + indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern')); + + var BytesFormat = Private(require('ui/registry/field_formats')).byId.bytes; + + indexPattern.fieldFormatMap.bytes = new BytesFormat({ + pattern: '0,0.[000] b' + }); + + indexPattern._indexFields(); + })); + + describe('formating', function () { + it('formats bucket keys properly', function () { + var vis = new Vis(indexPattern, { + type: 'histogram', + aggs: [ + { + type: 'range', + schema: 'segment', + params: { + field: 'bytes', + ranges: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 } + ] + } + } + ] + }); + + var agg = vis.aggs.byTypeName.range[0]; + var format = function (val) { + return agg.fieldFormatter()(agg.getKey(val)); + }; + expect(format(buckets[0])).to.be('[-∞, 1 KB)'); + expect(format(buckets[1])).to.be('[1 KB, 2.5 KB)'); + expect(format(buckets[2])).to.be('[2.5 KB, +∞)'); + + }); + }); +}); diff --git a/src/ui/public/agg_types/__tests__/buckets/create_filter/range.js b/src/ui/public/agg_types/__tests__/buckets/create_filter/range.js index 10b03bbc3b33..2a78530ac5e9 100644 --- a/src/ui/public/agg_types/__tests__/buckets/create_filter/range.js +++ b/src/ui/public/agg_types/__tests__/buckets/create_filter/range.js @@ -34,7 +34,7 @@ describe('AggConfig Filters', function () { }); var aggConfig = vis.aggs.byTypeName.range[0]; - var filter = createFilter(aggConfig, '1024.0-2048.0'); + var filter = createFilter(aggConfig, { gte: 1024, lt: 2048.0 }); expect(filter).to.have.property('range'); expect(filter).to.have.property('meta'); expect(filter.meta).to.have.property('index', indexPattern.id); diff --git a/src/ui/public/agg_types/__tests__/index.js b/src/ui/public/agg_types/__tests__/index.js index 0c7923677fa6..ac1e8c19bb91 100644 --- a/src/ui/public/agg_types/__tests__/index.js +++ b/src/ui/public/agg_types/__tests__/index.js @@ -6,6 +6,7 @@ describe('AggTypesComponent', function () { require('./AggParams'); require('./bucketCountBetween'); require('./buckets/_histogram'); + require('./buckets/_range'); describe('bucket aggs', function () { var bucketAggs; diff --git a/src/ui/public/agg_types/buckets/create_filter/range.js b/src/ui/public/agg_types/buckets/create_filter/range.js index 04c29b807e79..7ac4ce305ad7 100644 --- a/src/ui/public/agg_types/buckets/create_filter/range.js +++ b/src/ui/public/agg_types/buckets/create_filter/range.js @@ -2,13 +2,7 @@ define(function (require) { var buildRangeFilter = require('ui/filter_manager/lib/range'); return function createRangeFilterProvider(Private) { return function (aggConfig, key) { - var splits = key.split(/\-/); - var gte = Number(splits[0]); - var lt = Number(splits[1]); - return buildRangeFilter(aggConfig.params.field, { - gte: gte, - lt: lt - }, aggConfig.vis.indexPattern); + return buildRangeFilter(aggConfig.params.field, key, aggConfig.vis.indexPattern); }; }; }); diff --git a/src/ui/public/agg_types/buckets/date_range.js b/src/ui/public/agg_types/buckets/date_range.js index 222720a32a7b..9296485a425b 100644 --- a/src/ui/public/agg_types/buckets/date_range.js +++ b/src/ui/public/agg_types/buckets/date_range.js @@ -14,12 +14,7 @@ define(function (require) { title: 'Date Range', createFilter: createFilter, getKey: function (bucket, key, agg) { - var formatter; - if (agg.field()) { - formatter = agg.field().format.getConverterFor('text'); - } else { - formatter = fieldFormats.getDefaultInstance('date').getConverterFor('text'); - } + var formatter = agg.fieldOwnFormatter('text', fieldFormats.getDefaultInstance('date')); return dateRange.toString(bucket, formatter); }, getFormat: function () { diff --git a/src/ui/public/agg_types/buckets/range.js b/src/ui/public/agg_types/buckets/range.js index 122f14fd3e9b..7cb75f880b7c 100644 --- a/src/ui/public/agg_types/buckets/range.js +++ b/src/ui/public/agg_types/buckets/range.js @@ -3,7 +3,8 @@ define(function (require) { var _ = require('lodash'); var BucketAggType = Private(require('ui/agg_types/buckets/_bucket_agg_type')); var createFilter = Private(require('ui/agg_types/buckets/create_filter/range')); - var fieldFormats = Private(require('ui/registry/field_formats')); + var FieldFormat = Private(require('ui/index_patterns/_field_format/FieldFormat')); + return new BucketAggType({ name: 'range', @@ -13,12 +14,22 @@ define(function (require) { return aggConfig.params.field.displayName + ' ranges'; }, getKey: function (bucket, key, agg) { - let stringFormat = fieldFormats.getDefaultInstance('string'); - let format = _.get(agg.field(), 'format', stringFormat).getConverterFor('text'); - return `${format(bucket.from)} to ${format(bucket.to)}`; + let range = { gte: bucket.from, lt: bucket.to }; + + if (range.gte == null) range.gte = -Infinity; + if (range.lt == null) range.lt = +Infinity; + + return range; }, - getFormat: function () { - return fieldFormats.getDefaultInstance('string'); + getFormat: function (agg) { + if (agg.$$rangeAggTypeFormat) return agg.$$rangeAggTypeFormat; + + var RangeFormat = FieldFormat.from(function (range) { + var format = agg.fieldOwnFormatter(); + return `[${format(range.gte)}, ${format(range.lt)})`; + }); + + return (this.$$rangeAggTypeFormat = new RangeFormat()); }, params: [ { diff --git a/src/ui/public/filter_bar/lib/mapRange.js b/src/ui/public/filter_bar/lib/mapRange.js index e671e268fef9..0946b818b9e9 100644 --- a/src/ui/public/filter_bar/lib/mapRange.js +++ b/src/ui/public/filter_bar/lib/mapRange.js @@ -1,27 +1,29 @@ define(function (require) { - var _ = require('lodash'); + var {has} = require('lodash'); return function mapRangeProvider(Promise, courier) { return function (filter) { - var key; - var value; - var from; - var to; - var field; - if (filter.range) { - return courier - .indexPatterns - .get(filter.meta.index).then(function (indexPattern) { - key = _.keys(filter.range)[0]; - field = indexPattern.fields.byName[key]; - from = (filter.range[key].gte != null) ? filter.range[key].gte : filter.range[key].gt; - from = field.format.convert(from); - to = (filter.range[key].lte != null) ? filter.range[key].lte : filter.range[key].lt; - to = field.format.convert(to); - value = from + ' to ' + to; - return { key: key, value: value }; - }); - } - return Promise.reject(filter); + if (!filter.range) return Promise.reject(filter); + + return courier + .indexPatterns + .get(filter.meta.index) + .then(function (indexPattern) { + var key = Object.keys(filter.range)[0]; + var convert = indexPattern.fields.byName[key].format.getConverterFor('text'); + var range = filter.range[key]; + + var left = has(range, 'gte') ? range.gte : range.gt; + if (left == null) left = -Infinity; + + var right = has(range, 'lte') ? range.lte : range.lt; + if (right == null) right = Infinity; + + return { + key: key, + value: `[${convert(left)}, ${convert(right)})` + }; + }); + }; }; }); diff --git a/src/ui/public/index_patterns/_field_format/FieldFormat.js b/src/ui/public/index_patterns/_field_format/FieldFormat.js index bcf411d34b7a..c107e763b197 100644 --- a/src/ui/public/index_patterns/_field_format/FieldFormat.js +++ b/src/ui/public/index_patterns/_field_format/FieldFormat.js @@ -21,6 +21,15 @@ define(function (require) { contentTypes.setup(self); } + FieldFormat.from = function (converter) { + _.class(FieldFormatFromConverter).inherits(FieldFormat); + function FieldFormatFromConverter(params) { + FieldFormatFromConverter.Super.call(this, params); + } + FieldFormatFromConverter.prototype._convert = converter; + return FieldFormatFromConverter; + }; + /** * Convert a raw value to a formated string * @param {any} value diff --git a/src/ui/public/stringify/types/_Numeral.js b/src/ui/public/stringify/types/_Numeral.js index 4e9ba049f4ce..6c55a4616c5c 100644 --- a/src/ui/public/stringify/types/_Numeral.js +++ b/src/ui/public/stringify/types/_Numeral.js @@ -12,6 +12,8 @@ define(function (require) { } Numeral.prototype._convert = function (val) { + if (val === -Infinity) return '-∞'; + if (val === +Infinity) return '+∞'; if (typeof val !== 'number') { val = parseFloat(val); } From 4c1302dfc540ae14d782efe7b42119038f89b834 Mon Sep 17 00:00:00 2001 From: spalger Date: Sat, 8 Aug 2015 22:44:21 -0700 Subject: [PATCH 5/6] update a few outstanding tests --- src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js | 2 +- src/ui/public/filter_bar/__tests__/mapRange.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js b/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js index db93d8d12487..6648149d8f40 100644 --- a/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js +++ b/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js @@ -46,7 +46,7 @@ describe('Filter Bar Directive', function () { expect(results[2].meta).to.have.property('key', 'query'); expect(results[2].meta).to.have.property('value', 'foo:bar'); expect(results[3].meta).to.have.property('key', 'bytes'); - expect(results[3].meta).to.have.property('value', '1,024 to 2,048'); + expect(results[3].meta).to.have.property('value', '[1,024, 2,048)'); expect(results[4].meta).to.have.property('key', '_type'); expect(results[4].meta).to.have.property('value', 'apache'); done(); diff --git a/src/ui/public/filter_bar/__tests__/mapRange.js b/src/ui/public/filter_bar/__tests__/mapRange.js index dba4b114cad0..3eb24dcce5ae 100644 --- a/src/ui/public/filter_bar/__tests__/mapRange.js +++ b/src/ui/public/filter_bar/__tests__/mapRange.js @@ -24,7 +24,7 @@ describe('Filter Bar Directive', function () { var filter = { meta: { index: 'logstash-*' }, range: { bytes: { lt: 2048, gt: 1024 } } }; mapRange(filter).then(function (result) { expect(result).to.have.property('key', 'bytes'); - expect(result).to.have.property('value', '1,024 to 2,048'); + expect(result).to.have.property('value', '[1,024, 2,048)'); done(); }); $rootScope.$apply(); @@ -34,7 +34,7 @@ describe('Filter Bar Directive', function () { var filter = { meta: { index: 'logstash-*' }, range: { bytes: { lte: 2048, gte: 1024 } } }; mapRange(filter).then(function (result) { expect(result).to.have.property('key', 'bytes'); - expect(result).to.have.property('value', '1,024 to 2,048'); + expect(result).to.have.property('value', '[1,024, 2,048)'); done(); }); $rootScope.$apply(); From 0bbfc6c38a2213d41e2fcc1bf15e9dfde6863f30 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Aug 2015 18:29:26 -0700 Subject: [PATCH 6/6] switch back to "x to y" format for ranges --- src/ui/public/agg_types/__tests__/buckets/_range.js | 6 +++--- src/ui/public/agg_types/buckets/range.js | 2 +- src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js | 2 +- src/ui/public/filter_bar/__tests__/mapRange.js | 4 ++-- src/ui/public/filter_bar/lib/mapRange.js | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ui/public/agg_types/__tests__/buckets/_range.js b/src/ui/public/agg_types/__tests__/buckets/_range.js index f627194b0619..998b0857ba64 100644 --- a/src/ui/public/agg_types/__tests__/buckets/_range.js +++ b/src/ui/public/agg_types/__tests__/buckets/_range.js @@ -49,9 +49,9 @@ describe('Range Agg', function () { var format = function (val) { return agg.fieldFormatter()(agg.getKey(val)); }; - expect(format(buckets[0])).to.be('[-∞, 1 KB)'); - expect(format(buckets[1])).to.be('[1 KB, 2.5 KB)'); - expect(format(buckets[2])).to.be('[2.5 KB, +∞)'); + expect(format(buckets[0])).to.be('-∞ to 1 KB'); + expect(format(buckets[1])).to.be('1 KB to 2.5 KB'); + expect(format(buckets[2])).to.be('2.5 KB to +∞'); }); }); diff --git a/src/ui/public/agg_types/buckets/range.js b/src/ui/public/agg_types/buckets/range.js index 7cb75f880b7c..409e3fce009c 100644 --- a/src/ui/public/agg_types/buckets/range.js +++ b/src/ui/public/agg_types/buckets/range.js @@ -26,7 +26,7 @@ define(function (require) { var RangeFormat = FieldFormat.from(function (range) { var format = agg.fieldOwnFormatter(); - return `[${format(range.gte)}, ${format(range.lt)})`; + return `${format(range.gte)} to ${format(range.lt)}`; }); return (this.$$rangeAggTypeFormat = new RangeFormat()); diff --git a/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js b/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js index 6648149d8f40..db93d8d12487 100644 --- a/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js +++ b/src/ui/public/filter_bar/__tests__/mapAndFlattenFilters.js @@ -46,7 +46,7 @@ describe('Filter Bar Directive', function () { expect(results[2].meta).to.have.property('key', 'query'); expect(results[2].meta).to.have.property('value', 'foo:bar'); expect(results[3].meta).to.have.property('key', 'bytes'); - expect(results[3].meta).to.have.property('value', '[1,024, 2,048)'); + expect(results[3].meta).to.have.property('value', '1,024 to 2,048'); expect(results[4].meta).to.have.property('key', '_type'); expect(results[4].meta).to.have.property('value', 'apache'); done(); diff --git a/src/ui/public/filter_bar/__tests__/mapRange.js b/src/ui/public/filter_bar/__tests__/mapRange.js index 3eb24dcce5ae..dba4b114cad0 100644 --- a/src/ui/public/filter_bar/__tests__/mapRange.js +++ b/src/ui/public/filter_bar/__tests__/mapRange.js @@ -24,7 +24,7 @@ describe('Filter Bar Directive', function () { var filter = { meta: { index: 'logstash-*' }, range: { bytes: { lt: 2048, gt: 1024 } } }; mapRange(filter).then(function (result) { expect(result).to.have.property('key', 'bytes'); - expect(result).to.have.property('value', '[1,024, 2,048)'); + expect(result).to.have.property('value', '1,024 to 2,048'); done(); }); $rootScope.$apply(); @@ -34,7 +34,7 @@ describe('Filter Bar Directive', function () { var filter = { meta: { index: 'logstash-*' }, range: { bytes: { lte: 2048, gte: 1024 } } }; mapRange(filter).then(function (result) { expect(result).to.have.property('key', 'bytes'); - expect(result).to.have.property('value', '[1,024, 2,048)'); + expect(result).to.have.property('value', '1,024 to 2,048'); done(); }); $rootScope.$apply(); diff --git a/src/ui/public/filter_bar/lib/mapRange.js b/src/ui/public/filter_bar/lib/mapRange.js index 0946b818b9e9..a0d0c5bd18ee 100644 --- a/src/ui/public/filter_bar/lib/mapRange.js +++ b/src/ui/public/filter_bar/lib/mapRange.js @@ -20,7 +20,7 @@ define(function (require) { return { key: key, - value: `[${convert(left)}, ${convert(right)})` + value: `${convert(left)} to ${convert(right)}` }; });