spanTransactionsTable.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import {Fragment} from 'react';
  2. import * as qs from 'query-string';
  3. import GridEditable, {
  4. COL_WIDTH_UNDEFINED,
  5. GridColumnHeader,
  6. } from 'sentry/components/gridEditable';
  7. import Link from 'sentry/components/links/link';
  8. import Truncate from 'sentry/components/truncate';
  9. import {formatPercentage} from 'sentry/utils/formatters';
  10. import {useLocation} from 'sentry/utils/useLocation';
  11. import DurationCell from 'sentry/views/starfish/components/tableCells/durationCell';
  12. import ThroughputCell from 'sentry/views/starfish/components/tableCells/throughputCell';
  13. import {TimeSpentCell} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
  14. import type {IndexedSpan} from 'sentry/views/starfish/queries/types';
  15. import {
  16. SpanTransactionMetrics,
  17. useSpanTransactionMetrics,
  18. } from 'sentry/views/starfish/queries/useSpanTransactionMetrics';
  19. import {DataTitles} from 'sentry/views/starfish/views/spans/types';
  20. type Row = {
  21. metrics: SpanTransactionMetrics;
  22. transaction: string;
  23. };
  24. type Props = {
  25. span: Pick<IndexedSpan, 'group'>;
  26. onClickTransaction?: (row: Row) => void;
  27. openSidebar?: boolean;
  28. };
  29. export type Keys =
  30. | 'transaction'
  31. | 'p95(transaction.duration)'
  32. | 'time_spent_percentage(local)'
  33. | 'spm()';
  34. export type TableColumnHeader = GridColumnHeader<Keys>;
  35. export function SpanTransactionsTable({span, openSidebar, onClickTransaction}: Props) {
  36. const location = useLocation();
  37. const {data: spanTransactionMetrics, isLoading} = useSpanTransactionMetrics(span);
  38. const spanTransactionsWithMetrics = spanTransactionMetrics.map(row => {
  39. return {
  40. transaction: row.transaction,
  41. metrics: row,
  42. };
  43. });
  44. const renderHeadCell = (column: TableColumnHeader) => {
  45. return <span>{column.name}</span>;
  46. };
  47. const renderBodyCell = (column: TableColumnHeader, row: Row) => {
  48. return (
  49. <BodyCell
  50. span={span}
  51. column={column}
  52. row={row}
  53. openSidebar={openSidebar}
  54. onClickTransactionName={onClickTransaction}
  55. />
  56. );
  57. };
  58. return (
  59. <GridEditable
  60. isLoading={isLoading}
  61. data={spanTransactionsWithMetrics}
  62. columnOrder={COLUMN_ORDER}
  63. columnSortBy={[]}
  64. grid={{
  65. renderHeadCell,
  66. renderBodyCell,
  67. }}
  68. location={location}
  69. />
  70. );
  71. }
  72. type CellProps = {
  73. column: TableColumnHeader;
  74. row: Row;
  75. span: Pick<IndexedSpan, 'group'>;
  76. onClickTransactionName?: (row: Row) => void;
  77. openSidebar?: boolean;
  78. };
  79. function BodyCell({span, column, row, openSidebar, onClickTransactionName}: CellProps) {
  80. if (column.key === 'transaction') {
  81. return (
  82. <TransactionCell
  83. span={span}
  84. row={row}
  85. column={column}
  86. openSidebar={openSidebar}
  87. onClickTransactionName={onClickTransactionName}
  88. />
  89. );
  90. }
  91. if (column.key === 'p95(transaction.duration)') {
  92. return <DurationCell milliseconds={row.metrics?.['p95(span.duration)']} />;
  93. }
  94. if (column.key === 'spm()') {
  95. return <ThroughputCell throughputPerSecond={row.metrics?.['spm()']} />;
  96. }
  97. if (column.key === 'time_spent_percentage(local)') {
  98. return (
  99. <TimeSpentCell
  100. formattedTimeSpent={formatPercentage(
  101. row.metrics?.['time_spent_percentage(local)']
  102. )}
  103. totalSpanTime={row.metrics?.['sum(span.duration)']}
  104. />
  105. );
  106. }
  107. return <span>{row[column.key]}</span>;
  108. }
  109. function TransactionCell({span, column, row}: CellProps) {
  110. return (
  111. <Fragment>
  112. <Link
  113. to={`/starfish/span/${encodeURIComponent(span.group)}?${qs.stringify({
  114. transaction: row.transaction,
  115. })}`}
  116. >
  117. <Truncate value={row[column.key]} maxLength={75} />
  118. </Link>
  119. </Fragment>
  120. );
  121. }
  122. const COLUMN_ORDER: TableColumnHeader[] = [
  123. {
  124. key: 'transaction',
  125. name: 'In Endpoint',
  126. width: 500,
  127. },
  128. {
  129. key: 'spm()',
  130. name: DataTitles.throughput,
  131. width: COL_WIDTH_UNDEFINED,
  132. },
  133. {
  134. key: 'p95(transaction.duration)',
  135. name: DataTitles.p95,
  136. width: COL_WIDTH_UNDEFINED,
  137. },
  138. {
  139. key: 'time_spent_percentage(local)',
  140. name: DataTitles.timeSpent,
  141. width: COL_WIDTH_UNDEFINED,
  142. },
  143. ];