transactionDurationChart.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import {t} from 'sentry/locale';
  2. import type {EChartHighlightHandler} from 'sentry/types/echarts';
  3. import {decodeScalar} from 'sentry/utils/queryString';
  4. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  5. import useLocationQuery from 'sentry/utils/url/useLocationQuery';
  6. import {Referrer} from 'sentry/views/performance/cache/referrers';
  7. import {CHART_HEIGHT} from 'sentry/views/performance/cache/settings';
  8. import type {DataRow} from 'sentry/views/performance/cache/tables/spanSamplesTable';
  9. import {AVG_COLOR} from 'sentry/views/starfish/colors';
  10. import Chart, {ChartType} from 'sentry/views/starfish/components/chart';
  11. import ChartPanel from 'sentry/views/starfish/components/chartPanel';
  12. import {useMetricsSeries} from 'sentry/views/starfish/queries/useDiscoverSeries';
  13. import type {MetricsQueryFilters} from 'sentry/views/starfish/types';
  14. import {DataTitles} from 'sentry/views/starfish/views/spans/types';
  15. import {useSampleScatterPlotSeries} from 'sentry/views/starfish/views/spanSummaryPage/sampleList/durationChart/useSampleScatterPlotSeries';
  16. type Props = {
  17. averageTransactionDuration: number;
  18. onHighlight: EChartHighlightHandler;
  19. samples: DataRow[];
  20. highlightedSpanId?: string;
  21. };
  22. export function TransactionDurationChart({
  23. samples,
  24. averageTransactionDuration,
  25. onHighlight,
  26. highlightedSpanId,
  27. }: Props) {
  28. const {transaction} = useLocationQuery({
  29. fields: {
  30. project: decodeScalar,
  31. transaction: decodeScalar,
  32. },
  33. });
  34. const search: MetricsQueryFilters = {
  35. transaction,
  36. };
  37. const {data, isLoading} = useMetricsSeries(
  38. {
  39. yAxis: ['avg(transaction.duration)'],
  40. search: MutableSearch.fromQueryObject(search),
  41. },
  42. Referrer.SAMPLES_CACHE_TRANSACTION_DURATION_CHART
  43. );
  44. const sampledSpanDataSeries = useSampleScatterPlotSeries(
  45. samples,
  46. averageTransactionDuration,
  47. highlightedSpanId,
  48. 'transaction.duration'
  49. );
  50. // TODO: This is duplicated from `DurationChart` in `SampleList`. Resolve the duplication
  51. const handleChartHighlight: EChartHighlightHandler = function (event) {
  52. // TODO: Gross hack. Even though `scatterPlot` is a separate prop, it's just an array of `Series` that gets appended to the main series. To find the point that was hovered, we re-construct the correct series order. It would have been cleaner to just pass the scatter plot as its own, single series
  53. const allSeries = [
  54. data['avg(transaction.duration)'],
  55. ...(sampledSpanDataSeries ?? []),
  56. ];
  57. const highlightedDataPoints = event.batch.map(batch => {
  58. const {seriesIndex, dataIndex} = batch;
  59. const highlightedSeries = allSeries?.[seriesIndex];
  60. const highlightedDataPoint = highlightedSeries.data?.[dataIndex];
  61. return {series: highlightedSeries, dataPoint: highlightedDataPoint};
  62. });
  63. onHighlight?.(highlightedDataPoints, event);
  64. };
  65. return (
  66. <ChartPanel title={DataTitles['transaction.duration']}>
  67. <Chart
  68. height={CHART_HEIGHT}
  69. grid={{
  70. left: '0',
  71. right: '0',
  72. top: '8px',
  73. bottom: '0',
  74. }}
  75. scatterPlot={sampledSpanDataSeries}
  76. data={[
  77. {
  78. seriesName: t('Average Transaction Duration'),
  79. data: data['avg(transaction.duration)'].data,
  80. },
  81. ]}
  82. aggregateOutputFormat="duration"
  83. loading={isLoading}
  84. onHighlight={handleChartHighlight}
  85. chartColors={[AVG_COLOR]}
  86. type={ChartType.LINE}
  87. />
  88. </ChartPanel>
  89. );
  90. }