mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[registry/fieldFormats] replace indexPattern/fieldFormats with a registry
This commit is contained in:
parent
fcd2d6e42a
commit
171ea25ca0
6 changed files with 54 additions and 328 deletions
|
@ -79,6 +79,42 @@ define(function (require) {
|
|||
'truncate:maxHeight': {
|
||||
value: 115,
|
||||
description: 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.'
|
||||
},
|
||||
'deafultFormat:ip': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type ip.'
|
||||
},
|
||||
'deafultFormat:date': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type date.'
|
||||
},
|
||||
'deafultFormat:string': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type string.'
|
||||
},
|
||||
'deafultFormat:number': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type number.'
|
||||
},
|
||||
'deafultFormat:boolean': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type boolean.'
|
||||
},
|
||||
'deafultFormat:conflict': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type conflict.'
|
||||
},
|
||||
'deafultFormat:geo_point': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type geo_point.'
|
||||
},
|
||||
'deafultFormat:geo_shape': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type geo_shape.'
|
||||
},
|
||||
'deafultFormat:attachment': {
|
||||
value: 'string',
|
||||
description: 'The default format to be used for fields of type attachment.'
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,175 +0,0 @@
|
|||
/**
|
||||
|
||||
### Formatting a value
|
||||
To format a response value, you need to get ahold of the field list, which is usually available at `indexPattern.fields`. Each field object has a `format` property*, which is an object detailed in [_field_formats.js](https://github.com/elastic/kibana4/blob/master/src/kibana/components/index_patterns/_field_formats.js).
|
||||
|
||||
Once you have the field that a response value came from, pass the value to `field.format.convert(value)` and a formatted string representation of the field will be returned.
|
||||
|
||||
\* the `format` property on field object's is a non-enumerable getter, meaning that if you itterate/clone/stringify the field object the format property will not be present.
|
||||
|
||||
### Changing a field's format
|
||||
|
||||
Currently only one field format exists, `"string"`, which just [flattens any value down to a string](https://github.com/elastic/kibana4/blob/master/src/kibana/components/index_patterns/_field_formats.js#L18-L24).
|
||||
|
||||
To change the format for a specific field you can either change the default for a field type modify the [default format mapping here](https://github.com/elastic/kibana4/blob/master/src/kibana/components/index_patterns/_field_formats.js#L37-L46).
|
||||
|
||||
To change the format for a specific indexPattern's field, add the field and format name to `indexPattern.customFormats` object property.
|
||||
|
||||
```js
|
||||
$scope.onChangeFormat = function (field, format) {
|
||||
indexPattern.customFormats[field.name] = format.name;
|
||||
};
|
||||
```
|
||||
|
||||
### Passing the formats to a chart
|
||||
Currently, the [histogram formatter](https://github.com/elastic/kibana4/blob/master/src/plugins/visualize/saved_visualizations/resp_converters/histogram.js) passes the formatting function as the `xAxisFormatter` and `yAxisFormatter` function.
|
||||
|
||||
*/
|
||||
|
||||
define(function (require) {
|
||||
return function FieldFormattingService($rootScope, config) {
|
||||
var _ = require('lodash');
|
||||
var angular = require('angular');
|
||||
var moment = require('moment');
|
||||
|
||||
function stringConverter(val) {
|
||||
return formatField(val, function (val) {
|
||||
if (_.isObject(val)) {
|
||||
return angular.toJson(val);
|
||||
}
|
||||
else if (val == null) {
|
||||
return '';
|
||||
}
|
||||
else {
|
||||
return '' + val;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var formats = [
|
||||
{
|
||||
types: [
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'ip',
|
||||
'attachment',
|
||||
'geo_point',
|
||||
'geo_shape',
|
||||
'string',
|
||||
'conflict'
|
||||
],
|
||||
name: 'string',
|
||||
convert: stringConverter
|
||||
},
|
||||
{
|
||||
types: [
|
||||
'date'
|
||||
],
|
||||
name: 'date',
|
||||
convert: function (val) {
|
||||
return formatField(val, function (val) {
|
||||
if (_.isNumber(val) || _.isDate(val)) {
|
||||
return moment(val).format(config.get('dateFormat'));
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
types: [
|
||||
'ip'
|
||||
],
|
||||
name: 'ip',
|
||||
convert: function (val) {
|
||||
return formatField(val, function (val) {
|
||||
if (!isFinite(val)) return val;
|
||||
return [val >>> 24, val >>> 16 & 0xFF, val >>> 8 & 0xFF, val & 0xFF].join('.');
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
types: [
|
||||
'number'
|
||||
],
|
||||
name: 'kilobytes',
|
||||
convert: function (val) {
|
||||
return formatField(val, function (val) {
|
||||
return (val / 1024).toFixed(config.get('format:numberPrecision')) + ' kb';
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
types: [
|
||||
'number',
|
||||
'murmur3'
|
||||
],
|
||||
name: 'number',
|
||||
convert: function (val) {
|
||||
return formatField(val, function (val) {
|
||||
if (_.isNumber(val)) {
|
||||
return +val.toFixed(config.get('format:numberPrecision'));
|
||||
} else {
|
||||
return stringConverter(val);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function formatField(value, fn) {
|
||||
if (_.isArray(value)) {
|
||||
if (value.length === 1) {
|
||||
return fn(value[0]);
|
||||
} else {
|
||||
return angular.toJson(_.map(value, fn));
|
||||
}
|
||||
} else {
|
||||
return fn(value);
|
||||
}
|
||||
}
|
||||
|
||||
formats.byType = _.transform(formats, function (byType, formatter) {
|
||||
formatter.types.forEach(function (type) {
|
||||
var list = byType[type] || (byType[type] = []);
|
||||
list.push(formatter);
|
||||
});
|
||||
}, {});
|
||||
|
||||
formats.byName = _.indexBy(formats, 'name');
|
||||
|
||||
formats.defaultByType = {
|
||||
number: formats.byName.number,
|
||||
murmur3: formats.byName.number,
|
||||
date: formats.byName.date,
|
||||
boolean: formats.byName.string,
|
||||
ip: formats.byName.ip,
|
||||
attachment: formats.byName.string,
|
||||
geo_point: formats.byName.string,
|
||||
geo_shape: formats.byName.string,
|
||||
string: formats.byName.string,
|
||||
conflict: formats.byName.string
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the dateFormat.convert function in memoize,
|
||||
* as moment is a huge performance issue if not memoized.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function memoizeDateFormat() {
|
||||
var format = formats.byName.date;
|
||||
if (!format._origConvert) {
|
||||
format._origConvert = format.convert;
|
||||
}
|
||||
format.convert = _.memoize(format._origConvert);
|
||||
}
|
||||
|
||||
// memoize once config is ready, and every time the date format changes
|
||||
$rootScope.$on('init:config', memoizeDateFormat);
|
||||
$rootScope.$on('change:config.dateFormat', memoizeDateFormat);
|
||||
|
||||
return formats;
|
||||
};
|
||||
});
|
|
@ -42,7 +42,7 @@ define(function (require) {
|
|||
self.intervals = Private(require('components/index_patterns/_intervals'));
|
||||
self.mapper = Private(require('components/index_patterns/_mapper'));
|
||||
self.patternToWildcard = Private(require('components/index_patterns/_pattern_to_wildcard'));
|
||||
self.fieldFormats = Private(require('components/index_patterns/_field_formats'));
|
||||
self.fieldFormats = Private(require('registry/field_formats'));
|
||||
self.IndexPattern = IndexPattern;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define(function (require) {
|
||||
return function AggConfigFactory(Private, fieldTypeFilter) {
|
||||
var _ = require('lodash');
|
||||
var fieldFormats = Private(require('components/index_patterns/_field_formats'));
|
||||
var fieldFormats = Private(require('registry/field_formats'));
|
||||
|
||||
function AggConfig(vis, opts) {
|
||||
var self = this;
|
||||
|
|
16
src/kibana/registry/field_formats.js
Normal file
16
src/kibana/registry/field_formats.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
return require('registry/_registry')({
|
||||
name: 'fieldFormats',
|
||||
index: ['name'],
|
||||
group: ['compatability'],
|
||||
|
||||
constructor: function (config) {
|
||||
this.defaultForType = function (type) {
|
||||
var name = config.get('deafultFormat:' + type);
|
||||
return this.byName[name] || _.asString;
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,151 +0,0 @@
|
|||
define(function (require) {
|
||||
return ['Field Formatters', function () {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
|
||||
var _config;
|
||||
var formatters;
|
||||
var formatter;
|
||||
var types = [
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'ip',
|
||||
'attachment',
|
||||
'geo_point',
|
||||
'geo_shape',
|
||||
'murmur3',
|
||||
'string',
|
||||
'conflict'
|
||||
];
|
||||
|
||||
function formatFn(typeOrName) {
|
||||
return (formatters.byName[typeOrName] || formatters.defaultByType[typeOrName]).convert;
|
||||
}
|
||||
|
||||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private, $injector, config) {
|
||||
_config = config;
|
||||
formatters = Private(require('components/index_patterns/_field_formats'));
|
||||
}));
|
||||
|
||||
it('should be an Object', function () {
|
||||
expect(formatters).to.be.an(Object);
|
||||
});
|
||||
|
||||
it('should have formatters indexed by type and by name', function () {
|
||||
expect(formatters.byType).to.be.an(Object);
|
||||
expect(formatters.byName).to.be.an(Object);
|
||||
});
|
||||
|
||||
it('should have 1 or more formatters for each of ' + types.join(','), function () {
|
||||
_.each(types, function (type) {
|
||||
expect(formatters.byType[type]).to.be.an(Array);
|
||||
_.each(formatters.byType[type], function (formatter) {
|
||||
expect(formatter.convert).to.be.a(Function);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should expose default formatters for each type', function () {
|
||||
_.each(types, function (type) {
|
||||
expect(formatters.defaultByType[type]).to.be.an(Object);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Array handling', function () {
|
||||
|
||||
it('should unwrap single item arrays', function () {
|
||||
formatter = formatFn('string');
|
||||
expect(formatter(['foo'])).to.not.be.an(Array);
|
||||
expect(formatter(['foo'])).to.be('foo');
|
||||
});
|
||||
|
||||
it('should stringify arrays longer than 1 element', function () {
|
||||
formatter = formatFn('ip');
|
||||
expect(formatter([0, 2130706433])).to.not.be.an(Array);
|
||||
expect(formatter([0, 2130706433])).to.be('["0.0.0.0","127.0.0.1"]');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('string formatter', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
formatter = formatFn('string');
|
||||
});
|
||||
|
||||
it('should the string value of the field', function () {
|
||||
expect(formatter('foo')).to.be('foo');
|
||||
expect(formatter(5)).to.be('5');
|
||||
});
|
||||
|
||||
it('should return JSON for objects', function () {
|
||||
expect(formatter({foo: true})).to.be('{"foo":true}');
|
||||
});
|
||||
|
||||
it('should return an empty string for null', function () {
|
||||
expect(formatter(null)).to.be('');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('date formatter', function () {
|
||||
|
||||
var dateFormat = 'YYYY-MM-DD';
|
||||
beforeEach(function () {
|
||||
_config.set('dateFormat', dateFormat);
|
||||
formatter = formatFn('date');
|
||||
});
|
||||
|
||||
it('should format numbers', function () {
|
||||
expect(formatter(0)).to.be(moment(0).format(dateFormat));
|
||||
});
|
||||
|
||||
it('should format dates', function () {
|
||||
expect(formatter(new Date(0))).to.be(moment(0).format(dateFormat));
|
||||
});
|
||||
|
||||
it('should not format strings', function () {
|
||||
expect(formatter('2014-11')).to.be('2014-11');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ip formatter', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
formatter = formatFn('ip');
|
||||
});
|
||||
|
||||
it('should format numbers', function () {
|
||||
expect(formatter(2130706433)).to.be('127.0.0.1');
|
||||
});
|
||||
|
||||
it('should coerce numbers that are strings', function () {
|
||||
expect(formatter('2130706433')).to.be('127.0.0.1');
|
||||
});
|
||||
|
||||
it('should not coerce strings that are not numbers', function () {
|
||||
expect(formatter('foo')).to.be('foo');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('kilobyte formatter', function () {
|
||||
beforeEach(function () {
|
||||
formatter = formatFn('kilobytes');
|
||||
});
|
||||
|
||||
it('should be a function', function () {
|
||||
expect(formatter).to.be.a(Function);
|
||||
});
|
||||
|
||||
it('should format a number as kilobytes', function () {
|
||||
expect(formatter(1024)).to.be('1.000 kb');
|
||||
});
|
||||
});
|
||||
|
||||
}];
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue