transactionDurationChart.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {t} from 'sentry/locale';
  2. import type {EChartHighlightHandler, Series} 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 type {DataRow} from 'sentry/views/insights/cache/components/tables/spanSamplesTable';
  7. import {Referrer} from 'sentry/views/insights/cache/referrers';
  8. import {CHART_HEIGHT} from 'sentry/views/insights/cache/settings';
  9. import {AVG_COLOR} from 'sentry/views/insights/colors';
  10. import Chart, {ChartType} from 'sentry/views/insights/common/components/chart';
  11. import ChartPanel from 'sentry/views/insights/common/components/chartPanel';
  12. import {useMetricsSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries';
  13. import {AverageValueMarkLine} from 'sentry/views/insights/common/utils/averageValueMarkLine';
  14. import {DataTitles} from 'sentry/views/insights/common/views/spans/types';
  15. import {useSampleScatterPlotSeries} from 'sentry/views/insights/common/views/spanSummaryPage/sampleList/durationChart/useSampleScatterPlotSeries';
  16. import type {MetricsQueryFilters} from 'sentry/views/insights/types';
  17. type Props = {
  18. averageTransactionDuration: number;
  19. onHighlight: EChartHighlightHandler;
  20. samples: DataRow[];
  21. highlightedSpanId?: string;
  22. };
  23. export function TransactionDurationChart({
  24. samples,
  25. averageTransactionDuration,
  26. onHighlight,
  27. highlightedSpanId,
  28. }: Props) {
  29. const {transaction} = useLocationQuery({
  30. fields: {
  31. project: decodeScalar,
  32. transaction: decodeScalar,
  33. },
  34. });
  35. const search: MetricsQueryFilters = {
  36. transaction,
  37. };
  38. const {data, isLoading} = useMetricsSeries(
  39. {
  40. yAxis: ['avg(transaction.duration)'],
  41. search: MutableSearch.fromQueryObject(search),
  42. },
  43. Referrer.SAMPLES_CACHE_TRANSACTION_DURATION_CHART
  44. );
  45. const sampledSpanDataSeries = useSampleScatterPlotSeries(
  46. samples,
  47. averageTransactionDuration,
  48. highlightedSpanId,
  49. 'transaction.duration'
  50. );
  51. // TODO: This is duplicated from `DurationChart` in `SampleList`. Resolve the duplication
  52. const handleChartHighlight: EChartHighlightHandler = function (event) {
  53. // 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
  54. const allSeries = [
  55. data['avg(transaction.duration)'],
  56. ...(sampledSpanDataSeries ?? []),
  57. ];
  58. const highlightedDataPoints = event.batch.map(batch => {
  59. const {seriesIndex, dataIndex} = batch;
  60. const highlightedSeries = allSeries?.[seriesIndex];
  61. const highlightedDataPoint = highlightedSeries.data?.[dataIndex];
  62. return {series: highlightedSeries, dataPoint: highlightedDataPoint};
  63. });
  64. onHighlight?.(highlightedDataPoints, event);
  65. };
  66. const baselineAvgSeries: Series = {
  67. seriesName: 'Average',
  68. data: [],
  69. markLine: AverageValueMarkLine({
  70. value: averageTransactionDuration,
  71. }),
  72. };
  73. return (
  74. <ChartPanel title={DataTitles['transaction.duration']}>
  75. <Chart
  76. height={CHART_HEIGHT}
  77. grid={{
  78. left: '0',
  79. right: '0',
  80. top: '8px',
  81. bottom: '0',
  82. }}
  83. scatterPlot={sampledSpanDataSeries}
  84. data={[
  85. {
  86. seriesName: t('Average Transaction Duration'),
  87. data: data['avg(transaction.duration)'].data,
  88. },
  89. baselineAvgSeries,
  90. ]}
  91. aggregateOutputFormat="duration"
  92. loading={isLoading}
  93. onHighlight={handleChartHighlight}
  94. chartColors={[AVG_COLOR]}
  95. type={ChartType.LINE}
  96. />
  97. </ChartPanel>
  98. );
  99. }