Skip to content

Commit 3a8b60b

Browse files
c298leemifu67
authored andcommitted
fix(replay): CLS score is not in ms (#77397)
If the web vital is CLS, don't include `ms`. CLS is the only web vital in replays that isn't measured in milliseconds. Relates to #69881
1 parent ed1fc16 commit 3a8b60b

File tree

4 files changed

+19
-13
lines changed

4 files changed

+19
-13
lines changed

static/app/components/replays/breadcrumbs/breadcrumbItem.tsx

+2-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import type {
3434
} from 'sentry/utils/replays/types';
3535
import {
3636
isBreadcrumbFrame,
37+
isCLSFrame,
3738
isErrorFrame,
3839
isFeedbackFrame,
3940
isHydrationErrorFrame,
@@ -237,11 +238,7 @@ function WebVitalData({
237238
const selectors = frameToExtraction?.get(frame)?.selectors;
238239

239240
const webVitalData = {value: frame.data.value};
240-
if (
241-
frame.description === 'cumulative-layout-shift' &&
242-
frame.data.attributions &&
243-
selectors
244-
) {
241+
if (isCLSFrame(frame) && frame.data.attributions && selectors) {
245242
const layoutShifts: {[x: string]: ReactNode[]}[] = [];
246243
for (const attr of frame.data.attributions) {
247244
const elements: ReactNode[] = [];

static/app/utils/replays/getFrameDetails.tsx

+7-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import type {
4444
} from 'sentry/utils/replays/types';
4545
import {
4646
getFrameOpOrCategory,
47+
isCLSFrame,
4748
isDeadClick,
4849
isDeadRageClick,
4950
isRageClick,
@@ -286,8 +287,9 @@ const MAPPER_FOR_FRAME: Record<string, (frame) => Details> = {
286287
case 'good':
287288
return {
288289
color: 'green300',
289-
description: tct('[value]ms (Good)', {
290+
description: tct('[value][unit] (Good)', {
290291
value: frame.data.value.toFixed(2),
292+
unit: isCLSFrame(frame) ? '' : 'ms',
291293
}),
292294
tabKey: TabKey.NETWORK,
293295
title: 'Web Vital: ' + toTitleCase(explodeSlug(frame.description)),
@@ -296,8 +298,9 @@ const MAPPER_FOR_FRAME: Record<string, (frame) => Details> = {
296298
case 'needs-improvement':
297299
return {
298300
color: 'yellow300',
299-
description: tct('[value]ms (Meh)', {
301+
description: tct('[value][unit] (Meh)', {
300302
value: frame.data.value.toFixed(2),
303+
unit: isCLSFrame(frame) ? '' : 'ms',
301304
}),
302305
tabKey: TabKey.NETWORK,
303306
title: 'Web Vital: ' + toTitleCase(explodeSlug(frame.description)),
@@ -306,8 +309,9 @@ const MAPPER_FOR_FRAME: Record<string, (frame) => Details> = {
306309
default:
307310
return {
308311
color: 'red300',
309-
description: tct('[value]ms (Poor)', {
312+
description: tct('[value][unit] (Poor)', {
310313
value: frame.data.value.toFixed(2),
314+
unit: isCLSFrame(frame) ? '' : 'ms',
311315
}),
312316
tabKey: TabKey.NETWORK,
313317
title: 'Web Vital: ' + toTitleCase(explodeSlug(frame.description)),

static/app/utils/replays/replayReader.tsx

+6-5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
EventType,
4242
getNodeIds,
4343
IncrementalSource,
44+
isCLSFrame,
4445
isDeadClick,
4546
isDeadRageClick,
4647
isPaintFrame,
@@ -637,12 +638,12 @@ export default class ReplayReader {
637638
let lastTimestamp = 0;
638639
const groupedCls: WebVitalFrame[] = [];
639640

640-
for (const cls of allWebVitals) {
641-
if (cls.description === 'cumulative-layout-shift') {
642-
if (lastTimestamp === cls.timestampMs) {
643-
groupedCls.push(cls);
641+
for (const frame of allWebVitals) {
642+
if (isCLSFrame(frame)) {
643+
if (lastTimestamp === frame.timestampMs) {
644+
groupedCls.push(frame);
644645
} else {
645-
lastTimestamp = cls.timestampMs;
646+
lastTimestamp = frame.timestampMs;
646647
}
647648
}
648649
}

static/app/utils/replays/types.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ export function isWebVitalFrame(frame: SpanFrame): frame is WebVitalFrame {
202202
return frame.op === 'web-vital';
203203
}
204204

205+
export function isCLSFrame(frame: WebVitalFrame): frame is WebVitalFrame {
206+
return frame.description === 'cumulative-layout-shift';
207+
}
208+
205209
export function isPaintFrame(frame: SpanFrame): frame is PaintFrame {
206210
return frame.op === 'paint';
207211
}

0 commit comments

Comments
 (0)