messageSpanSamplesTable.tsx 4.2 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 {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
  15. import {SpanIdCell} from 'sentry/views/starfish/components/tableCells/spanIdCell';
  16. import type {IndexedResponse} from 'sentry/views/starfish/types';
  17. import {SpanIndexedField} from 'sentry/views/starfish/types';
  18. type DataRowKeys =
  19. | SpanIndexedField.PROJECT
  20. | SpanIndexedField.TRANSACTION_ID
  21. | SpanIndexedField.TRACE
  22. | SpanIndexedField.TIMESTAMP
  23. | SpanIndexedField.ID
  24. | SpanIndexedField.SPAN_DESCRIPTION
  25. | SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE
  26. | SpanIndexedField.MESSAGING_MESSAGE_RECEIVE_LATENCY
  27. | SpanIndexedField.MESSAGING_MESSAGE_ID
  28. | SpanIndexedField.TRACE_STATUS
  29. | SpanIndexedField.SPAN_DURATION;
  30. type ColumnKeys =
  31. | SpanIndexedField.ID
  32. | SpanIndexedField.MESSAGING_MESSAGE_ID
  33. | SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE
  34. | SpanIndexedField.TRACE_STATUS
  35. | SpanIndexedField.SPAN_DURATION;
  36. type DataRow = Pick<IndexedResponse, DataRowKeys>;
  37. type Column = GridColumnHeader<ColumnKeys>;
  38. const COLUMN_ORDER: Column[] = [
  39. {
  40. key: SpanIndexedField.ID,
  41. name: t('Span ID'),
  42. width: 150,
  43. },
  44. {
  45. key: SpanIndexedField.MESSAGING_MESSAGE_ID,
  46. name: t('Message ID'),
  47. width: COL_WIDTH_UNDEFINED,
  48. },
  49. {
  50. key: SpanIndexedField.SPAN_DURATION,
  51. name: t('Processing Time'),
  52. width: COL_WIDTH_UNDEFINED,
  53. },
  54. {
  55. key: SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE,
  56. name: t('Message Size'),
  57. width: COL_WIDTH_UNDEFINED,
  58. },
  59. {
  60. key: SpanIndexedField.TRACE_STATUS,
  61. name: t('Status'),
  62. width: COL_WIDTH_UNDEFINED,
  63. },
  64. ];
  65. interface Props {
  66. data: DataRow[];
  67. isLoading: boolean;
  68. error?: Error | null;
  69. highlightedSpanId?: string;
  70. meta?: EventsMetaType;
  71. onSampleMouseOut?: ComponentProps<typeof GridEditable>['onRowMouseOut'];
  72. onSampleMouseOver?: ComponentProps<typeof GridEditable>['onRowMouseOver'];
  73. }
  74. export function MessageSpanSamplesTable({
  75. data,
  76. isLoading,
  77. error,
  78. meta,
  79. onSampleMouseOver,
  80. onSampleMouseOut,
  81. highlightedSpanId,
  82. }: Props) {
  83. const location = useLocation();
  84. const organization = useOrganization();
  85. return (
  86. <GridEditable
  87. aria-label={t('Span Samples')}
  88. isLoading={isLoading}
  89. error={error}
  90. data={data}
  91. columnOrder={COLUMN_ORDER}
  92. columnSortBy={[]}
  93. grid={{
  94. renderHeadCell: col =>
  95. renderHeadCell({
  96. column: col,
  97. location,
  98. }),
  99. renderBodyCell: (column, row) =>
  100. renderBodyCell(column, row, meta, location, organization),
  101. }}
  102. highlightedRowKey={data.findIndex(row => row.span_id === highlightedSpanId)}
  103. onRowMouseOver={onSampleMouseOver}
  104. onRowMouseOut={onSampleMouseOut}
  105. location={location}
  106. />
  107. );
  108. }
  109. function renderBodyCell(
  110. column: Column,
  111. row: DataRow,
  112. meta: EventsMetaType | undefined,
  113. location: Location,
  114. organization: Organization
  115. ) {
  116. const key = column.key;
  117. if (row[key] === undefined) {
  118. return (
  119. <AlignRight>
  120. <NoValue>{' \u2014 '}</NoValue>
  121. </AlignRight>
  122. );
  123. }
  124. if (key === SpanIndexedField.ID) {
  125. return (
  126. <SpanIdCell
  127. projectSlug={row.project}
  128. traceId={row.trace}
  129. timestamp={row.timestamp}
  130. transactionId={row[SpanIndexedField.TRANSACTION_ID]}
  131. spanId={row[SpanIndexedField.ID]}
  132. />
  133. );
  134. }
  135. if (!meta?.fields) {
  136. return row[column.key];
  137. }
  138. const renderer = getFieldRenderer(column.key, meta.fields, false);
  139. return renderer(row, {
  140. location,
  141. organization,
  142. unit: meta.units?.[column.key],
  143. });
  144. }
  145. const AlignRight = styled('span')`
  146. text-align: right;
  147. `;
  148. const NoValue = styled('span')`
  149. color: ${p => p.theme.gray300};
  150. `;