diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx
index 310c01291aea4..0b4dcea5d12e0 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx
@@ -22,6 +22,24 @@ const ClFlexGroup = styled(EuiFlexGroup)`
}
`;
+function formatTitle(unit: string, value?: number) {
+ if (typeof value === 'undefined') return I18LABELS.dataMissing;
+ return formatToSec(value, unit);
+}
+
+function PageViewsTotalTitle({ pageViews }: { pageViews?: number }) {
+ if (typeof pageViews === 'undefined') {
+ return <>{I18LABELS.dataMissing}>;
+ }
+ return pageViews < 10000 ? (
+ <>{numeral(pageViews).format('0,0')}>
+ ) : (
+
+ <>{numeral(pageViews).format('0 a')}>
+
+ );
+}
+
export function ClientMetrics() {
const uxQuery = useUxQuery();
@@ -50,14 +68,12 @@ export function ClientMetrics() {
const STAT_STYLE = { width: '240px' };
- const pageViewsTotal = data?.pageViews?.value ?? 0;
-
return (
@@ -65,7 +81,7 @@ export function ClientMetrics() {
@@ -73,15 +89,7 @@ export function ClientMetrics() {
- <>{numeral(pageViewsTotal).format('0 a')}>
-
- )
- }
+ title={}
description={I18LABELS.pageViews}
isLoading={status !== 'success'}
/>
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx
index f30a3ea5fb2dd..793c9619edb3d 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/KeyUXMetrics.tsx
@@ -8,6 +8,7 @@ import React from 'react';
import { EuiFlexItem, EuiStat, EuiFlexGroup } from '@elastic/eui';
import numeral from '@elastic/numeral';
import {
+ DATA_UNDEFINED_LABEL,
FCP_LABEL,
LONGEST_LONG_TASK,
NO_OF_LONG_TASK,
@@ -36,6 +37,11 @@ interface Props {
loading: boolean;
}
+function formatTitle(unit: string, value?: number) {
+ if (typeof value === 'undefined') return DATA_UNDEFINED_LABEL;
+ return formatToSec(value, unit);
+}
+
export function KeyUXMetrics({ data, loading }: Props) {
const uxQuery = useUxQuery();
@@ -62,7 +68,7 @@ export function KeyUXMetrics({ data, loading }: Props) {
@@ -70,7 +76,7 @@ export function KeyUXMetrics({ data, loading }: Props) {
@@ -78,7 +84,11 @@ export function KeyUXMetrics({ data, loading }: Props) {
@@ -86,7 +96,7 @@ export function KeyUXMetrics({ data, loading }: Props) {
@@ -94,7 +104,7 @@ export function KeyUXMetrics({ data, loading }: Props) {
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts
index e6d8f881bee57..8f3a71f669ecf 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/translations.ts
@@ -6,6 +6,13 @@
import { i18n } from '@kbn/i18n';
+export const DATA_UNDEFINED_LABEL = i18n.translate(
+ 'xpack.apm.rum.coreVitals.dataUndefined',
+ {
+ defaultMessage: 'N/A',
+ }
+);
+
export const FCP_LABEL = i18n.translate('xpack.apm.rum.coreVitals.fcp', {
defaultMessage: 'First contentful paint',
});
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts
index c8db011874a89..a8c4d67305c98 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts
@@ -7,6 +7,9 @@
import { i18n } from '@kbn/i18n';
export const I18LABELS = {
+ dataMissing: i18n.translate('xpack.apm.rum.dashboard.dataMissing', {
+ defaultMessage: 'N/A',
+ }),
backEnd: i18n.translate('xpack.apm.rum.dashboard.backend', {
defaultMessage: 'Backend',
}),
diff --git a/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx b/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx
index cb23e4782a2d5..ef1820eaaeb3e 100644
--- a/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx
+++ b/x-pack/plugins/observability/public/components/app/section/ux/index.test.tsx
@@ -76,4 +76,27 @@ describe('UXSection', () => {
expect(queryAllByText('View in app')).toEqual([]);
expect(getByText('elastic-co-frontend')).toBeInTheDocument();
});
+ it('shows empty state', () => {
+ jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({
+ data: undefined,
+ status: fetcherHook.FETCH_STATUS.SUCCESS,
+ refetch: jest.fn(),
+ });
+ const { getByText, queryAllByText, getAllByText } = render(
+
+ );
+
+ expect(getByText('User Experience')).toBeInTheDocument();
+ expect(getAllByText('No data is available.')).toHaveLength(3);
+ expect(queryAllByText('View in app')).toEqual([]);
+ expect(getByText('elastic-co-frontend')).toBeInTheDocument();
+ });
});
diff --git a/x-pack/plugins/observability/public/components/shared/core_web_vitals/core_vital_item.tsx b/x-pack/plugins/observability/public/components/shared/core_web_vitals/core_vital_item.tsx
index e5b8d2c243617..0d0a388855ff2 100644
--- a/x-pack/plugins/observability/public/components/shared/core_web_vitals/core_vital_item.tsx
+++ b/x-pack/plugins/observability/public/components/shared/core_web_vitals/core_vital_item.tsx
@@ -4,7 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiFlexGroup, EuiIconTip, euiPaletteForStatus, EuiSpacer, EuiStat } from '@elastic/eui';
+import {
+ EuiCard,
+ EuiFlexGroup,
+ EuiIconTip,
+ euiPaletteForStatus,
+ EuiSpacer,
+ EuiStat,
+} from '@elastic/eui';
import React, { useState } from 'react';
import { i18n } from '@kbn/i18n';
import { PaletteLegends } from './palette_legends';
@@ -14,6 +21,7 @@ import {
CV_GOOD_LABEL,
LESS_LABEL,
MORE_LABEL,
+ NO_DATA,
CV_POOR_LABEL,
IS_LABEL,
TAKES_LABEL,
@@ -26,7 +34,7 @@ export interface Thresholds {
interface Props {
title: string;
- value: string;
+ value?: string;
ranks?: number[];
loading: boolean;
thresholds: Thresholds;
@@ -80,6 +88,9 @@ export function CoreVitalItem({
const biggestValIndex = ranks.indexOf(Math.max(...ranks));
+ if (value === undefined && ranks[0] === 100 && !loading) {
+ return ;
+ }
return (
<>