mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* [ui/registry] allow custom provider invokation * [fieldFormats] define custom formats as functions of FieldFormat class * [fieldFormats/registerFieldFormat] call format creator to get class * [fieldFormats/fieldFormatsService] fix tests * [fieldFormats/registerFieldFormat] add tests * [metrics/tickFormatter] fix import from test
This commit is contained in:
parent
92bad847b5
commit
65c7e65053
34 changed files with 629 additions and 474 deletions
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { BoolFormat } from '../boolean';
|
||||
import { createBoolFormat } from '../boolean';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const BoolFormat = createBoolFormat(FieldFormat);
|
||||
|
||||
describe('Boolean Format', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { BytesFormat } from '../bytes';
|
||||
import { createBytesFormat } from '../bytes';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const BytesFormat = createBytesFormat(FieldFormat);
|
||||
|
||||
describe('BytesFormat', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { ColorFormat } from '../color';
|
||||
import { createColorFormat } from '../color';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const ColorFormat = createColorFormat(FieldFormat);
|
||||
|
||||
describe('Color Format', function () {
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import expect from 'expect.js';
|
||||
import moment from 'moment-timezone';
|
||||
import { DateFormat } from '../date';
|
||||
import { createDateFormat } from '../date';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const DateFormat = createDateFormat(FieldFormat);
|
||||
|
||||
describe('Date Format', function () {
|
||||
let convert;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { DurationFormat } from '../duration';
|
||||
import { createDurationFormat } from '../duration';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const DurationFormat = createDurationFormat(FieldFormat);
|
||||
|
||||
describe('Duration Format', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { IpFormat } from '../ip';
|
||||
import { createIpFormat } from '../ip';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const IpFormat = createIpFormat(FieldFormat);
|
||||
|
||||
describe('IP Address Format', function () {
|
||||
let ip;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { NumberFormat } from '../number';
|
||||
import { createNumberFormat } from '../number';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const NumberFormat = createNumberFormat(FieldFormat);
|
||||
|
||||
describe('NumberFormat', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { PercentFormat } from '../percent';
|
||||
import { createPercentFormat } from '../percent';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const PercentFormat = createPercentFormat(FieldFormat);
|
||||
|
||||
describe('PercentFormat', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { StringFormat } from '../string';
|
||||
import { createStringFormat } from '../string';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const StringFormat = createStringFormat(FieldFormat);
|
||||
|
||||
describe('String Format', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { TruncateFormat } from '../truncate';
|
||||
import { createTruncateFormat } from '../truncate';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const TruncateFormat = createTruncateFormat(FieldFormat);
|
||||
|
||||
describe('String TruncateFormat', function () {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import expect from 'expect.js';
|
||||
import { UrlFormat } from '../url';
|
||||
import { createUrlFormat } from '../url';
|
||||
import { FieldFormat } from '../../../../../../ui/field_formats/field_format';
|
||||
|
||||
const UrlFormat = createUrlFormat(FieldFormat);
|
||||
|
||||
describe('UrlFormat', function () {
|
||||
|
||||
|
|
|
@ -1,49 +1,50 @@
|
|||
import _ from 'lodash';
|
||||
import numeral from '@elastic/numeral';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
const numeralInst = numeral();
|
||||
|
||||
export class Numeral extends FieldFormat {
|
||||
_convert(val) {
|
||||
if (val === -Infinity) return '-∞';
|
||||
if (val === +Infinity) return '+∞';
|
||||
if (typeof val !== 'number') {
|
||||
val = parseFloat(val);
|
||||
export function createNumeralFormat(FieldFormat, opts) {
|
||||
class NumeralFormat extends FieldFormat {
|
||||
static id = opts.id;
|
||||
static title = opts.title;
|
||||
static fieldType = 'number';
|
||||
|
||||
constructor(params, getConfig) {
|
||||
super(params);
|
||||
|
||||
this.getConfig = getConfig;
|
||||
}
|
||||
|
||||
if (isNaN(val)) return '';
|
||||
|
||||
return numeralInst.set(val).format(this.param('pattern'));
|
||||
}
|
||||
|
||||
static factory(opts) {
|
||||
class Class extends Numeral {
|
||||
constructor(params, getConfig) {
|
||||
super(params);
|
||||
|
||||
this.getConfig = getConfig;
|
||||
getParamDefaults() {
|
||||
if (_.has(opts, 'getParamDefaults')) {
|
||||
return opts.getParamDefaults(this.getConfig);
|
||||
}
|
||||
|
||||
getParamDefaults() {
|
||||
if (_.has(opts, 'getParamDefaults')) {
|
||||
return opts.getParamDefaults(this.getConfig);
|
||||
}
|
||||
return {
|
||||
pattern: this.getConfig(`format:${opts.id}:defaultPattern`)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
pattern: this.getConfig(`format:${opts.id}:defaultPattern`)
|
||||
};
|
||||
_convert(val) {
|
||||
if (val === -Infinity) return '-∞';
|
||||
if (val === +Infinity) return '+∞';
|
||||
if (typeof val !== 'number') {
|
||||
val = parseFloat(val);
|
||||
}
|
||||
|
||||
static id = opts.id;
|
||||
static title = opts.title;
|
||||
static fieldType = 'number';
|
||||
}
|
||||
if (isNaN(val)) return '';
|
||||
|
||||
if (opts.prototype) {
|
||||
_.assign(Class.prototype, opts.prototype);
|
||||
}
|
||||
const formatted = numeralInst.set(val).format(this.param('pattern'));
|
||||
|
||||
return Class;
|
||||
return opts.afterConvert
|
||||
? opts.afterConvert.call(this, formatted)
|
||||
: formatted;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.prototype) {
|
||||
_.assign(NumeralFormat.prototype, opts.prototype);
|
||||
}
|
||||
|
||||
return NumeralFormat;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
import { asPrettyString } from '../../utils/as_pretty_string';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
export class BoolFormat extends FieldFormat {
|
||||
_convert(value) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.trim().toLowerCase();
|
||||
export function createBoolFormat(FieldFormat) {
|
||||
return class BoolFormat extends FieldFormat {
|
||||
_convert(value) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.trim().toLowerCase();
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case false:
|
||||
case 0:
|
||||
case 'false':
|
||||
case 'no':
|
||||
return 'false';
|
||||
case true:
|
||||
case 1:
|
||||
case 'true':
|
||||
case 'yes':
|
||||
return 'true';
|
||||
default:
|
||||
return asPrettyString(value);
|
||||
}
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case false:
|
||||
case 0:
|
||||
case 'false':
|
||||
case 'no':
|
||||
return 'false';
|
||||
case true:
|
||||
case 1:
|
||||
case 'true':
|
||||
case 'yes':
|
||||
return 'true';
|
||||
default:
|
||||
return asPrettyString(value);
|
||||
}
|
||||
}
|
||||
|
||||
static id = 'boolean';
|
||||
static title = 'Boolean';
|
||||
static fieldType = ['boolean', 'number', 'string'];
|
||||
static id = 'boolean';
|
||||
static title = 'Boolean';
|
||||
static fieldType = ['boolean', 'number', 'string'];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { Numeral } from './_numeral';
|
||||
import { createNumeralFormat } from './_numeral';
|
||||
|
||||
export const BytesFormat = Numeral.factory({
|
||||
id: 'bytes',
|
||||
title: 'Bytes'
|
||||
});
|
||||
export function createBytesFormat(FieldFormat) {
|
||||
return createNumeralFormat(FieldFormat, {
|
||||
id: 'bytes',
|
||||
title: 'Bytes'
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,53 +1,56 @@
|
|||
import _ from 'lodash';
|
||||
import { asPrettyString } from '../../utils/as_pretty_string';
|
||||
import { DEFAULT_COLOR } from './color_default';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
const convertTemplate = _.template('<span style="<%- style %>"><%- val %></span>');
|
||||
|
||||
export class ColorFormat extends FieldFormat {
|
||||
getParamDefaults() {
|
||||
return {
|
||||
fieldType: null, // populated by editor, see controller below
|
||||
colors: [_.cloneDeep(DEFAULT_COLOR)]
|
||||
};
|
||||
}
|
||||
|
||||
findColorRuleForVal(val) {
|
||||
switch (this.param('fieldType')) {
|
||||
case 'string':
|
||||
return _.findLast(this.param('colors'), (colorParam) => {
|
||||
return new RegExp(colorParam.regex).test(val);
|
||||
});
|
||||
|
||||
case 'number':
|
||||
return _.findLast(this.param('colors'), ({ range }) => {
|
||||
if (!range) return;
|
||||
const [start, end] = range.split(':');
|
||||
return val >= Number(start) && val <= Number(end);
|
||||
});
|
||||
|
||||
default:
|
||||
return null;
|
||||
export function createColorFormat(FieldFormat) {
|
||||
class ColorFormat extends FieldFormat {
|
||||
getParamDefaults() {
|
||||
return {
|
||||
fieldType: null, // populated by editor, see controller below
|
||||
colors: [_.cloneDeep(DEFAULT_COLOR)]
|
||||
};
|
||||
}
|
||||
|
||||
findColorRuleForVal(val) {
|
||||
switch (this.param('fieldType')) {
|
||||
case 'string':
|
||||
return _.findLast(this.param('colors'), (colorParam) => {
|
||||
return new RegExp(colorParam.regex).test(val);
|
||||
});
|
||||
|
||||
case 'number':
|
||||
return _.findLast(this.param('colors'), ({ range }) => {
|
||||
if (!range) return;
|
||||
const [start, end] = range.split(':');
|
||||
return val >= Number(start) && val <= Number(end);
|
||||
});
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static id = 'color';
|
||||
static title = 'Color';
|
||||
static fieldType = [
|
||||
'number',
|
||||
'string'
|
||||
];
|
||||
}
|
||||
|
||||
static id = 'color';
|
||||
static title = 'Color';
|
||||
static fieldType = [
|
||||
'number',
|
||||
'string'
|
||||
];
|
||||
ColorFormat.prototype._convert = {
|
||||
html(val) {
|
||||
const color = this.findColorRuleForVal(val);
|
||||
if (!color) return asPrettyString(val);
|
||||
|
||||
let style = '';
|
||||
if (color.text) style += `color: ${color.text};`;
|
||||
if (color.background) style += `background-color: ${color.background};`;
|
||||
return convertTemplate({ val, style });
|
||||
}
|
||||
};
|
||||
|
||||
return ColorFormat;
|
||||
}
|
||||
|
||||
ColorFormat.prototype._convert = {
|
||||
html(val) {
|
||||
const color = this.findColorRuleForVal(val);
|
||||
if (!color) return asPrettyString(val);
|
||||
|
||||
let style = '';
|
||||
if (color.text) style += `color: ${color.text};`;
|
||||
if (color.background) style += `background-color: ${color.background};`;
|
||||
return convertTemplate({ val, style });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,51 +1,52 @@
|
|||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
export class DateFormat extends FieldFormat {
|
||||
constructor(params, getConfig) {
|
||||
super(params);
|
||||
export function createDateFormat(FieldFormat) {
|
||||
return class DateFormat extends FieldFormat {
|
||||
constructor(params, getConfig) {
|
||||
super(params);
|
||||
|
||||
this.getConfig = getConfig;
|
||||
}
|
||||
|
||||
getParamDefaults() {
|
||||
return {
|
||||
pattern: this.getConfig('dateFormat'),
|
||||
timezone: this.getConfig('dateFormat:tz')
|
||||
};
|
||||
}
|
||||
|
||||
_convert(val) {
|
||||
// don't give away our ref to converter so
|
||||
// we can hot-swap when config changes
|
||||
const pattern = this.param('pattern');
|
||||
const timezone = this.param('timezone');
|
||||
|
||||
const timezoneChanged = this._timeZone !== timezone;
|
||||
const datePatternChanged = this._memoizedPattern !== pattern;
|
||||
if (timezoneChanged || datePatternChanged) {
|
||||
this._timeZone = timezone;
|
||||
this._memoizedPattern = pattern;
|
||||
|
||||
this._memoizedConverter = _.memoize(function converter(val) {
|
||||
if (val === null || val === undefined) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const date = moment(val);
|
||||
if (date.isValid()) {
|
||||
return date.format(pattern);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
});
|
||||
this.getConfig = getConfig;
|
||||
}
|
||||
|
||||
return this._memoizedConverter(val);
|
||||
}
|
||||
getParamDefaults() {
|
||||
return {
|
||||
pattern: this.getConfig('dateFormat'),
|
||||
timezone: this.getConfig('dateFormat:tz')
|
||||
};
|
||||
}
|
||||
|
||||
static id = 'date';
|
||||
static title = 'Date';
|
||||
static fieldType = 'date';
|
||||
_convert(val) {
|
||||
// don't give away our ref to converter so
|
||||
// we can hot-swap when config changes
|
||||
const pattern = this.param('pattern');
|
||||
const timezone = this.param('timezone');
|
||||
|
||||
const timezoneChanged = this._timeZone !== timezone;
|
||||
const datePatternChanged = this._memoizedPattern !== pattern;
|
||||
if (timezoneChanged || datePatternChanged) {
|
||||
this._timeZone = timezone;
|
||||
this._memoizedPattern = pattern;
|
||||
|
||||
this._memoizedConverter = _.memoize(function converter(val) {
|
||||
if (val === null || val === undefined) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const date = moment(val);
|
||||
if (date.isValid()) {
|
||||
return date.format(pattern);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this._memoizedConverter(val);
|
||||
}
|
||||
|
||||
static id = 'date';
|
||||
static title = 'Date';
|
||||
static fieldType = 'date';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import moment from 'moment';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
const ratioToSeconds = {
|
||||
picoseconds: 0.000000000001,
|
||||
|
@ -35,39 +34,41 @@ const outputFormats = [
|
|||
{ text: 'Years', method: 'asYears' }
|
||||
];
|
||||
|
||||
export class DurationFormat extends FieldFormat {
|
||||
isHuman() {
|
||||
return this.param('outputFormat') === HUMAN_FRIENDLY;
|
||||
}
|
||||
getParamDefaults() {
|
||||
return {
|
||||
inputFormat: DEFAULT_INPUT_FORMAT.kind,
|
||||
outputFormat: DEFAULT_OUTPUT_FORMAT.method,
|
||||
outputPrecision: DEFAULT_OUTPUT_PRECISION
|
||||
};
|
||||
}
|
||||
_convert(val) {
|
||||
const inputFormat = this.param('inputFormat');
|
||||
const outputFormat = this.param('outputFormat');
|
||||
const outputPrecision = this.param('outputPrecision');
|
||||
const human = this.isHuman();
|
||||
const prefix = val < 0 && human ? 'minus ' : '';
|
||||
const duration = parseInputAsDuration(val, inputFormat);
|
||||
const formatted = duration[outputFormat]();
|
||||
const precise = human ? formatted : formatted.toFixed(outputPrecision);
|
||||
return prefix + precise;
|
||||
}
|
||||
|
||||
static id = 'duration';
|
||||
static title = 'Duration';
|
||||
static fieldType = 'number';
|
||||
|
||||
static inputFormats = inputFormats;
|
||||
static outputFormats = outputFormats;
|
||||
}
|
||||
|
||||
function parseInputAsDuration(val, inputFormat) {
|
||||
const ratio = ratioToSeconds[inputFormat] || 1;
|
||||
const kind = inputFormat in ratioToSeconds ? 'seconds' : inputFormat;
|
||||
return moment.duration(val * ratio, kind);
|
||||
}
|
||||
|
||||
export function createDurationFormat(FieldFormat) {
|
||||
return class DurationFormat extends FieldFormat {
|
||||
isHuman() {
|
||||
return this.param('outputFormat') === HUMAN_FRIENDLY;
|
||||
}
|
||||
getParamDefaults() {
|
||||
return {
|
||||
inputFormat: DEFAULT_INPUT_FORMAT.kind,
|
||||
outputFormat: DEFAULT_OUTPUT_FORMAT.method,
|
||||
outputPrecision: DEFAULT_OUTPUT_PRECISION
|
||||
};
|
||||
}
|
||||
_convert(val) {
|
||||
const inputFormat = this.param('inputFormat');
|
||||
const outputFormat = this.param('outputFormat');
|
||||
const outputPrecision = this.param('outputPrecision');
|
||||
const human = this.isHuman();
|
||||
const prefix = val < 0 && human ? 'minus ' : '';
|
||||
const duration = parseInputAsDuration(val, inputFormat);
|
||||
const formatted = duration[outputFormat]();
|
||||
const precise = human ? formatted : formatted.toFixed(outputPrecision);
|
||||
return prefix + precise;
|
||||
}
|
||||
|
||||
static id = 'duration';
|
||||
static title = 'Duration';
|
||||
static fieldType = 'number';
|
||||
|
||||
static inputFormats = inputFormats;
|
||||
static outputFormats = outputFormats;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
export function createIpFormat(FieldFormat) {
|
||||
return class IpFormat extends FieldFormat {
|
||||
_convert(val) {
|
||||
if (val === undefined || val === null) return '-';
|
||||
if (!isFinite(val)) return val;
|
||||
|
||||
export class IpFormat extends FieldFormat {
|
||||
_convert(val) {
|
||||
if (val === undefined || val === null) return '-';
|
||||
if (!isFinite(val)) return val;
|
||||
// shazzam!
|
||||
return [val >>> 24, val >>> 16 & 0xFF, val >>> 8 & 0xFF, val & 0xFF].join('.');
|
||||
}
|
||||
|
||||
// shazzam!
|
||||
return [val >>> 24, val >>> 16 & 0xFF, val >>> 8 & 0xFF, val & 0xFF].join('.');
|
||||
}
|
||||
|
||||
static id = 'ip';
|
||||
static title = 'IP Address';
|
||||
static fieldType = 'ip';
|
||||
static id = 'ip';
|
||||
static title = 'IP Address';
|
||||
static fieldType = 'ip';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { Numeral } from './_numeral';
|
||||
import { createNumeralFormat } from './_numeral';
|
||||
|
||||
export const NumberFormat = Numeral.factory({
|
||||
id: 'number',
|
||||
title: 'Number'
|
||||
});
|
||||
export function createNumberFormat(FieldFormat) {
|
||||
return createNumeralFormat(FieldFormat, {
|
||||
id: 'number',
|
||||
title: 'Number'
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import _ from 'lodash';
|
||||
import { Numeral } from './_numeral';
|
||||
import { createNumeralFormat } from './_numeral';
|
||||
|
||||
export const PercentFormat = Numeral.factory({
|
||||
id: 'percent',
|
||||
title: 'Percentage',
|
||||
getParamDefaults: (getConfig) => {
|
||||
return {
|
||||
pattern: getConfig('format:percent:defaultPattern'),
|
||||
fractional: true
|
||||
};
|
||||
},
|
||||
prototype: {
|
||||
_convert: _.compose(Numeral.prototype._convert, function (val) {
|
||||
export function createPercentFormat(FieldFormat) {
|
||||
return createNumeralFormat(FieldFormat, {
|
||||
id: 'percent',
|
||||
title: 'Percentage',
|
||||
getParamDefaults: (getConfig) => {
|
||||
return {
|
||||
pattern: getConfig('format:percent:defaultPattern'),
|
||||
fractional: true
|
||||
};
|
||||
},
|
||||
afterConvert(val) {
|
||||
return this.param('fractional') ? val : val / 100;
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import { noWhiteSpace } from '../../utils/no_white_space';
|
||||
import { toJson } from '../../utils/aggressive_parse';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
import { shortenDottedString } from '../../utils/shorten_dotted_string';
|
||||
|
||||
const templateHtml = `
|
||||
|
@ -14,36 +13,40 @@ const templateHtml = `
|
|||
</dl>`;
|
||||
const template = _.template(noWhiteSpace(templateHtml));
|
||||
|
||||
export class SourceFormat extends FieldFormat {
|
||||
constructor(params, getConfig) {
|
||||
super(params);
|
||||
export function createSourceFormat(FieldFormat) {
|
||||
class SourceFormat extends FieldFormat {
|
||||
constructor(params, getConfig) {
|
||||
super(params);
|
||||
|
||||
this.getConfig = getConfig;
|
||||
this.getConfig = getConfig;
|
||||
}
|
||||
|
||||
static id = '_source';
|
||||
static title = '_source';
|
||||
static fieldType = '_source';
|
||||
}
|
||||
|
||||
static id = '_source';
|
||||
static title = '_source';
|
||||
static fieldType = '_source';
|
||||
SourceFormat.prototype._convert = {
|
||||
text: (value) => toJson(value),
|
||||
html: function sourceToHtml(source, field, hit) {
|
||||
if (!field) return this.getConverterFor('text')(source, field, hit);
|
||||
|
||||
const highlights = (hit && hit.highlight) || {};
|
||||
const formatted = field.indexPattern.formatHit(hit);
|
||||
const highlightPairs = [];
|
||||
const sourcePairs = [];
|
||||
|
||||
const isShortDots = this.getConfig('shortDots:enable');
|
||||
_.keys(formatted).forEach((key) => {
|
||||
const pairs = highlights[key] ? highlightPairs : sourcePairs;
|
||||
const field = isShortDots ? shortenDottedString(key) : key;
|
||||
const val = formatted[key];
|
||||
pairs.push([field, val]);
|
||||
}, []);
|
||||
|
||||
return template({ defPairs: highlightPairs.concat(sourcePairs) });
|
||||
}
|
||||
};
|
||||
|
||||
return SourceFormat;
|
||||
}
|
||||
|
||||
SourceFormat.prototype._convert = {
|
||||
text: (value) => toJson(value),
|
||||
html: function sourceToHtml(source, field, hit) {
|
||||
if (!field) return this.getConverterFor('text')(source, field, hit);
|
||||
|
||||
const highlights = (hit && hit.highlight) || {};
|
||||
const formatted = field.indexPattern.formatHit(hit);
|
||||
const highlightPairs = [];
|
||||
const sourcePairs = [];
|
||||
|
||||
const isShortDots = this.getConfig('shortDots:enable');
|
||||
_.keys(formatted).forEach((key) => {
|
||||
const pairs = highlights[key] ? highlightPairs : sourcePairs;
|
||||
const field = isShortDots ? shortenDottedString(key) : key;
|
||||
const val = formatted[key];
|
||||
pairs.push([field, val]);
|
||||
}, []);
|
||||
|
||||
return template({ defPairs: highlightPairs.concat(sourcePairs) });
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,50 +1,51 @@
|
|||
import { asPrettyString } from '../../utils/as_pretty_string';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
import { shortenDottedString } from '../../utils/shorten_dotted_string';
|
||||
|
||||
export class StringFormat extends FieldFormat {
|
||||
getParamDefaults() {
|
||||
return {
|
||||
transform: false
|
||||
};
|
||||
}
|
||||
|
||||
_base64Decode(val) {
|
||||
try {
|
||||
return Buffer.from(val, 'base64').toString('utf8');
|
||||
} catch (e) {
|
||||
return asPrettyString(val);
|
||||
export function createStringFormat(FieldFormat) {
|
||||
return class StringFormat extends FieldFormat {
|
||||
getParamDefaults() {
|
||||
return {
|
||||
transform: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
_toTitleCase(val) {
|
||||
return val.replace(/\w\S*/g, txt => { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
|
||||
}
|
||||
|
||||
_convert(val) {
|
||||
switch (this.param('transform')) {
|
||||
case 'lower': return String(val).toLowerCase();
|
||||
case 'upper': return String(val).toUpperCase();
|
||||
case 'title': return this._toTitleCase(val);
|
||||
case 'short': return shortenDottedString(val);
|
||||
case 'base64': return this._base64Decode(val);
|
||||
default: return asPrettyString(val);
|
||||
_base64Decode(val) {
|
||||
try {
|
||||
return Buffer.from(val, 'base64').toString('utf8');
|
||||
} catch (e) {
|
||||
return asPrettyString(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static id = 'string';
|
||||
static title = 'String';
|
||||
static fieldType = [
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'ip',
|
||||
'attachment',
|
||||
'geo_point',
|
||||
'geo_shape',
|
||||
'string',
|
||||
'murmur3',
|
||||
'unknown',
|
||||
'conflict'
|
||||
];
|
||||
_toTitleCase(val) {
|
||||
return val.replace(/\w\S*/g, txt => { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
|
||||
}
|
||||
|
||||
_convert(val) {
|
||||
switch (this.param('transform')) {
|
||||
case 'lower': return String(val).toLowerCase();
|
||||
case 'upper': return String(val).toUpperCase();
|
||||
case 'title': return this._toTitleCase(val);
|
||||
case 'short': return shortenDottedString(val);
|
||||
case 'base64': return this._base64Decode(val);
|
||||
default: return asPrettyString(val);
|
||||
}
|
||||
}
|
||||
|
||||
static id = 'string';
|
||||
static title = 'String';
|
||||
static fieldType = [
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'ip',
|
||||
'attachment',
|
||||
'geo_point',
|
||||
'geo_shape',
|
||||
'string',
|
||||
'murmur3',
|
||||
'unknown',
|
||||
'conflict'
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
import _ from 'lodash';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
const omission = '...';
|
||||
|
||||
export class TruncateFormat extends FieldFormat {
|
||||
_convert(val) {
|
||||
const length = this.param('fieldLength');
|
||||
if (length > 0) {
|
||||
return _.trunc(val, {
|
||||
'length': length + omission.length,
|
||||
'omission': omission
|
||||
});
|
||||
export function createTruncateFormat(FieldFormat) {
|
||||
return class TruncateFormat extends FieldFormat {
|
||||
_convert(val) {
|
||||
const length = this.param('fieldLength');
|
||||
if (length > 0) {
|
||||
return _.trunc(val, {
|
||||
'length': length + omission.length,
|
||||
'omission': omission
|
||||
});
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static id = 'truncate';
|
||||
static title = 'Truncated String';
|
||||
static fieldType = ['string'];
|
||||
static id = 'truncate';
|
||||
static title = 'Truncated String';
|
||||
static fieldType = ['string'];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,112 +1,115 @@
|
|||
import _ from 'lodash';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
import { getHighlightHtml } from '../../highlight/highlight_html';
|
||||
|
||||
const templateMatchRE = /{{([\s\S]+?)}}/g;
|
||||
|
||||
export class UrlFormat extends FieldFormat {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
this._compileTemplate = _.memoize(this._compileTemplate);
|
||||
}
|
||||
|
||||
getParamDefaults() {
|
||||
return {
|
||||
type: 'a',
|
||||
urlTemplate: null,
|
||||
labelTemplate: null
|
||||
};
|
||||
}
|
||||
|
||||
_formatLabel(value, url) {
|
||||
const template = this.param('labelTemplate');
|
||||
if (url == null) url = this._formatUrl(value);
|
||||
if (!template) return url;
|
||||
|
||||
return this._compileTemplate(template)({
|
||||
value: value,
|
||||
url: url
|
||||
});
|
||||
}
|
||||
|
||||
_formatUrl(value) {
|
||||
const template = this.param('urlTemplate');
|
||||
if (!template) return value;
|
||||
|
||||
return this._compileTemplate(template)({
|
||||
value: encodeURIComponent(value),
|
||||
rawValue: value
|
||||
});
|
||||
}
|
||||
|
||||
_compileTemplate(template) {
|
||||
const parts = template.split(templateMatchRE).map(function (part, i) {
|
||||
// trim all the odd bits, the variable names
|
||||
return (i % 2) ? part.trim() : part;
|
||||
});
|
||||
|
||||
return function (locals) {
|
||||
// replace all the odd bits with their local var
|
||||
let output = '';
|
||||
let i = -1;
|
||||
while (++i < parts.length) {
|
||||
if (i % 2) {
|
||||
if (locals.hasOwnProperty(parts[i])) {
|
||||
const local = locals[parts[i]];
|
||||
output += local == null ? '' : local;
|
||||
}
|
||||
} else {
|
||||
output += parts[i];
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
}
|
||||
|
||||
static id = 'url';
|
||||
static title = 'Url';
|
||||
static fieldType = [
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'ip',
|
||||
'string',
|
||||
'murmur3',
|
||||
'unknown',
|
||||
'conflict'
|
||||
];
|
||||
}
|
||||
|
||||
UrlFormat.prototype._convert = {
|
||||
text: function (value) {
|
||||
return this._formatLabel(value);
|
||||
},
|
||||
|
||||
html: function (rawValue, field, hit) {
|
||||
const url = _.escape(this._formatUrl(rawValue));
|
||||
const label = _.escape(this._formatLabel(rawValue, url));
|
||||
|
||||
switch (this.param('type')) {
|
||||
case 'img':
|
||||
// If the URL hasn't been formatted to become a meaningful label then the best we can do
|
||||
// is tell screen readers where the image comes from.
|
||||
const imageLabel =
|
||||
label === url
|
||||
? `A dynamically-specified image located at ${url}`
|
||||
: label;
|
||||
|
||||
return `<img src="${url}" alt="${imageLabel}">`;
|
||||
default:
|
||||
let linkLabel;
|
||||
|
||||
if (hit && hit.highlight && hit.highlight[field.name]) {
|
||||
linkLabel = getHighlightHtml(label, hit.highlight[field.name]);
|
||||
} else {
|
||||
linkLabel = label;
|
||||
}
|
||||
|
||||
return `<a href="${url}" target="_blank">${linkLabel}</a>`;
|
||||
export function createUrlFormat(FieldFormat) {
|
||||
class UrlFormat extends FieldFormat {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
this._compileTemplate = _.memoize(this._compileTemplate);
|
||||
}
|
||||
|
||||
getParamDefaults() {
|
||||
return {
|
||||
type: 'a',
|
||||
urlTemplate: null,
|
||||
labelTemplate: null
|
||||
};
|
||||
}
|
||||
|
||||
_formatLabel(value, url) {
|
||||
const template = this.param('labelTemplate');
|
||||
if (url == null) url = this._formatUrl(value);
|
||||
if (!template) return url;
|
||||
|
||||
return this._compileTemplate(template)({
|
||||
value: value,
|
||||
url: url
|
||||
});
|
||||
}
|
||||
|
||||
_formatUrl(value) {
|
||||
const template = this.param('urlTemplate');
|
||||
if (!template) return value;
|
||||
|
||||
return this._compileTemplate(template)({
|
||||
value: encodeURIComponent(value),
|
||||
rawValue: value
|
||||
});
|
||||
}
|
||||
|
||||
_compileTemplate(template) {
|
||||
const parts = template.split(templateMatchRE).map(function (part, i) {
|
||||
// trim all the odd bits, the variable names
|
||||
return (i % 2) ? part.trim() : part;
|
||||
});
|
||||
|
||||
return function (locals) {
|
||||
// replace all the odd bits with their local var
|
||||
let output = '';
|
||||
let i = -1;
|
||||
while (++i < parts.length) {
|
||||
if (i % 2) {
|
||||
if (locals.hasOwnProperty(parts[i])) {
|
||||
const local = locals[parts[i]];
|
||||
output += local == null ? '' : local;
|
||||
}
|
||||
} else {
|
||||
output += parts[i];
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
}
|
||||
|
||||
static id = 'url';
|
||||
static title = 'Url';
|
||||
static fieldType = [
|
||||
'number',
|
||||
'boolean',
|
||||
'date',
|
||||
'ip',
|
||||
'string',
|
||||
'murmur3',
|
||||
'unknown',
|
||||
'conflict'
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
UrlFormat.prototype._convert = {
|
||||
text: function (value) {
|
||||
return this._formatLabel(value);
|
||||
},
|
||||
|
||||
html: function (rawValue, field, hit) {
|
||||
const url = _.escape(this._formatUrl(rawValue));
|
||||
const label = _.escape(this._formatLabel(rawValue, url));
|
||||
|
||||
switch (this.param('type')) {
|
||||
case 'img':
|
||||
// If the URL hasn't been formatted to become a meaningful label then the best we can do
|
||||
// is tell screen readers where the image comes from.
|
||||
const imageLabel =
|
||||
label === url
|
||||
? `A dynamically-specified image located at ${url}`
|
||||
: label;
|
||||
|
||||
return `<img src="${url}" alt="${imageLabel}">`;
|
||||
default:
|
||||
let linkLabel;
|
||||
|
||||
if (hit && hit.highlight && hit.highlight[field.name]) {
|
||||
linkLabel = getHighlightHtml(label, hit.highlight[field.name]);
|
||||
} else {
|
||||
linkLabel = label;
|
||||
}
|
||||
|
||||
return `<a href="${url}" target="_blank">${linkLabel}</a>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return UrlFormat;
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import { RegistryFieldFormatsProvider } from 'ui/registry/field_formats';
|
||||
import { UrlFormat } from '../../common/field_formats/types/url';
|
||||
import { BytesFormat } from '../../common/field_formats/types/bytes';
|
||||
import { DateFormat } from '../../common/field_formats/types/date';
|
||||
import { DurationFormat } from '../../common/field_formats/types/duration';
|
||||
import { IpFormat } from '../../common/field_formats/types/ip';
|
||||
import { NumberFormat } from '../../common/field_formats/types/number';
|
||||
import { PercentFormat } from '../../common/field_formats/types/percent';
|
||||
import { StringFormat } from '../../common/field_formats/types/string';
|
||||
import { SourceFormat } from '../../common/field_formats/types/source';
|
||||
import { ColorFormat } from '../../common/field_formats/types/color';
|
||||
import { TruncateFormat } from '../../common/field_formats/types/truncate';
|
||||
import { BoolFormat } from '../../common/field_formats/types/boolean';
|
||||
import { createUrlFormat } from '../../common/field_formats/types/url';
|
||||
import { createBytesFormat } from '../../common/field_formats/types/bytes';
|
||||
import { createDateFormat } from '../../common/field_formats/types/date';
|
||||
import { createDurationFormat } from '../../common/field_formats/types/duration';
|
||||
import { createIpFormat } from '../../common/field_formats/types/ip';
|
||||
import { createNumberFormat } from '../../common/field_formats/types/number';
|
||||
import { createPercentFormat } from '../../common/field_formats/types/percent';
|
||||
import { createStringFormat } from '../../common/field_formats/types/string';
|
||||
import { createSourceFormat } from '../../common/field_formats/types/source';
|
||||
import { createColorFormat } from '../../common/field_formats/types/color';
|
||||
import { createTruncateFormat } from '../../common/field_formats/types/truncate';
|
||||
import { createBoolFormat } from '../../common/field_formats/types/boolean';
|
||||
|
||||
RegistryFieldFormatsProvider.register(() => UrlFormat);
|
||||
RegistryFieldFormatsProvider.register(() => BytesFormat);
|
||||
RegistryFieldFormatsProvider.register(() => DateFormat);
|
||||
RegistryFieldFormatsProvider.register(() => DurationFormat);
|
||||
RegistryFieldFormatsProvider.register(() => IpFormat);
|
||||
RegistryFieldFormatsProvider.register(() => NumberFormat);
|
||||
RegistryFieldFormatsProvider.register(() => PercentFormat);
|
||||
RegistryFieldFormatsProvider.register(() => StringFormat);
|
||||
RegistryFieldFormatsProvider.register(() => SourceFormat);
|
||||
RegistryFieldFormatsProvider.register(() => ColorFormat);
|
||||
RegistryFieldFormatsProvider.register(() => TruncateFormat);
|
||||
RegistryFieldFormatsProvider.register(() => BoolFormat);
|
||||
RegistryFieldFormatsProvider.register(createUrlFormat);
|
||||
RegistryFieldFormatsProvider.register(createBytesFormat);
|
||||
RegistryFieldFormatsProvider.register(createDateFormat);
|
||||
RegistryFieldFormatsProvider.register(createDurationFormat);
|
||||
RegistryFieldFormatsProvider.register(createIpFormat);
|
||||
RegistryFieldFormatsProvider.register(createNumberFormat);
|
||||
RegistryFieldFormatsProvider.register(createPercentFormat);
|
||||
RegistryFieldFormatsProvider.register(createStringFormat);
|
||||
RegistryFieldFormatsProvider.register(createSourceFormat);
|
||||
RegistryFieldFormatsProvider.register(createColorFormat);
|
||||
RegistryFieldFormatsProvider.register(createTruncateFormat);
|
||||
RegistryFieldFormatsProvider.register(createBoolFormat);
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
import { UrlFormat } from '../../common/field_formats/types/url';
|
||||
import { BytesFormat } from '../../common/field_formats/types/bytes';
|
||||
import { DateFormat } from '../../common/field_formats/types/date';
|
||||
import { DurationFormat } from '../../common/field_formats/types/duration';
|
||||
import { IpFormat } from '../../common/field_formats/types/ip';
|
||||
import { NumberFormat } from '../../common/field_formats/types/number';
|
||||
import { PercentFormat } from '../../common/field_formats/types/percent';
|
||||
import { StringFormat } from '../../common/field_formats/types/string';
|
||||
import { SourceFormat } from '../../common/field_formats/types/source';
|
||||
import { ColorFormat } from '../../common/field_formats/types/color';
|
||||
import { TruncateFormat } from '../../common/field_formats/types/truncate';
|
||||
import { BoolFormat } from '../../common/field_formats/types/boolean';
|
||||
import { createUrlFormat } from '../../common/field_formats/types/url';
|
||||
import { createBytesFormat } from '../../common/field_formats/types/bytes';
|
||||
import { createDateFormat } from '../../common/field_formats/types/date';
|
||||
import { createDurationFormat } from '../../common/field_formats/types/duration';
|
||||
import { createIpFormat } from '../../common/field_formats/types/ip';
|
||||
import { createNumberFormat } from '../../common/field_formats/types/number';
|
||||
import { createPercentFormat } from '../../common/field_formats/types/percent';
|
||||
import { createStringFormat } from '../../common/field_formats/types/string';
|
||||
import { createSourceFormat } from '../../common/field_formats/types/source';
|
||||
import { createColorFormat } from '../../common/field_formats/types/color';
|
||||
import { createTruncateFormat } from '../../common/field_formats/types/truncate';
|
||||
import { createBoolFormat } from '../../common/field_formats/types/boolean';
|
||||
|
||||
export function registerFieldFormats(server) {
|
||||
server.registerFieldFormatClass(UrlFormat);
|
||||
server.registerFieldFormatClass(BytesFormat);
|
||||
server.registerFieldFormatClass(DateFormat);
|
||||
server.registerFieldFormatClass(DurationFormat);
|
||||
server.registerFieldFormatClass(IpFormat);
|
||||
server.registerFieldFormatClass(NumberFormat);
|
||||
server.registerFieldFormatClass(PercentFormat);
|
||||
server.registerFieldFormatClass(StringFormat);
|
||||
server.registerFieldFormatClass(SourceFormat);
|
||||
server.registerFieldFormatClass(ColorFormat);
|
||||
server.registerFieldFormatClass(TruncateFormat);
|
||||
server.registerFieldFormatClass(BoolFormat);
|
||||
server.registerFieldFormat(createUrlFormat);
|
||||
server.registerFieldFormat(createBytesFormat);
|
||||
server.registerFieldFormat(createDateFormat);
|
||||
server.registerFieldFormat(createDurationFormat);
|
||||
server.registerFieldFormat(createIpFormat);
|
||||
server.registerFieldFormat(createNumberFormat);
|
||||
server.registerFieldFormat(createPercentFormat);
|
||||
server.registerFieldFormat(createStringFormat);
|
||||
server.registerFieldFormat(createSourceFormat);
|
||||
server.registerFieldFormat(createColorFormat);
|
||||
server.registerFieldFormat(createTruncateFormat);
|
||||
server.registerFieldFormat(createBoolFormat);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import numeral from '@elastic/numeral';
|
||||
import handlebars from 'handlebars/dist/handlebars';
|
||||
import { durationInputOptions } from './durations';
|
||||
import { DurationFormat } from '../../../../kibana/common/field_formats/types/duration';
|
||||
import { capitalize, isNumber } from 'lodash';
|
||||
|
||||
import { createDurationFormat } from '../../../../kibana/common/field_formats/types/duration';
|
||||
import { FieldFormat } from '../../../../../ui/field_formats/field_format';
|
||||
|
||||
const DurationFormat = createDurationFormat(FieldFormat);
|
||||
|
||||
const formatLookup = {
|
||||
'bytes': '0.0b',
|
||||
'number': '0,0.[00]',
|
||||
|
|
64
src/ui/field_formats/__tests__/field_formats_mixin.js
Normal file
64
src/ui/field_formats/__tests__/field_formats_mixin.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import expect from 'expect.js';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { FieldFormat } from '../field_format';
|
||||
import * as FieldFormatsServiceNS from '../field_formats_service';
|
||||
import { createServer } from '../../../test_utils/kbn_server';
|
||||
|
||||
describe('server.registerFieldFormat(createFormat)', () => {
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
let server;
|
||||
beforeEach(async () => {
|
||||
const kbnServer = createServer();
|
||||
await kbnServer.ready();
|
||||
server = kbnServer.server;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('throws if createFormat is not a function', () => {
|
||||
expect(() => server.registerFieldFormat()).to.throwError(error => {
|
||||
expect(error.message).to.match(/createFormat is not a function/i);
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the createFormat() function with the FieldFormat class', () => {
|
||||
const createFormat = sinon.stub();
|
||||
server.registerFieldFormat(createFormat);
|
||||
sinon.assert.calledOnce(createFormat);
|
||||
sinon.assert.calledWithExactly(createFormat, sinon.match.same(FieldFormat));
|
||||
});
|
||||
|
||||
it('passes the returned class to the FieldFormatsService', async () => {
|
||||
const { FieldFormatsService: ActualFFS } = FieldFormatsServiceNS;
|
||||
sinon.stub(FieldFormatsServiceNS, 'FieldFormatsService', function (...args) {
|
||||
return new ActualFFS(...args);
|
||||
});
|
||||
|
||||
const { FieldFormatsService } = FieldFormatsServiceNS;
|
||||
class FooFormat {
|
||||
static id = 'foo'
|
||||
}
|
||||
server.registerFieldFormat(() => FooFormat);
|
||||
|
||||
const fieldFormats = await server.fieldFormatServiceFactory({
|
||||
getAll: () => ({}),
|
||||
getDefaults: () => ({})
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(FieldFormatsService);
|
||||
sinon.assert.calledWithExactly(
|
||||
FieldFormatsService,
|
||||
// array of fieldFormat classes
|
||||
[sinon.match.same(FooFormat)],
|
||||
// getConfig() function
|
||||
sinon.match.func
|
||||
);
|
||||
|
||||
const format = fieldFormats.getInstance({ id: 'foo' });
|
||||
expect(format).to.be.a(FooFormat);
|
||||
});
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
import expect from 'expect.js';
|
||||
import { FieldFormat } from '../field_format';
|
||||
import { FieldFormatsService } from '../field_formats_service';
|
||||
import { NumberFormat } from '../../../core_plugins/kibana/common/field_formats/types/number';
|
||||
import { createNumberFormat } from '../../../core_plugins/kibana/common/field_formats/types/number';
|
||||
|
||||
describe('FieldFormatsService', function () {
|
||||
|
||||
|
@ -11,7 +12,7 @@ describe('FieldFormatsService', function () {
|
|||
};
|
||||
config['format:number:defaultPattern'] = '0,0.[000]';
|
||||
const getConfig = (key) => config[key];
|
||||
const fieldFormatClasses = [NumberFormat];
|
||||
const fieldFormatClasses = [createNumberFormat(FieldFormat)];
|
||||
|
||||
let fieldFormats;
|
||||
beforeEach(function () {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import { FieldFormatsService } from './field_formats/field_formats_service';
|
||||
import { FieldFormatsService } from './field_formats_service';
|
||||
import { FieldFormat } from './field_format';
|
||||
|
||||
export function fieldFormatsMixin(kbnServer, server) {
|
||||
const fieldFormatClasses = [];
|
||||
|
@ -22,7 +23,7 @@ export function fieldFormatsMixin(kbnServer, server) {
|
|||
return new FieldFormatsService(fieldFormatClasses, getConfig);
|
||||
});
|
||||
|
||||
server.decorate('server', 'registerFieldFormatClass', (FieldFormat) => {
|
||||
fieldFormatClasses.push(FieldFormat);
|
||||
server.decorate('server', 'registerFieldFormat', (createFormat) => {
|
||||
fieldFormatClasses.push(createFormat(FieldFormat));
|
||||
});
|
||||
}
|
|
@ -10,7 +10,7 @@ import UiBundlerEnv from './ui_bundler_env';
|
|||
import { UiI18n } from './ui_i18n';
|
||||
|
||||
import { uiSettingsMixin } from './ui_settings';
|
||||
import { fieldFormatsMixin } from './field_formats_mixin';
|
||||
import { fieldFormatsMixin } from './field_formats/field_formats_mixin';
|
||||
|
||||
export default async (kbnServer, server, config) => {
|
||||
const uiExports = kbnServer.uiExports = new UiExports({
|
||||
|
|
|
@ -95,6 +95,26 @@ describe('Registry', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('spec.invokeProviders', () => {
|
||||
it('is called with the registered providers and defines the initial set of values in the registry', () => {
|
||||
const reg = uiRegistry({
|
||||
invokeProviders(providers) {
|
||||
return providers.map(i => i * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
reg.register(1);
|
||||
reg.register(2);
|
||||
reg.register(3);
|
||||
expect(Private(reg).toJSON()).to.eql([1000, 2000, 3000]);
|
||||
});
|
||||
it('does not get assigned as a property of the registry', () => {
|
||||
expect(uiRegistry({
|
||||
invokeProviders() {}
|
||||
})).to.not.have.property('invokeProviders');
|
||||
});
|
||||
});
|
||||
|
||||
describe('spec[any]', function () {
|
||||
it('mixes the extra properties into the module list', function () {
|
||||
const reg = uiRegistry({
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import { IndexedArray } from 'ui/indexed_array';
|
||||
const notPropsOptNames = IndexedArray.OPT_NAMES.concat('constructor');
|
||||
const notPropsOptNames = IndexedArray.OPT_NAMES.concat('constructor', 'invokeProviders');
|
||||
|
||||
/**
|
||||
* Create a registry, which is just a Private module provider.
|
||||
|
@ -49,6 +49,7 @@ export function uiRegistry(spec) {
|
|||
spec = spec || {};
|
||||
|
||||
const constructor = _.has(spec, 'constructor') && spec.constructor;
|
||||
const invokeProviders = _.has(spec, 'invokeProviders') && spec.invokeProviders;
|
||||
const iaOpts = _.defaults(_.pick(spec, IndexedArray.OPT_NAMES), { index: ['name'] });
|
||||
const props = _.omit(spec, notPropsOptNames);
|
||||
const providers = [];
|
||||
|
@ -62,8 +63,12 @@ export function uiRegistry(spec) {
|
|||
* defines how things will be indexed.
|
||||
*/
|
||||
const registry = function (Private, $injector) {
|
||||
// call the registered providers to get their values
|
||||
iaOpts.initialSet = invokeProviders
|
||||
? $injector.invoke(invokeProviders, undefined, { providers })
|
||||
: providers.map(Private);
|
||||
|
||||
// index all of the modules
|
||||
iaOpts.initialSet = providers.map(Private);
|
||||
let modules = new IndexedArray(iaOpts);
|
||||
|
||||
// mixin other props
|
||||
|
@ -86,4 +91,3 @@ export function uiRegistry(spec) {
|
|||
|
||||
return registry;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
import _ from 'lodash';
|
||||
import { uiRegistry } from 'ui/registry/_registry';
|
||||
import { FieldFormat } from '../../field_formats/field_format';
|
||||
|
||||
export const RegistryFieldFormatsProvider = uiRegistry({
|
||||
name: 'fieldFormats',
|
||||
index: ['id'],
|
||||
group: ['fieldType'],
|
||||
|
||||
invokeProviders(providers) {
|
||||
// in order to ensure that FieldFormats can be instantiated on the
|
||||
// server and the browser we don't provide them access to the Angular
|
||||
// injector, just the FieldFormat class.
|
||||
return providers.map(createSomeFormat => (
|
||||
createSomeFormat(FieldFormat)
|
||||
));
|
||||
},
|
||||
|
||||
constructor: function (config) {
|
||||
const getConfig = (...args) => config.get(...args);
|
||||
const self = this;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue