durationChartWithSamples.tsx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import type {ComponentProps} from 'react';
  2. import type {EChartHighlightHandler, Series} from 'sentry/types/echarts';
  3. import {AVG_COLOR} from 'sentry/views/insights/colors';
  4. import Chart, {ChartType} from 'sentry/views/insights/common/components/chart';
  5. import ChartPanel from 'sentry/views/insights/common/components/chartPanel';
  6. import {getDurationChartTitle} from 'sentry/views/insights/common/views/spans/types';
  7. import {CHART_HEIGHT} from 'sentry/views/insights/http/settings';
  8. interface Props {
  9. isLoading: boolean;
  10. series: Series[];
  11. error?: Error | null;
  12. onHighlight?: (highlights: Highlight[], event: Event) => void; // TODO: Correctly type this
  13. scatterPlot?: ComponentProps<typeof Chart>['scatterPlot'];
  14. }
  15. interface Highlight {
  16. dataPoint: Series['data'][number];
  17. series: Series[];
  18. }
  19. export function DurationChartWithSamples({
  20. series,
  21. scatterPlot,
  22. isLoading,
  23. error,
  24. onHighlight,
  25. }: Props) {
  26. // TODO: This is duplicated from `DurationChart` in `SampleList`. Resolve the duplication
  27. const handleChartHighlight: EChartHighlightHandler = function (event) {
  28. // ignore mouse hovering over the chart legend
  29. if (!event.batch) {
  30. return;
  31. }
  32. // 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
  33. const allSeries = [...series, ...(scatterPlot ?? [])];
  34. const highlightedDataPoints = event.batch.map((batch: any) => {
  35. let {seriesIndex} = batch;
  36. const {dataIndex} = batch;
  37. // TODO: More hacks. The Chart component partitions the data series into a complete and incomplete series. Wrap the series index to work around overflowing index.
  38. seriesIndex = seriesIndex % allSeries.length;
  39. const highlightedSeries = allSeries?.[seriesIndex];
  40. const highlightedDataPoint = highlightedSeries?.data?.[dataIndex];
  41. return {series: highlightedSeries, dataPoint: highlightedDataPoint};
  42. });
  43. onHighlight?.(highlightedDataPoints, event);
  44. };
  45. return (
  46. <ChartPanel title={getDurationChartTitle('http')}>
  47. <Chart
  48. height={CHART_HEIGHT}
  49. grid={{
  50. left: '0',
  51. right: '0',
  52. top: '8px',
  53. bottom: '0',
  54. }}
  55. data={series}
  56. onHighlight={handleChartHighlight}
  57. scatterPlot={scatterPlot}
  58. loading={isLoading}
  59. error={error}
  60. chartColors={[AVG_COLOR]}
  61. type={ChartType.LINE}
  62. aggregateOutputFormat="duration"
  63. />
  64. </ChartPanel>
  65. );
  66. }