[CSM] Fix core vital legend background (#78273)
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
406c47af46
commit
fdee5e59a7
|
@ -15,11 +15,11 @@ import { i18n } from '@kbn/i18n';
|
|||
import { PaletteLegends } from './PaletteLegends';
|
||||
import { ColorPaletteFlexItem } from './ColorPaletteFlexItem';
|
||||
import {
|
||||
AVERAGE_LABEL,
|
||||
GOOD_LABEL,
|
||||
CV_AVERAGE_LABEL,
|
||||
CV_GOOD_LABEL,
|
||||
LESS_LABEL,
|
||||
MORE_LABEL,
|
||||
POOR_LABEL,
|
||||
CV_POOR_LABEL,
|
||||
} from './translations';
|
||||
|
||||
export interface Thresholds {
|
||||
|
@ -51,7 +51,7 @@ export function getCoreVitalTooltipMessage(
|
|||
values: {
|
||||
percentage,
|
||||
title: title?.toLowerCase(),
|
||||
exp: good ? GOOD_LABEL : bad ? POOR_LABEL : AVERAGE_LABEL,
|
||||
exp: good ? CV_GOOD_LABEL : bad ? CV_POOR_LABEL : CV_AVERAGE_LABEL,
|
||||
moreOrLess: bad || average ? MORE_LABEL : LESS_LABEL,
|
||||
value: good || average ? thresholds.good : thresholds.bad,
|
||||
averageMessage: average
|
||||
|
@ -90,7 +90,7 @@ export function CoreVitalItem({
|
|||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
alignItems="flexStart"
|
||||
style={{ maxWidth: 340 }}
|
||||
style={{ maxWidth: 350 }}
|
||||
responsive={false}
|
||||
>
|
||||
{palette.map((hexCode, ind) => (
|
||||
|
|
|
@ -10,16 +10,36 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiHealth,
|
||||
euiPaletteForStatus,
|
||||
EuiText,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
|
||||
import { getCoreVitalTooltipMessage, Thresholds } from './CoreVitalItem';
|
||||
import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||
import {
|
||||
LEGEND_NEEDS_IMPROVEMENT_LABEL,
|
||||
LEGEND_GOOD_LABEL,
|
||||
LEGEND_POOR_LABEL,
|
||||
} from './translations';
|
||||
|
||||
const PaletteLegend = styled(EuiHealth)`
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
background-color: #e7f0f7;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSpan = styled.span<{
|
||||
darkMode: boolean;
|
||||
}>`
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.darkMode
|
||||
? euiDarkVars.euiColorLightestShade
|
||||
: euiLightVars.euiColorLightestShade};
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -36,10 +56,17 @@ export function PaletteLegends({
|
|||
onItemHover,
|
||||
thresholds,
|
||||
}: Props) {
|
||||
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
||||
|
||||
const palette = euiPaletteForStatus(3);
|
||||
const labels = [
|
||||
LEGEND_GOOD_LABEL,
|
||||
LEGEND_NEEDS_IMPROVEMENT_LABEL,
|
||||
LEGEND_POOR_LABEL,
|
||||
];
|
||||
|
||||
return (
|
||||
<EuiFlexGroup responsive={false}>
|
||||
<EuiFlexGroup responsive={false} gutterSize="s">
|
||||
{palette.map((color, ind) => (
|
||||
<EuiFlexItem
|
||||
key={ind}
|
||||
|
@ -60,7 +87,21 @@ export function PaletteLegends({
|
|||
)}
|
||||
position="bottom"
|
||||
>
|
||||
<PaletteLegend color={color}>{ranks?.[ind]}%</PaletteLegend>
|
||||
<StyledSpan darkMode={darkMode}>
|
||||
<PaletteLegend color={color}>
|
||||
<EuiText size="xs">
|
||||
{labels[ind]} ({ranks?.[ind]}%)
|
||||
<FormattedMessage
|
||||
id="xpack.apm.rum.coreVitals.paletteLegend.rankPercentage"
|
||||
defaultMessage="{labelsInd} ({ranksInd}%)"
|
||||
values={{
|
||||
labelsInd: labels[ind],
|
||||
ranksInd: ranks?.[ind],
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</PaletteLegend>
|
||||
</StyledSpan>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
|||
import { CLS_LABEL, FID_LABEL, LCP_LABEL } from './translations';
|
||||
import { CoreVitalItem } from './CoreVitalItem';
|
||||
import { UXMetrics } from '../UXMetrics';
|
||||
import { formatToSec } from '../UXMetrics/KeyUXMetrics';
|
||||
|
||||
const CoreVitalsThresholds = {
|
||||
LCP: { good: '2.5s', bad: '4.0s' },
|
||||
|
@ -28,7 +29,7 @@ export function CoreVitals({ data, loading }: Props) {
|
|||
<EuiFlexItem>
|
||||
<CoreVitalItem
|
||||
title={LCP_LABEL}
|
||||
value={lcp ? lcp + ' s' : '0'}
|
||||
value={formatToSec(lcp, 'ms')}
|
||||
ranks={lcpRanks}
|
||||
loading={loading}
|
||||
thresholds={CoreVitalsThresholds.LCP}
|
||||
|
@ -37,7 +38,7 @@ export function CoreVitals({ data, loading }: Props) {
|
|||
<EuiFlexItem>
|
||||
<CoreVitalItem
|
||||
title={FID_LABEL}
|
||||
value={fid ? fid + ' s' : '0'}
|
||||
value={formatToSec(fid, 'ms')}
|
||||
ranks={fidRanks}
|
||||
loading={loading}
|
||||
thresholds={CoreVitalsThresholds.FID}
|
||||
|
|
|
@ -47,21 +47,42 @@ export const SUM_LONG_TASKS = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const POOR_LABEL = i18n.translate('xpack.apm.rum.coreVitals.poor', {
|
||||
export const CV_POOR_LABEL = i18n.translate('xpack.apm.rum.coreVitals.poor', {
|
||||
defaultMessage: 'a poor',
|
||||
});
|
||||
|
||||
export const GOOD_LABEL = i18n.translate('xpack.apm.rum.coreVitals.good', {
|
||||
export const CV_GOOD_LABEL = i18n.translate('xpack.apm.rum.coreVitals.good', {
|
||||
defaultMessage: 'a good',
|
||||
});
|
||||
|
||||
export const AVERAGE_LABEL = i18n.translate(
|
||||
export const CV_AVERAGE_LABEL = i18n.translate(
|
||||
'xpack.apm.rum.coreVitals.average',
|
||||
{
|
||||
defaultMessage: 'an average',
|
||||
}
|
||||
);
|
||||
|
||||
export const LEGEND_POOR_LABEL = i18n.translate(
|
||||
'xpack.apm.rum.coreVitals.legends.poor',
|
||||
{
|
||||
defaultMessage: 'Poor',
|
||||
}
|
||||
);
|
||||
|
||||
export const LEGEND_GOOD_LABEL = i18n.translate(
|
||||
'xpack.apm.rum.coreVitals.legends.good',
|
||||
{
|
||||
defaultMessage: 'Good',
|
||||
}
|
||||
);
|
||||
|
||||
export const LEGEND_NEEDS_IMPROVEMENT_LABEL = i18n.translate(
|
||||
'xpack.apm.rum.coreVitals.legends.needsImprovement',
|
||||
{
|
||||
defaultMessage: 'Needs improvement',
|
||||
}
|
||||
);
|
||||
|
||||
export const MORE_LABEL = i18n.translate('xpack.apm.rum.coreVitals.more', {
|
||||
defaultMessage: 'more',
|
||||
});
|
||||
|
|
|
@ -4,15 +4,20 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
EuiLink,
|
||||
EuiPanel,
|
||||
EuiPopover,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { I18LABELS } from '../translations';
|
||||
import { CoreVitals } from '../CoreVitals';
|
||||
import { KeyUXMetrics } from './KeyUXMetrics';
|
||||
|
@ -21,8 +26,8 @@ import { useFetcher } from '../../../../hooks/useFetcher';
|
|||
|
||||
export interface UXMetrics {
|
||||
cls: string;
|
||||
fid: string;
|
||||
lcp: string;
|
||||
fid: number;
|
||||
lcp: number;
|
||||
tbt: number;
|
||||
fcp: number;
|
||||
lcpRanks: number[];
|
||||
|
@ -56,6 +61,10 @@ export function UXMetrics() {
|
|||
[start, end, uiFilters, searchTerm]
|
||||
);
|
||||
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
|
||||
const closePopover = () => setIsPopoverOpen(false);
|
||||
|
||||
return (
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
|
@ -72,7 +81,37 @@ export function UXMetrics() {
|
|||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={1} data-cy={`client-metrics`}>
|
||||
<EuiTitle size="xs">
|
||||
<h3>{I18LABELS.coreWebVitals}</h3>
|
||||
<h3>
|
||||
{I18LABELS.coreWebVitals}
|
||||
<EuiPopover
|
||||
isOpen={isPopoverOpen}
|
||||
button={
|
||||
<EuiButtonIcon
|
||||
onClick={() => setIsPopoverOpen(true)}
|
||||
color={'text'}
|
||||
iconType={'questionInCircle'}
|
||||
/>
|
||||
}
|
||||
closePopover={closePopover}
|
||||
>
|
||||
<div style={{ width: '300px' }}>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.apm.ux.dashboard.webCoreVitals.help"
|
||||
defaultMessage="Learn more about"
|
||||
/>
|
||||
<EuiLink
|
||||
href="https://web.dev/vitals/"
|
||||
external
|
||||
target="_blank"
|
||||
>
|
||||
{' '}
|
||||
{I18LABELS.coreWebVitals}
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
</div>
|
||||
</EuiPopover>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<CoreVitals data={data} loading={status !== 'success'} />
|
||||
|
|
|
@ -81,6 +81,7 @@ export async function getLongTaskMetrics({
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
noOfLongTasks,
|
||||
sumOfLongTasks,
|
||||
|
|
|
@ -124,13 +124,12 @@ export async function getWebCoreVitals({
|
|||
{ value: 0, key: 0 },
|
||||
];
|
||||
|
||||
// Divide by 1000 to convert ms into seconds
|
||||
return {
|
||||
cls: String(cls?.values['50.0']?.toFixed(2) || 0),
|
||||
fid: ((fid?.values['50.0'] || 0) / 1000).toFixed(2),
|
||||
lcp: ((lcp?.values['50.0'] || 0) / 1000).toFixed(2),
|
||||
tbt: tbt?.values['50.0'] || 0,
|
||||
fcp: fcp?.values['50.0'] || 0,
|
||||
fid: fid?.values['50.0'] ?? 0,
|
||||
lcp: lcp?.values['50.0'] ?? 0,
|
||||
tbt: tbt?.values['50.0'] ?? 0,
|
||||
fcp: fcp?.values['50.0'] ?? 0,
|
||||
|
||||
lcpRanks: getRanksPercentages(lcpRanks?.values ?? defaultRanks),
|
||||
fidRanks: getRanksPercentages(fidRanks?.values ?? defaultRanks),
|
||||
|
|
|
@ -59,13 +59,13 @@ export default function rumServicesApiTests({ getService }: FtrProviderContext)
|
|||
0,
|
||||
],
|
||||
"fcp": 1072,
|
||||
"fid": "1.35",
|
||||
"fid": 1352.13,
|
||||
"fidRanks": Array [
|
||||
0,
|
||||
0,
|
||||
100,
|
||||
],
|
||||
"lcp": "1.27",
|
||||
"lcp": 1270.5,
|
||||
"lcpRanks": Array [
|
||||
100,
|
||||
0,
|
||||
|
|
Loading…
Reference in a new issue