Skip to content

Commit 7aea79c

Browse files
authored
ref(replay): Convert Errors Tab to use *Frame types (#51559)
Relates to #47991
1 parent 65c1ea2 commit 7aea79c

File tree

14 files changed

+213
-240
lines changed

14 files changed

+213
-240
lines changed

fixtures/js-stubs/replay/error.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ export function RawReplayError(
66
error: Overwrite<Partial<TRawReplayError>, {timestamp: Date}>
77
): TRawReplayError {
88
return {
9-
'error.type': [] as string[],
9+
'error.type': error['error.type'] ?? ([] as string[]),
1010
id: error.id ?? 'e123',
1111
issue: error.issue ?? 'JS-374',
12-
'issue.id': 3740335939,
13-
'project.name': 'javascript',
12+
'issue.id': error['issue.id'] ?? 3740335939,
13+
'project.name': error['project.name'] ?? 'javascript',
1414
timestamp: error.timestamp.toISOString(),
15-
title: 'A Redirect with :orgId param on customer domain',
15+
title: error.title ?? 'A Redirect with :orgId param on customer domain',
1616
};
1717
}

fixtures/js-stubs/replayError.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function ReplayError(
1010
issue: error.issue,
1111
'issue.id': error['issue.id'] ?? 3740335939,
1212
'project.name': error['project.name'] ?? 'javascript',
13-
timestamp: error.id,
13+
timestamp: error.timestamp,
1414
title: error.title ?? 'A Redirect with :orgId param on customer domain',
1515
};
1616
}

static/app/components/replays/virtualizedGrid/headerCell.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {Tooltip} from 'sentry/components/tooltip';
55
import {IconArrow, IconInfo} from 'sentry/icons';
66
import {space} from 'sentry/styles/space';
77
import type {Crumb} from 'sentry/types/breadcrumbs';
8+
import type {BreadcrumbFrame, SpanFrame} from 'sentry/utils/replays/types';
89
import type {NetworkSpan} from 'sentry/views/replays/types';
910

