import {Fragment, ReactNode} from 'react'; import styled from '@emotion/styled'; import {Location} from 'history'; import {Alert} from 'sentry/components/alert'; import ExternalLink from 'sentry/components/links/externalLink'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import PanelTable from 'sentry/components/panels/panelTable'; import {t, tct} from 'sentry/locale'; import EventView from 'sentry/utils/discover/eventView'; import type {Sort} from 'sentry/utils/discover/fields'; import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjectSdkNeedsUpdate from 'sentry/utils/useProjectSdkNeedsUpdate'; import {useRoutes} from 'sentry/utils/useRoutes'; import type {ReplayListRecordWithTx} from 'sentry/views/performance/transactionSummary/transactionReplays/useReplaysWithTxData'; import HeaderCell from 'sentry/views/replays/replayTable/headerCell'; import { ActivityCell, BrowserCell, DeadClickCountCell, DurationCell, ErrorCountCell, OSCell, RageClickCountCell, ReplayCell, TransactionCell, } from 'sentry/views/replays/replayTable/tableCell'; import {ReplayColumn} from 'sentry/views/replays/replayTable/types'; import type {ReplayListRecord} from 'sentry/views/replays/types'; const MIN_DEAD_RAGE_CLICK_SDK = '7.60.1'; type Props = { fetchError: undefined | Error; isFetching: boolean; replays: undefined | ReplayListRecord[] | ReplayListRecordWithTx[]; sort: Sort | undefined; visibleColumns: ReplayColumn[]; emptyMessage?: ReactNode; footer?: ReactNode; gridRows?: string; saveLocation?: boolean; }; function ReplayTable({ fetchError, isFetching, replays, sort, visibleColumns, emptyMessage, saveLocation, gridRows, footer, }: Props) { const routes = useRoutes(); const newLocation = useLocation(); const organization = useOrganization(); const { selection: {projects}, } = usePageFilters(); const needSDKUpgrade = useProjectSdkNeedsUpdate({ minVersion: MIN_DEAD_RAGE_CLICK_SDK, organization, projectId: projects.map(String), }); const location: Location = saveLocation ? { pathname: '', search: '', query: {}, hash: '', state: '', action: 'PUSH', key: '', } : newLocation; const tableHeaders = visibleColumns .filter(Boolean) .map(column => ); if (fetchError && !isFetching) { return ( {typeof fetchError === 'string' ? fetchError : t( 'Sorry, the list of replays could not be loaded. This could be due to invalid search parameters or an internal systems error.' )} ); } if ( needSDKUpgrade.needsUpdate && (visibleColumns.includes(ReplayColumn.COUNT_DEAD_CLICKS) || visibleColumns.includes(ReplayColumn.COUNT_RAGE_CLICKS)) ) { return ( } disablePadding > {tct('[data] requires [sdkPrompt]. [link:Upgrade now.]', { data: Rage and dead clicks, sdkPrompt: {t('SDK version >= 7.60.1')}, link: , })} ); } const referrer = getRouteStringFromRoutes(routes); const eventView = EventView.fromLocation(location); return ( } > {replays?.map(replay => { return ( {visibleColumns.map(column => { switch (column) { case ReplayColumn.ACTIVITY: return ; case ReplayColumn.BROWSER: return ; case ReplayColumn.COUNT_DEAD_CLICKS: return ; case ReplayColumn.COUNT_ERRORS: return ; case ReplayColumn.COUNT_RAGE_CLICKS: return ; case ReplayColumn.DURATION: return ; case ReplayColumn.OS: return ; case ReplayColumn.REPLAY: return ( ); case ReplayColumn.SLOWEST_TRANSACTION: return ( ); case ReplayColumn.MOST_RAGE_CLICKS: return ( ); case ReplayColumn.MOST_DEAD_CLICKS: return ( ); case ReplayColumn.MOST_ERRONEOUS_REPLAYS: return ( ); default: return null; } })} ); })} {footer} ); } const flexibleColumns = [ ReplayColumn.REPLAY, ReplayColumn.MOST_RAGE_CLICKS, ReplayColumn.MOST_DEAD_CLICKS, ReplayColumn.MOST_ERRONEOUS_REPLAYS, ]; const StyledPanelTable = styled(PanelTable)<{ visibleColumns: ReplayColumn[]; gridRows?: string; }>` ${props => props.visibleColumns.includes(ReplayColumn.MOST_RAGE_CLICKS) || props.visibleColumns.includes(ReplayColumn.MOST_DEAD_CLICKS) || props.visibleColumns.includes(ReplayColumn.MOST_ERRONEOUS_REPLAYS) ? `border-bottom-left-radius: 0; border-bottom-right-radius: 0;` : ``} margin-bottom: 0; grid-template-columns: ${p => p.visibleColumns .filter(Boolean) .map(column => flexibleColumns.includes(column) ? 'minmax(100px, 1fr)' : 'max-content' ) .join(' ')}; ${props => props.gridRows ? `grid-template-rows: ${props.gridRows};` : `grid-template-rows: 44px max-content;`} `; const StyledAlert = styled(Alert)` border-radius: 0; border-width: 1px 0 0 0; grid-column: 1/-1; margin-bottom: 0; `; export default ReplayTable;