spanSamplesTable.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import {CSSProperties} from 'react';
  2. import {Link} from 'react-router';
  3. import GridEditable, {GridColumnHeader} from 'sentry/components/gridEditable';
  4. import {useLocation} from 'sentry/utils/useLocation';
  5. import {DurationComparisonCell} from 'sentry/views/starfish/components/samplesTable/common';
  6. import DurationCell from 'sentry/views/starfish/components/tableCells/durationCell';
  7. import {
  8. OverflowEllipsisTextContainer,
  9. TextAlignRight,
  10. } from 'sentry/views/starfish/components/textAlign';
  11. import {SpanSample} from 'sentry/views/starfish/queries/useSpanSamples';
  12. type Keys =
  13. | 'transaction_id'
  14. | 'timestamp'
  15. | 'duration'
  16. | 'p95_comparison'
  17. | 'avg_comparison';
  18. type TableColumnHeader = GridColumnHeader<Keys>;
  19. const COLUMN_ORDER: TableColumnHeader[] = [
  20. {
  21. key: 'transaction_id',
  22. name: 'Event ID',
  23. width: 200,
  24. },
  25. {
  26. key: 'duration',
  27. name: 'Span Duration',
  28. width: 200,
  29. },
  30. {
  31. key: 'avg_comparison',
  32. name: 'Compared to Average',
  33. width: 200,
  34. },
  35. ];
  36. type SpanTableRow = {
  37. op: string;
  38. transaction: {
  39. id: string;
  40. 'project.name': string;
  41. timestamp: string;
  42. 'transaction.duration': number;
  43. };
  44. } & SpanSample;
  45. type Props = {
  46. avg: number;
  47. data: SpanTableRow[];
  48. isLoading: boolean;
  49. highlightedSpanId?: string;
  50. onMouseLeaveSample?: () => void;
  51. onMouseOverSample?: (sample: SpanSample) => void;
  52. };
  53. export function SpanSamplesTable({
  54. isLoading,
  55. data,
  56. avg,
  57. highlightedSpanId,
  58. onMouseLeaveSample,
  59. onMouseOverSample,
  60. }: Props) {
  61. const location = useLocation();
  62. function handleMouseOverBodyCell(row: SpanTableRow) {
  63. if (onMouseOverSample) {
  64. onMouseOverSample(row);
  65. }
  66. }
  67. function handleMouseLeave() {
  68. if (onMouseLeaveSample) {
  69. onMouseLeaveSample();
  70. }
  71. }
  72. function renderHeadCell(column: GridColumnHeader): React.ReactNode {
  73. if (
  74. column.key === 'p95_comparison' ||
  75. column.key === 'avg_comparison' ||
  76. column.key === 'duration'
  77. ) {
  78. return (
  79. <TextAlignRight>
  80. <OverflowEllipsisTextContainer>{column.name}</OverflowEllipsisTextContainer>
  81. </TextAlignRight>
  82. );
  83. }
  84. return <OverflowEllipsisTextContainer>{column.name}</OverflowEllipsisTextContainer>;
  85. }
  86. function renderBodyCell(column: GridColumnHeader, row: SpanTableRow): React.ReactNode {
  87. const shouldHighlight = row.span_id === highlightedSpanId;
  88. const commonProps = {
  89. style: (shouldHighlight ? {fontWeight: 'bold'} : {}) satisfies CSSProperties,
  90. onMouseEnter: () => handleMouseOverBodyCell(row),
  91. };
  92. if (column.key === 'transaction_id') {
  93. return (
  94. <Link
  95. to={`/performance/${row.project}:${row['transaction.id']}#span-${row.span_id}`}
  96. {...commonProps}
  97. >
  98. {row['transaction.id'].slice(0, 8)}
  99. </Link>
  100. );
  101. }
  102. if (column.key === 'duration') {
  103. return (
  104. <DurationCell containerProps={commonProps} milliseconds={row['span.self_time']} />
  105. );
  106. }
  107. if (column.key === 'avg_comparison') {
  108. return (
  109. <DurationComparisonCell
  110. containerProps={commonProps}
  111. duration={row['span.self_time']}
  112. compareToDuration={avg}
  113. />
  114. );
  115. }
  116. return <span {...commonProps}>{row[column.key]}</span>;
  117. }
  118. return (
  119. <div onMouseLeave={handleMouseLeave}>
  120. <GridEditable
  121. isLoading={isLoading}
  122. data={data}
  123. columnOrder={COLUMN_ORDER}
  124. columnSortBy={[]}
  125. grid={{
  126. renderHeadCell,
  127. renderBodyCell,
  128. }}
  129. location={location}
  130. />
  131. </div>
  132. );
  133. }