spanSamplesTable.tsx 3.4 KB

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