Skip to content

Commit 7e2cea7

Browse files
authored
feat(replay): Read the has_viewed field on replay records and reflect that in the list (#67951)
Depends on backend support for the new `has_viewed` field. Follows the blueprint in https://github.com/getsentry/sentry/blob/master/src/sentry/replays/blueprints/api.md Relates to getsentry/team-replay#19 Relates to #64924 Depends on #68628
1 parent 26383a3 commit 7e2cea7

File tree

6 files changed

+51
-16
lines changed

6 files changed

+51
-16
lines changed

fixtures/js-stubs/replayList.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export function ReplayListFixture(
2020
count_errors: 0,
2121
duration: duration(30000),
2222
finished_at: new Date('2022-09-15T06:54:00+00:00'),
23+
has_viewed: false,
2324
id: '346789a703f6454384f1de473b8b9fcc',
2425
is_archived: false,
2526
os: {

fixtures/js-stubs/replayRecord.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export function ReplayRecordFixture(
2727
environment: 'demo',
2828
error_ids: ['5c83aaccfffb4a708ae893bad9be3a1c'],
2929
finished_at: new Date('Sep 22, 2022 5:00:03 PM UTC'),
30+
has_viewed: false,
3031
id: '761104e184c64d439ee1014b72b4d83b',
3132
is_archived: false,
3233
os: {

static/app/utils/replays/replayDataUtils.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import isValidDate from 'sentry/utils/date/isValidDate';
55
import getMinMax from 'sentry/utils/getMinMax';
66
import type {ReplayRecord} from 'sentry/views/replays/types';
77

8+
const defaultValues = {
9+
has_viewed: false,
10+
};
11+
812
export function mapResponseToReplayRecord(apiResponse: any): ReplayRecord {
913
// Marshal special fields into tags
1014
const user = Object.fromEntries(
@@ -40,6 +44,7 @@ export function mapResponseToReplayRecord(apiResponse: any): ReplayRecord {
4044
const finishedAt = new Date(apiResponse.finished_at);
4145
invariant(isValidDate(finishedAt), 'replay.finished_at is invalid');
4246
return {
47+
...defaultValues,
4348
...apiResponse,
4449
...(apiResponse.started_at ? {started_at: startedAt} : {}),
4550
...(apiResponse.finished_at ? {finished_at: finishedAt} : {}),

static/app/views/issueDetails/groupReplays/groupReplays.spec.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ describe('GroupReplays', () => {
201201
'count_rage_clicks',
202202
'duration',
203203
'finished_at',
204+
'has_viewed',
204205
'id',
205206
'is_archived',
206207
'os',

static/app/views/replays/replayTable/tableCell.tsx

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import styled from '@emotion/styled';
44
import type {Location} from 'history';
55

66
import Avatar from 'sentry/components/avatar';
7+
import UserAvatar from 'sentry/components/avatar/userAvatar';
78
import {Button} from 'sentry/components/button';
89
import {DropdownMenu} from 'sentry/components/dropdownMenu';
9-
import UserBadge from 'sentry/components/idBadge/userBadge';
1010
import Link from 'sentry/components/links/link';
1111
import ContextIcon from 'sentry/components/replays/contextIcon';
1212
import ReplayPlayPauseButton from 'sentry/components/replays/replayPlayPauseButton';
@@ -374,21 +374,25 @@ export function ReplayCell({
374374

375375
return (
376376
<Item isWidget={isWidget} isReplayCell className={className}>
377-
<UserBadge
378-
avatarSize={24}
379-
displayName={
380-
replay.is_archived ? (
381-
replay.user.display_name || t('Anonymous User')
382-
) : (
383-
<MainLink to={detailsTab} onClick={trackNavigationEvent}>
384-
{replay.user.display_name || t('Anonymous User')}
385-
</MainLink>
386-
)
387-
}
388-
user={getUserBadgeUser(replay)}
389-
// this is the subheading for the avatar, so displayEmail in this case is a misnomer
390-
displayEmail={subText}
391-
/>
377+
<Row gap={1}>
378+
<UserAvatar user={getUserBadgeUser(replay)} size={24} />
379+
<SubText>
380+
<Row gap={0.5}>
381+
{replay.is_archived ? (
382+
replay.user.display_name || t('Anonymous User')
383+
) : (
384+
<MainLink
385+
to={detailsTab}
386+
onClick={trackNavigationEvent}
387+
data-has-viewed={replay.has_viewed}
388+
>
389+
{replay.user.display_name || t('Anonymous User')}
390+
</MainLink>
391+
)}
392+
</Row>
393+
<Row gap={0.5}>{subText}</Row>
394+
</SubText>
395+
</Row>
392396
</Item>
393397
);
394398
}
@@ -417,6 +421,23 @@ const Row = styled('div')<{gap: ValidSize; minWidth?: number}>`
417421

418422
const MainLink = styled(Link)`
419423
font-size: ${p => p.theme.fontSizeLarge};
424+
line-height: normal;
425+
${p => p.theme.overflowEllipsis};
426+
427+
font-weight: bold;
428+
&[data-has-viewed='true'] {
429+
font-weight: normal;
430+
}
431+
`;
432+
433+
const SubText = styled('div')`
434+
font-size: 0.875em;
435+
line-height: normal;
436+
color: ${p => p.theme.gray300};
437+
${p => p.theme.overflowEllipsis};
438+
display: flex;
439+
flex-direction: column;
440+
gap: ${space(0.25)};
420441
`;
421442

422443
export function TransactionCell({

static/app/views/replays/types.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export type ReplayRecord = {
4040
* The **latest** timestamp received as determined by the SDK.
4141
*/
4242
finished_at: Date;
43+
/**
44+
* Whether the currently authenticated user has seen this replay or not.
45+
*/
46+
has_viewed: boolean;
4347
/**
4448
* The ID of the Replay instance
4549
*/
@@ -120,6 +124,7 @@ export const REPLAY_LIST_FIELDS = [
120124
'count_rage_clicks',
121125
'duration',
122126
'finished_at',
127+
'has_viewed',
123128
'id',
124129
'is_archived',
125130
'os.name',
@@ -139,6 +144,7 @@ export type ReplayListRecord = Pick<
139144
| 'count_rage_clicks'
140145
| 'duration'
141146
| 'finished_at'
147+
| 'has_viewed'
142148
| 'id'
143149
| 'is_archived'
144150
| 'os'

0 commit comments

Comments
 (0)