import type {CSSProperties} from 'react'; import {Fragment} from 'react'; import styled from '@emotion/styled'; import DateTime from 'sentry/components/dateTime'; import type {GridColumnHeader} from 'sentry/components/gridEditable'; import GridEditable, {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable'; import Link from 'sentry/components/links/link'; import QuestionTooltip from 'sentry/components/questionTooltip'; import {t} from 'sentry/locale'; import type {NewQuery} from 'sentry/types'; import EventView from 'sentry/utils/discover/eventView'; import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers'; import {SPAN_OP_RELATIVE_BREAKDOWN_FIELD} from 'sentry/utils/discover/fields'; import {DiscoverDatasets} from 'sentry/utils/discover/types'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import {normalizeUrl} from 'sentry/utils/withDomainRequired'; import {DurationComparisonCell} from 'sentry/views/starfish/components/samplesTable/common'; import useErrorSamples from 'sentry/views/starfish/components/samplesTable/useErrorSamples'; import {DurationCell} from 'sentry/views/starfish/components/tableCells/durationCell'; import { OverflowEllipsisTextContainer, TextAlignLeft, TextAlignRight, } from 'sentry/views/starfish/components/textAlign'; import {DataTitles} from 'sentry/views/starfish/views/spans/types'; import type {SampleFilter} from 'sentry/views/starfish/views/webServiceView/endpointOverview'; type Keys = | 'id' | 'profile_id' | 'timestamp' | 'transaction.duration' | 'avg_comparison' | 'span_ops_breakdown.relative' | 'http.status_code' | 'transaction.status'; type TableColumnHeader = GridColumnHeader; type Props = { data: DataRow[]; isLoading: boolean; queryConditions: string[]; sampleFilter: SampleFilter; setHighlightedId: (string) => void; averageDuration?: number; highlightedId?: string; }; export type DataRow = { 'http.status_code': number; id: string; profile_id: string; 'spans.browser': number; 'spans.db': number; 'spans.http': number; 'spans.resource': number; 'spans.ui': number; timestamp: string; 'transaction.duration': number; 'transaction.status': string; }; export function TransactionSamplesTable({ queryConditions, sampleFilter, data, isLoading, averageDuration, setHighlightedId, highlightedId, }: Props) { const location = useLocation(); const organization = useOrganization(); const query = new MutableSearch(queryConditions); const savedQuery: NewQuery = { id: undefined, name: 'Endpoint Overview Samples', query: query.formatString(), fields: [], dataset: DiscoverDatasets.DISCOVER, version: 2, }; const columnOrder: TableColumnHeader[] = [ { key: 'id', name: 'Event ID', width: 100, }, ...(sampleFilter === 'ALL' ? [ { key: 'profile_id', name: 'Profile ID', width: 140, } as TableColumnHeader, { key: SPAN_OP_RELATIVE_BREAKDOWN_FIELD, name: 'Operation Duration', width: 180, } as TableColumnHeader, { key: 'timestamp', name: 'Timestamp', width: 230, } as TableColumnHeader, { key: 'transaction.duration', name: DataTitles.duration, width: 100, } as TableColumnHeader, { key: 'avg_comparison', name: 'Compared to Average', width: 100, } as TableColumnHeader, ] : [ { key: 'http.status_code', name: 'Response Code', width: COL_WIDTH_UNDEFINED, } as TableColumnHeader, { key: 'transaction.status', name: 'Status', width: COL_WIDTH_UNDEFINED, } as TableColumnHeader, { key: 'timestamp', name: 'Timestamp', width: 230, } as TableColumnHeader, ]), ]; const eventView = EventView.fromNewQueryWithLocation(savedQuery, location); const {isLoading: isErrorSamplesLoading, data: errorSamples} = useErrorSamples(eventView); function renderHeadCell(column: GridColumnHeader): React.ReactNode { if (column.key === 'avg_comparison' || column.key === 'transaction.duration') { return ( {column.name} ); } if (column.key === SPAN_OP_RELATIVE_BREAKDOWN_FIELD) { return ( {column.name} ); } return {column.name}; } function renderBodyCell(column: TableColumnHeader, row: DataRow): React.ReactNode { const commonProps = { style: (row.id === highlightedId ? {fontWeight: 'bold'} : {}) satisfies CSSProperties, onMouseEnter: () => setHighlightedId(row.id), }; if (column.key === 'id') { return ( {row.id.slice(0, 8)} ); } if (column.key === 'profile_id') { return row.profile_id ? ( {row.profile_id.slice(0, 8)} ) : (
(no value)
); } if (column.key === 'transaction.duration') { return ; } if (column.key === 'timestamp') { return ; } if (column.key === 'avg_comparison') { return ( ); } if (column.key === SPAN_OP_RELATIVE_BREAKDOWN_FIELD) { return getFieldRenderer(column.key, {})(row, { location, organization, eventView, }); } return {row[column.key]}; } return (
setHighlightedId(undefined)}>
); } const DurationComparisonContainer = styled('div')` text-align: right; width: 100%; display: inline-block; `; const StyledIconQuestion = styled(QuestionTooltip)` position: relative; left: 4px; `;