diff --git a/static/app/components/replays/table/replayTableColumns.tsx b/static/app/components/replays/table/replayTableColumns.tsx index 4610062550c5..591bda2de053 100644 --- a/static/app/components/replays/table/replayTableColumns.tsx +++ b/static/app/components/replays/table/replayTableColumns.tsx @@ -23,7 +23,6 @@ import {ScoreBar} from 'sentry/components/scoreBar'; import {SimpleTable} from 'sentry/components/tables/simpleTable'; import {IconNot} from 'sentry/icons'; import {IconCursorArrow} from 'sentry/icons/iconCursorArrow'; -import {IconFire} from 'sentry/icons/iconFire'; import {IconOpen} from 'sentry/icons/iconOpen'; import {IconPlay} from 'sentry/icons/iconPlay'; import {t, tct} from 'sentry/locale'; @@ -249,16 +248,7 @@ export const ReplayCountErrorsColumn: ReplayTableColumn = { key="countErrors" data-test-id="replay-table-column-count-errors" > - - {replay.count_errors ? ( - - - {replay.count_errors} - - ) : ( - 0 - )} - + {replay.count_errors ?? 0} {showDropdownFilters ? ( ) : null} diff --git a/static/app/views/issueDetails/groupReplays/groupReplays.spec.tsx b/static/app/views/issueDetails/groupReplays/groupReplays.spec.tsx index f07fd8a1ec72..bdf6861c13fc 100644 --- a/static/app/views/issueDetails/groupReplays/groupReplays.spec.tsx +++ b/static/app/views/issueDetails/groupReplays/groupReplays.spec.tsx @@ -458,6 +458,7 @@ describe('GroupReplays', () => { const expectedQuery = 'playlistEnd=2022-09-28T23%3A29%3A13&playlistStart=2022-06-30T23%3A29%3A13&query=id%3A%5B346789a703f6454384f1de473b8b9fcc%2Cb05dae9b6be54d21a4d5ad9f8f02b780%5D&referrer=issueReplays'; + const expectedErrorsQuery = `${expectedQuery}&t_main=errors`; // Expect the first row to have the correct href expect( @@ -479,6 +480,18 @@ describe('GroupReplays', () => { `/organizations/org-slug/explore/replays/${REPLAY_ID_2}/?${expectedQuery}` ); + const issueEventLinks = screen.getAllByRole('link', { + name: 'View events for this issue', + }); + expect(issueEventLinks[0]).toHaveAttribute( + 'href', + `/organizations/org-slug/explore/replays/${REPLAY_ID_1}/?${expectedErrorsQuery}` + ); + expect(issueEventLinks[1]).toHaveAttribute( + 'href', + `/organizations/org-slug/explore/replays/${REPLAY_ID_2}/?${expectedErrorsQuery}` + ); + // Expect the first row to have the correct duration expect(screen.getByText('14:32:26')).toBeInTheDocument(); diff --git a/static/app/views/issueDetails/groupReplays/groupReplays.tsx b/static/app/views/issueDetails/groupReplays/groupReplays.tsx index 007c7892c444..7da8cb9aa33e 100644 --- a/static/app/views/issueDetails/groupReplays/groupReplays.tsx +++ b/static/app/views/issueDetails/groupReplays/groupReplays.tsx @@ -4,6 +4,7 @@ import type {Location, Query} from 'history'; import {Button} from '@sentry/scraps/button'; import {Flex, Stack} from '@sentry/scraps/layout'; +import {Link} from '@sentry/scraps/link'; import {Placeholder} from 'sentry/components/placeholder'; import { @@ -25,6 +26,7 @@ import { ReplayOSColumn, ReplayPlayPauseColumn, ReplaySessionColumn, + type ReplayTableColumn, } from 'sentry/components/replays/table/replayTableColumns'; import {usePlaylistQuery} from 'sentry/components/replays/usePlaylistQuery'; import {replayVideoPlatforms} from 'sentry/data/platformCategories'; @@ -34,12 +36,14 @@ import type {Group} from 'sentry/types/group'; import {trackAnalytics} from 'sentry/utils/analytics'; import type {EventView} from 'sentry/utils/discover/eventView'; import {useReplayCountForIssues} from 'sentry/utils/replayCount/useReplayCountForIssues'; +import {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab'; import {useLoadReplayReader} from 'sentry/utils/replays/hooks/useLoadReplayReader'; import {useReplayList} from 'sentry/utils/replays/hooks/useReplayList'; import {useCleanQueryParamsOnRouteLeave} from 'sentry/utils/useCleanQueryParamsOnRouteLeave'; import {useLocation} from 'sentry/utils/useLocation'; import {useOrganization} from 'sentry/utils/useOrganization'; import {useParams} from 'sentry/utils/useParams'; +import {makeReplaysPathname} from 'sentry/views/explore/replays/pathnames'; import type {ReplayListRecord} from 'sentry/views/explore/replays/types'; import {GroupReplaysPlayer} from 'sentry/views/issueDetails/groupReplays/groupReplaysPlayer'; @@ -49,12 +53,47 @@ type Props = { group: Group; }; +const IssueErrorsColumn: ReplayTableColumn = { + ...ReplayCountErrorsColumn, + Component: props => { + const {replay, to} = props; + const organization = useOrganization(); + + if (replay.is_archived) { + return null; + } + + return ( + event.stopPropagation()} + title={t('View events for this issue')} + to={{ + pathname: makeReplaysPathname({path: `/${replay.id}/`, organization}), + query: { + ...(typeof to === 'string' ? undefined : to.query), + t_main: TabKey.ERRORS, + }, + }} + > + + + ); + }, +}; + +const IssueErrorsLink = styled(Link)` + position: relative; + z-index: 1; + text-decoration: underline; +`; + const VISIBLE_COLUMNS = [ ReplaySessionColumn, ReplayOSColumn, ReplayBrowserColumn, ReplayDurationColumn, - ReplayCountErrorsColumn, + IssueErrorsColumn, ReplayActivityColumn, ReplayDetailsLinkColumn, ]; @@ -63,7 +102,7 @@ const VISIBLE_COLUMNS_MOBILE = [ ReplaySessionColumn, ReplayOSColumn, ReplayDurationColumn, - ReplayCountErrorsColumn, + IssueErrorsColumn, ReplayActivityColumn, ReplayDetailsLinkColumn, ];