useChartInterval.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import {useCallback, useMemo} from 'react';
  2. import type {Location} from 'history';
  3. import {
  4. FORTY_EIGHT_HOURS,
  5. getDiffInMinutes,
  6. GranularityLadder,
  7. ONE_WEEK,
  8. SIX_HOURS,
  9. THIRTY_DAYS,
  10. TWO_WEEKS,
  11. } from 'sentry/components/charts/utils';
  12. import {t} from 'sentry/locale';
  13. import type {PageFilters} from 'sentry/types/core';
  14. import {parsePeriodToHours} from 'sentry/utils/duration/parsePeriodToHours';
  15. import {decodeScalar} from 'sentry/utils/queryString';
  16. import {useLocation} from 'sentry/utils/useLocation';
  17. import {useNavigate} from 'sentry/utils/useNavigate';
  18. import usePageFilters from 'sentry/utils/usePageFilters';
  19. interface Options {
  20. location: Location;
  21. navigate: ReturnType<typeof useNavigate>;
  22. pagefilters: ReturnType<typeof usePageFilters>;
  23. }
  24. export function useChartInterval(): [
  25. string,
  26. (interval: string) => void,
  27. intervalOptions: Array<{label: string; value: string}>,
  28. ] {
  29. const location = useLocation();
  30. const navigate = useNavigate();
  31. const pagefilters = usePageFilters();
  32. const options = {location, navigate, pagefilters};
  33. return useChartIntervalImpl(options);
  34. }
  35. function useChartIntervalImpl({
  36. location,
  37. navigate,
  38. pagefilters,
  39. }: Options): [
  40. string,
  41. (interval: string) => void,
  42. intervalOptions: Array<{label: string; value: string}>,
  43. ] {
  44. const {datetime} = pagefilters.selection;
  45. const intervalOptions = useMemo(
  46. () => getIntervalOptionsForPageFilter(datetime),
  47. [datetime]
  48. );
  49. const interval: string = useMemo(() => {
  50. const decodedInterval = decodeScalar(location.query.interval);
  51. return decodedInterval &&
  52. intervalOptions.some(option => option.value === decodedInterval)
  53. ? decodedInterval
  54. : // Default to the second option so we're not defaulting to the smallest option
  55. intervalOptions[1]!.value;
  56. }, [location.query.interval, intervalOptions]);
  57. const setInterval = useCallback(
  58. (newInterval: string) => {
  59. navigate({
  60. ...location,
  61. query: {
  62. ...location.query,
  63. interval: newInterval,
  64. },
  65. });
  66. },
  67. [location, navigate]
  68. );
  69. return [interval, setInterval, intervalOptions];
  70. }
  71. const ALL_INTERVAL_OPTIONS = [
  72. {value: '1m', label: t('1 minute')},
  73. {value: '5m', label: t('5 minutes')},
  74. {value: '15m', label: t('15 minutes')},
  75. {value: '30m', label: t('30 minutes')},
  76. {value: '1h', label: t('1 hour')},
  77. {value: '3h', label: t('3 hours')},
  78. {value: '12h', label: t('12 hours')},
  79. {value: '1d', label: t('1 day')},
  80. ];
  81. /**
  82. * The minimum interval is chosen in such a way that there will be
  83. * at most 1000 data points per series for the chosen period.
  84. */
  85. const MINIMUM_INTERVAL = new GranularityLadder([
  86. [THIRTY_DAYS, '3h'],
  87. [TWO_WEEKS, '1h'],
  88. [ONE_WEEK, '30m'],
  89. [FORTY_EIGHT_HOURS, '15m'],
  90. [SIX_HOURS, '5m'],
  91. [0, '1m'],
  92. ]);
  93. const MAXIMUM_INTERVAL = new GranularityLadder([
  94. [THIRTY_DAYS, '1d'],
  95. [TWO_WEEKS, '1d'],
  96. [ONE_WEEK, '1d'],
  97. [FORTY_EIGHT_HOURS, '4h'],
  98. [SIX_HOURS, '1h'],
  99. [0, '15m'],
  100. ]);
  101. export function getIntervalOptionsForPageFilter(datetime: PageFilters['datetime']) {
  102. const diffInMinutes = getDiffInMinutes(datetime);
  103. const minimumOption = MINIMUM_INTERVAL.getInterval(diffInMinutes);
  104. const minimumOptionInHours = parsePeriodToHours(minimumOption);
  105. const maximumOption = MAXIMUM_INTERVAL.getInterval(diffInMinutes);
  106. const maximumOptionInHours = parsePeriodToHours(maximumOption);
  107. return ALL_INTERVAL_OPTIONS.filter(option => {
  108. const optionInHours = parsePeriodToHours(option.value);
  109. return optionInHours >= minimumOptionInHours && optionInHours <= maximumOptionInHours;
  110. });
  111. }