Skip to content

Commit 15c5b60

Browse files
[8.19] [Lens] Always show number sign when comparing to Primary metric (#222824) (#223201)
# Backport This will backport the following commits from `main` to `8.19`: - [[Lens] Always show number sign when comparing to Primary metric (#222824)](#222824) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Marco Liberati","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-06-10T09:46:13Z","message":"[Lens] Always show number sign when comparing to Primary metric (#222824)\n\n## Summary\n\nFixes #221882 \n\nThis is a possible take of the enhancement request in #221882.\nIn this scenario the chart automatically enters the `alwaysShowSign`\nmode when rendering the delta difference with the Primary Metric in the\nSecondary badge.\n\nSome notes:\n* The user has no control over it.\n* The behaviour is disabled automatically when moving into `Static\nvalue` mode, while it can be replicated using the `custom format` in the\n`Value format` control\n* The affected formats are `number`, `bytes`, `bits`, `percentage` in\nany possible configuration (i.e. also compact mode)\n* I've noticed that some formats change a bit when the sign is displayed\n(ie Currency goes from `$ xx.xxx` to `+ xx.xx # Backport This will backport the following commits from `main` to `8.19`: {{{{raw}}}} - [[Lens] Always show number sign when comparing to Primary metric (#222824)](https://github.com/elastic/kibana/pull/222824){{{{/raw}}}} <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT )\n\n**Compare to Primary Metric**\n| Default | Number | Number (compact) | Custom Format (i.e. Currency) |\nPercentage | Bytes | Bits |\n| ---- | ---- | ---- | ---- | ---- | ---- | ---- |\n| <img width=\"819\" alt=\"Screenshot 2025-06-05 at 14 41 09\"\nsrc=\"https://github.com/user-attachments/assets/3e836e07-a5eb-479a-96af-463069cabc35\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 40 37\"\nsrc=\"https://github.com/user-attachments/assets/097548c5-4c68-4041-89a7-a46af228fd7a\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 15 41 29\"\nsrc=\"https://github.com/user-attachments/assets/52943f01-c302-4631-8c2c-55fc60d91d99\"\n/> | <img width=\"480\" alt=\"Screenshot 2025-06-05 at 15 42 33\"\nsrc=\"https://github.com/user-attachments/assets/b2dbbaec-4c11-4e3f-80ac-20f810511bf7\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 14 48 18\"\nsrc=\"https://github.com/user-attachments/assets/13a1b102-30dd-46b4-b8f4-52ade1e9eadb\"\n/> | <img width=\"478\" alt=\"Screenshot 2025-06-05 at 15 44 11\"\nsrc=\"https://github.com/user-attachments/assets/e9acbb69-6535-4ee2-962a-f1e5446b93dd\"\n/> | <img width=\"477\" alt=\"Screenshot 2025-06-05 at 14 47 54\"\nsrc=\"https://github.com/user-attachments/assets/c6bb99af-5f08-4d0d-b302-e8fbe42a764b\"\n/> |\n\nWhen using Static value:\n\n| Default | Number | Number (compact) | Custom format (i.e. Currency) |\nPercentage | Bytes | Bits |\n| ---- | --- | ---- | ---- | ---- | ---- | ---- | \n| <img width=\"471\" alt=\"Screenshot 2025-06-05 at 14 56 17\"\nsrc=\"https://github.com/user-attachments/assets/6135823f-b644-48aa-b236-076bcc0692ff\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 49 51\"\nsrc=\"https://github.com/user-attachments/assets/afe492ad-c908-45ee-b831-2108553c15ce\"\n/> | <img width=\"477\" alt=\"Screenshot 2025-06-05 at 15 46 24\"\nsrc=\"https://github.com/user-attachments/assets/29eaccf5-0be8-46a6-9e87-3b6f99912e26\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 15 52 27\"\nsrc=\"https://github.com/user-attachments/assets/3867b435-a1e2-4cb3-9b4d-687a33f4ff78\"\n/> | <img width=\"482\" alt=\"Screenshot 2025-06-05 at 15 46 40\"\nsrc=\"https://github.com/user-attachments/assets/0e1521b3-6ed3-45e4-a913-44e4f99f027a\"\n/> | <img width=\"480\" alt=\"Screenshot 2025-06-05 at 15 45 50\"\nsrc=\"https://github.com/user-attachments/assets/0343fd8c-6d22-46bb-9676-f27cad4ca9ee\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 46 05\"\nsrc=\"https://github.com/user-attachments/assets/072e948d-71ce-48f0-862a-6932c5c510fa\"\n/> |\n\nExtra bits:\n* I did notice that when rendering in Icon mode only and the secondary\nraw value is `null` an empty badge was rendered. Now it should not.\n* When running Jest tests a warning about a missing `act` wrapping was\nshown, which was due to the `jest.advanceTimers` call. Now it is\nproperly wrapped\n* When testing with a time shift it is very likely to encounter into\nhttps://github.com//issues/221886 and have all badges set\nto `NA`. In such case close the inline editor and hit `Refresh` again to\nsee fresh values.\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios","sha":"af3b804ed331d7a5802fbc7e6ae78912ed603c06","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Visualizations","release_note:skip","Feature:Lens","backport:version","v9.1.0","v8.19.0"],"title":"[Lens] Always show number sign when comparing to Primary metric","number":222824,"url":"https://github.com/elastic/kibana/pull/222824","mergeCommit":{"message":"[Lens] Always show number sign when comparing to Primary metric (#222824)\n\n## Summary\n\nFixes #221882 \n\nThis is a possible take of the enhancement request in #221882.\nIn this scenario the chart automatically enters the `alwaysShowSign`\nmode when rendering the delta difference with the Primary Metric in the\nSecondary badge.\n\nSome notes:\n* The user has no control over it.\n* The behaviour is disabled automatically when moving into `Static\nvalue` mode, while it can be replicated using the `custom format` in the\n`Value format` control\n* The affected formats are `number`, `bytes`, `bits`, `percentage` in\nany possible configuration (i.e. also compact mode)\n* I've noticed that some formats change a bit when the sign is displayed\n(ie Currency goes from `$ xx.xxx` to `+ xx.xx # Backport This will backport the following commits from `main` to `8.19`: {{{{raw}}}} - [[Lens] Always show number sign when comparing to Primary metric (#222824)](https://github.com/elastic/kibana/pull/222824){{{{/raw}}}} <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT )\n\n**Compare to Primary Metric**\n| Default | Number | Number (compact) | Custom Format (i.e. Currency) |\nPercentage | Bytes | Bits |\n| ---- | ---- | ---- | ---- | ---- | ---- | ---- |\n| <img width=\"819\" alt=\"Screenshot 2025-06-05 at 14 41 09\"\nsrc=\"https://github.com/user-attachments/assets/3e836e07-a5eb-479a-96af-463069cabc35\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 40 37\"\nsrc=\"https://github.com/user-attachments/assets/097548c5-4c68-4041-89a7-a46af228fd7a\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 15 41 29\"\nsrc=\"https://github.com/user-attachments/assets/52943f01-c302-4631-8c2c-55fc60d91d99\"\n/> | <img width=\"480\" alt=\"Screenshot 2025-06-05 at 15 42 33\"\nsrc=\"https://github.com/user-attachments/assets/b2dbbaec-4c11-4e3f-80ac-20f810511bf7\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 14 48 18\"\nsrc=\"https://github.com/user-attachments/assets/13a1b102-30dd-46b4-b8f4-52ade1e9eadb\"\n/> | <img width=\"478\" alt=\"Screenshot 2025-06-05 at 15 44 11\"\nsrc=\"https://github.com/user-attachments/assets/e9acbb69-6535-4ee2-962a-f1e5446b93dd\"\n/> | <img width=\"477\" alt=\"Screenshot 2025-06-05 at 14 47 54\"\nsrc=\"https://github.com/user-attachments/assets/c6bb99af-5f08-4d0d-b302-e8fbe42a764b\"\n/> |\n\nWhen using Static value:\n\n| Default | Number | Number (compact) | Custom format (i.e. Currency) |\nPercentage | Bytes | Bits |\n| ---- | --- | ---- | ---- | ---- | ---- | ---- | \n| <img width=\"471\" alt=\"Screenshot 2025-06-05 at 14 56 17\"\nsrc=\"https://github.com/user-attachments/assets/6135823f-b644-48aa-b236-076bcc0692ff\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 49 51\"\nsrc=\"https://github.com/user-attachments/assets/afe492ad-c908-45ee-b831-2108553c15ce\"\n/> | <img width=\"477\" alt=\"Screenshot 2025-06-05 at 15 46 24\"\nsrc=\"https://github.com/user-attachments/assets/29eaccf5-0be8-46a6-9e87-3b6f99912e26\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 15 52 27\"\nsrc=\"https://github.com/user-attachments/assets/3867b435-a1e2-4cb3-9b4d-687a33f4ff78\"\n/> | <img width=\"482\" alt=\"Screenshot 2025-06-05 at 15 46 40\"\nsrc=\"https://github.com/user-attachments/assets/0e1521b3-6ed3-45e4-a913-44e4f99f027a\"\n/> | <img width=\"480\" alt=\"Screenshot 2025-06-05 at 15 45 50\"\nsrc=\"https://github.com/user-attachments/assets/0343fd8c-6d22-46bb-9676-f27cad4ca9ee\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 46 05\"\nsrc=\"https://github.com/user-attachments/assets/072e948d-71ce-48f0-862a-6932c5c510fa\"\n/> |\n\nExtra bits:\n* I did notice that when rendering in Icon mode only and the secondary\nraw value is `null` an empty badge was rendered. Now it should not.\n* When running Jest tests a warning about a missing `act` wrapping was\nshown, which was due to the `jest.advanceTimers` call. Now it is\nproperly wrapped\n* When testing with a time shift it is very likely to encounter into\nhttps://github.com//issues/221886 and have all badges set\nto `NA`. In such case close the inline editor and hit `Refresh` again to\nsee fresh values.\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios","sha":"af3b804ed331d7a5802fbc7e6ae78912ed603c06"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/222824","number":222824,"mergeCommit":{"message":"[Lens] Always show number sign when comparing to Primary metric (#222824)\n\n## Summary\n\nFixes #221882 \n\nThis is a possible take of the enhancement request in #221882.\nIn this scenario the chart automatically enters the `alwaysShowSign`\nmode when rendering the delta difference with the Primary Metric in the\nSecondary badge.\n\nSome notes:\n* The user has no control over it.\n* The behaviour is disabled automatically when moving into `Static\nvalue` mode, while it can be replicated using the `custom format` in the\n`Value format` control\n* The affected formats are `number`, `bytes`, `bits`, `percentage` in\nany possible configuration (i.e. also compact mode)\n* I've noticed that some formats change a bit when the sign is displayed\n(ie Currency goes from `$ xx.xxx` to `+ xx.xx # Backport This will backport the following commits from `main` to `8.19`: {{{{raw}}}} - [[Lens] Always show number sign when comparing to Primary metric (#222824)](https://github.com/elastic/kibana/pull/222824){{{{/raw}}}} <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT )\n\n**Compare to Primary Metric**\n| Default | Number | Number (compact) | Custom Format (i.e. Currency) |\nPercentage | Bytes | Bits |\n| ---- | ---- | ---- | ---- | ---- | ---- | ---- |\n| <img width=\"819\" alt=\"Screenshot 2025-06-05 at 14 41 09\"\nsrc=\"https://github.com/user-attachments/assets/3e836e07-a5eb-479a-96af-463069cabc35\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 40 37\"\nsrc=\"https://github.com/user-attachments/assets/097548c5-4c68-4041-89a7-a46af228fd7a\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 15 41 29\"\nsrc=\"https://github.com/user-attachments/assets/52943f01-c302-4631-8c2c-55fc60d91d99\"\n/> | <img width=\"480\" alt=\"Screenshot 2025-06-05 at 15 42 33\"\nsrc=\"https://github.com/user-attachments/assets/b2dbbaec-4c11-4e3f-80ac-20f810511bf7\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 14 48 18\"\nsrc=\"https://github.com/user-attachments/assets/13a1b102-30dd-46b4-b8f4-52ade1e9eadb\"\n/> | <img width=\"478\" alt=\"Screenshot 2025-06-05 at 15 44 11\"\nsrc=\"https://github.com/user-attachments/assets/e9acbb69-6535-4ee2-962a-f1e5446b93dd\"\n/> | <img width=\"477\" alt=\"Screenshot 2025-06-05 at 14 47 54\"\nsrc=\"https://github.com/user-attachments/assets/c6bb99af-5f08-4d0d-b302-e8fbe42a764b\"\n/> |\n\nWhen using Static value:\n\n| Default | Number | Number (compact) | Custom format (i.e. Currency) |\nPercentage | Bytes | Bits |\n| ---- | --- | ---- | ---- | ---- | ---- | ---- | \n| <img width=\"471\" alt=\"Screenshot 2025-06-05 at 14 56 17\"\nsrc=\"https://github.com/user-attachments/assets/6135823f-b644-48aa-b236-076bcc0692ff\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 49 51\"\nsrc=\"https://github.com/user-attachments/assets/afe492ad-c908-45ee-b831-2108553c15ce\"\n/> | <img width=\"477\" alt=\"Screenshot 2025-06-05 at 15 46 24\"\nsrc=\"https://github.com/user-attachments/assets/29eaccf5-0be8-46a6-9e87-3b6f99912e26\"\n/> | <img width=\"472\" alt=\"Screenshot 2025-06-05 at 15 52 27\"\nsrc=\"https://github.com/user-attachments/assets/3867b435-a1e2-4cb3-9b4d-687a33f4ff78\"\n/> | <img width=\"482\" alt=\"Screenshot 2025-06-05 at 15 46 40\"\nsrc=\"https://github.com/user-attachments/assets/0e1521b3-6ed3-45e4-a913-44e4f99f027a\"\n/> | <img width=\"480\" alt=\"Screenshot 2025-06-05 at 15 45 50\"\nsrc=\"https://github.com/user-attachments/assets/0343fd8c-6d22-46bb-9676-f27cad4ca9ee\"\n/> | <img width=\"473\" alt=\"Screenshot 2025-06-05 at 15 46 05\"\nsrc=\"https://github.com/user-attachments/assets/072e948d-71ce-48f0-862a-6932c5c510fa\"\n/> |\n\nExtra bits:\n* I did notice that when rendering in Icon mode only and the secondary\nraw value is `null` an empty badge was rendered. Now it should not.\n* When running Jest tests a warning about a missing `act` wrapping was\nshown, which was due to the `jest.advanceTimers` call. Now it is\nproperly wrapped\n* When testing with a time shift it is very likely to encounter into\nhttps://github.com//issues/221886 and have all badges set\nto `NA`. In such case close the inline editor and hit `Refresh` again to\nsee fresh values.\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios","sha":"af3b804ed331d7a5802fbc7e6ae78912ed603c06"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Marco Liberati <[email protected]>
1 parent 554ebbe commit 15c5b60

File tree

7 files changed

+93
-23
lines changed

7 files changed

+93
-23
lines changed

src/platform/plugins/shared/chart_expressions/expression_metric/public/components/helpers.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,16 @@ import { getColumnByAccessor, getFormatByAccessor } from '@kbn/visualizations-pl
1616
import { getFormatService, getPaletteService } from '../services';
1717
import { getDataBoundsForPalette } from '../utils';
1818

19-
function enhanceFieldFormat(serializedFieldFormat: SerializedFieldFormat | undefined) {
19+
export interface FormatOverrides {
20+
number?: { alwaysShowSign?: boolean };
21+
percent?: { alwaysShowSign?: boolean };
22+
bytes?: { alwaysShowSign?: boolean };
23+
}
24+
25+
function enhanceFieldFormat(
26+
serializedFieldFormat: SerializedFieldFormat | undefined,
27+
formatOverrides: FormatOverrides | undefined
28+
): SerializedFieldFormat {
2029
const formatId = serializedFieldFormat?.id || 'number';
2130
if (formatId === 'duration' && !serializedFieldFormat?.params?.formatOverride) {
2231
return {
@@ -31,17 +40,28 @@ function enhanceFieldFormat(serializedFieldFormat: SerializedFieldFormat | undef
3140
},
3241
};
3342
}
43+
if (formatOverrides && formatId in formatOverrides) {
44+
return {
45+
...serializedFieldFormat,
46+
params: {
47+
...serializedFieldFormat?.params,
48+
...formatOverrides[formatId as keyof FormatOverrides],
49+
},
50+
};
51+
}
52+
3453
return serializedFieldFormat ?? { id: formatId };
3554
}
3655

3756
export const getMetricFormatter = (
3857
accessor: ExpressionValueVisDimension | string,
39-
columns: Datatable['columns']
58+
columns: Datatable['columns'],
59+
formatOverrides?: FormatOverrides | undefined
4060
) => {
4161
const type = getColumnByAccessor(accessor, columns)?.meta.type;
4262
const defaultFormat = type ? { id: type } : undefined;
4363
const serializedFieldFormat = getFormatByAccessor(accessor, columns, defaultFormat);
44-
const enhancedFieldFormat = enhanceFieldFormat(serializedFieldFormat);
64+
const enhancedFieldFormat = enhanceFieldFormat(serializedFieldFormat, formatOverrides);
4565
return getFormatService().deserialize(enhancedFieldFormat).getConverterFor('text');
4666
};
4767

src/platform/plugins/shared/chart_expressions/expression_metric/public/components/metric_vis.test.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import React from 'react';
1111
import userEvent from '@testing-library/user-event';
12-
import { render, screen, waitFor } from '@testing-library/react';
12+
import { act, render, screen, waitFor } from '@testing-library/react';
1313
import { Datatable, DatatableColumn } from '@kbn/expressions-plugin/common';
1414
import { MetricVis, MetricVisComponentProps } from './metric_vis';
1515
import { MetricWTrend } from '@elastic/charts';
@@ -238,8 +238,12 @@ describe('MetricVisComponent', function () {
238238
});
239239

240240
async function waitForChartToRender(renderComplete: MetricVisComponentProps['renderComplete']) {
241-
// wait for 1 rAF tick (~16ms)
242-
jest.advanceTimersByTime(30);
241+
// Interestingly we have to wrap this into an act() call to avoid
242+
// issues with the React scheduling when testing
243+
await act(async () => {
244+
// wait for 1 rAF tick (~16ms)
245+
jest.advanceTimersByTime(30);
246+
});
243247
// wait for render complete callback
244248
await waitFor(() => expect(renderComplete).toHaveBeenCalled());
245249
}

src/platform/plugins/shared/chart_expressions/expression_metric/public/components/metric_vis.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,13 @@ export const MetricVis = ({
184184
title: String(title),
185185
subtitle,
186186
icon: config.metric?.icon ? getIcon(config.metric?.icon) : undefined,
187-
extra: ({ fontSize, color }) => (
187+
extra: ({ color }) => (
188188
<SecondaryMetric
189189
row={row}
190190
config={config}
191191
columns={data.columns}
192192
getMetricFormatter={getMetricFormatter}
193193
color={config.metric.secondaryColor}
194-
fontSize={fontSize}
195194
trendConfig={
196195
hasDynamicColoring && trendConfig
197196
? { ...trendConfig, borderColor: color }
@@ -212,14 +211,13 @@ export const MetricVis = ({
212211
title: String(title),
213212
subtitle,
214213
icon: config.metric?.icon ? getIcon(config.metric?.icon) : undefined,
215-
extra: ({ fontSize, color }) => (
214+
extra: ({ color }) => (
216215
<SecondaryMetric
217216
row={row}
218217
config={config}
219218
columns={data.columns}
220219
getMetricFormatter={getMetricFormatter}
221220
color={config.metric.secondaryColor}
222-
fontSize={fontSize}
223221
trendConfig={
224222
hasDynamicColoring && trendConfig ? { ...trendConfig, borderColor: color } : trendConfig
225223
}

src/platform/plugins/shared/chart_expressions/expression_metric/public/components/secondary_metric.test.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ function renderSecondaryMetric(props: Partial<SecondaryMetricProps> = {}) {
4343
metric: { secondaryPrefix: '' },
4444
}}
4545
getMetricFormatter={jest.fn(() => () => formattedValue)}
46-
fontSize={16}
4746
{...props}
4847
/>
4948
);
@@ -257,9 +256,10 @@ describe('Secondary metric', () => {
257256
it.each(trendCombinationCompareToPrimary)(
258257
'[Compare to primary] should render a badge with the trend icon "$icon" and the formatted value (rawValue: $valueFinite, baseline: $baselineFinite)',
259258
({ value, baseline, color, icon }) => {
259+
const getMetricFormatterMock = jest.fn(() => (v: unknown) => String(v));
260260
renderSecondaryMetric({
261261
row: { [id]: value },
262-
getMetricFormatter: jest.fn(() => (v: unknown) => String(v)),
262+
getMetricFormatter: getMetricFormatterMock,
263263
trendConfig: {
264264
icon: showIcon,
265265
value: showValue,
@@ -280,6 +280,13 @@ describe('Secondary metric', () => {
280280
const el = screen.getByTitle(badgeText);
281281
expect(el).toBeInTheDocument();
282282
expect(el).toHaveStyle(`--euiBadgeBackgroundColor: ${color}`);
283+
expect(getMetricFormatterMock).toHaveBeenCalledWith(
284+
expect.any(String),
285+
expect.any(Object),
286+
expect.objectContaining({
287+
number: expect.objectContaining({ alwaysShowSign: true }),
288+
})
289+
);
283290
}
284291
if (showValue) {
285292
expect(

src/platform/plugins/shared/chart_expressions/expression_metric/public/components/secondary_metric.tsx

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type { DatatableColumn, DatatableRow } from '@kbn/expressions-plugin/comm
1515
import { type FieldFormatConvertFunction } from '@kbn/field-formats-plugin/common';
1616
import { type VisParams } from '@kbn/visualizations-plugin/common';
1717
import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils';
18+
import { FormatOverrides } from './helpers';
1819

1920
export interface TrendConfig {
2021
icon: boolean;
@@ -119,14 +120,12 @@ function SecondaryMetricValue({
119120
formattedValue,
120121
trendConfig,
121122
color,
122-
fontSize,
123123
formatter,
124124
}: {
125125
rawValue?: number | string;
126126
formattedValue?: string;
127127
trendConfig?: TrendConfig;
128128
color?: string;
129-
fontSize: number;
130129
formatter?: FieldFormatConvertFunction;
131130
}) {
132131
const safeFormattedValue = formattedValue ?? notAvailable;
@@ -152,6 +151,15 @@ function SecondaryMetricValue({
152151
formatter,
153152
trendConfig.compareToPrimary
154153
);
154+
// If no value is shown and no icon should be shown (i.e. N/A) then do not render the badge at all
155+
if (trendConfig.icon && !trendConfig.value && !icon) {
156+
return (
157+
<span
158+
data-test-subj={`expressionMetricVis-secondaryMetric-badge-${rawValue}`}
159+
aria-label={getTrendDescription(trendConfig.value, icon != null, valueToShow, iconLabel)}
160+
/>
161+
);
162+
}
155163
return (
156164
<EuiBadge
157165
aria-label={
@@ -189,21 +197,43 @@ export interface SecondaryMetricProps {
189197
config: Pick<VisParams, 'metric' | 'dimensions'>;
190198
trendConfig?: TrendConfig;
191199
color?: string;
192-
fontSize: number;
193-
getMetricFormatter: (accessor: string, columns: DatatableColumn[]) => FieldFormatConvertFunction;
200+
getMetricFormatter: (
201+
accessor: string,
202+
columns: DatatableColumn[],
203+
formatOverrides?: FormatOverrides | undefined
204+
) => FieldFormatConvertFunction;
194205
}
195206

196207
function getMetricColumnAndFormatter(
197208
columns: SecondaryMetricProps['columns'],
198209
config: SecondaryMetricProps['config'],
199-
getMetricFormatter: SecondaryMetricProps['getMetricFormatter']
210+
getMetricFormatter: SecondaryMetricProps['getMetricFormatter'],
211+
formatOverrides: FormatOverrides | undefined
200212
) {
201213
if (!config.dimensions.secondaryMetric) {
202214
return;
203215
}
204216
return {
205217
metricColumn: getColumnByAccessor(config.dimensions.secondaryMetric, columns),
206-
metricFormatter: getMetricFormatter(config.dimensions.secondaryMetric, columns),
218+
metricFormatter: getMetricFormatter(
219+
config.dimensions.secondaryMetric,
220+
columns,
221+
formatOverrides
222+
),
223+
};
224+
}
225+
226+
function getEnhancedNumberSignFormatter(
227+
trendConfig: TrendConfig | undefined
228+
): FormatOverrides | undefined {
229+
if (!trendConfig?.compareToPrimary) {
230+
return;
231+
}
232+
const paramsOverride = { alwaysShowSign: true };
233+
return {
234+
number: paramsOverride,
235+
percent: paramsOverride,
236+
bytes: paramsOverride,
207237
};
208238
}
209239

@@ -214,10 +244,14 @@ export function SecondaryMetric({
214244
getMetricFormatter,
215245
trendConfig,
216246
color,
217-
fontSize,
218247
}: SecondaryMetricProps) {
219248
const { metricFormatter, metricColumn } =
220-
getMetricColumnAndFormatter(columns, config, getMetricFormatter) || {};
249+
getMetricColumnAndFormatter(
250+
columns,
251+
config,
252+
getMetricFormatter,
253+
getEnhancedNumberSignFormatter(trendConfig)
254+
) || {};
221255
const prefix = config.metric.secondaryPrefix ?? metricColumn?.name;
222256
const value = metricColumn ? row[metricColumn.id] : undefined;
223257

@@ -230,7 +264,6 @@ export function SecondaryMetric({
230264
formattedValue={metricFormatter?.(value)}
231265
trendConfig={color ? undefined : trendConfig}
232266
color={color}
233-
fontSize={fontSize}
234267
formatter={metricFormatter}
235268
/>
236269
</span>

src/platform/plugins/shared/field_formats/common/converters/numeral.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export abstract class NumeralFormat extends FieldFormat {
3030
abstract title: string;
3131

3232
getParamDefaults = () => ({
33-
pattern: this.getConfig!(`format:${this.id}:defaultPattern`),
33+
// While this should be always defined, it is not guaranteed in testing that the function is available
34+
pattern: this.getConfig?.(`format:${this.id}:defaultPattern`),
35+
alwaysShowSign: false,
3436
});
3537

3638
protected getConvertedValue(val: number | string | object): string {
@@ -50,7 +52,12 @@ export abstract class NumeralFormat extends FieldFormat {
5052
(this.getConfig && this.getConfig(FORMATS_UI_SETTINGS.FORMAT_NUMBER_DEFAULT_LOCALE)) || 'en';
5153
numeral.language(defaultLocale);
5254

53-
const formatted = numeralInst.set(val).format(this.param('pattern'));
55+
let pattern: string = this.param('pattern');
56+
if (pattern && this.param('alwaysShowSign')) {
57+
pattern = pattern.startsWith('+') || val === 0 ? pattern : `+ ${pattern}`;
58+
}
59+
60+
const formatted = numeralInst.set(val).format(pattern);
5461

5562
numeral.language(previousLocale);
5663

src/platform/plugins/shared/field_formats/common/converters/percent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class PercentFormat extends NumeralFormat {
2626
getParamDefaults = () => ({
2727
pattern: this.getConfig!(FORMATS_UI_SETTINGS.FORMAT_PERCENT_DEFAULT_PATTERN),
2828
fractional: true,
29+
alwaysShowSign: false,
2930
});
3031

3132
textConvert: TextContextTypeConvert = (val: string | number) => {

0 commit comments

Comments
 (0)