useMultiQueryTimeseries.tsx 3.4 KB

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