diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts index 40ef7329dee6b..1dc24ca80035c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts @@ -20,21 +20,19 @@ import { get } from 'lodash'; import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; +import { convertDateRangeToString, DateRangeKey } from './lib/date_range'; import { BUCKET_TYPES } from './bucket_agg_types'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; +export { convertDateRangeToString, DateRangeKey }; + const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', { defaultMessage: 'Date Range', }); -export interface DateRangeKey { - from: number; - to: number; -} - export const dateRangeBucketAgg = new BucketAggType({ name: BUCKET_TYPES.DATE_RANGE, title: dateRangeTitle, @@ -106,16 +104,3 @@ export const dateRangeBucketAgg = new BucketAggType({ }, ], }); - -export const convertDateRangeToString = ( - { from, to }: DateRangeKey, - format: (val: any) => string -) => { - if (!from) { - return 'Before ' + format(to); - } else if (!to) { - return 'After ' + format(from); - } else { - return format(from) + ' to ' + format(to); - } -}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts index e5497bef49165..91bdf53e7f809 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts @@ -20,21 +20,19 @@ import { noop, map, omit, isNull } from 'lodash'; import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; +import { IpRangeKey, convertIPRangeToString } from './lib/ip_range'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; // @ts-ignore import { createFilterIpRange } from './create_filter/ip_range'; import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; +export { IpRangeKey, convertIPRangeToString }; const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', }); -export type IpRangeKey = - | { type: 'mask'; mask: string } - | { type: 'range'; from: string; to: string }; - export const ipRangeBucketAgg = new BucketAggType({ name: BUCKET_TYPES.IP_RANGE, title: ipRangeTitle, @@ -97,13 +95,3 @@ export const ipRangeBucketAgg = new BucketAggType({ }, ], }); - -export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { - if (range.type === 'mask') { - return format(range.mask); - } - const from = range.from ? format(range.from) : '-Infinity'; - const to = range.to ? format(range.to) : 'Infinity'; - - return `${from} to ${to}`; -}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts new file mode 100644 index 0000000000000..01b853fc669b5 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface DateRangeKey { + from: number; + to: number; +} + +export const convertDateRangeToString = ( + { from, to }: DateRangeKey, + format: (val: any) => string +) => { + if (!from) { + return 'Before ' + format(to); + } else if (!to) { + return 'After ' + format(from); + } else { + return format(from) + ' to ' + format(to); + } +}; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts new file mode 100644 index 0000000000000..be1ac28934c7c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export type IpRangeKey = + | { type: 'mask'; mask: string } + | { type: 'range'; from: string; to: string }; + +export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { + if (range.type === 'mask') { + return format(range.mask); + } + const from = range.from ? format(range.from) : '-Infinity'; + const to = range.to ? format(range.to) : 'Infinity'; + + return `${from} to ${to}`; +}; diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx index 32c99f68a066e..6a466c9cd0211 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx @@ -22,6 +22,10 @@ import { shallow } from 'enzyme'; import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { MetricVisComponent, MetricVisComponentProps } from './metric_vis_component'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { npStart } from 'ui/new_platform'; +import { fieldFormats } from '../../../../../plugins/data/public'; +import { identity } from 'lodash'; jest.mock('ui/new_platform'); @@ -62,6 +66,12 @@ describe('MetricVisComponent', function() { return shallow(); }; + beforeAll(() => { + (npStart.plugins.data.fieldFormats.deserialize as jest.Mock).mockImplementation(() => { + return new (fieldFormats.FieldFormat.from(identity))(); + }); + }); + it('should render component', () => { expect(getComponent().exists()).toBe(true); }); diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index 28565e0181b84..15cd920b79e4a 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -44,6 +44,9 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { (npStart.plugins.data.fieldFormats.getType as jest.Mock).mockImplementation(() => { return fieldFormats.UrlFormat; }); + (npStart.plugins.data.fieldFormats.deserialize as jest.Mock).mockImplementation(mapping => { + return new fieldFormats.UrlFormat(mapping ? mapping.params : {}); + }); }); const setup = () => { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts index 3d04c04f9b1a6..9c79be98a320c 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts @@ -18,10 +18,11 @@ */ export { AggType, AggGroupNames, IAggConfig, IAggType, Schemas } from 'ui/agg_types'; -export { getFormat, getTableAggs } from 'ui/visualize/loader/pipeline_helpers/utilities'; +export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; // @ts-ignore export { tabifyAggResponse } from 'ui/agg_response/tabify'; // @ts-ignore export { buildHierarchicalData } from 'ui/agg_response/hierarchical/build_hierarchical_data'; // @ts-ignore export { buildPointSeriesData } from 'ui/agg_response/point_series/point_series'; +export { tabifyGetColumns } from '../../../ui/public/agg_response/tabify/_get_columns'; diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index a170af33583df..c1563625c3b8c 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -22,14 +22,24 @@ import { compact, uniq, map } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiPopoverProps, EuiIcon, keyCodes, htmlIdGenerator } from '@elastic/eui'; +import { IAggConfig } from '../../../../../data/public'; // @ts-ignore -// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { createFiltersFromEvent } from '../../../../../data/public/actions/filters/create_filters_from_event'; import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models'; import { VisLegendItem } from './legend_item'; import { getPieNames } from './pie_utils'; -import { getTableAggs } from '../../../legacy_imports'; + +import { Vis } from '../../../../../visualizations/public'; +import { tabifyGetColumns } from '../../../legacy_imports'; + +const getTableAggs = (vis: Vis): IAggConfig[] => { + if (!vis.aggs || !vis.aggs.getResponseAggs) { + return []; + } + const columns = tabifyGetColumns(vis.aggs.getResponseAggs(), !vis.isHierarchical()); + return columns.map(c => c.aggConfig); +}; export interface VisLegendProps { vis: any; diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index 7228e506accb9..cb25c66dfd2fe 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -17,150 +17,15 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -import { identity } from 'lodash'; -import { IAggConfig } from 'ui/agg_types'; import { npStart } from 'ui/new_platform'; -import { SerializedFieldFormat } from 'src/plugins/expressions/public'; -import { - fieldFormats, - IFieldFormat, - FieldFormatId, - FieldFormatsContentType, -} from '../../../../../../plugins/data/public'; -import { Vis } from '../../../../../core_plugins/visualizations/public'; +import { fieldFormats, IFieldFormat } from '../../../../../../plugins/data/public'; +import { SerializedFieldFormat } from '../../../../../../plugins/expressions/common/types'; -import { tabifyGetColumns } from '../../../agg_response/tabify/_get_columns'; -import { DateRangeKey, convertDateRangeToString } from '../../../agg_types'; -import { IpRangeKey, convertIPRangeToString } from '../../../agg_types'; +type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; -interface TermsFieldFormatParams { - otherBucketLabel: string; - missingBucketLabel: string; - id: string; -} - -function isTermsFieldFormat( - serializedFieldFormat: SerializedFieldFormat -): serializedFieldFormat is SerializedFieldFormat { - return serializedFieldFormat.id === 'terms'; -} - -const getConfig = (key: string, defaultOverride?: any): any => - npStart.core.uiSettings.get(key, defaultOverride); -const DefaultFieldFormat = fieldFormats.FieldFormat.from(identity); - -const getFieldFormat = (id?: FieldFormatId, params: object = {}): IFieldFormat => { - const fieldFormatsService = npStart.plugins.data.fieldFormats; - - if (id) { - const Format = fieldFormatsService.getType(id); - - if (Format) { - return new Format(params, getConfig); - } - } - - return new DefaultFieldFormat(); -}; - -export const createFormat = (agg: IAggConfig): SerializedFieldFormat => { - const format: SerializedFieldFormat = agg.params.field ? agg.params.field.format.toJSON() : {}; - const formats: Record SerializedFieldFormat> = { - date_range: () => ({ id: 'date_range', params: format }), - ip_range: () => ({ id: 'ip_range', params: format }), - percentile_ranks: () => ({ id: 'percent' }), - count: () => ({ id: 'number' }), - cardinality: () => ({ id: 'number' }), - date_histogram: () => ({ - id: 'date', - params: { - pattern: (agg as any).buckets.getScaledDateFormat(), - }, - }), - terms: () => ({ - id: 'terms', - params: { - id: format.id, - otherBucketLabel: agg.params.otherBucketLabel, - missingBucketLabel: agg.params.missingBucketLabel, - ...format.params, - }, - }), - range: () => ({ - id: 'range', - params: { id: format.id, ...format.params }, - }), - }; - - return formats[agg.type.name] ? formats[agg.type.name]() : format; -}; - -export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; - -export const getFormat: FormatFactory = mapping => { - if (!mapping) { - return new DefaultFieldFormat(); - } - const { id } = mapping; - if (id === 'range') { - const RangeFormat = fieldFormats.FieldFormat.from((range: any) => { - const format = getFieldFormat(id, mapping.params); - const gte = '\u2265'; - const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.rangesFormatMessage', { - defaultMessage: '{gte} {from} and {lt} {to}', - values: { - gte, - from: format.convert(range.gte), - lt, - to: format.convert(range.lt), - }, - }); - }); - return new RangeFormat(); - } else if (id === 'date_range') { - const nestedFormatter = mapping.params as SerializedFieldFormat; - const DateRangeFormat = fieldFormats.FieldFormat.from((range: DateRangeKey) => { - const format = getFieldFormat(nestedFormatter.id, nestedFormatter.params); - return convertDateRangeToString(range, format.convert.bind(format)); - }); - return new DateRangeFormat(); - } else if (id === 'ip_range') { - const nestedFormatter = mapping.params as SerializedFieldFormat; - const IpRangeFormat = fieldFormats.FieldFormat.from((range: IpRangeKey) => { - const format = getFieldFormat(nestedFormatter.id, nestedFormatter.params); - return convertIPRangeToString(range, format.convert.bind(format)); - }); - return new IpRangeFormat(); - } else if (isTermsFieldFormat(mapping) && mapping.params) { - const { params } = mapping; - const convert = (val: string, type: FieldFormatsContentType) => { - const format = getFieldFormat(params.id, mapping.params); - - if (val === '__other__') { - return params.otherBucketLabel; - } - if (val === '__missing__') { - return params.missingBucketLabel; - } - - return format.convert(val, type); - }; - - return { - convert, - getConverterFor: (type: FieldFormatsContentType) => (val: string) => convert(val, type), - } as IFieldFormat; - } else { - return getFieldFormat(id, mapping.params); - } +const createFormat = fieldFormats.serialize; +const getFormat: FormatFactory = (mapping?) => { + return npStart.plugins.data.fieldFormats.deserialize(mapping as any); }; -export const getTableAggs = (vis: Vis): IAggConfig[] => { - if (!vis.aggs || !vis.aggs.getResponseAggs) { - return []; - } - const columns = tabifyGetColumns(vis.aggs.getResponseAggs(), !vis.isHierarchical()); - return columns.map(c => c.aggConfig); -}; +export { getFormat, createFormat, FormatFactory }; diff --git a/src/plugins/data/common/field_formats/field_formats_registry.ts b/src/plugins/data/common/field_formats/field_formats_registry.ts index 6e4880a221c46..9fe9a31307b6a 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.ts @@ -18,9 +18,9 @@ */ // eslint-disable-next-line max-classes-per-file -import { forOwn, isFunction, memoize } from 'lodash'; +import { forOwn, isFunction, memoize, identity } from 'lodash'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../common'; +import { ES_FIELD_TYPES, IFieldFormat, KBN_FIELD_TYPES } from '../../common'; import { FieldFormatsGetConfigFn, @@ -32,12 +32,17 @@ import { } from './types'; import { baseFormatters } from './constants/base_formatters'; import { FieldFormat } from './field_format'; +import { SerializedFieldFormat } from '../../../expressions/common/types'; export class FieldFormatsRegistry { protected fieldFormats: Map = new Map(); protected defaultMap: Record = {}; protected metaParamsOptions: Record = {}; protected getConfig?: FieldFormatsGetConfigFn; + // overriden on the public contract + public deserialize: (mapping: SerializedFieldFormat) => IFieldFormat = () => { + return new (FieldFormat.from(identity))(); + }; init( getConfig: FieldFormatsGetConfigFn, diff --git a/src/plugins/data/common/field_formats/index.ts b/src/plugins/data/common/field_formats/index.ts index 0847ac0db745f..d7858966f2620 100644 --- a/src/plugins/data/common/field_formats/index.ts +++ b/src/plugins/data/common/field_formats/index.ts @@ -41,7 +41,7 @@ export { TruncateFormat, } from './converters'; -export { getHighlightRequest } from './utils'; +export { getHighlightRequest, serializeFieldFormat } from './utils'; export { DEFAULT_CONVERTER_COLOR } from './constants/color_default'; export { FIELD_FORMAT_IDS } from './types'; diff --git a/src/plugins/data/common/field_formats/utils/index.ts b/src/plugins/data/common/field_formats/utils/index.ts index 81b33115a44bb..3832c941ffad7 100644 --- a/src/plugins/data/common/field_formats/utils/index.ts +++ b/src/plugins/data/common/field_formats/utils/index.ts @@ -17,5 +17,11 @@ * under the License. */ +import { SerializedFieldFormat } from '../../../../expressions/common/types'; +import { IFieldFormat } from '../index'; + export { asPrettyString } from './as_pretty_string'; export { getHighlightHtml, getHighlightRequest } from './highlight'; +export { serializeFieldFormat } from './serialize'; + +export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; diff --git a/src/plugins/data/common/field_formats/utils/serialize.ts b/src/plugins/data/common/field_formats/utils/serialize.ts new file mode 100644 index 0000000000000..9931f55c30a9e --- /dev/null +++ b/src/plugins/data/common/field_formats/utils/serialize.ts @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IAggConfig } from '../../../../../legacy/ui/public/agg_types'; +import { SerializedFieldFormat } from '../../../../expressions/common/types'; + +export const serializeFieldFormat = (agg: IAggConfig): SerializedFieldFormat => { + const format: SerializedFieldFormat = agg.params.field ? agg.params.field.format.toJSON() : {}; + const formats: Record SerializedFieldFormat> = { + date_range: () => ({ id: 'date_range', params: format }), + ip_range: () => ({ id: 'ip_range', params: format }), + percentile_ranks: () => ({ id: 'percent' }), + count: () => ({ id: 'number' }), + cardinality: () => ({ id: 'number' }), + date_histogram: () => ({ + id: 'date', + params: { + pattern: (agg as any).buckets.getScaledDateFormat(), + }, + }), + terms: () => ({ + id: 'terms', + params: { + id: format.id, + otherBucketLabel: agg.params.otherBucketLabel, + missingBucketLabel: agg.params.missingBucketLabel, + ...format.params, + }, + }), + range: () => ({ + id: 'range', + params: { id: format.id, ...format.params }, + }), + }; + + return formats[agg.type.name] ? formats[agg.type.name]() : format; +}; diff --git a/src/plugins/data/public/field_formats/field_formats_service.ts b/src/plugins/data/public/field_formats/field_formats_service.ts index 1c43ce2198645..785bedf9b35d3 100644 --- a/src/plugins/data/public/field_formats/field_formats_service.ts +++ b/src/plugins/data/public/field_formats/field_formats_service.ts @@ -19,6 +19,8 @@ import { CoreSetup } from 'src/core/public'; import { FieldFormatsRegistry } from '../../common/field_formats'; +import { deserializeFieldFormat } from './utils/deserialize'; +import { FormatFactory } from '../../common/field_formats/utils'; export class FieldFormatsService { private readonly fieldFormatsRegistry: FieldFormatsRegistry = new FieldFormatsRegistry(); @@ -44,6 +46,10 @@ export class FieldFormatsService { } public start() { + this.fieldFormatsRegistry.deserialize = deserializeFieldFormat.bind( + this.fieldFormatsRegistry as FieldFormatsStart + ); + return this.fieldFormatsRegistry as FieldFormatsStart; } } @@ -52,4 +58,6 @@ export class FieldFormatsService { export type FieldFormatsSetup = Pick; /** @public */ -export type FieldFormatsStart = Omit; +export type FieldFormatsStart = Omit & { + deserialize: FormatFactory; +}; diff --git a/src/plugins/data/public/field_formats/utils/deserialize.ts b/src/plugins/data/public/field_formats/utils/deserialize.ts new file mode 100644 index 0000000000000..c10ebfbe3eb1e --- /dev/null +++ b/src/plugins/data/public/field_formats/utils/deserialize.ts @@ -0,0 +1,129 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { identity } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { + convertDateRangeToString, + DateRangeKey, +} from '../../../../../legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range'; +import { + convertIPRangeToString, + IpRangeKey, +} from '../../../../../legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range'; +import { SerializedFieldFormat } from '../../../../expressions/common/types'; +import { FieldFormatId, FieldFormatsContentType, IFieldFormat } from '../..'; +import { FieldFormat } from '../../../common'; +import { DataPublicPluginStart } from '../../../public'; +import { getUiSettings } from '../../../public/services'; +import { FormatFactory } from '../../../common/field_formats/utils'; + +interface TermsFieldFormatParams { + otherBucketLabel: string; + missingBucketLabel: string; + id: string; +} + +function isTermsFieldFormat( + serializedFieldFormat: SerializedFieldFormat +): serializedFieldFormat is SerializedFieldFormat { + return serializedFieldFormat.id === 'terms'; +} + +const getConfig = (key: string, defaultOverride?: any): any => + getUiSettings().get(key, defaultOverride); +const DefaultFieldFormat = FieldFormat.from(identity); + +const getFieldFormat = ( + fieldFormatsService: DataPublicPluginStart['fieldFormats'], + id?: FieldFormatId, + params: object = {} +): IFieldFormat => { + if (id) { + const Format = fieldFormatsService.getType(id); + + if (Format) { + return new Format(params, getConfig); + } + } + + return new DefaultFieldFormat(); +}; + +export const deserializeFieldFormat: FormatFactory = function( + this: DataPublicPluginStart['fieldFormats'], + mapping?: SerializedFieldFormat +) { + if (!mapping) { + return new DefaultFieldFormat(); + } + const { id } = mapping; + if (id === 'range') { + const RangeFormat = FieldFormat.from((range: any) => { + const format = getFieldFormat(this, id, mapping.params); + const gte = '\u2265'; + const lt = '\u003c'; + return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessage', { + defaultMessage: '{gte} {from} and {lt} {to}', + values: { + gte, + from: format.convert(range.gte), + lt, + to: format.convert(range.lt), + }, + }); + }); + return new RangeFormat(); + } else if (id === 'date_range') { + const nestedFormatter = mapping.params as SerializedFieldFormat; + const DateRangeFormat = FieldFormat.from((range: DateRangeKey) => { + const format = getFieldFormat(this, nestedFormatter.id, nestedFormatter.params); + return convertDateRangeToString(range, format.convert.bind(format)); + }); + return new DateRangeFormat(); + } else if (id === 'ip_range') { + const nestedFormatter = mapping.params as SerializedFieldFormat; + const IpRangeFormat = FieldFormat.from((range: IpRangeKey) => { + const format = getFieldFormat(this, nestedFormatter.id, nestedFormatter.params); + return convertIPRangeToString(range, format.convert.bind(format)); + }); + return new IpRangeFormat(); + } else if (isTermsFieldFormat(mapping) && mapping.params) { + const { params } = mapping; + const convert = (val: string, type: FieldFormatsContentType) => { + const format = getFieldFormat(this, params.id, mapping.params); + + if (val === '__other__') { + return params.otherBucketLabel; + } + if (val === '__missing__') { + return params.missingBucketLabel; + } + + return format.convert(val, type); + }; + + return { + convert, + getConverterFor: (type: FieldFormatsContentType) => (val: string) => convert(val, type), + } as IFieldFormat; + } else { + return getFieldFormat(this, id, mapping.params); + } +}; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 32d421cf85604..cdc4167f545af 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -168,6 +168,7 @@ import { UrlFormat, StringFormat, TruncateFormat, + serializeFieldFormat, } from '../common/field_formats'; // Field formats helpers namespace: @@ -175,6 +176,8 @@ export const fieldFormats = { FieldFormat, FieldFormatsRegistry, // exported only for tests. Consider mock. + serialize: serializeFieldFormat, + DEFAULT_CONVERTER_COLOR, HTML_CONTEXT_TYPE, TEXT_CONTEXT_TYPE, diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts index 103f9d385b3f9..b6ca91169a933 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.test.ts @@ -31,7 +31,7 @@ import { setNotifications, setFieldFormats } from '../../services'; // Temporary disable eslint, will be removed after moving to new platform folder // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { notificationServiceMock } from '../../../../../core/public/notifications/notifications_service.mock'; -import { FieldFormatsRegistry } from '../../../common/field_formats'; +import { FieldFormatsStart } from '../../field_formats'; jest.mock('../../../../kibana_utils/public', () => { const originalModule = jest.requireActual('../../../../kibana_utils/public'); @@ -125,7 +125,8 @@ describe('IndexPattern', () => { setNotifications(notifications); setFieldFormats(({ getDefaultInstance: jest.fn(), - } as unknown) as FieldFormatsRegistry); + deserialize: jest.fn() as any, + } as unknown) as FieldFormatsStart); return create(indexPatternId).then((pattern: IndexPattern) => { indexPattern = pattern; diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 0a093644c3939..c723c34cd0a22 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -49,6 +49,7 @@ const fieldFormatsMock: IFieldFormatsRegistry = { init: jest.fn(), register: jest.fn(), parseDefaultTypeMap: jest.fn(), + deserialize: jest.fn(), }; const createSetupContract = (): Setup => { diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index eebbc63f6f1e4..990386687bade 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -173,6 +173,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { + "deserialize": [MockFunction], "getByFieldType": [MockFunction], "getDefaultConfig": [MockFunction], "getDefaultInstance": [MockFunction], @@ -825,6 +826,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { + "deserialize": [MockFunction], "getByFieldType": [MockFunction], "getDefaultConfig": [MockFunction], "getDefaultInstance": [MockFunction], @@ -1459,6 +1461,7 @@ exports[`QueryStringInput Should pass the query language to the language switche "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { + "deserialize": [MockFunction], "getByFieldType": [MockFunction], "getDefaultConfig": [MockFunction], "getDefaultInstance": [MockFunction], @@ -2108,6 +2111,7 @@ exports[`QueryStringInput Should pass the query language to the language switche "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { + "deserialize": [MockFunction], "getByFieldType": [MockFunction], "getDefaultConfig": [MockFunction], "getDefaultInstance": [MockFunction], @@ -2742,6 +2746,7 @@ exports[`QueryStringInput Should render the given query 1`] = ` "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { + "deserialize": [MockFunction], "getByFieldType": [MockFunction], "getDefaultConfig": [MockFunction], "getDefaultInstance": [MockFunction], @@ -3391,6 +3396,7 @@ exports[`QueryStringInput Should render the given query 1`] = ` "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { + "deserialize": [MockFunction], "getByFieldType": [MockFunction], "getDefaultConfig": [MockFunction], "getDefaultInstance": [MockFunction], diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index e8f422d94909f..3ee98a318de35 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -95,12 +95,15 @@ import { UrlFormat, StringFormat, TruncateFormat, + serializeFieldFormat, } from '../common/field_formats'; export const fieldFormats = { FieldFormatsRegistry, FieldFormat, + serializeFieldFormat, + BoolFormat, BytesFormat, ColorFormat, diff --git a/src/test_utils/public/stub_field_formats.ts b/src/test_utils/public/stub_field_formats.ts index 32bdca1eea258..5a20823134ebd 100644 --- a/src/test_utils/public/stub_field_formats.ts +++ b/src/test_utils/public/stub_field_formats.ts @@ -17,7 +17,8 @@ * under the License. */ import { CoreSetup } from 'kibana/public'; -import { fieldFormats } from '../../plugins/data/public'; +import { DataPublicPluginStart, fieldFormats } from '../../plugins/data/public'; +import { deserializeFieldFormat } from '../../plugins/data/public/field_formats/utils/deserialize'; export const getFieldFormatsRegistry = (core: CoreSetup) => { const fieldFormatsRegistry = new fieldFormats.FieldFormatsRegistry(); @@ -25,5 +26,9 @@ export const getFieldFormatsRegistry = (core: CoreSetup) => { fieldFormatsRegistry.init(getConfig, {}); + fieldFormatsRegistry.deserialize = deserializeFieldFormat.bind( + fieldFormatsRegistry as DataPublicPluginStart['fieldFormats'] + ); + return fieldFormatsRegistry; }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ffd780842552e..6b2dc984eefda 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -77,7 +77,6 @@ }, "messages": { "common.ui.aggResponse.allDocsTitle": "すべてのドキュメント", - "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} と {lt} {to}", "data.search.aggs.aggGroups.bucketsText": "バケット", "data.search.aggs.aggGroups.metricsText": "メトリック", "data.search.aggs.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", @@ -13844,4 +13843,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "フィールドを選択してください。", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d27dd65c03075..c4d94c31ecfdc 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -77,7 +77,6 @@ }, "messages": { "common.ui.aggResponse.allDocsTitle": "所有文档", - "common.ui.aggTypes.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", "data.search.aggs.aggGroups.bucketsText": "存储桶", "data.search.aggs.aggGroups.metricsText": "指标", "data.search.aggs.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", @@ -13843,4 +13842,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "此字段必填。", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} \ No newline at end of file +}