Merge pull request #4613 from spalger/merge/4434

Fix range formatting
This commit is contained in:
Joe Fleming 2015-08-12 10:56:09 -07:00
commit 31836a6302
16 changed files with 177 additions and 55 deletions

View file

@ -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
}
}
}
}
};

View file

@ -36,6 +36,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) {
@ -67,7 +71,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
});
@ -91,19 +95,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({

View file

@ -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 () {

View file

@ -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) {

View file

@ -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;
});

View file

@ -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,

View file

@ -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;

View file

@ -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('-∞ 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 +∞');
});
});
});

View file

@ -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);

View file

@ -6,6 +6,7 @@ describe('AggTypesComponent', function () {
require('./AggParams');
require('./bucketCountBetween');
require('./buckets/_histogram');
require('./buckets/_range');
describe('bucket aggs', function () {
var bucketAggs;

View file

@ -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);
};
};
});

View file

@ -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 () {

View file

@ -1,10 +1,10 @@
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 FieldFormat = Private(require('ui/index_patterns/_field_format/FieldFormat'));
return new BucketAggType({
name: 'range',
@ -13,6 +13,24 @@ define(function (require) {
makeLabel: function (aggConfig) {
return aggConfig.params.field.displayName + ' ranges';
},
getKey: function (bucket, key, agg) {
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 (agg) {
if (agg.$$rangeAggTypeFormat) return agg.$$rangeAggTypeFormat;
var RangeFormat = FieldFormat.from(function (range) {
var format = agg.fieldOwnFormatter();
return `${format(range.gte)} to ${format(range.lt)}`;
});
return (this.$$rangeAggTypeFormat = new RangeFormat());
},
params: [
{
name: 'field',

View file

@ -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)} to ${convert(right)}`
};
});
};
};
});

View file

@ -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

View file

@ -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);
}