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;