import React, {Fragment, useMemo} from '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 Placeholder from 'sentry/components/placeholder'; import TimeSince from 'sentry/components/timeSince'; import {IconCalendar} from 'sentry/icons'; import space from 'sentry/styles/space'; import {generateEventSlug} from 'sentry/utils/discover/urls'; import getUrlPathname from 'sentry/utils/getUrlPathname'; import useDiscoverQuery from 'sentry/utils/replays/hooks/useDiscoveryQuery'; import theme from 'sentry/utils/theme'; import useMedia from 'sentry/utils/useMedia'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; import {Replay} from './types'; type Props = { idKey: string; replayList: Replay[]; showProjectColumn?: boolean; }; type ReplayDurationAndErrors = { count_if_event_type_equals_error: number; 'equation[0]': number; id: string; max_timestamp: string; min_timestamp: string; replayId: string; }; function ReplayTable({replayList, idKey, showProjectColumn}: Props) { const organization = useOrganization(); const {projects} = useProjects(); const isScreenLarge = useMedia(`(min-width: ${theme.breakpoints.small})`); const query = replayList.map(item => `replayId:${item[idKey]}`).join(' OR '); const discoverQuery = useMemo( () => ({ fields: [ 'replayId', 'max(timestamp)', 'min(timestamp)', 'equation|max(timestamp)-min(timestamp)', 'count_if(event.type,equals,error)', ], orderby: '-min_timestamp', query: `(title:"sentry-replay-event-*" OR event.type:error) AND (${query})`, }), [query] ); const {data} = useDiscoverQuery({discoverQuery}); const dataEntries = data ? Object.fromEntries(data.map(item => [item.replayId, item])) : {}; return ( {replayList?.map(replay => ( {replay['user.display']} } user={{ username: replay['user.username'] ?? '', id: replay['user.id'] ?? '', ip_address: replay['user.ip_address'] ?? '', name: replay['user.name'] ?? '', email: replay['user.email'] ?? '', }} // this is the subheading for the avatar, so displayEmail in this case is a misnomer displayEmail={getUrlPathname(replay.url) ?? ''} /> {isScreenLarge && showProjectColumn && ( p.slug === replay.project) || { slug: replay.project, } } avatarSize={16} /> )} {isScreenLarge && } {data ? ( {dataEntries[replay[idKey]] ? dataEntries[replay[idKey]]?.count_if_event_type_equals_error : 0} ) : ( )} ))} ); } 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;