1011
interface SortCrumbs {
@@ -18,11 +19,22 @@ interface SortSpans {
1819
getValue: (row: NetworkSpan) => any;
1920
}
2021

22+
interface SortBreadcrumbFrame {
23+
asc: boolean;
24+
by: keyof BreadcrumbFrame | string;
25+
getValue: (row: BreadcrumbFrame) => any;
26+
}
27+
interface SortSpanFrame {
28+
asc: boolean;
29+
by: keyof SpanFrame | string;
30+
getValue: (row: SpanFrame) => any;
31+
}
32+
2133
type Props = {
2234
field: string;
2335
handleSort: (fieldName: string) => void;
2436
label: string;
25-
sortConfig: SortCrumbs | SortSpans;
37+
sortConfig: SortCrumbs | SortSpans | SortBreadcrumbFrame | SortSpanFrame;
2638
style: CSSProperties;
2739
tooltipTitle: undefined | ReactNode;
2840
};

static/app/utils/replays/hydrateErrors.spec.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe('hydrateErrors', () => {
2020
groupId: 3740335939,
2121
groupShortId: 'JS-374',
2222
label: '',
23+
labels: [],
2324
projectSlug: 'javascript',
2425
},
2526
message: 'A Redirect with :orgId param on customer domain',
@@ -35,6 +36,7 @@ describe('hydrateErrors', () => {
3536
groupId: 3740335939,
3637
groupShortId: 'JS-374',
3738
label: '',
39+
labels: [],
3840
projectSlug: 'javascript',
3941
},
4042
message: 'A Redirect with :orgId param on customer domain',
@@ -50,6 +52,7 @@ describe('hydrateErrors', () => {
5052
groupId: 3740335939,
5153
groupShortId: 'JS-374',
5254
label: '',
55+
labels: [],
5356
projectSlug: 'javascript',
5457
},
5558
message: 'A Redirect with :orgId param on customer domain',

static/app/utils/replays/hydrateErrors.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default function hydrateErrors(
3030
(Array.isArray(error['error.type'])
3131
? error['error.type'][0]
3232
: error['error.type']) ?? '',
33+
labels: error['error.type'],
3334
projectSlug: error['project.name'],
3435
},
3536
message: error.title,

static/app/utils/replays/types.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,12 @@ export type ErrorFrame = Overwrite<
187187
{
188188
category: 'issue';
189189
data: {
190-
eventId: string; // error['id']
191-
groupId: number; // error['issue.id']
192-
groupShortId: string; // error['issue']
193-
label: string; // error['error.type'].join('')
194-
projectSlug: string; // error['project.name']
190+
eventId: string;
191+
groupId: number;
192+
groupShortId: string;
193+
label: string;
194+
labels: string[];
195+
projectSlug: string;
195196
};
196197
message: string;
197198
}

static/app/views/replays/detail/errorList/errorFilters.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import {CompactSelect, SelectOption} from 'sentry/components/compactSelect';
22
import SearchBar from 'sentry/components/searchBar';
33
import {t} from 'sentry/locale';
4-
import type {Crumb} from 'sentry/types/breadcrumbs';
4+
import type {ErrorFrame} from 'sentry/utils/replays/types';
55
import useErrorFilters from 'sentry/views/replays/detail/errorList/useErrorFilters';
66
import FiltersGrid from 'sentry/views/replays/detail/filtersGrid';
77

88
type Props = {
9-
errorCrumbs: undefined | Crumb[];
9+
errorFrames: undefined | ErrorFrame[];
1010
} & ReturnType<typeof useErrorFilters>;
1111

1212
function ErrorFilters({
1313
getProjectOptions,
14-
errorCrumbs,
14+
errorFrames,
1515
searchTerm,
1616
selectValue,
1717
setFilters,
@@ -36,7 +36,7 @@ function ErrorFilters({
3636
onChange={setSearchTerm}
3737
placeholder={t('Search Errors')}
3838
query={searchTerm}
39-
disabled={!errorCrumbs || !errorCrumbs.length}
39+
disabled={!errorFrames || !errorFrames.length}
4040
/>
4141
</FiltersGrid>
4242
);

static/app/views/replays/detail/errorList/errorTableCell.tsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import classNames from 'classnames';
44

55
import Avatar from 'sentry/components/avatar';
66
import Link from 'sentry/components/links/link';
7-
import {relativeTimeInMs} from 'sentry/components/replays/utils';
87
import {
98
AvatarWrapper,
109
Cell,
1110
StyledTimestampButton,
1211
Text,
1312
} from 'sentry/components/replays/virtualizedGrid/bodyCell';
14-
import type {Crumb} from 'sentry/types/breadcrumbs';
1513
import {getShortEventId} from 'sentry/utils/events';
14+
import type {ErrorFrame} from 'sentry/utils/replays/types';
1615
import useOrganization from 'sentry/utils/useOrganization';
1716
import useProjects from 'sentry/utils/useProjects';
1817
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
@@ -24,12 +23,12 @@ const EMPTY_CELL = '--';
2423

2524
type Props = {
2625
columnIndex: number;
27-
crumb: Crumb;
2826
currentHoverTime: number | undefined;
2927
currentTime: number;
30-
onClickTimestamp: (crumb: Crumb) => void;
31-
onMouseEnter: (crumb: Crumb) => void;
32-
onMouseLeave: (crumb: Crumb) => void;
28+
frame: ErrorFrame;
29+
onClickTimestamp: (frame: ErrorFrame) => void;
30+
onMouseEnter: (frame: ErrorFrame) => void;
31+
onMouseLeave: (frame: ErrorFrame) => void;
3332
rowIndex: number;
3433
sortConfig: ReturnType<typeof useSortErrors>['sortConfig'];
3534
startTimestampMs: number;
@@ -42,21 +41,20 @@ const ErrorTableCell = forwardRef<HTMLDivElement, Props>(
4241
columnIndex,
4342
currentHoverTime,
4443
currentTime,
44+
frame,
45+
onClickTimestamp,
4546
onMouseEnter,
4647
onMouseLeave,
47-
onClickTimestamp,
4848
sortConfig,
49-
crumb,
5049
startTimestampMs,
5150
style,
5251
}: Props,
5352
ref
5453
) => {
5554
const organization = useOrganization();
5655

57-
// @ts-expect-error
58-
const {eventId, groupId, groupShortId, project: projectSlug} = crumb.data;
59-
const title = crumb.message;
56+
const {eventId, groupId, groupShortId, projectSlug} = frame.data;
57+
const title = frame.message;
6058
const {projects} = useProjects();
6159
const project = useMemo(
6260
() => projects.find(p => p.slug === projectSlug),
@@ -75,13 +73,9 @@ const ErrorTableCell = forwardRef<HTMLDivElement, Props>(
7573
}
7674
: null;
7775

78-
const crumbTime = useMemo(
79-
// @ts-expect-error
80-
() => relativeTimeInMs(new Date(crumb.timestamp).getTime(), startTimestampMs),
81-
[crumb.timestamp, startTimestampMs]
82-
);
83-
const hasOccurred = currentTime >= crumbTime;
84-
const isBeforeHover = currentHoverTime === undefined || currentHoverTime >= crumbTime;
76+
const hasOccurred = currentTime >= frame.offsetMs;
77+
const isBeforeHover =
78+
currentHoverTime === undefined || currentHoverTime >= frame.offsetMs;
8579

8680
const isByTimestamp = sortConfig.by === 'timestamp';
8781
const isAsc = isByTimestamp ? sortConfig.asc : undefined;
@@ -111,8 +105,8 @@ const ErrorTableCell = forwardRef<HTMLDivElement, Props>(
111105
: undefined,
112106
}),
113107
hasOccurred: isByTimestamp ? hasOccurred : undefined,
114-
onMouseEnter: () => onMouseEnter(crumb),
115-
onMouseLeave: () => onMouseLeave(crumb),
108+
onMouseEnter: () => onMouseEnter(frame),
109+
onMouseLeave: () => onMouseLeave(frame),
116110
ref,
117111
style,
118112
} as ComponentProps<typeof Cell>;
@@ -176,10 +170,10 @@ const ErrorTableCell = forwardRef<HTMLDivElement, Props>(
176170
<StyledTimestampButton
177171
format="mm:ss.SSS"
178172
onClick={() => {
179-
onClickTimestamp(crumb);
173+
onClickTimestamp(frame);
180174
}}
181175
startTimestampMs={startTimestampMs}
182-
timestampMs={crumb.timestamp || ''}
176+
timestampMs={frame.timestampMs}
183177
/>
184178
</Cell>
185179
),

static/app/views/replays/detail/errorList/index.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import styled from '@emotion/styled';
55
import Placeholder from 'sentry/components/placeholder';
66
import {useReplayContext} from 'sentry/components/replays/replayContext';
77
import {t} from 'sentry/locale';
8-
import type {Crumb} from 'sentry/types/breadcrumbs';
98
import useCrumbHandlers from 'sentry/utils/replays/hooks/useCrumbHandlers';
9+
import type {ErrorFrame} from 'sentry/utils/replays/types';
1010
import ErrorFilters from 'sentry/views/replays/detail/errorList/errorFilters';
1111
import ErrorHeaderCell, {
1212
COLUMN_COUNT,
@@ -22,7 +22,7 @@ const HEADER_HEIGHT = 25;
2222
const BODY_HEIGHT = 28;
2323

2424
type Props = {
25-
errorCrumbs: undefined | Crumb[];
25+
errorFrames: undefined | ErrorFrame[];
2626
startTimestampMs: number;
2727
};
2828

@@ -32,10 +32,10 @@ const cellMeasurer = {
3232
fixedHeight: true,
3333
};
3434

35-
function ErrorList({errorCrumbs, startTimestampMs}: Props) {
35+
function ErrorList({errorFrames, startTimestampMs}: Props) {
3636
const {currentTime, currentHoverTime} = useReplayContext();
3737

38-
const filterProps = useErrorFilters({errorCrumbs: errorCrumbs || []});
38+
const filterProps = useErrorFilters({errorFrames: errorFrames || []});
3939
const {items: filteredItems, searchTerm, setSearchTerm} = filterProps;
4040
const clearSearchTerm = () => setSearchTerm('');
4141
const {handleSort, items, sortConfig} = useSortErrors({items: filteredItems});
@@ -91,7 +91,7 @@ function ErrorList({errorCrumbs, startTimestampMs}: Props) {
9191
ref={e => e && registerChild?.(e)}
9292
rowIndex={rowIndex}
9393
sortConfig={sortConfig}
94-
crumb={error}
94+
frame={error}
9595
startTimestampMs={startTimestampMs}
9696
style={{...style, height: BODY_HEIGHT}}
9797
/>
@@ -103,9 +103,9 @@ function ErrorList({errorCrumbs, startTimestampMs}: Props) {
103103

104104
return (
105105
<FluidHeight>
106-
<ErrorFilters errorCrumbs={errorCrumbs} {...filterProps} />
106+
<ErrorFilters errorFrames={errorFrames} {...filterProps} />
107107
<ErrorTable>
108-
{errorCrumbs ? (
108+
{errorFrames ? (
109109
<OverflowHidden>
110110
<AutoSizer onResize={onWrapperResize}>
111111
{({height, width}) => (
@@ -121,7 +121,7 @@ function ErrorList({errorCrumbs, startTimestampMs}: Props) {
121121
height={height}
122122
noContentRenderer={() => (
123123
<NoRowRenderer
124-
unfilteredItems={errorCrumbs}
124+
unfilteredItems={errorFrames}
125125
clearSearchTerm={clearSearchTerm}
126126
>
127127
{t('No errors! Go make some.')}

0 commit comments

Comments
 (0)