Skip to content

Commit 65b0e09

Browse files
committed
[Lens] Add suffix formatter (elastic#82852)
1 parent d283252 commit 65b0e09

File tree

6 files changed

+98
-2
lines changed

6 files changed

+98
-2
lines changed

x-pack/plugins/lens/public/indexpattern_datasource/format_column.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,18 @@ export const formatColumn: ExpressionFunctionDefinition<
116116
});
117117
}
118118
if (parentFormatParams) {
119-
const innerParams = (col.meta.params?.params as Record<string, unknown>) ?? {};
119+
// if original format is already a nested one, we are just replacing the wrapper params
120+
// otherwise wrapping it inside parentFormatId/parentFormatParams
121+
const isNested = isNestedFormat(col.meta.params);
122+
const innerParams = isNested
123+
? col.meta.params?.params
124+
: { id: col.meta.params?.id, params: col.meta.params?.params };
125+
126+
const formatId = isNested ? col.meta.params?.id : parentFormatId;
127+
120128
return withParams(col, {
121129
...col.meta.params,
130+
id: formatId,
122131
params: {
123132
...innerParams,
124133
...parentFormatParams,
@@ -132,6 +141,11 @@ export const formatColumn: ExpressionFunctionDefinition<
132141
},
133142
};
134143

144+
function isNestedFormat(params: DatatableColumn['meta']['params']) {
145+
// if there is a nested params object with an id, it's a nested format
146+
return !!params?.params?.id;
147+
}
148+
135149
function withParams(col: DatatableColumn, params: Record<string, unknown>) {
136150
return { ...col, meta: { ...col.meta, params } };
137151
}

x-pack/plugins/lens/public/indexpattern_datasource/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ export class IndexPatternDatasource {
3838
renameColumns,
3939
formatColumn,
4040
getTimeScaleFunction,
41+
getSuffixFormatter,
4142
} = await import('../async_services');
4243
return core.getStartServices().then(([coreStart, { data }]) => {
44+
data.fieldFormats.register([getSuffixFormatter(data.fieldFormats.deserialize)]);
4345
expressions.registerFunction(getTimeScaleFunction(data));
4446
expressions.registerFunction(renameColumns);
4547
expressions.registerFunction(formatColumn);

x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export function columnToOperation(column: IndexPatternColumn, uniqueLabel?: stri
7878
export * from './rename_columns';
7979
export * from './format_column';
8080
export * from './time_scale';
81+
export * from './suffix_formatter';
8182

8283
export function getIndexPatternDatasource({
8384
core,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { FormatFactory } from '../types';
8+
import { getSuffixFormatter } from './suffix_formatter';
9+
10+
describe('suffix formatter', () => {
11+
it('should call nested formatter and apply suffix', () => {
12+
const convertMock = jest.fn((x) => x);
13+
const formatFactory = jest.fn(() => ({ convert: convertMock }));
14+
const SuffixFormatter = getSuffixFormatter((formatFactory as unknown) as FormatFactory);
15+
const nestedParams = { abc: 123 };
16+
const formatterInstance = new SuffixFormatter({
17+
unit: 'h',
18+
id: 'nestedFormatter',
19+
params: nestedParams,
20+
});
21+
22+
const result = formatterInstance.convert(12345);
23+
24+
expect(result).toEqual('12345/h');
25+
expect(convertMock).toHaveBeenCalledWith(12345);
26+
expect(formatFactory).toHaveBeenCalledWith({ id: 'nestedFormatter', params: nestedParams });
27+
});
28+
});
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { i18n } from '@kbn/i18n';
8+
import { FieldFormat, KBN_FIELD_TYPES } from '../../../../../src/plugins/data/public';
9+
import { FormatFactory } from '../types';
10+
import { TimeScaleUnit } from './time_scale';
11+
12+
const unitSuffixes: Record<TimeScaleUnit, string> = {
13+
s: i18n.translate('xpack.lens.fieldFormats.suffix.s', { defaultMessage: '/h' }),
14+
m: i18n.translate('xpack.lens.fieldFormats.suffix.m', { defaultMessage: '/m' }),
15+
h: i18n.translate('xpack.lens.fieldFormats.suffix.h', { defaultMessage: '/h' }),
16+
d: i18n.translate('xpack.lens.fieldFormats.suffix.d', { defaultMessage: '/d' }),
17+
};
18+
19+
export function getSuffixFormatter(formatFactory: FormatFactory) {
20+
return class SuffixFormatter extends FieldFormat {
21+
static id = 'suffix';
22+
static title = i18n.translate('xpack.lens.fieldFormats.suffix.title', {
23+
defaultMessage: 'Suffix',
24+
});
25+
static fieldType = KBN_FIELD_TYPES.NUMBER;
26+
allowsNumericalAggregations = true;
27+
28+
getParamDefaults() {
29+
return {
30+
unit: undefined,
31+
nestedParams: {},
32+
};
33+
}
34+
35+
textConvert = (val: unknown) => {
36+
const unit = this.param('unit') as TimeScaleUnit | undefined;
37+
const suffix = unit ? unitSuffixes[unit] : undefined;
38+
const nestedFormatter = this.param('id');
39+
const nestedParams = this.param('params');
40+
41+
const formattedValue = formatFactory({ id: nestedFormatter, params: nestedParams }).convert(
42+
val
43+
);
44+
45+
if (suffix) {
46+
return `${formattedValue}${suffix}`;
47+
}
48+
return formattedValue;
49+
};
50+
};
51+
}

x-pack/plugins/lens/public/indexpattern_datasource/time_scale.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { DataPublicPluginStart } from 'src/plugins/data/public';
1111
import { search } from '../../../../../src/plugins/data/public';
1212
import { buildResultColumns } from '../../../../../src/plugins/expressions/common';
1313

14-
type TimeScaleUnit = 's' | 'm' | 'h' | 'd';
14+
export type TimeScaleUnit = 's' | 'm' | 'h' | 'd';
1515

1616
export interface TimeScaleArgs {
1717
dateColumnId: string;

0 commit comments

Comments
 (0)