import {Fragment} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import Duration from 'sentry/components/duration'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import UserBadge from 'sentry/components/idBadge/userBadge'; import Link from 'sentry/components/links/link'; import {PanelTable} from 'sentry/components/panels'; import ReplayHighlight from 'sentry/components/replays/replayHighlight'; import {StringWalker} from 'sentry/components/replays/walker/urlWalker'; import TimeSince from 'sentry/components/timeSince'; import {IconArrow, IconCalendar} from 'sentry/icons'; import {t} from 'sentry/locale'; import space from 'sentry/styles/space'; import type {Organization} from 'sentry/types'; import type {Sort} from 'sentry/utils/discover/fields'; import {useLocation} from 'sentry/utils/useLocation'; import useMedia from 'sentry/utils/useMedia'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; import type {ReplayListLocationQuery, ReplayListRecord} from 'sentry/views/replays/types'; type Props = { isFetching: boolean; replays: undefined | ReplayListRecord[]; showProjectColumn: boolean; sort: Sort; }; type RowProps = { minWidthIsSmall: boolean; organization: Organization; replay: ReplayListRecord; showProjectColumn: boolean; }; function SortableHeader({ fieldName, label, sort, }: { fieldName: string; label: string; sort: Sort; }) { const location = useLocation(); const arrowDirection = sort.kind === 'asc' ? 'up' : 'down'; const sortArrow = ; return ( {label} {sort.field === fieldName && sortArrow} ); } function ReplayTable({isFetching, replays, showProjectColumn, sort}: Props) { const organization = useOrganization(); const theme = useTheme(); const minWidthIsSmall = useMedia(`(min-width: ${theme.breakpoints.small})`); return ( ) : null, , , , t('Activity'), ].filter(Boolean)} > {replays?.map(replay => ( ))} ); } function ReplayTableRow({ minWidthIsSmall, organization, replay, showProjectColumn, }: RowProps) { const {projects} = useProjects(); const project = projects.find(p => p.id === replay.projectId); return ( {replay.user.username || replay.user.name || replay.user.email || replay.user.ip_address || replay.user.id || ''} } user={replay.user} // this is the subheading for the avatar, so displayEmail in this case is a misnomer displayEmail={} /> {showProjectColumn && minWidthIsSmall && ( {project ? : null} )} {minWidthIsSmall && } {replay.countErrors || 0} ); } const StyledPanelTable = styled(PanelTable)<{showProjectColumn: boolean}>` ${p => p.showProjectColumn ? `grid-template-columns: minmax(0, 1fr) repeat(5, max-content);` : `grid-template-columns: minmax(0, 1fr) repeat(4, max-content);`} @media (max-width: ${p => p.theme.breakpoints.small}) { grid-template-columns: minmax(0, 1fr) repeat(4, max-content); } `; const SortLink = styled(Link)` color: inherit; :hover { color: inherit; } svg { vertical-align: top; } `; const Item = styled('div')` display: flex; align-items: center; `; const TimeSinceWrapper = styled('div')` display: grid; grid-template-columns: repeat(2, minmax(auto, max-content)); align-items: center; gap: ${space(1)}; `; const StyledIconCalendarWrapper = styled(IconCalendar)` position: relative; top: -1px; `; export default ReplayTable;