useExploreTimeseries.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {useMemo} from 'react';
  2. import isEqual from 'lodash/isEqual';
  3. import {dedupeArray} from 'sentry/utils/dedupeArray';
  4. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  5. import usePrevious from 'sentry/utils/usePrevious';
  6. import {
  7. useExploreDataset,
  8. useExploreGroupBys,
  9. useExploreMode,
  10. useExploreSortBys,
  11. useExploreVisualizes,
  12. } from 'sentry/views/explore/contexts/pageParamsContext';
  13. import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode';
  14. import {formatSort} from 'sentry/views/explore/contexts/pageParamsContext/sortBys';
  15. import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
  16. import {useTopEvents} from 'sentry/views/explore/hooks/useTopEvents';
  17. import {useSortedTimeSeries} from 'sentry/views/insights/common/queries/useSortedTimeSeries';
  18. interface UseExploreTimeseriesOptions {
  19. enabled: boolean;
  20. query: string;
  21. }
  22. interface UseExploreTimeseriesResults {
  23. canUsePreviousResults: boolean;
  24. timeseriesResult: ReturnType<typeof useSortedTimeSeries>;
  25. }
  26. export function useExploreTimeseries({
  27. enabled,
  28. query,
  29. }: UseExploreTimeseriesOptions): UseExploreTimeseriesResults {
  30. const dataset = useExploreDataset();
  31. const groupBys = useExploreGroupBys();
  32. const mode = useExploreMode();
  33. const sortBys = useExploreSortBys();
  34. const visualizes = useExploreVisualizes();
  35. const [interval] = useChartInterval();
  36. const topEvents = useTopEvents();
  37. const fields: string[] = useMemo(() => {
  38. if (mode === Mode.SAMPLES) {
  39. return [];
  40. }
  41. return [...groupBys, ...visualizes.flatMap(visualize => visualize.yAxes)].filter(
  42. Boolean
  43. );
  44. }, [mode, groupBys, visualizes]);
  45. const orderby: string | string[] | undefined = useMemo(() => {
  46. if (!sortBys.length) {
  47. return undefined;
  48. }
  49. return sortBys.map(formatSort);
  50. }, [sortBys]);
  51. const yAxes = useMemo(() => {
  52. const deduped = dedupeArray(visualizes.flatMap(visualize => visualize.yAxes));
  53. deduped.sort();
  54. return deduped;
  55. }, [visualizes]);
  56. const options = useMemo(() => {
  57. const search = new MutableSearch(query);
  58. // Filtering out all spans with op like 'ui.interaction*' which aren't
  59. // embedded under transactions. The trace view does not support rendering
  60. // such spans yet.
  61. search.addFilterValues('!transaction.span_id', ['00']);
  62. return {
  63. search,
  64. yAxis: yAxes,
  65. interval,
  66. fields,
  67. orderby,
  68. topEvents,
  69. enabled,
  70. };
  71. }, [query, yAxes, interval, fields, orderby, topEvents, enabled]);
  72. const previousQuery = usePrevious(query);
  73. const previousOptions = usePrevious(options);
  74. const canUsePreviousResults = useMemo(() => {
  75. if (!isEqual(query, previousQuery)) {
  76. return false;
  77. }
  78. if (!isEqual(options.interval, previousOptions.interval)) {
  79. return false;
  80. }
  81. if (!isEqual(options.fields, previousOptions.fields)) {
  82. return false;
  83. }
  84. if (!isEqual(options.orderby, previousOptions.orderby)) {
  85. return false;
  86. }
  87. if (!isEqual(options.topEvents, previousOptions.topEvents)) {
  88. return false;
  89. }
  90. // The query we're using has remained the same except for the y axis.
  91. // This means we can re-use the previous results to prevent a loading state.
  92. return true;
  93. }, [query, previousQuery, options, previousOptions]);
  94. const timeseriesResult = useSortedTimeSeries(options, 'api.explorer.stats', dataset);
  95. return {timeseriesResult, canUsePreviousResults};
  96. }