import {Fragment} from 'react'; import styled from '@emotion/styled'; import type {Location} from 'history'; import qs from 'qs'; import GridEditable, { COL_WIDTH_UNDEFINED, type GridColumnHeader, } from 'sentry/components/gridEditable'; import Link from 'sentry/components/links/link'; import type {CursorHandler} from 'sentry/components/pagination'; import Pagination from 'sentry/components/pagination'; import {t} from 'sentry/locale'; import type {Organization} from 'sentry/types'; import {browserHistory} from 'sentry/utils/browserHistory'; import type {EventsMetaType} from 'sentry/utils/discover/eventView'; import {FIELD_FORMATTERS, getFieldRenderer} from 'sentry/utils/discover/fieldRenderers'; import {decodeScalar} from 'sentry/utils/queryString'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import {normalizeUrl} from 'sentry/utils/withDomainRequired'; import {useQueuesByTransactionQuery} from 'sentry/views/performance/queues/queries/useQueuesByTransactionQuery'; import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell'; import type {SpanMetricsResponse} from 'sentry/views/starfish/types'; import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters'; type Row = Pick< SpanMetricsResponse, | 'sum(span.duration)' | 'transaction' | `avg_if(${string},${string},${string})` | `count_op(${string})` >; type Column = GridColumnHeader; const COLUMN_ORDER: Column[] = [ { key: 'transaction', name: t('Transactions'), width: COL_WIDTH_UNDEFINED, }, { key: 'span.op', name: t('Type'), width: COL_WIDTH_UNDEFINED, }, { key: 'avg(messaging.message.receive.latency)', name: t('Avg Time in Queue'), width: COL_WIDTH_UNDEFINED, }, { key: 'avg_if(span.duration,span.op,queue.process)', name: t('Avg Processing Time'), width: COL_WIDTH_UNDEFINED, }, { key: '', // TODO name: t('Error Rate'), width: COL_WIDTH_UNDEFINED, }, { key: 'count_op(queue.publish)', name: t('Published'), width: COL_WIDTH_UNDEFINED, }, { key: 'count_op(queue.process)', name: t('Processed'), width: COL_WIDTH_UNDEFINED, }, { key: 'sum(span.duration)', name: t('Time Spent'), width: COL_WIDTH_UNDEFINED, }, ]; export function TransactionsTable() { const organization = useOrganization(); const location = useLocation(); const destination = decodeScalar(location.query.destination); const {data, isLoading, meta, pageLinks, error} = useQueuesByTransactionQuery({ destination, }); const handleCursor: CursorHandler = (newCursor, pathname, query) => { browserHistory.push({ pathname, query: {...query, [QueryParameterNames.TRANSACTIONS_CURSOR]: newCursor}, }); }; return ( renderHeadCell({ column: col, location, }), renderBodyCell: (column, row) => renderBodyCell(column, row, meta, location, organization), }} location={location} /> ); } function renderBodyCell( column: Column, row: Row, meta: EventsMetaType | undefined, location: Location, organization: Organization ) { const op = row['span.op']; const isProducer = op === 'queue.publish'; const isConsumer = op === 'queue.process'; const key = column.key; if ( row[key] === undefined || (isConsumer && ['count_op(queue.publish)'].includes(key)) || (isProducer && [ 'count_op(queue.process)', 'avg(messaging.message.receive.latency)', 'avg_if(span.duration,span.op,queue.process)', ].includes(key)) ) { return ( {' \u2014 '} ); } if (key === 'transaction') { return ; } if (!meta?.fields) { return row[column.key]; } if (key.startsWith('avg')) { const renderer = FIELD_FORMATTERS.duration.renderFunc; return renderer(key, row); } if (key === 'span.op') { switch (row[key]) { case 'queue.publish': return t('Producer'); case 'queue.process': return t('Consumer'); default: return row[key]; } } const renderer = getFieldRenderer(column.key, meta.fields, false); return renderer(row, { location, organization, unit: meta.units?.[column.key], }); } function TransactionCell({transaction}: {transaction: string}) { const organization = useOrganization(); const {query} = useLocation(); const queryString = { ...query, transaction, }; return ( {transaction} ); } const NoOverflow = styled('span')` overflow: hidden; `; const AlignRight = styled('span')` text-align: right; `; const NoValue = styled('span')` color: ${p => p.theme.gray300}; `;