import type {FC, ReactText} from 'react'; import type {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 type {DateString} from 'sentry/types'; import {defined} from 'sentry/utils'; import {Container, FieldDateTime} from 'sentry/utils/discover/styles'; import {getShortEventId} from 'sentry/utils/events'; import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls'; import Projects from 'sentry/utils/projects'; import {decodeScalar} from 'sentry/utils/queryString'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; import {getTraceDetailsUrl} from 'sentry/views/performance/traceDetails/utils'; import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils'; import type {ColumnKey, DataRow} from './types'; interface FieldRendererProps { column: GridColumnOrder; row: DataRow; } export function getFieldRenderer(field: ColumnKey): FC { return fieldRenderers[field] ?? DefaultRenderer; } const fieldRenderers: Record> = { project: ProjectRenderer, span_id: SpanIdRenderer, 'span.duration': SpanDurationRenderer, 'span.self_time': SpanSelfTimeRenderer, timestamp: TimestampRenderer, trace: TraceIdRenderer, transaction: TransactionRenderer, 'transaction.id': TransactionIdRenderer, }; function DefaultRenderer({row, column}: FieldRendererProps) { // TODO: this can be smarter based on the type of the value return {row[column.key]}; } function ProjectRenderer(props: FieldRendererProps) { const projectSlug = props.row.project; if (!defined(projectSlug)) { return ; } return <_ProjectRenderer {...props} projectSlug={projectSlug} />; } interface ProjectRendererProps extends FieldRendererProps { projectSlug: string; } function _ProjectRenderer({projectSlug}: ProjectRendererProps) { const organization = useOrganization(); return ( {({projects}) => { const project = projects.find(p => p.slug === projectSlug); return ( ); }} ); } function SpanIdRenderer(props: FieldRendererProps) { const projectSlug = props.row.project; const spanId = props.row.span_id; const transactionId = props.row['transaction.id']; if (!defined(projectSlug) || !defined(spanId) || !defined(transactionId)) { return ; } return ( <_SpanIdRenderer {...props} projectSlug={projectSlug} spanId={spanId} transactionId={transactionId} /> ); } interface _SpanIdRendererProps extends FieldRendererProps { projectSlug: string; spanId: string; transactionId: string; } function _SpanIdRenderer({projectSlug, spanId, transactionId}: _SpanIdRendererProps) { const organization = useOrganization(); const target = getTransactionDetailsUrl( organization.slug, `${projectSlug}:${transactionId}`, undefined, undefined, spanId ); return {getShortEventId(spanId)}; } function TraceIdRenderer(props: FieldRendererProps) { const traceId = props.row.trace; if (!defined(traceId)) { return ; } return ( <_TraceIdRenderer {...props} traceId={traceId} transactionId={props.row['transaction.id'] ?? undefined} timestamp={props.row.timestamp} /> ); } interface TraceIdRendererProps extends FieldRendererProps { traceId: string; timestamp?: DateString; transactionId?: string; } function _TraceIdRenderer({traceId, timestamp, transactionId}: TraceIdRendererProps) { const organization = useOrganization(); const {selection} = usePageFilters(); const stringOrNumberTimestamp = timestamp instanceof Date ? timestamp.toISOString() : timestamp ?? ''; const target = getTraceDetailsUrl( organization, traceId, { start: selection.datetime.start, end: selection.datetime.end, statsPeriod: selection.datetime.period, }, {}, stringOrNumberTimestamp, transactionId ); return ( {getShortEventId(traceId)} ); } function TransactionIdRenderer(props: FieldRendererProps) { const projectSlug = props.row.project; const transactionId = props.row['transaction.id']; if (!defined(projectSlug) || !defined(transactionId)) { return ; } return ( <_TransactionIdRenderer {...props} projectSlug={projectSlug} transactionId={transactionId} /> ); } interface TransactionIdRendererProps extends FieldRendererProps { projectSlug: string; transactionId: string; } function _TransactionIdRenderer({ projectSlug, transactionId, }: TransactionIdRendererProps) { const organization = useOrganization(); const target = getTransactionDetailsUrl( organization.slug, `${projectSlug}:${transactionId}`, undefined, undefined ); return {getShortEventId(transactionId)}; } function TransactionRenderer(props: FieldRendererProps) { const projectSlug = props.row.project; const transaction = props.row.transaction; if (!defined(projectSlug) || !defined(transaction)) { return ; } return ( <_TransactionRenderer {...props} projectSlug={projectSlug} transaction={transaction} /> ); } interface TransactionRendererProps { projectSlug: string; transaction: string; } function _TransactionRenderer({projectSlug, transaction}: TransactionRendererProps) { const location = useLocation(); const organization = useOrganization(); const {projects} = useProjects({slugs: [projectSlug]}); const target = transactionSummaryRouteWithQuery({ orgSlug: organization.slug, transaction, query: { ...location.query, query: undefined, }, projectID: String(projects[0]?.id ?? ''), }); return ( {transaction} ); } function TimestampRenderer(props: FieldRendererProps) { const location = useLocation(); const timestamp = props.row.timestamp; if (!defined(timestamp)) { return ; } const utc = decodeScalar(location?.query?.utc) === 'true'; return ; } function SpanDurationRenderer(props: FieldRendererProps) { const duration = props.row['span.duration']; if (!defined(duration)) { return ; } return ; } function SpanSelfTimeRenderer(props: FieldRendererProps) { const duration = props.row['span.duration']; if (!defined(duration)) { return ; } return ; }