Skip to content

Commit 9765e40

Browse files
authored
feat(replay): Show Seen-by list of users on Replay Details (#68760)
<img width="450" alt="SCR-20240411-nzaf" src="https://github.com/getsentry/sentry/assets/187460/413b7be7-0e2e-44f3-905e-ba2c0c0d013a"> Avatar list is kinda weird, it sticks out to the left: <img width="488" alt="SCR-20240411-nzka" src="https://github.com/getsentry/sentry/assets/187460/71fe5267-e5a3-4fb3-b86f-2e6b7a98ebc1"> Relates to getsentry/team-replay#19 Relates to #64924 Depends on #68990
1 parent 2b9ba9d commit 9765e40

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

static/app/components/replays/header/replayMetaData.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import {Fragment} from 'react';
1+
import {Fragment, useEffect} from 'react';
22
import {Link} from 'react-router';
33
import styled from '@emotion/styled';
4+
import * as Sentry from '@sentry/react';
45

6+
import AvatarList from 'sentry/components/avatar/avatarList';
57
import ErrorCounts from 'sentry/components/replays/header/errorCounts';
68
import HeaderPlaceholder from 'sentry/components/replays/header/headerPlaceholder';
79
import {IconCursorArrow} from 'sentry/icons';
@@ -10,6 +12,7 @@ import {space} from 'sentry/styles/space';
1012
import EventView from 'sentry/utils/discover/eventView';
1113
import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes';
1214
import {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab';
15+
import useReplayViewedByData from 'sentry/utils/replays/hooks/useReplayViewedByData';
1316
import {useLocation} from 'sentry/utils/useLocation';
1417
import {useRoutes} from 'sentry/utils/useRoutes';
1518
import type {ReplayError, ReplayRecord} from 'sentry/views/replays/types';
@@ -25,6 +28,16 @@ function ReplayMetaData({replayErrors, replayRecord, showDeadRageClicks = true}:
2528
const routes = useRoutes();
2629
const referrer = getRouteStringFromRoutes(routes);
2730
const eventView = EventView.fromLocation(location);
31+
const viewersResult = useReplayViewedByData({
32+
projectSlug: replayRecord?.project_id,
33+
replayId: replayRecord?.id,
34+
});
35+
36+
useEffect(() => {
37+
if (viewersResult.isError) {
38+
Sentry.captureException(viewersResult.error);
39+
}
40+
});
2841

2942
const breadcrumbTab = {
3043
...location,
@@ -82,6 +95,14 @@ function ReplayMetaData({replayErrors, replayRecord, showDeadRageClicks = true}:
8295
<HeaderPlaceholder width="20px" height="16px" />
8396
)}
8497
</KeyMetricData>
98+
<KeyMetricLabel>{t('Seen By')}</KeyMetricLabel>
99+
<KeyMetricData>
100+
{viewersResult.isLoading ? (
101+
<HeaderPlaceholder width="55px" height="27px" />
102+
) : (
103+
<AvatarList avatarSize={25} users={viewersResult.data?.data.viewed_by} />
104+
)}
105+
</KeyMetricData>
85106
</KeyMetrics>
86107
);
87108
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type {User} from 'sentry/types';
2+
import {useApiQuery, type UseApiQueryOptions} from 'sentry/utils/queryClient';
3+
import useOrganization from 'sentry/utils/useOrganization';
4+
5+
interface Props {
6+
projectSlug: undefined | string;
7+
replayId: undefined | string;
8+
}
9+
10+
type TResponseData = {
11+
data: {
12+
viewed_by: User[];
13+
};
14+
};
15+
16+
export default function useReplayViewedByData(
17+
{projectSlug, replayId}: Props,
18+
options: Partial<UseApiQueryOptions<TResponseData>> = {}
19+
) {
20+
const organization = useOrganization();
21+
return useApiQuery<TResponseData>(
22+
[`/projects/${organization.slug}/${projectSlug}/replays/${replayId}/viewed-by/`],
23+
{
24+
enabled: Boolean(projectSlug && replayId),
25+
staleTime: Infinity,
26+
retry: false,
27+
...options,
28+
}
29+
);
30+
}

0 commit comments

Comments
 (0)