import styled from '@emotion/styled'; import {LinkButton} from 'sentry/components/button'; import type {GridColumnHeader} from 'sentry/components/gridEditable'; import GridEditable, {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable'; import Link from 'sentry/components/links/link'; import {Tooltip} from 'sentry/components/tooltip'; import {IconProfiling} from 'sentry/icons/iconProfiling'; import {t} from 'sentry/locale'; import {trackAnalytics} from 'sentry/utils/analytics'; import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls'; import normalizeUrl from 'sentry/utils/url/normalizeUrl'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import {DurationComparisonCell} from 'sentry/views/insights/common/components/samplesTable/common'; import {DurationCell} from 'sentry/views/insights/common/components/tableCells/durationCell'; import FilenameCell from 'sentry/views/insights/common/components/tableCells/filenameCell'; import ResourceSizeCell from 'sentry/views/insights/common/components/tableCells/resourceSizeCell'; import { OverflowEllipsisTextContainer, TextAlignRight, } from 'sentry/views/insights/common/components/textAlign'; import type {SpanSample} from 'sentry/views/insights/common/queries/useSpanSamples'; import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; import {type ModuleName, SpanMetricsField} from 'sentry/views/insights/types'; const {HTTP_RESPONSE_CONTENT_LENGTH, SPAN_DESCRIPTION} = SpanMetricsField; type Keys = | 'transaction_id' | 'span_id' | 'profile_id' | 'timestamp' | 'duration' | 'p95_comparison' | 'avg_comparison' | 'http.response_content_length' | 'span.description'; export type SamplesTableColumnHeader = GridColumnHeader; export const DEFAULT_COLUMN_ORDER: SamplesTableColumnHeader[] = [ { key: 'span_id', name: 'Span ID', width: COL_WIDTH_UNDEFINED, }, { key: 'duration', name: 'Span Duration', width: COL_WIDTH_UNDEFINED, }, { key: 'avg_comparison', name: 'Compared to Average', width: COL_WIDTH_UNDEFINED, }, ]; type SpanTableRow = { op: string; trace: string; transaction: { 'project.name': string; timestamp: string; 'transaction.duration': number; }; 'transaction.id': string; } & SpanSample; type Props = { avg: number; data: SpanTableRow[]; groupId: string; isLoading: boolean; moduleName: ModuleName; columnOrder?: SamplesTableColumnHeader[]; highlightedSpanId?: string; onMouseLeaveSample?: () => void; onMouseOverSample?: (sample: SpanSample) => void; source?: string; }; export function SpanSamplesTable({ groupId, isLoading, data, avg, moduleName, highlightedSpanId, onMouseLeaveSample, onMouseOverSample, columnOrder, source, }: Props) { const location = useLocation(); const organization = useOrganization(); const {view} = useDomainViewFilters(); function renderHeadCell(column: GridColumnHeader): React.ReactNode { if ( column.key === 'p95_comparison' || column.key === 'avg_comparison' || column.key === 'duration' || column.key === HTTP_RESPONSE_CONTENT_LENGTH ) { return ( {column.name} ); } return {column.name}; } function renderBodyCell(column: GridColumnHeader, row: SpanTableRow): React.ReactNode { if (column.key === 'transaction_id') { return ( {row['transaction.id'].slice(0, 8)} ); } if (column.key === 'span_id') { return ( trackAnalytics('performance_views.sample_spans.span_clicked', { organization, source: moduleName, }) } to={generateLinkToEventInTraceView({ eventId: row['transaction.id'], timestamp: row.timestamp, traceSlug: row.trace, projectSlug: row.project, organization, location: { ...location, query: { ...location.query, groupId, }, }, spanId: row.span_id, source, view, })} > {row.span_id} ); } if (column.key === HTTP_RESPONSE_CONTENT_LENGTH) { const size = parseInt(row[HTTP_RESPONSE_CONTENT_LENGTH], 10); return ; } if (column.key === SPAN_DESCRIPTION) { return ; } if (column.key === 'profile_id') { return ( {row.profile_id ? ( ) : (
(no value)
)}
); } if (column.key === 'duration') { return ; } if (column.key === 'avg_comparison') { return ( ); } return {row[column.key]}; } return ( sample.span_id === highlightedSpanId)} grid={{ renderHeadCell, renderBodyCell, }} /> ); } const IconWrapper = styled('div')` text-align: right; width: 100%; height: 26px; `;