mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[fieldFormat] refactor contentTypes, text is now the default
This commit is contained in:
parent
9e8eb3aecb
commit
874c32e01b
22 changed files with 264 additions and 155 deletions
|
@ -17,7 +17,7 @@ define(function () {
|
|||
// the field exists.
|
||||
var bucket = item.name;
|
||||
if (col) {
|
||||
bucket = col.fieldFormatter('text')(bucket);
|
||||
bucket = col.fieldFormatter()(bucket);
|
||||
}
|
||||
|
||||
// Add the row to the tooltipScope.rows
|
||||
|
|
|
@ -23,7 +23,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
if (series) {
|
||||
point.series = series.agg.fieldFormatter('text')(unwrap(row[series.i]));
|
||||
point.series = series.agg.fieldFormatter()(unwrap(row[series.i]));
|
||||
}
|
||||
|
||||
if (yScale) {
|
||||
|
|
|
@ -2,7 +2,7 @@ define(function () {
|
|||
return function PointSeriesInitX() {
|
||||
return function initXAxis(chart) {
|
||||
var x = chart.aspects.x;
|
||||
chart.xAxisFormatter = x.agg ? x.agg.fieldFormatter('text') : String;
|
||||
chart.xAxisFormatter = x.agg ? x.agg.fieldFormatter() : String;
|
||||
chart.xAxisLabel = x.col.title;
|
||||
|
||||
if (!x.agg || !x.agg.type.ordered) return;
|
||||
|
|
|
@ -8,10 +8,10 @@ define(function (require) {
|
|||
|
||||
if (_.isArray(y)) {
|
||||
// TODO: vis option should allow choosing this format
|
||||
chart.yAxisFormatter = y[0].agg.fieldFormatter('text');
|
||||
chart.yAxisFormatter = y[0].agg.fieldFormatter();
|
||||
chart.yAxisLabel = ''; // use the legend
|
||||
} else {
|
||||
chart.yAxisFormatter = y.agg.fieldFormatter('text');
|
||||
chart.yAxisFormatter = y.agg.fieldFormatter();
|
||||
chart.yAxisLabel = y.col.title;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,14 +18,14 @@ define(function (require) {
|
|||
var value = result.value;
|
||||
|
||||
var detail = {
|
||||
value: agg.fieldFormatter('text')(value),
|
||||
value: agg.fieldFormatter()(value),
|
||||
label: agg.makeLabel()
|
||||
};
|
||||
|
||||
if (agg === datum.aggConfigResult.aggConfig) {
|
||||
detail.percent = event.percent;
|
||||
if (datum.yScale != null) {
|
||||
detail.value = agg.fieldFormatter('text')(value * datum.yScale);
|
||||
detail.value = agg.fieldFormatter()(value * datum.yScale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
43
src/kibana/components/bound_to_config_obj.js
Normal file
43
src/kibana/components/bound_to_config_obj.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
define(function (require) {
|
||||
return function BoundToConfigObjProvider($rootScope, config) {
|
||||
var _ = require('lodash');
|
||||
|
||||
/**
|
||||
* Create an object with properties that may be bound to config values.
|
||||
* The input object is basically cloned unless one of it's own properties
|
||||
* resolved to a string value that starts with an equal sign. When that is
|
||||
* found, that property is forever bound to the corresponding config key.
|
||||
*
|
||||
* example:
|
||||
*
|
||||
* // name is cloned, height is bound to the defaultHeight config key
|
||||
* { name: 'john', height: '=defaultHeight' };
|
||||
*
|
||||
* @param {Object} input
|
||||
* @return {Object}
|
||||
*/
|
||||
function BoundToConfigObj(input) {
|
||||
var self = this;
|
||||
|
||||
_.forOwn(input, function (val, prop) {
|
||||
if (!_.isString(val) || val.charAt(0) !== '=') {
|
||||
self[prop] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
var configKey = val.substr(1);
|
||||
|
||||
update();
|
||||
$rootScope.$on('init:config', update);
|
||||
$rootScope.$on('change:config.' + configKey, update);
|
||||
function update() {
|
||||
self[prop] = config.get(configKey);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return BoundToConfigObj;
|
||||
|
||||
};
|
||||
});
|
|
@ -10,9 +10,9 @@ define(function (require) {
|
|||
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, 'text');
|
||||
from = field.format.convert(from);
|
||||
to = (filter.range[key].lte != null) ? filter.range[key].lte : filter.range[key].lt;
|
||||
to = field.format.convert(to, 'text');
|
||||
to = field.format.convert(to);
|
||||
value = from + ' to ' + to;
|
||||
return { key: key, value: value };
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ define(function () {
|
|||
key = filter.meta.field;
|
||||
field = indexPattern.fields.byName[key];
|
||||
value = filter.script.params.value;
|
||||
value = field.format.convert(value, 'text');
|
||||
value = field.format.convert(value);
|
||||
return { key: key, value: value };
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ define(function (require) {
|
|||
key = _.keys(filter.query.match)[0];
|
||||
field = indexPattern.fields.byName[key];
|
||||
value = filter.query.match[key].query;
|
||||
value = field.format.convert(value, 'text');
|
||||
value = field.format.convert(value);
|
||||
return { key: key, value: value };
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ define(function (require) {
|
|||
return function FieldObjectProvider(Private, shortDotsFilter, $rootScope, Notifier, kbnUrl) {
|
||||
var notify = new Notifier({ location: 'IndexPattern Field' });
|
||||
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
var fieldTypes = Private(require('components/index_patterns/_field_types'));
|
||||
var fieldFormats = Private(require('registry/field_formats'));
|
||||
var ObjDefine = require('utils/obj_define');
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
define(function (require) {
|
||||
return function FieldFormatClassProvider(config, $rootScope) {
|
||||
var _ = require('lodash');
|
||||
|
||||
function FieldFormat(params) {
|
||||
var self = this;
|
||||
|
||||
if (!self._convert) {
|
||||
throw new Error('#_convert must be implemented by the FieldFormat subclass');
|
||||
}
|
||||
|
||||
// give the constructor a more appropriate name
|
||||
self.type = self.constructor;
|
||||
|
||||
// keep the params and defaults seperate
|
||||
self._params = params || {};
|
||||
self._paramDefaults = self.type.paramDefaults || {};
|
||||
|
||||
// memoize after default contentType is enforced so that
|
||||
// #getConverterFor() and #getConverterFor('default') are ===
|
||||
var getBoundConverter = _.memoize(function (contentType) {
|
||||
return function boundConverter(value) {
|
||||
if (value && typeof value.map === 'function') {
|
||||
// rudimentary array testing
|
||||
return JSON.stringify(value.map(boundConverter));
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
value = +value;
|
||||
} else {
|
||||
value = _.escape(value);
|
||||
}
|
||||
|
||||
return self._convert(value, contentType);
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Convert a raw value to a formated string
|
||||
* @param {any} value
|
||||
* @param {string} [contentType=html] - optional content type, the only two contentTypes
|
||||
* currently supported are "html" and "text", which helps
|
||||
* formatters adjust to different contexts
|
||||
* @return {string} - the formatted string, which is assumed to be html, safe for
|
||||
* injecting into the DOM
|
||||
*/
|
||||
self.convert = function (value, contentType) {
|
||||
return self.getConverterFor(contentType)(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a convert function that is bound to a specific contentType
|
||||
* @param {string} [contentType=html]
|
||||
* @return {function} - a bound converter function, which accepts a single "value"
|
||||
* argument of any type
|
||||
*/
|
||||
self.getConverterFor = function (contentType) {
|
||||
return getBoundConverter(contentType || 'html');
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of a param. This value may be a default value.
|
||||
*
|
||||
* @param {string} name - the param name to fetch
|
||||
* @return {any}
|
||||
*/
|
||||
self.param = function (name) {
|
||||
var val = this._params[name];
|
||||
if (val || val === false || val === 0) {
|
||||
// truthy, false, or 0 are fine
|
||||
// '', NaN, null, undefined, etc are not
|
||||
return val;
|
||||
}
|
||||
|
||||
return this._paramDefaults[name];
|
||||
};
|
||||
|
||||
self.params = function () {
|
||||
return _.cloneDeep(_.defaults({}, this._params, this._paramDefaults));
|
||||
};
|
||||
}
|
||||
|
||||
FieldFormat.initConfig = function (input) {
|
||||
return _.transform(input, function (params, val, key) {
|
||||
if (!_.isString(val) || val.charAt(0) !== '=') {
|
||||
params[key] = val;
|
||||
return;
|
||||
}
|
||||
|
||||
var configKey = val.substr(1);
|
||||
|
||||
update();
|
||||
$rootScope.$on('init:config', update);
|
||||
$rootScope.$on('change:config.' + configKey, update);
|
||||
function update() {
|
||||
params[key] = config.get(configKey);
|
||||
}
|
||||
|
||||
}, {});
|
||||
};
|
||||
|
||||
FieldFormat.prototype.toJSON = function () {
|
||||
var type = this.type;
|
||||
var defaults = this._paramDefaults;
|
||||
|
||||
var params = _.transform(this._params, function (uniqParams, val, param) {
|
||||
if (val !== defaults[param]) {
|
||||
uniqParams[param] = val;
|
||||
}
|
||||
}, {});
|
||||
|
||||
if (!_.size(params)) {
|
||||
params = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
id: type.id,
|
||||
params: params
|
||||
};
|
||||
};
|
||||
|
||||
return FieldFormat;
|
||||
};
|
||||
});
|
|
@ -0,0 +1,100 @@
|
|||
define(function (require) {
|
||||
return function FieldFormatClassProvider(config, $rootScope, Private) {
|
||||
var _ = require('lodash');
|
||||
var contentTypes = Private(require('components/index_patterns/_field_format/contentTypes'));
|
||||
|
||||
function FieldFormat(params) {
|
||||
var self = this;
|
||||
|
||||
// give the constructor a more appropriate name
|
||||
self.type = self.constructor;
|
||||
|
||||
// keep the params and defaults seperate
|
||||
self._params = params || {};
|
||||
self._paramDefaults = self.type.paramDefaults || {};
|
||||
|
||||
// one content type, so assume text
|
||||
if (_.isFunction(self._convert)) {
|
||||
self._convert = { text: self._convert };
|
||||
}
|
||||
|
||||
contentTypes.setup(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a raw value to a formated string
|
||||
* @param {any} value
|
||||
* @param {string} [contentType=text] - optional content type, the only two contentTypes
|
||||
* currently supported are "html" and "text", which helps
|
||||
* formatters adjust to different contexts
|
||||
* @return {string} - the formatted string, which is assumed to be html, safe for
|
||||
* injecting into the DOM or a DOM attribute
|
||||
*/
|
||||
FieldFormat.prototype.convert = function (value, contentType) {
|
||||
return this.getConverterFor(contentType)(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a convert function that is bound to a specific contentType
|
||||
* @param {string} [contentType=html]
|
||||
* @return {function} - a bound converter function, which accepts a single "value"
|
||||
* argument of any type
|
||||
*/
|
||||
FieldFormat.prototype.getConverterFor = function (contentType) {
|
||||
return this._convert[contentType] || this._convert.text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of a param. This value may be a default value.
|
||||
*
|
||||
* @param {string} name - the param name to fetch
|
||||
* @return {any}
|
||||
*/
|
||||
FieldFormat.prototype.param = function (name) {
|
||||
var val = this._params[name];
|
||||
if (val || val === false || val === 0) {
|
||||
// truthy, false, or 0 are fine
|
||||
// '', NaN, null, undefined, etc are not
|
||||
return val;
|
||||
}
|
||||
|
||||
return this._paramDefaults[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all of the params in a single object
|
||||
* @return {object}
|
||||
*/
|
||||
FieldFormat.prototype.params = function () {
|
||||
return _.cloneDeep(_.defaults({}, this._params, this._paramDefaults));
|
||||
};
|
||||
|
||||
/**
|
||||
* serialize this format to a simple POJO, with only the params
|
||||
* that are not default
|
||||
*
|
||||
* @return {object}
|
||||
*/
|
||||
FieldFormat.prototype.toJSON = function () {
|
||||
var type = this.type;
|
||||
var defaults = this._paramDefaults;
|
||||
|
||||
var params = _.transform(this._params, function (uniqParams, val, param) {
|
||||
if (val !== defaults[param]) {
|
||||
uniqParams[param] = val;
|
||||
}
|
||||
}, {});
|
||||
|
||||
if (!_.size(params)) {
|
||||
params = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
id: type.id,
|
||||
params: params
|
||||
};
|
||||
};
|
||||
|
||||
return FieldFormat;
|
||||
};
|
||||
});
|
|
@ -0,0 +1,61 @@
|
|||
define(function (require) {
|
||||
return function contentTypesProvider() {
|
||||
var _ = require('lodash');
|
||||
var angular = require('angular');
|
||||
|
||||
var types = {
|
||||
html: function (format, convert) {
|
||||
return function recurse(value) {
|
||||
var type = typeof value;
|
||||
|
||||
if (type === 'object' && typeof value.map === 'function') {
|
||||
if (value.$$_formattedField) return value.$$_formattedField;
|
||||
|
||||
var subVals = value.map(recurse);
|
||||
var useMultiLine = subVals.some(function (sub) {
|
||||
return sub.indexOf('\n') > -1;
|
||||
});
|
||||
|
||||
return value.$$_formattedField = subVals.join(',' + (useMultiLine ? '\n' : ' '));
|
||||
}
|
||||
|
||||
return convert.call(format, value);
|
||||
};
|
||||
},
|
||||
|
||||
text: function (format, convert) {
|
||||
return function recurse(value) {
|
||||
if (value && typeof value.map === 'function') {
|
||||
return angular.toJson(value.map(recurse));
|
||||
}
|
||||
|
||||
return _.escape(convert.call(format, value));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function setup(format) {
|
||||
var src = format._convert || {};
|
||||
var converters = format._convert = {};
|
||||
|
||||
if (src.text) {
|
||||
converters.text = types.text(format, src.text);
|
||||
} else {
|
||||
converters.text = types.text(format, _.escape);
|
||||
}
|
||||
|
||||
if (src.html) {
|
||||
converters.html = types.html(format, src.html);
|
||||
} else {
|
||||
converters.html = types.html(format, converters.text);
|
||||
}
|
||||
|
||||
return format._convert;
|
||||
}
|
||||
|
||||
return {
|
||||
types: types,
|
||||
setup: setup
|
||||
};
|
||||
};
|
||||
});
|
13
src/kibana/components/index_patterns/_object.tmpl.html
Normal file
13
src/kibana/components/index_patterns/_object.tmpl.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<dl class="source truncate-by-height">
|
||||
<% _.each(highlight, function (value, field) { /* show fields that match the query first */ %>
|
||||
<dt><%- shortDotsFilter(field) %>:</dt>
|
||||
<dd><%= source[field] %></dd>
|
||||
<%= ' ' %>
|
||||
<% }); %>
|
||||
<% _.each(source, function (value, field) { %>
|
||||
<% if (_.has(highlight, field)) return; %>
|
||||
<dt><%- shortDotsFilter(field) %>:</dt>
|
||||
<dd><%= value %></dd>
|
||||
<%= ' ' %>
|
||||
<% }); %>
|
||||
</dl>
|
10
src/kibana/components/stringify/editors/string.html
Normal file
10
src/kibana/components/stringify/editors/string.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<div class="form-group">
|
||||
<label>Transform</label>
|
||||
<select
|
||||
ng-model="editor.formatParams.transform"
|
||||
ng-options="opt.id as opt.name for opt in editor.field.format.type.transformOpts"
|
||||
class="form-control">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<field-format-editor-samples inputs="editor.field.format.type.sampleStrings"></field-format-editor-samples>
|
|
@ -1,7 +1,8 @@
|
|||
define(function (require) {
|
||||
return function DateTimeFormatProvider(Private) {
|
||||
var _ = require('lodash');
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
var BoundToConfigObj = Private(require('components/bound_to_config_obj'));
|
||||
var moment = require('moment');
|
||||
|
||||
require('components/field_format_editor/pattern/pattern');
|
||||
|
@ -15,7 +16,7 @@ define(function (require) {
|
|||
DateTime.title = 'Date';
|
||||
DateTime.fieldType = 'date';
|
||||
|
||||
DateTime.paramDefaults = FieldFormat.initConfig({
|
||||
DateTime.paramDefaults = new BoundToConfigObj({
|
||||
pattern: '=dateFormat'
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define(function (require) {
|
||||
return function IpFormatProvider(Private) {
|
||||
var _ = require('lodash');
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
|
||||
_(Ip).inherits(FieldFormat);
|
||||
function Ip(params) {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
define(function (require) {
|
||||
return function NumberFormatProvider(Private) {
|
||||
var _ = require('lodash');
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var BoundToConfigObj = Private(require('components/bound_to_config_obj'));
|
||||
var Numeral = Private(require('components/stringify/types/_Numeral'));
|
||||
|
||||
return Numeral.factory({
|
||||
id: 'percent',
|
||||
title: 'Percentage',
|
||||
editorTemplate: require('text!components/stringify/editors/_numeral.html'),
|
||||
paramDefaults: FieldFormat.initConfig({
|
||||
paramDefaults: new BoundToConfigObj({
|
||||
pattern: '=format:percent:defaultPattern',
|
||||
fractional: true
|
||||
}),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define(function (require) {
|
||||
return function _StringProvider(Private) {
|
||||
var _ = require('lodash');
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
|
||||
require('components/field_format_editor/samples/samples');
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ define(function (require) {
|
|||
return function UrlFormatProvider(Private) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
var StringFormat = Private(require('components/stringify/types/String'));
|
||||
require('components/field_format_editor/pattern/pattern');
|
||||
|
||||
|
@ -34,16 +34,21 @@ define(function (require) {
|
|||
{ id: 'img', name: 'Image' }
|
||||
];
|
||||
|
||||
Url.prototype._convert = function (rawValue, contentType) {
|
||||
var template = this.param('template');
|
||||
var val = !template ? rawValue : this._compileTemplate(template)(rawValue);
|
||||
Url.prototype._convert = {
|
||||
html: function (rawValue) {
|
||||
var url = this.convert(rawValue, 'text');
|
||||
var value = _.escape(rawValue);
|
||||
|
||||
if (contentType !== 'html') return val;
|
||||
switch (this.param('type')) {
|
||||
case 'img': return '<img src="' + url + '" alt="' + value + '">';
|
||||
default:
|
||||
return '<a href="' + url + '" target="_blank">' + url + '</a>';
|
||||
}
|
||||
},
|
||||
|
||||
switch (this.param('type')) {
|
||||
case 'img': return '<img src="' + val + '" alt="' + rawValue + '">';
|
||||
default:
|
||||
return '<a href="' + val + '" target="_blank">' + val + '</a>';
|
||||
text: function (value) {
|
||||
var template = this.param('template');
|
||||
return !template ? value : this._compileTemplate(template)(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
define(function (require) {
|
||||
return function AbstractNumeralFormatProvider(Private) {
|
||||
var _ = require('lodash');
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
var FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
var BoundToConfigObj = Private(require('components/bound_to_config_obj'));
|
||||
var numeral = require('numeral')();
|
||||
require('components/field_format_editor/numeral/numeral');
|
||||
|
||||
|
@ -31,7 +32,7 @@ define(function (require) {
|
|||
Class.title = opts.title;
|
||||
Class.fieldType = 'number';
|
||||
|
||||
Class.paramDefaults = opts.paramDefaults || FieldFormat.initConfig({
|
||||
Class.paramDefaults = opts.paramDefaults || new BoundToConfigObj({
|
||||
pattern: '=format:' + opts.id + ':defaultPattern',
|
||||
});
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ define(function (require) {
|
|||
describe('Stringify Component', function () {
|
||||
var _ = require('lodash');
|
||||
var $ = require('jquery');
|
||||
var moment = require('moment');
|
||||
|
||||
var fieldFormats;
|
||||
var FieldFormat;
|
||||
|
@ -23,7 +22,7 @@ define(function (require) {
|
|||
beforeEach(module('kibana'));
|
||||
beforeEach(inject(function (Private, $injector) {
|
||||
fieldFormats = Private(require('registry/field_formats'));
|
||||
FieldFormat = Private(require('components/index_patterns/_field_format'));
|
||||
FieldFormat = Private(require('components/index_patterns/_field_format/FieldFormat'));
|
||||
config = $injector.get('config');
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
}));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue