transactionDurationChart.tsx 4.0 KB

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