import {useMemo} from 'react'; import Count from 'sentry/components/count'; import DateTime from 'sentry/components/dateTime'; import GridEditable, { COL_WIDTH_UNDEFINED, GridColumnOrder, } from 'sentry/components/gridEditable'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import Link from 'sentry/components/links/link'; import PerformanceDuration from 'sentry/components/performanceDuration'; import {t} from 'sentry/locale'; import {ProfileTransaction} from 'sentry/types/profiling/core'; import {defined} from 'sentry/utils'; import {Container, NumberContainer} from 'sentry/utils/discover/styles'; import {generateProfileSummaryRouteWithQuery} from 'sentry/utils/profiling/routes'; import {renderTableHead} from 'sentry/utils/profiling/tableRenderer'; import {decodeScalar} from 'sentry/utils/queryString'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; interface ProfileTransactionsTableProps { error: string | null; isLoading: boolean; sort: string; transactions: ProfileTransaction[]; } function ProfileTransactionsTable(props: ProfileTransactionsTableProps) { const location = useLocation(); const organization = useOrganization(); const {projects} = useProjects(); const sort = useMemo(() => { let column = decodeScalar(props.sort, '-count()'); let order: 'asc' | 'desc' = 'asc' as const; if (column.startsWith('-')) { column = column.substring(1); order = 'desc' as const; } if (!SORTABLE_COLUMNS.has(column as any)) { column = 'count()'; } return { key: column as TableColumnKey, order, }; }, [props.sort]); const transactions: TableDataRow[] = useMemo(() => { return props.transactions.map(transaction => { const project = projects.find(proj => proj.id === transaction.project_id); return { _transactionName: transaction.name, transaction: project ? ( {transaction.name} ) : ( transaction.name ), 'count()': transaction.profiles_count, project, 'p50()': transaction.duration_ms.p50, 'p75()': transaction.duration_ms.p75, 'p90()': transaction.duration_ms.p90, 'p95()': transaction.duration_ms.p95, 'p99()': transaction.duration_ms.p99, 'last_seen()': transaction.last_profile_at, }; }); }, [props.transactions, location, organization, projects]); const generateSortLink = (column: string) => () => { let dir = 'desc'; if (column === sort.key && sort.order === dir) { dir = 'asc'; } return { ...location, query: { ...location.query, sort: `${dir === 'desc' ? '-' : ''}${column}`, }, }; }; return ( COLUMNS[key])} columnSortBy={[sort]} grid={{ renderHeadCell: renderTableHead({ generateSortLink, sortableColumns: SORTABLE_COLUMNS, currentSort: sort, rightAlignedColumns: RIGHT_ALIGNED_COLUMNS, }), renderBodyCell: renderTableBody, }} location={location} /> ); } const RIGHT_ALIGNED_COLUMNS = new Set([ 'count()', 'p50()', 'p75()', 'p90()', 'p95()', 'p99()', ]); const SORTABLE_COLUMNS = new Set([ 'project', 'transaction', 'count()', 'p50()', 'p75()', 'p90()', 'p95()', 'p99()', 'last_seen()', ]); function renderTableBody( column: GridColumnOrder, dataRow: TableDataRow, rowIndex: number, columnIndex: number ) { return ( ); } interface ProfilingTransactionsTableCellProps { column: GridColumnOrder; columnIndex: number; dataRow: TableDataRow; rowIndex: number; } function ProfilingTransactionsTableCell({ column, dataRow, }: ProfilingTransactionsTableCellProps) { const value = dataRow[column.key]; switch (column.key) { case 'project': if (!defined(value)) { // should never happen but just in case return {t('n/a')}; } return ( ); case 'count()': return ( ); case 'p50()': case 'p75()': case 'p90()': case 'p95()': case 'p99()': return ( ); case 'last_seen()': return ( ); default: return {value}; } } type TableColumnKey = | 'transaction' | 'count()' | 'project' | 'p50()' | 'p75()' | 'p90()' | 'p95()' | 'p99()' | 'last_seen()'; type TableDataRow = Record; type TableColumn = GridColumnOrder; const COLUMN_ORDER: TableColumnKey[] = [ 'transaction', 'project', 'last_seen()', 'p75()', 'p95()', 'count()', ]; const COLUMNS: Record = { transaction: { key: 'transaction', name: t('Transaction'), width: COL_WIDTH_UNDEFINED, }, 'count()': { key: 'count()', name: t('Count'), width: COL_WIDTH_UNDEFINED, }, project: { key: 'project', name: t('Project'), width: COL_WIDTH_UNDEFINED, }, 'p50()': { key: 'p50()', name: t('P50'), width: COL_WIDTH_UNDEFINED, }, 'p75()': { key: 'p75()', name: t('P75'), width: COL_WIDTH_UNDEFINED, }, 'p90()': { key: 'p90()', name: t('P90'), width: COL_WIDTH_UNDEFINED, }, 'p95()': { key: 'p95()', name: t('P95'), width: COL_WIDTH_UNDEFINED, }, 'p99()': { key: 'p99()', name: t('P99'), width: COL_WIDTH_UNDEFINED, }, 'last_seen()': { key: 'last_seen()', name: t('Last Seen'), width: COL_WIDTH_UNDEFINED, }, }; export {ProfileTransactionsTable};