useExploreTimeseries.tsx 3.3 KB

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