import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import Avatar from 'sentry/components/avatar'; import UserBadge from 'sentry/components/idBadge/userBadge'; import Link from 'sentry/components/links/link'; import ContextIcon from 'sentry/components/replays/contextIcon'; import ErrorCount from 'sentry/components/replays/header/errorCount'; import {formatTime} from 'sentry/components/replays/utils'; import {StringWalker} from 'sentry/components/replays/walker/urlWalker'; import ScoreBar from 'sentry/components/scoreBar'; import TimeSince from 'sentry/components/timeSince'; import CHART_PALETTE from 'sentry/constants/chartPalette'; import {IconCalendar} from 'sentry/icons'; import {space, ValidSize} from 'sentry/styles/space'; import type {Organization} from 'sentry/types'; import EventView from 'sentry/utils/discover/eventView'; import {spanOperationRelativeBreakdownRenderer} from 'sentry/utils/discover/fieldRenderers'; import {getShortEventId} from 'sentry/utils/events'; import {useLocation} from 'sentry/utils/useLocation'; import useMedia from 'sentry/utils/useMedia'; import useProjects from 'sentry/utils/useProjects'; import type {ReplayListRecordWithTx} from 'sentry/views/performance/transactionSummary/transactionReplays/useReplaysWithTxData'; import type {ReplayListRecord} from 'sentry/views/replays/types'; type Props = { replay: ReplayListRecord | ReplayListRecordWithTx; }; export function ReplayCell({ eventView, organization, referrer, replay, }: Props & {eventView: EventView; organization: Organization; referrer: string}) { const {projects} = useProjects(); const project = projects.find(p => p.id === replay.project_id); const replayDetails = { pathname: `/organizations/${organization.slug}/replays/${project?.slug}:${replay.id}/`, query: { referrer, ...eventView.generateQueryStringObject(), }, }; return ( {replay.user.display_name || ''} } user={{ username: replay.user.display_name || '', email: replay.user.email || '', id: replay.user.id || '', ip_address: replay.user.ip || '', name: replay.user.username || '', }} // this is the subheading for the avatar, so displayEmail in this case is a misnomer displayEmail={ {project ? : null} {getShortEventId(replay.id)} } /> ); } // Need to be full width for StringWalker to take up full width and truncate properly const UserBadgeFullWidth = styled(UserBadge)` width: 100%; `; const Cols = styled('div')` display: flex; flex-direction: column; gap: ${space(0.25)}; width: 100%; `; const Row = styled('div')<{gap: ValidSize}>` display: flex; gap: ${p => space(p.gap)}; align-items: center; `; const MainLink = styled(Link)` font-size: ${p => p.theme.fontSizeLarge}; `; export function TransactionCell({ organization, replay, }: Props & {organization: Organization}) { const location = useLocation(); const hasTxEvent = 'txEvent' in replay; const txDuration = hasTxEvent ? replay.txEvent?.['transaction.duration'] : undefined; return hasTxEvent ? ( {txDuration ?
{txDuration}ms
: null} {spanOperationRelativeBreakdownRenderer( replay.txEvent, {organization, location}, {enableOnClick: false} )}
) : null; } export function OSCell({replay}: Props) { const {name, version} = replay.os; const theme = useTheme(); const hasRoomForColumns = useMedia(`(min-width: ${theme.breakpoints.large})`); return ( ); } export function BrowserCell({replay}: Props) { const {name, version} = replay.browser; const theme = useTheme(); const hasRoomForColumns = useMedia(`(min-width: ${theme.breakpoints.large})`); return ( ); } export function DurationCell({replay}: Props) { return ( ); } export function ErrorCountCell({replay}: Props) { return ( ); } export function ActivityCell({replay}: Props) { const scoreBarPalette = new Array(10).fill([CHART_PALETTE[0][0]]); return ( ); } const Item = styled('div')` display: flex; align-items: center; gap: ${space(1)}; padding: ${space(1.5)}; `; const Time = styled('span')` font-variant-numeric: tabular-nums; `; const SpanOperationBreakdown = styled('div')` width: 100%; display: flex; flex-direction: column; gap: ${space(0.5)}; color: ${p => p.theme.gray500}; font-size: ${p => p.theme.fontSizeMedium}; text-align: right; `;