spanSamplesTable.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import type {ComponentProps} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {Location} from 'history';
  4. import GridEditable, {
  5. COL_WIDTH_UNDEFINED,
  6. type GridColumnHeader,
  7. } from 'sentry/components/gridEditable';
  8. import {t} from 'sentry/locale';
  9. import type {Organization} from 'sentry/types/organization';
  10. import type {EventsMetaType} from 'sentry/utils/discover/eventView';
  11. import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
  12. import {useLocation} from 'sentry/utils/useLocation';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import {CacheHitMissCell} from 'sentry/views/insights/cache/components/tables/cacheHitMissCell';
  15. import {renderHeadCell} from 'sentry/views/insights/common/components/tableCells/renderHeadCell';
  16. import {SpanIdCell} from 'sentry/views/insights/common/components/tableCells/spanIdCell';
  17. import type {SpanIndexedResponse} from 'sentry/views/insights/types';
  18. import {ModuleName, SpanIndexedField} from 'sentry/views/insights/types';
  19. import {TraceViewSources} from 'sentry/views/performance/newTraceDetails/traceMetadataHeader';
  20. type DataRowKeys =
  21. | SpanIndexedField.PROJECT
  22. | SpanIndexedField.TRANSACTION_ID
  23. | SpanIndexedField.TRACE
  24. | SpanIndexedField.TIMESTAMP
  25. | SpanIndexedField.ID
  26. | SpanIndexedField.SPAN_DESCRIPTION
  27. | SpanIndexedField.CACHE_HIT
  28. | SpanIndexedField.CACHE_ITEM_SIZE;
  29. type ColumnKeys =
  30. | SpanIndexedField.ID
  31. | SpanIndexedField.SPAN_DESCRIPTION
  32. | SpanIndexedField.CACHE_HIT
  33. | SpanIndexedField.CACHE_ITEM_SIZE
  34. | 'transaction.duration';
  35. export type DataRow = Pick<SpanIndexedResponse, DataRowKeys> & {
  36. 'transaction.duration': number;
  37. };
  38. type Column = GridColumnHeader<ColumnKeys>;
  39. const COLUMN_ORDER: Column[] = [
  40. {
  41. key: SpanIndexedField.ID,
  42. name: t('Span ID'),
  43. width: 150,
  44. },
  45. {
  46. key: SpanIndexedField.SPAN_DESCRIPTION,
  47. name: t('Span Description'),
  48. width: COL_WIDTH_UNDEFINED,
  49. },
  50. {
  51. key: 'transaction.duration',
  52. name: t('Transaction Duration'),
  53. width: COL_WIDTH_UNDEFINED,
  54. },
  55. {
  56. key: SpanIndexedField.CACHE_ITEM_SIZE,
  57. name: t('Value Size'),
  58. width: COL_WIDTH_UNDEFINED,
  59. },
  60. {
  61. key: SpanIndexedField.CACHE_HIT,
  62. name: t('Status'),
  63. width: COL_WIDTH_UNDEFINED,
  64. },
  65. ];
  66. interface Props {
  67. data: DataRow[];
  68. isLoading: boolean;
  69. error?: Error | null;
  70. highlightedSpanId?: string;
  71. meta?: EventsMetaType;
  72. onSampleMouseOut?: ComponentProps<typeof GridEditable>['onRowMouseOut'];
  73. onSampleMouseOver?: ComponentProps<typeof GridEditable>['onRowMouseOver'];
  74. }
  75. export function SpanSamplesTable({
  76. data,
  77. isLoading,
  78. error,
  79. meta,
  80. onSampleMouseOver,
  81. onSampleMouseOut,
  82. highlightedSpanId,
  83. }: Props) {
  84. const location = useLocation();
  85. const organization = useOrganization();
  86. return (
  87. <GridEditable
  88. aria-label={t('Span Samples')}
  89. isLoading={isLoading}
  90. error={error}
  91. data={data}
  92. columnOrder={COLUMN_ORDER}
  93. columnSortBy={[]}
  94. grid={{
  95. renderHeadCell: col =>
  96. renderHeadCell({
  97. column: col,
  98. location,
  99. }),
  100. renderBodyCell: (column, row) =>
  101. renderBodyCell(column, row, meta, location, organization),
  102. }}
  103. highlightedRowKey={data.findIndex(row => row.span_id === highlightedSpanId)}
  104. onRowMouseOver={onSampleMouseOver}
  105. onRowMouseOut={onSampleMouseOut}
  106. />
  107. );
  108. }
  109. function renderBodyCell(
  110. column: Column,
  111. row: DataRow,
  112. meta: EventsMetaType | undefined,
  113. location: Location,
  114. organization: Organization
  115. ) {
  116. if (column.key === SpanIndexedField.ID) {
  117. return (
  118. <SpanIdCell
  119. moduleName={ModuleName.CACHE}
  120. projectSlug={row.project}
  121. traceId={row.trace}
  122. timestamp={row.timestamp}
  123. transactionId={row[SpanIndexedField.TRANSACTION_ID]}
  124. spanId={row[SpanIndexedField.ID]}
  125. source={TraceViewSources.CACHES_MODULE}
  126. location={location}
  127. />
  128. );
  129. }
  130. if (column.key === SpanIndexedField.SPAN_DESCRIPTION) {
  131. return (
  132. <SpanDescriptionCell>{row[SpanIndexedField.SPAN_DESCRIPTION]}</SpanDescriptionCell>
  133. );
  134. }
  135. if (column.key === SpanIndexedField.CACHE_HIT) {
  136. return <CacheHitMissCell hit={row[column.key]} />;
  137. }
  138. if (!meta?.fields) {
  139. return row[column.key];
  140. }
  141. const renderer = getFieldRenderer(column.key, meta.fields, false);
  142. return renderer(row, {
  143. location,
  144. organization,
  145. unit: meta.units?.[column.key],
  146. });
  147. }
  148. const SpanDescriptionCell = styled('span')`
  149. word-break: break-word;
  150. `;