From 6aacfbd25dc38ef4717745203b9048168ca68ea3 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 2 Jul 2020 12:04:28 -0700 Subject: [PATCH 01/11] [Data Plugin] Allow server-side date formatters to accept custom timezone When Advanced Settings shows the date format timezone to be "Browser," this means nothing to field formatters in the server-side context. The field formatters need a way to accept custom format parameters. This allows a server-side module that creates a FieldFormatMap to set a timezone as a custom parameter. When custom formatting parameters exist, they get combined with the defaults. --- .../constants/base_formatters.ts | 2 - .../common/field_formats/converters/index.ts | 1 - .../field_formats/field_formats_registry.ts | 20 ++- .../data/common/field_formats/index.ts | 1 - .../converters/date_nanos.test.ts | 0 .../field_formats/converters/date_nanos.ts | 11 +- .../public/field_formats/converters/index.ts | 1 + .../data/public/field_formats/index.ts | 2 +- src/plugins/data/public/index.ts | 3 +- .../converters/date_nanos_server.test.ts | 129 ++++++++++++++++ .../converters/date_nanos_server.ts | 141 ++++++++++++++++++ .../server/field_formats/converters/index.ts | 1 + .../field_formats/field_formats_service.ts | 8 +- src/plugins/data/server/index.ts | 2 - 14 files changed, 305 insertions(+), 17 deletions(-) rename src/plugins/data/{common => public}/field_formats/converters/date_nanos.test.ts (100%) rename src/plugins/data/{common => public}/field_formats/converters/date_nanos.ts (96%) create mode 100644 src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts create mode 100644 src/plugins/data/server/field_formats/converters/date_nanos_server.ts diff --git a/src/plugins/data/common/field_formats/constants/base_formatters.ts b/src/plugins/data/common/field_formats/constants/base_formatters.ts index 921c50571f727..99c24496cf220 100644 --- a/src/plugins/data/common/field_formats/constants/base_formatters.ts +++ b/src/plugins/data/common/field_formats/constants/base_formatters.ts @@ -23,7 +23,6 @@ import { BoolFormat, BytesFormat, ColorFormat, - DateNanosFormat, DurationFormat, IpFormat, NumberFormat, @@ -40,7 +39,6 @@ export const baseFormatters: FieldFormatInstanceType[] = [ BoolFormat, BytesFormat, ColorFormat, - DateNanosFormat, DurationFormat, IpFormat, NumberFormat, diff --git a/src/plugins/data/common/field_formats/converters/index.ts b/src/plugins/data/common/field_formats/converters/index.ts index cc9fae7fc9965..f71ddf5f781f7 100644 --- a/src/plugins/data/common/field_formats/converters/index.ts +++ b/src/plugins/data/common/field_formats/converters/index.ts @@ -19,7 +19,6 @@ export { UrlFormat } from './url'; export { BytesFormat } from './bytes'; -export { DateNanosFormat } from './date_nanos'; export { RelativeDateFormat } from './relative_date'; export { DurationFormat } from './duration'; export { IpFormat } from './ip'; 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 74a942b51583d..f76bdc530bc82 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.ts @@ -40,6 +40,7 @@ export class FieldFormatsRegistry { protected defaultMap: Record = {}; protected metaParamsOptions: Record = {}; protected getConfig?: FieldFormatsGetConfigFn; + protected customParams: Record = {}; // overriden on the public contract public deserialize: (mapping: SerializedFieldFormat) => IFieldFormat = () => { return new (FieldFormat.from(identity))(); @@ -57,6 +58,13 @@ export class FieldFormatsRegistry { this.metaParamsOptions = metaParamsOptions; } + /* + * Allow use-case specific params that are reflected in getInstance / getDefaultInstancePlain + */ + setCustomParams(params: Record) { + this.customParams = params; + } + /** * Get the id of the default type for this field type * using the format:defaultTypeMap config map @@ -157,7 +165,11 @@ export class FieldFormatsRegistry { * @return {FieldFormat} */ getInstance = memoize( - (formatId: FieldFormatId, params: Record = {}): FieldFormat => { + (formatId: FieldFormatId, instanceParams: Record = {}): FieldFormat => { + const params = { + ...instanceParams, + ...this.customParams, + }; const ConcreteFieldFormat = this.getType(formatId); if (!ConcreteFieldFormat) { @@ -182,8 +194,12 @@ export class FieldFormatsRegistry { */ getDefaultInstancePlain(fieldType: KBN_FIELD_TYPES, esTypes?: ES_FIELD_TYPES[]): FieldFormat { const conf = this.getDefaultConfig(fieldType, esTypes); + const defaultParams = { + ...conf.params, + ...this.customParams, + }; - return this.getInstance(conf.id, conf.params); + return this.getInstance(conf.id, defaultParams); } /** * Returns a cache key built by the given variables for caching in memoized diff --git a/src/plugins/data/common/field_formats/index.ts b/src/plugins/data/common/field_formats/index.ts index 104ff030873aa..d622af2f663a1 100644 --- a/src/plugins/data/common/field_formats/index.ts +++ b/src/plugins/data/common/field_formats/index.ts @@ -27,7 +27,6 @@ export { BoolFormat, BytesFormat, ColorFormat, - DateNanosFormat, DurationFormat, IpFormat, NumberFormat, diff --git a/src/plugins/data/common/field_formats/converters/date_nanos.test.ts b/src/plugins/data/public/field_formats/converters/date_nanos.test.ts similarity index 100% rename from src/plugins/data/common/field_formats/converters/date_nanos.test.ts rename to src/plugins/data/public/field_formats/converters/date_nanos.test.ts diff --git a/src/plugins/data/common/field_formats/converters/date_nanos.ts b/src/plugins/data/public/field_formats/converters/date_nanos.ts similarity index 96% rename from src/plugins/data/common/field_formats/converters/date_nanos.ts rename to src/plugins/data/public/field_formats/converters/date_nanos.ts index 3fa2b1c276cd7..3345d49cac30e 100644 --- a/src/plugins/data/common/field_formats/converters/date_nanos.ts +++ b/src/plugins/data/public/field_formats/converters/date_nanos.ts @@ -18,11 +18,14 @@ */ import { i18n } from '@kbn/i18n'; -import moment, { Moment } from 'moment'; import { memoize, noop } from 'lodash'; -import { KBN_FIELD_TYPES } from '../../kbn_field_types/types'; -import { FieldFormat } from '../field_format'; -import { TextContextTypeConvert, FIELD_FORMAT_IDS } from '../types'; +import moment, { Moment } from 'moment'; +import { + FieldFormat, + FIELD_FORMAT_IDS, + KBN_FIELD_TYPES, + TextContextTypeConvert, +} from '../../../common'; /** * Analyse the given moment.js format pattern for the fractional sec part (S,SS,SSS...) diff --git a/src/plugins/data/public/field_formats/converters/index.ts b/src/plugins/data/public/field_formats/converters/index.ts index c51111092beca..f5f154084242f 100644 --- a/src/plugins/data/public/field_formats/converters/index.ts +++ b/src/plugins/data/public/field_formats/converters/index.ts @@ -18,3 +18,4 @@ */ export { DateFormat } from './date'; +export { DateNanosFormat } from './date_nanos'; diff --git a/src/plugins/data/public/field_formats/index.ts b/src/plugins/data/public/field_formats/index.ts index 015d5b39561bb..4525959fb864d 100644 --- a/src/plugins/data/public/field_formats/index.ts +++ b/src/plugins/data/public/field_formats/index.ts @@ -18,5 +18,5 @@ */ export { FieldFormatsService, FieldFormatsSetup, FieldFormatsStart } from './field_formats_service'; -export { DateFormat } from './converters'; +export { DateFormat, DateNanosFormat } from './converters'; export { baseFormattersPublic } from './constants'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 89b0d7e0303b9..fb685821058f0 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -157,7 +157,6 @@ import { BoolFormat, BytesFormat, ColorFormat, - DateNanosFormat, DurationFormat, IpFormat, NumberFormat, @@ -170,7 +169,7 @@ import { TruncateFormat, } from '../common/field_formats'; -import { DateFormat } from './field_formats'; +import { DateNanosFormat, DateFormat } from './field_formats'; export { baseFormattersPublic } from './field_formats'; // Field formats helpers namespace: diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts new file mode 100644 index 0000000000000..83e24cb76c864 --- /dev/null +++ b/src/plugins/data/server/field_formats/converters/date_nanos_server.test.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 moment from 'moment-timezone'; +import { DateNanosFormat, analysePatternForFract, formatWithNanos } from './date_nanos_server'; + +describe('Date Nanos Format', () => { + let convert: Function; + let mockConfig: Record; + + beforeEach(() => { + mockConfig = {}; + mockConfig.dateNanosFormat = 'MMMM Do YYYY, HH:mm:ss.SSSSSSSSS'; + mockConfig['dateFormat:tz'] = 'Browser'; + + const getConfig = (key: string) => mockConfig[key]; + const date = new DateNanosFormat({}, getConfig); + + convert = date.convert.bind(date); + }); + + test('should inject fractional seconds into formatted timestamp', () => { + [ + { + input: '2019-05-20T14:04:56.357001234Z', + pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', + expected: 'May 20, 2019 @ 14:04:56.357001234', + }, + { + input: '2019-05-05T14:04:56.357111234Z', + pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', + expected: 'May 5, 2019 @ 14:04:56.357111234', + }, + { + input: '2019-05-05T14:04:56.357Z', + pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', + expected: 'May 5, 2019 @ 14:04:56.357000000', + }, + { + input: '2019-05-05T14:04:56Z', + pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', + expected: 'May 5, 2019 @ 14:04:56.000000000', + }, + { + input: '2019-05-05T14:04:56.201900001Z', + pattern: 'MMM D, YYYY @ HH:mm:ss SSSS', + expected: 'May 5, 2019 @ 14:04:56 2019', + }, + { + input: '2019-05-05T14:04:56.201900001Z', + pattern: 'SSSSSSSSS', + expected: '201900001', + }, + ].forEach((fixture) => { + const fracPattern = analysePatternForFract(fixture.pattern); + const momentDate = moment(fixture.input).utc(); + const value = formatWithNanos(momentDate, fixture.input, fracPattern); + expect(value).toBe(fixture.expected); + }); + }); + + test('decoding an undefined or null date should return an empty string', () => { + expect(convert(null)).toBe('-'); + expect(convert(undefined)).toBe('-'); + }); + + test('should clear the memoization cache after changing the date', () => { + function setDefaultTimezone() { + moment.tz.setDefault(mockConfig['dateFormat:tz']); + } + + const dateTime = '2019-05-05T14:04:56.201900001Z'; + + mockConfig['dateFormat:tz'] = 'America/Chicago'; + setDefaultTimezone(); + const chicagoTime = convert(dateTime); + + mockConfig['dateFormat:tz'] = 'America/Phoenix'; + setDefaultTimezone(); + const phoenixTime = convert(dateTime); + + expect(chicagoTime).not.toBe(phoenixTime); + }); + + test('should return the value itself when it cannot successfully be formatted', () => { + const dateMath = 'now+1M/d'; + expect(convert(dateMath)).toBe(dateMath); + }); +}); + +describe('analysePatternForFract', () => { + test('analysePatternForFract using timestamp format containing fractional seconds', () => { + expect(analysePatternForFract('MMM, YYYY @ HH:mm:ss.SSS')).toMatchInlineSnapshot(` + Object { + "length": 3, + "pattern": "MMM, YYYY @ HH:mm:ss.SSS", + "patternEscaped": "MMM, YYYY @ HH:mm:ss.[SSS]", + "patternNanos": "SSS", + } + `); + }); + + test('analysePatternForFract using timestamp format without fractional seconds', () => { + expect(analysePatternForFract('MMM, YYYY @ HH:mm:ss')).toMatchInlineSnapshot(` + Object { + "length": 0, + "pattern": "MMM, YYYY @ HH:mm:ss", + "patternEscaped": "", + "patternNanos": "", + } + `); + }); +}); diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts new file mode 100644 index 0000000000000..c5828fd9c51b9 --- /dev/null +++ b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts @@ -0,0 +1,141 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { memoize, noop } from 'lodash'; +import moment, { Moment } from 'moment-timezone'; +import { + FieldFormat, + FIELD_FORMAT_IDS, + KBN_FIELD_TYPES, + TextContextTypeConvert, +} from '../../../common'; + +/** + * Analyse the given moment.js format pattern for the fractional sec part (S,SS,SSS...) + * returning length, match, pattern and an escaped pattern, that excludes the fractional + * part when formatting with moment.js -> e.g. [SSS] + */ +export function analysePatternForFract(pattern: string) { + const fracSecMatch = pattern.match('S+') as any; // extract fractional seconds sub-pattern + const fracSecMatchStr = fracSecMatch ? fracSecMatch[0] : ''; + + return { + length: fracSecMatchStr.length, + patternNanos: fracSecMatchStr, + pattern, + patternEscaped: fracSecMatchStr ? pattern.replace(fracSecMatch, `[${fracSecMatch}]`) : '', + }; +} + +/** + * Format a given moment.js date object + * Since momentjs would loose the exact value for fractional seconds with a higher resolution than + * milliseconds, the fractional pattern is replaced by the fractional value of the raw timestamp + */ +export function formatWithNanos( + dateMomentObj: Moment, + valRaw: string, + fracPatternObj: Record +) { + if (fracPatternObj.length <= 3) { + // S,SS,SSS is formatted correctly by moment.js + return dateMomentObj.format(fracPatternObj.pattern); + } else { + // Beyond SSS the precise value of the raw datetime string is used + const valFormatted = dateMomentObj.format(fracPatternObj.patternEscaped); + // Extract fractional value of ES formatted timestamp, zero pad if necessary: + // 2020-05-18T20:45:05.957Z -> 957000000 + // 2020-05-18T20:45:05.957000123Z -> 957000123 + // we do not need to take care of the year 10000 bug since max year of date_nanos is 2262 + const valNanos = valRaw + .substr(20, valRaw.length - 21) // remove timezone(Z) + .padEnd(9, '0') // pad shorter fractionals + .substr(0, fracPatternObj.patternNanos.length); + return valFormatted.replace(fracPatternObj.patternNanos, valNanos); + } +} + +export class DateNanosFormat extends FieldFormat { + static id = FIELD_FORMAT_IDS.DATE_NANOS; + static title = i18n.translate('data.fieldFormats.date_nanos.title', { + defaultMessage: 'Date nanos', + }); + static fieldType = KBN_FIELD_TYPES.DATE; + + private memoizedConverter: Function = noop; + private memoizedPattern: string = ''; + private timeZone: string = ''; + + getParamDefaults() { + return { + pattern: this.getConfig!('dateNanosFormat'), + fallbackPattern: this.getConfig!('dateFormat'), + timezone: this.getConfig!('dateFormat:tz'), + }; + } + + textConvert: TextContextTypeConvert = (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 fractPattern = analysePatternForFract(pattern); + const fallbackPattern = this.param('patternFallback'); + + const timezoneChanged = this.timeZone !== timezone; + const datePatternChanged = this.memoizedPattern !== pattern; + if (timezoneChanged || datePatternChanged) { + this.timeZone = timezone; + this.memoizedPattern = pattern; + + this.memoizedConverter = memoize((value: any) => { + if (value === null || value === undefined) { + return '-'; + } + + /* On the server, importing moment returns a new instance. Unlike on + * the client side, it doesn't have the dateFormat:tz configuration + * baked in. + * We need to set the timezone manually here. The date is taken in as + * UTC and converted into the desired timezone. */ + let date; + if (this.timeZone === 'Browser') { + // Assume a warning has been logged that this can be unpredictable. It + // would be too verbose to log anything here. + date = moment.utc(val); + } else { + date = moment.utc(val).tz(this.timeZone); + } + + if (typeof value !== 'string' && date.isValid()) { + // fallback for max/min aggregation, where unixtime in ms is returned as a number + // aggregations in Elasticsearch generally just return ms + return date.format(fallbackPattern); + } else if (date.isValid()) { + return formatWithNanos(date, value, fractPattern); + } else { + return value; + } + }); + } + + return this.memoizedConverter(val); + }; +} diff --git a/src/plugins/data/server/field_formats/converters/index.ts b/src/plugins/data/server/field_formats/converters/index.ts index f5c69df972869..1c6b827e2fbb5 100644 --- a/src/plugins/data/server/field_formats/converters/index.ts +++ b/src/plugins/data/server/field_formats/converters/index.ts @@ -18,3 +18,4 @@ */ export { DateFormat } from './date_server'; +export { DateNanosFormat } from './date_nanos_server'; diff --git a/src/plugins/data/server/field_formats/field_formats_service.ts b/src/plugins/data/server/field_formats/field_formats_service.ts index 70584efbee0a0..cafb88de4b893 100644 --- a/src/plugins/data/server/field_formats/field_formats_service.ts +++ b/src/plugins/data/server/field_formats/field_formats_service.ts @@ -23,10 +23,14 @@ import { baseFormatters, } from '../../common/field_formats'; import { IUiSettingsClient } from '../../../../core/server'; -import { DateFormat } from './converters'; +import { DateFormat, DateNanosFormat } from './converters'; export class FieldFormatsService { - private readonly fieldFormatClasses: FieldFormatInstanceType[] = [DateFormat, ...baseFormatters]; + private readonly fieldFormatClasses: FieldFormatInstanceType[] = [ + DateFormat, + DateNanosFormat, + ...baseFormatters, + ]; public setup() { return { diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 6a4eb38b552ff..c9f94ee25bd35 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -86,7 +86,6 @@ import { BoolFormat, BytesFormat, ColorFormat, - DateNanosFormat, DurationFormat, IpFormat, NumberFormat, @@ -105,7 +104,6 @@ export const fieldFormats = { BoolFormat, BytesFormat, ColorFormat, - DateNanosFormat, DurationFormat, IpFormat, NumberFormat, From 642845587386af39d367eb687acd3f7162202e17 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 2 Jul 2020 16:05:57 -0700 Subject: [PATCH 02/11] add more to tests - need help though --- .../field_formats_registry.test.ts | 18 ++++++++++++++ .../field_formats_service.test.ts | 24 +++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/plugins/data/common/field_formats/field_formats_registry.test.ts b/src/plugins/data/common/field_formats/field_formats_registry.test.ts index f04524505a711..162c9eefe0043 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.test.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.test.ts @@ -163,4 +163,22 @@ describe('FieldFormatsRegistry', () => { expect(params).toHaveProperty('parsedUrl'); }); }); + + describe('setCustomParams', () => { + test('should provide custom setting to formatters: timezone', () => { + fieldFormatsRegistry = new FieldFormatsRegistry(); + fieldFormatsRegistry.init( + getConfig, + { + parsedUrl: { + origin: '', + pathname: '', + basePath: '', + }, + }, + [] + ); + fieldFormatsRegistry.setCustomParams({ timezone: 'America/New_York' }); + }); + }); }); diff --git a/src/plugins/data/server/field_formats/field_formats_service.test.ts b/src/plugins/data/server/field_formats/field_formats_service.test.ts index 2e7ce0fa435a7..4124d81f885b5 100644 --- a/src/plugins/data/server/field_formats/field_formats_service.test.ts +++ b/src/plugins/data/server/field_formats/field_formats_service.test.ts @@ -17,9 +17,10 @@ * under the License. */ -import { FieldFormatsService } from './field_formats_service'; -import { DateFormat } from './converters/date_server'; import { coreMock } from '../../../../core/server/mocks'; +import { FIELD_FORMAT_IDS } from '../../common'; +import { DateFormat } from './converters/date_server'; +import { FieldFormatsService } from './field_formats_service'; describe('FieldFormatService', () => { test('DateFormat is server version', async () => { @@ -32,3 +33,22 @@ describe('FieldFormatService', () => { expect(DateFormatFromRegsitry).toEqual(DateFormat); }); }); + +describe('DateFormat with custom timezone', () => { + test('should provide custom setting to formatters: timezone', async () => { + const service = new FieldFormatsService(); + const fieldFormatsService = await service.start(); + const uiSettings = coreMock.createStart().uiSettings.asScopedToClient({} as any); + const fieldFormatsRegistry = await fieldFormatsService.fieldFormatServiceFactory(uiSettings); + + fieldFormatsRegistry.setCustomParams({ timezone: 'America/Phoenix' }); // set the timezone into the registry + + const fieldFormats = fieldFormatsRegistry.getByFieldType(FIELD_FORMAT_IDS.DATE as any); + const DateFormatInstance = fieldFormats.find((F) => F.id === 'date'); + expect(DateFormatInstance).toBeDefined(); + if (DateFormatInstance) { + const formatter = new DateFormatInstance(); + // how to call the formatter? + } + }); +}); From 1789afcdc9d8cace21bed34049d5244e62a8df85 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 3 Jul 2020 11:23:03 -0700 Subject: [PATCH 03/11] simplify changes --- .../field_formats_registry.test.ts | 18 --- .../field_formats/field_formats_registry.ts | 26 ++-- .../converters/date_nanos_server.test.ts | 129 ------------------ .../field_formats_service.test.ts | 24 +--- 4 files changed, 11 insertions(+), 186 deletions(-) delete mode 100644 src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts diff --git a/src/plugins/data/common/field_formats/field_formats_registry.test.ts b/src/plugins/data/common/field_formats/field_formats_registry.test.ts index 162c9eefe0043..f04524505a711 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.test.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.test.ts @@ -163,22 +163,4 @@ describe('FieldFormatsRegistry', () => { expect(params).toHaveProperty('parsedUrl'); }); }); - - describe('setCustomParams', () => { - test('should provide custom setting to formatters: timezone', () => { - fieldFormatsRegistry = new FieldFormatsRegistry(); - fieldFormatsRegistry.init( - getConfig, - { - parsedUrl: { - origin: '', - pathname: '', - basePath: '', - }, - }, - [] - ); - fieldFormatsRegistry.setCustomParams({ timezone: 'America/New_York' }); - }); - }); }); 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 f76bdc530bc82..84bedd2f9dee0 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.ts @@ -40,7 +40,6 @@ export class FieldFormatsRegistry { protected defaultMap: Record = {}; protected metaParamsOptions: Record = {}; protected getConfig?: FieldFormatsGetConfigFn; - protected customParams: Record = {}; // overriden on the public contract public deserialize: (mapping: SerializedFieldFormat) => IFieldFormat = () => { return new (FieldFormat.from(identity))(); @@ -58,13 +57,6 @@ export class FieldFormatsRegistry { this.metaParamsOptions = metaParamsOptions; } - /* - * Allow use-case specific params that are reflected in getInstance / getDefaultInstancePlain - */ - setCustomParams(params: Record) { - this.customParams = params; - } - /** * Get the id of the default type for this field type * using the format:defaultTypeMap config map @@ -165,11 +157,7 @@ export class FieldFormatsRegistry { * @return {FieldFormat} */ getInstance = memoize( - (formatId: FieldFormatId, instanceParams: Record = {}): FieldFormat => { - const params = { - ...instanceParams, - ...this.customParams, - }; + (formatId: FieldFormatId, params: Record = {}): FieldFormat => { const ConcreteFieldFormat = this.getType(formatId); if (!ConcreteFieldFormat) { @@ -192,14 +180,18 @@ export class FieldFormatsRegistry { * @param {ES_FIELD_TYPES[]} esTypes * @return {FieldFormat} */ - getDefaultInstancePlain(fieldType: KBN_FIELD_TYPES, esTypes?: ES_FIELD_TYPES[]): FieldFormat { + getDefaultInstancePlain( + fieldType: KBN_FIELD_TYPES, + esTypes?: ES_FIELD_TYPES[], + params: Record = {} + ): FieldFormat { const conf = this.getDefaultConfig(fieldType, esTypes); - const defaultParams = { + const instanceParams = { ...conf.params, - ...this.customParams, + ...params, }; - return this.getInstance(conf.id, defaultParams); + return this.getInstance(conf.id, instanceParams); } /** * Returns a cache key built by the given variables for caching in memoized diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts deleted file mode 100644 index 83e24cb76c864..0000000000000 --- a/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 moment from 'moment-timezone'; -import { DateNanosFormat, analysePatternForFract, formatWithNanos } from './date_nanos_server'; - -describe('Date Nanos Format', () => { - let convert: Function; - let mockConfig: Record; - - beforeEach(() => { - mockConfig = {}; - mockConfig.dateNanosFormat = 'MMMM Do YYYY, HH:mm:ss.SSSSSSSSS'; - mockConfig['dateFormat:tz'] = 'Browser'; - - const getConfig = (key: string) => mockConfig[key]; - const date = new DateNanosFormat({}, getConfig); - - convert = date.convert.bind(date); - }); - - test('should inject fractional seconds into formatted timestamp', () => { - [ - { - input: '2019-05-20T14:04:56.357001234Z', - pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', - expected: 'May 20, 2019 @ 14:04:56.357001234', - }, - { - input: '2019-05-05T14:04:56.357111234Z', - pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', - expected: 'May 5, 2019 @ 14:04:56.357111234', - }, - { - input: '2019-05-05T14:04:56.357Z', - pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', - expected: 'May 5, 2019 @ 14:04:56.357000000', - }, - { - input: '2019-05-05T14:04:56Z', - pattern: 'MMM D, YYYY @ HH:mm:ss.SSSSSSSSS', - expected: 'May 5, 2019 @ 14:04:56.000000000', - }, - { - input: '2019-05-05T14:04:56.201900001Z', - pattern: 'MMM D, YYYY @ HH:mm:ss SSSS', - expected: 'May 5, 2019 @ 14:04:56 2019', - }, - { - input: '2019-05-05T14:04:56.201900001Z', - pattern: 'SSSSSSSSS', - expected: '201900001', - }, - ].forEach((fixture) => { - const fracPattern = analysePatternForFract(fixture.pattern); - const momentDate = moment(fixture.input).utc(); - const value = formatWithNanos(momentDate, fixture.input, fracPattern); - expect(value).toBe(fixture.expected); - }); - }); - - test('decoding an undefined or null date should return an empty string', () => { - expect(convert(null)).toBe('-'); - expect(convert(undefined)).toBe('-'); - }); - - test('should clear the memoization cache after changing the date', () => { - function setDefaultTimezone() { - moment.tz.setDefault(mockConfig['dateFormat:tz']); - } - - const dateTime = '2019-05-05T14:04:56.201900001Z'; - - mockConfig['dateFormat:tz'] = 'America/Chicago'; - setDefaultTimezone(); - const chicagoTime = convert(dateTime); - - mockConfig['dateFormat:tz'] = 'America/Phoenix'; - setDefaultTimezone(); - const phoenixTime = convert(dateTime); - - expect(chicagoTime).not.toBe(phoenixTime); - }); - - test('should return the value itself when it cannot successfully be formatted', () => { - const dateMath = 'now+1M/d'; - expect(convert(dateMath)).toBe(dateMath); - }); -}); - -describe('analysePatternForFract', () => { - test('analysePatternForFract using timestamp format containing fractional seconds', () => { - expect(analysePatternForFract('MMM, YYYY @ HH:mm:ss.SSS')).toMatchInlineSnapshot(` - Object { - "length": 3, - "pattern": "MMM, YYYY @ HH:mm:ss.SSS", - "patternEscaped": "MMM, YYYY @ HH:mm:ss.[SSS]", - "patternNanos": "SSS", - } - `); - }); - - test('analysePatternForFract using timestamp format without fractional seconds', () => { - expect(analysePatternForFract('MMM, YYYY @ HH:mm:ss')).toMatchInlineSnapshot(` - Object { - "length": 0, - "pattern": "MMM, YYYY @ HH:mm:ss", - "patternEscaped": "", - "patternNanos": "", - } - `); - }); -}); diff --git a/src/plugins/data/server/field_formats/field_formats_service.test.ts b/src/plugins/data/server/field_formats/field_formats_service.test.ts index 4124d81f885b5..2e7ce0fa435a7 100644 --- a/src/plugins/data/server/field_formats/field_formats_service.test.ts +++ b/src/plugins/data/server/field_formats/field_formats_service.test.ts @@ -17,10 +17,9 @@ * under the License. */ -import { coreMock } from '../../../../core/server/mocks'; -import { FIELD_FORMAT_IDS } from '../../common'; -import { DateFormat } from './converters/date_server'; import { FieldFormatsService } from './field_formats_service'; +import { DateFormat } from './converters/date_server'; +import { coreMock } from '../../../../core/server/mocks'; describe('FieldFormatService', () => { test('DateFormat is server version', async () => { @@ -33,22 +32,3 @@ describe('FieldFormatService', () => { expect(DateFormatFromRegsitry).toEqual(DateFormat); }); }); - -describe('DateFormat with custom timezone', () => { - test('should provide custom setting to formatters: timezone', async () => { - const service = new FieldFormatsService(); - const fieldFormatsService = await service.start(); - const uiSettings = coreMock.createStart().uiSettings.asScopedToClient({} as any); - const fieldFormatsRegistry = await fieldFormatsService.fieldFormatServiceFactory(uiSettings); - - fieldFormatsRegistry.setCustomParams({ timezone: 'America/Phoenix' }); // set the timezone into the registry - - const fieldFormats = fieldFormatsRegistry.getByFieldType(FIELD_FORMAT_IDS.DATE as any); - const DateFormatInstance = fieldFormats.find((F) => F.id === 'date'); - expect(DateFormatInstance).toBeDefined(); - if (DateFormatInstance) { - const formatter = new DateFormatInstance(); - // how to call the formatter? - } - }); -}); From 5aa2d802ec6539e6428025c3a662e92943195976 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 8 Jul 2020 12:12:31 -0700 Subject: [PATCH 04/11] api doc changes --- ...plugin-plugins-data-server.fieldformats.md | 1 - src/plugins/data/public/public.api.md | 72 +++++++++---------- src/plugins/data/server/server.api.md | 50 +++++++------ 3 files changed, 60 insertions(+), 63 deletions(-) diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md index 45fc1a608e8ca..0dddc65f4db92 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md @@ -13,7 +13,6 @@ fieldFormats: { BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; - DateNanosFormat: typeof DateNanosFormat; DurationFormat: typeof DurationFormat; IpFormat: typeof IpFormat; NumberFormat: typeof NumberFormat; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index c8110dbfd0041..67dd12f5c63cf 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1954,42 +1954,42 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:372:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:373:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:385:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:394:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:371:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:372:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:382:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:40:60 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 0048816456e17..2969b51304b64 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -295,7 +295,6 @@ export const fieldFormats: { BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; - DateNanosFormat: typeof DateNanosFormat; DurationFormat: typeof DurationFormat; IpFormat: typeof IpFormat; NumberFormat: typeof NumberFormat; @@ -803,31 +802,30 @@ export const UI_SETTINGS: { // src/plugins/data/server/index.ts:40:23 - (ae-forgotten-export) The symbol "buildFilter" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:71:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:71:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:129:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:129:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:189:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:190:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:193:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:183:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:184:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:191:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) From 231f7939436a06ec5a429d5b3bd5bf3d34577a9b Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 9 Jul 2020 16:31:55 -0700 Subject: [PATCH 05/11] fix src/plugins/data/public/field_formats/constants.ts --- src/plugins/data/public/field_formats/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/data/public/field_formats/constants.ts b/src/plugins/data/public/field_formats/constants.ts index a5c2b4e379908..d5e292c0e78e5 100644 --- a/src/plugins/data/public/field_formats/constants.ts +++ b/src/plugins/data/public/field_formats/constants.ts @@ -18,6 +18,6 @@ */ import { baseFormatters } from '../../common'; -import { DateFormat } from './converters/date'; +import { DateFormat, DateNanosFormat } from './converters'; -export const baseFormattersPublic = [DateFormat, ...baseFormatters]; +export const baseFormattersPublic = [DateFormat, DateNanosFormat, ...baseFormatters]; From 1e1d3c58ab766bd4ebce4795115107d7c07c2c8e Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 9 Jul 2020 16:35:30 -0700 Subject: [PATCH 06/11] rerun api changes --- .../kibana-plugin-plugins-data-public.baseformatterspublic.md | 2 +- src/plugins/data/public/public.api.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md index ddbf1a8459d1f..1aa9f460c4fac 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md @@ -7,5 +7,5 @@ Signature: ```typescript -baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat)[] +baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat | typeof DateNanosFormat)[] ``` diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index dc1dd9b7e02c2..4a78a80e3ae55 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -247,10 +247,11 @@ export class AggParamType extends Ba } // Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "baseFormattersPublic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat)[]; +export const baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat | typeof DateNanosFormat)[]; // Warning: (ae-missing-release-tag) "BUCKET_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1959,7 +1960,6 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts From 1bebcc83e687d707112d77d03865a28fc74481fe Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 9 Jul 2020 17:25:09 -0700 Subject: [PATCH 07/11] re-use public code in server, add test --- .../field_formats/converters/date_nanos.ts | 6 +- .../converters/date_nanos_server.test.ts | 74 +++++++++++++++++ .../converters/date_nanos_server.ts | 83 +++---------------- 3 files changed, 88 insertions(+), 75 deletions(-) create mode 100644 src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts diff --git a/src/plugins/data/public/field_formats/converters/date_nanos.ts b/src/plugins/data/public/field_formats/converters/date_nanos.ts index 3345d49cac30e..cc61f8f5cd44e 100644 --- a/src/plugins/data/public/field_formats/converters/date_nanos.ts +++ b/src/plugins/data/public/field_formats/converters/date_nanos.ts @@ -79,9 +79,9 @@ export class DateNanosFormat extends FieldFormat { }); static fieldType = KBN_FIELD_TYPES.DATE; - private memoizedConverter: Function = noop; - private memoizedPattern: string = ''; - private timeZone: string = ''; + protected memoizedConverter: Function = noop; + protected memoizedPattern: string = ''; + protected timeZone: string = ''; getParamDefaults() { return { diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts new file mode 100644 index 0000000000000..ba8e128f32728 --- /dev/null +++ b/src/plugins/data/server/field_formats/converters/date_nanos_server.test.ts @@ -0,0 +1,74 @@ +/* + * 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 { DateNanosFormat } from './date_nanos_server'; +import { FieldFormatsGetConfigFn } from 'src/plugins/data/common'; + +describe('Date Nanos Format: Server side edition', () => { + let convert: Function; + let mockConfig: Record; + let getConfig: FieldFormatsGetConfigFn; + + const dateTime = '2019-05-05T14:04:56.201900001Z'; + + beforeEach(() => { + mockConfig = {}; + mockConfig.dateNanosFormat = 'MMMM Do YYYY, HH:mm:ss.SSSSSSSSS'; + mockConfig['dateFormat:tz'] = 'Browser'; + + getConfig = (key: string) => mockConfig[key]; + }); + + test('should format according to the given timezone parameter', () => { + const dateNy = new DateNanosFormat({ timezone: 'America/New_York' }, getConfig); + convert = dateNy.convert.bind(dateNy); + expect(convert(dateTime)).toMatchInlineSnapshot(`"May 5th 2019, 10:04:56.201900001"`); + + const datePhx = new DateNanosFormat({ timezone: 'America/Phoenix' }, getConfig); + convert = datePhx.convert.bind(datePhx); + expect(convert(dateTime)).toMatchInlineSnapshot(`"May 5th 2019, 07:04:56.201900001"`); + }); + + test('should format according to UTC if no timezone parameter is given or exists in settings', () => { + const utcFormat = 'May 5th 2019, 14:04:56.201900001'; + const dateUtc = new DateNanosFormat({ timezone: 'UTC' }, getConfig); + convert = dateUtc.convert.bind(dateUtc); + expect(convert(dateTime)).toBe(utcFormat); + + const dateDefault = new DateNanosFormat({}, getConfig); + convert = dateDefault.convert.bind(dateDefault); + expect(convert(dateTime)).toBe(utcFormat); + }); + + test('should format according to dateFormat:tz if the setting is not "Browser"', () => { + mockConfig['dateFormat:tz'] = 'America/Phoenix'; + + const date = new DateNanosFormat({}, getConfig); + convert = date.convert.bind(date); + expect(convert(dateTime)).toMatchInlineSnapshot(`"May 5th 2019, 07:04:56.201900001"`); + }); + + test('should defer to meta params for timezone, not the UI config', () => { + mockConfig['dateFormat:tz'] = 'America/Phoenix'; + + const date = new DateNanosFormat({ timezone: 'America/New_York' }, getConfig); + convert = date.convert.bind(date); + expect(convert(dateTime)).toMatchInlineSnapshot(`"May 5th 2019, 10:04:56.201900001"`); + }); +}); diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts index c5828fd9c51b9..2bf533ab85bef 100644 --- a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts +++ b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts @@ -17,80 +17,17 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -import { memoize, noop } from 'lodash'; -import moment, { Moment } from 'moment-timezone'; +import { memoize } from 'lodash'; +import moment from 'moment-timezone'; import { - FieldFormat, - FIELD_FORMAT_IDS, - KBN_FIELD_TYPES, - TextContextTypeConvert, -} from '../../../common'; - -/** - * Analyse the given moment.js format pattern for the fractional sec part (S,SS,SSS...) - * returning length, match, pattern and an escaped pattern, that excludes the fractional - * part when formatting with moment.js -> e.g. [SSS] - */ -export function analysePatternForFract(pattern: string) { - const fracSecMatch = pattern.match('S+') as any; // extract fractional seconds sub-pattern - const fracSecMatchStr = fracSecMatch ? fracSecMatch[0] : ''; - - return { - length: fracSecMatchStr.length, - patternNanos: fracSecMatchStr, - pattern, - patternEscaped: fracSecMatchStr ? pattern.replace(fracSecMatch, `[${fracSecMatch}]`) : '', - }; -} - -/** - * Format a given moment.js date object - * Since momentjs would loose the exact value for fractional seconds with a higher resolution than - * milliseconds, the fractional pattern is replaced by the fractional value of the raw timestamp - */ -export function formatWithNanos( - dateMomentObj: Moment, - valRaw: string, - fracPatternObj: Record -) { - if (fracPatternObj.length <= 3) { - // S,SS,SSS is formatted correctly by moment.js - return dateMomentObj.format(fracPatternObj.pattern); - } else { - // Beyond SSS the precise value of the raw datetime string is used - const valFormatted = dateMomentObj.format(fracPatternObj.patternEscaped); - // Extract fractional value of ES formatted timestamp, zero pad if necessary: - // 2020-05-18T20:45:05.957Z -> 957000000 - // 2020-05-18T20:45:05.957000123Z -> 957000123 - // we do not need to take care of the year 10000 bug since max year of date_nanos is 2262 - const valNanos = valRaw - .substr(20, valRaw.length - 21) // remove timezone(Z) - .padEnd(9, '0') // pad shorter fractionals - .substr(0, fracPatternObj.patternNanos.length); - return valFormatted.replace(fracPatternObj.patternNanos, valNanos); - } -} - -export class DateNanosFormat extends FieldFormat { - static id = FIELD_FORMAT_IDS.DATE_NANOS; - static title = i18n.translate('data.fieldFormats.date_nanos.title', { - defaultMessage: 'Date nanos', - }); - static fieldType = KBN_FIELD_TYPES.DATE; - - private memoizedConverter: Function = noop; - private memoizedPattern: string = ''; - private timeZone: string = ''; - - getParamDefaults() { - return { - pattern: this.getConfig!('dateNanosFormat'), - fallbackPattern: this.getConfig!('dateFormat'), - timezone: this.getConfig!('dateFormat:tz'), - }; - } + analysePatternForFract, + DateNanosFormat, + formatWithNanos, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from 'src/plugins/data/public/field_formats/converters/date_nanos'; +import { TextContextTypeConvert } from '../../../common'; +class DateNanosFormatServer extends DateNanosFormat { textConvert: TextContextTypeConvert = (val) => { // don't give away our ref to converter so // we can hot-swap when config changes @@ -139,3 +76,5 @@ export class DateNanosFormat extends FieldFormat { return this.memoizedConverter(val); }; } + +export { DateNanosFormatServer as DateNanosFormat }; From 736e9eecddb8b5a037ed6726ef1518e05f056599 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 9 Jul 2020 17:43:10 -0700 Subject: [PATCH 08/11] fix path for tests --- .../data/server/field_formats/converters/date_nanos_server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts index 2bf533ab85bef..a9b8f36d7481f 100644 --- a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts +++ b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts @@ -24,7 +24,7 @@ import { DateNanosFormat, formatWithNanos, // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from 'src/plugins/data/public/field_formats/converters/date_nanos'; +} from '../../../public/field_formats/converters/date_nanos'; import { TextContextTypeConvert } from '../../../common'; class DateNanosFormatServer extends DateNanosFormat { From 1b6e9e87192630e4ea20b882235af2d2f1852c31 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 10 Jul 2020 15:03:08 -0700 Subject: [PATCH 09/11] weird api change needed but no real diff --- .../kibana-plugin-plugins-data-public.baseformatterspublic.md | 2 +- src/plugins/data/public/public.api.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md index 1aa9f460c4fac..25f046983cbce 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md @@ -7,5 +7,5 @@ Signature: ```typescript -baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat | typeof DateNanosFormat)[] +baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateNanosFormat | typeof DateFormat)[] ``` diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 0a2bd094f8a63..f276deeef371e 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -246,12 +246,12 @@ export class AggParamType extends Ba makeAgg: (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig; } -// Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "baseFormattersPublic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat | typeof DateNanosFormat)[]; +export const baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateNanosFormat | typeof DateFormat)[]; // Warning: (ae-missing-release-tag) "BUCKET_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // From 4e5eebd93b71d267980dab5eb6b031693540f178 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 13 Jul 2020 09:07:32 -0700 Subject: [PATCH 10/11] 3td time api doc chagens --- src/plugins/data/public/public.api.md | 71 +++++++++++++-------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index dc31f12cdc65b..0c23ba340304f 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1956,42 +1956,41 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:233:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:370:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:372:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:373:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:385:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:394:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:371:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:372:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:382:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:41:60 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts From ed749eb5ad92a34cadb619c160b642fc6aebcc64 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Mon, 13 Jul 2020 10:12:28 -0700 Subject: [PATCH 11/11] move shared code to common --- .../converters/date_nanos_shared.test.ts} | 2 +- .../converters/date_nanos_shared.ts | 124 ++++++++++++++++++ .../field_formats/converters/date_nanos.ts | 111 +--------------- .../converters/date_nanos_server.ts | 3 +- 4 files changed, 127 insertions(+), 113 deletions(-) rename src/plugins/data/{public/field_formats/converters/date_nanos.test.ts => common/field_formats/converters/date_nanos_shared.test.ts} (99%) create mode 100644 src/plugins/data/common/field_formats/converters/date_nanos_shared.ts diff --git a/src/plugins/data/public/field_formats/converters/date_nanos.test.ts b/src/plugins/data/common/field_formats/converters/date_nanos_shared.test.ts similarity index 99% rename from src/plugins/data/public/field_formats/converters/date_nanos.test.ts rename to src/plugins/data/common/field_formats/converters/date_nanos_shared.test.ts index 267f023e9b69d..6843427d273ff 100644 --- a/src/plugins/data/public/field_formats/converters/date_nanos.test.ts +++ b/src/plugins/data/common/field_formats/converters/date_nanos_shared.test.ts @@ -18,7 +18,7 @@ */ import moment from 'moment-timezone'; -import { DateNanosFormat, analysePatternForFract, formatWithNanos } from './date_nanos'; +import { DateNanosFormat, analysePatternForFract, formatWithNanos } from './date_nanos_shared'; describe('Date Nanos Format', () => { let convert: Function; diff --git a/src/plugins/data/common/field_formats/converters/date_nanos_shared.ts b/src/plugins/data/common/field_formats/converters/date_nanos_shared.ts new file mode 100644 index 0000000000000..89a63243c76f0 --- /dev/null +++ b/src/plugins/data/common/field_formats/converters/date_nanos_shared.ts @@ -0,0 +1,124 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { memoize, noop } from 'lodash'; +import moment, { Moment } from 'moment'; +import { FieldFormat, FIELD_FORMAT_IDS, KBN_FIELD_TYPES, TextContextTypeConvert } from '../../'; + +/** + * Analyse the given moment.js format pattern for the fractional sec part (S,SS,SSS...) + * returning length, match, pattern and an escaped pattern, that excludes the fractional + * part when formatting with moment.js -> e.g. [SSS] + */ +export function analysePatternForFract(pattern: string) { + const fracSecMatch = pattern.match('S+') as any; // extract fractional seconds sub-pattern + const fracSecMatchStr = fracSecMatch ? fracSecMatch[0] : ''; + + return { + length: fracSecMatchStr.length, + patternNanos: fracSecMatchStr, + pattern, + patternEscaped: fracSecMatchStr ? pattern.replace(fracSecMatch, `[${fracSecMatch}]`) : '', + }; +} + +/** + * Format a given moment.js date object + * Since momentjs would loose the exact value for fractional seconds with a higher resolution than + * milliseconds, the fractional pattern is replaced by the fractional value of the raw timestamp + */ +export function formatWithNanos( + dateMomentObj: Moment, + valRaw: string, + fracPatternObj: Record +) { + if (fracPatternObj.length <= 3) { + // S,SS,SSS is formatted correctly by moment.js + return dateMomentObj.format(fracPatternObj.pattern); + } else { + // Beyond SSS the precise value of the raw datetime string is used + const valFormatted = dateMomentObj.format(fracPatternObj.patternEscaped); + // Extract fractional value of ES formatted timestamp, zero pad if necessary: + // 2020-05-18T20:45:05.957Z -> 957000000 + // 2020-05-18T20:45:05.957000123Z -> 957000123 + // we do not need to take care of the year 10000 bug since max year of date_nanos is 2262 + const valNanos = valRaw + .substr(20, valRaw.length - 21) // remove timezone(Z) + .padEnd(9, '0') // pad shorter fractionals + .substr(0, fracPatternObj.patternNanos.length); + return valFormatted.replace(fracPatternObj.patternNanos, valNanos); + } +} + +export class DateNanosFormat extends FieldFormat { + static id = FIELD_FORMAT_IDS.DATE_NANOS; + static title = i18n.translate('data.fieldFormats.date_nanos.title', { + defaultMessage: 'Date nanos', + }); + static fieldType = KBN_FIELD_TYPES.DATE; + + protected memoizedConverter: Function = noop; + protected memoizedPattern: string = ''; + protected timeZone: string = ''; + + getParamDefaults() { + return { + pattern: this.getConfig!('dateNanosFormat'), + fallbackPattern: this.getConfig!('dateFormat'), + timezone: this.getConfig!('dateFormat:tz'), + }; + } + + textConvert: TextContextTypeConvert = (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 fractPattern = analysePatternForFract(pattern); + const fallbackPattern = this.param('patternFallback'); + + const timezoneChanged = this.timeZone !== timezone; + const datePatternChanged = this.memoizedPattern !== pattern; + if (timezoneChanged || datePatternChanged) { + this.timeZone = timezone; + this.memoizedPattern = pattern; + + this.memoizedConverter = memoize(function converter(value: any) { + if (value === null || value === undefined) { + return '-'; + } + + const date = moment(value); + + if (typeof value !== 'string' && date.isValid()) { + // fallback for max/min aggregation, where unixtime in ms is returned as a number + // aggregations in Elasticsearch generally just return ms + return date.format(fallbackPattern); + } else if (date.isValid()) { + return formatWithNanos(date, value, fractPattern); + } else { + return value; + } + }); + } + + return this.memoizedConverter(val); + }; +} diff --git a/src/plugins/data/public/field_formats/converters/date_nanos.ts b/src/plugins/data/public/field_formats/converters/date_nanos.ts index cc61f8f5cd44e..d83926826011a 100644 --- a/src/plugins/data/public/field_formats/converters/date_nanos.ts +++ b/src/plugins/data/public/field_formats/converters/date_nanos.ts @@ -17,113 +17,4 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -import { memoize, noop } from 'lodash'; -import moment, { Moment } from 'moment'; -import { - FieldFormat, - FIELD_FORMAT_IDS, - KBN_FIELD_TYPES, - TextContextTypeConvert, -} from '../../../common'; - -/** - * Analyse the given moment.js format pattern for the fractional sec part (S,SS,SSS...) - * returning length, match, pattern and an escaped pattern, that excludes the fractional - * part when formatting with moment.js -> e.g. [SSS] - */ -export function analysePatternForFract(pattern: string) { - const fracSecMatch = pattern.match('S+') as any; // extract fractional seconds sub-pattern - const fracSecMatchStr = fracSecMatch ? fracSecMatch[0] : ''; - - return { - length: fracSecMatchStr.length, - patternNanos: fracSecMatchStr, - pattern, - patternEscaped: fracSecMatchStr ? pattern.replace(fracSecMatch, `[${fracSecMatch}]`) : '', - }; -} - -/** - * Format a given moment.js date object - * Since momentjs would loose the exact value for fractional seconds with a higher resolution than - * milliseconds, the fractional pattern is replaced by the fractional value of the raw timestamp - */ -export function formatWithNanos( - dateMomentObj: Moment, - valRaw: string, - fracPatternObj: Record -) { - if (fracPatternObj.length <= 3) { - // S,SS,SSS is formatted correctly by moment.js - return dateMomentObj.format(fracPatternObj.pattern); - } else { - // Beyond SSS the precise value of the raw datetime string is used - const valFormatted = dateMomentObj.format(fracPatternObj.patternEscaped); - // Extract fractional value of ES formatted timestamp, zero pad if necessary: - // 2020-05-18T20:45:05.957Z -> 957000000 - // 2020-05-18T20:45:05.957000123Z -> 957000123 - // we do not need to take care of the year 10000 bug since max year of date_nanos is 2262 - const valNanos = valRaw - .substr(20, valRaw.length - 21) // remove timezone(Z) - .padEnd(9, '0') // pad shorter fractionals - .substr(0, fracPatternObj.patternNanos.length); - return valFormatted.replace(fracPatternObj.patternNanos, valNanos); - } -} - -export class DateNanosFormat extends FieldFormat { - static id = FIELD_FORMAT_IDS.DATE_NANOS; - static title = i18n.translate('data.fieldFormats.date_nanos.title', { - defaultMessage: 'Date nanos', - }); - static fieldType = KBN_FIELD_TYPES.DATE; - - protected memoizedConverter: Function = noop; - protected memoizedPattern: string = ''; - protected timeZone: string = ''; - - getParamDefaults() { - return { - pattern: this.getConfig!('dateNanosFormat'), - fallbackPattern: this.getConfig!('dateFormat'), - timezone: this.getConfig!('dateFormat:tz'), - }; - } - - textConvert: TextContextTypeConvert = (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 fractPattern = analysePatternForFract(pattern); - const fallbackPattern = this.param('patternFallback'); - - const timezoneChanged = this.timeZone !== timezone; - const datePatternChanged = this.memoizedPattern !== pattern; - if (timezoneChanged || datePatternChanged) { - this.timeZone = timezone; - this.memoizedPattern = pattern; - - this.memoizedConverter = memoize(function converter(value: any) { - if (value === null || value === undefined) { - return '-'; - } - - const date = moment(value); - - if (typeof value !== 'string' && date.isValid()) { - // fallback for max/min aggregation, where unixtime in ms is returned as a number - // aggregations in Elasticsearch generally just return ms - return date.format(fallbackPattern); - } else if (date.isValid()) { - return formatWithNanos(date, value, fractPattern); - } else { - return value; - } - }); - } - - return this.memoizedConverter(val); - }; -} +export { DateNanosFormat } from '../../../common/field_formats/converters/date_nanos_shared'; diff --git a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts index a9b8f36d7481f..299b2aac93d49 100644 --- a/src/plugins/data/server/field_formats/converters/date_nanos_server.ts +++ b/src/plugins/data/server/field_formats/converters/date_nanos_server.ts @@ -23,8 +23,7 @@ import { analysePatternForFract, DateNanosFormat, formatWithNanos, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../public/field_formats/converters/date_nanos'; +} from '../../../common/field_formats/converters/date_nanos_shared'; import { TextContextTypeConvert } from '../../../common'; class DateNanosFormatServer extends DateNanosFormat {