useReleases.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import {getInterval} from 'sentry/components/charts/utils';
  2. import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
  3. import {Release} from 'sentry/types';
  4. import {defined} from 'sentry/utils';
  5. import {useApiQuery} from 'sentry/utils/queryClient';
  6. import {decodeScalar} from 'sentry/utils/queryString';
  7. import {useLocation} from 'sentry/utils/useLocation';
  8. import useOrganization from 'sentry/utils/useOrganization';
  9. import usePageFilters from 'sentry/utils/usePageFilters';
  10. export function useReleases(searchTerm?: string) {
  11. const organization = useOrganization();
  12. const {selection} = usePageFilters();
  13. const {environments, projects} = selection;
  14. return useApiQuery<Release[]>(
  15. [
  16. `/organizations/${organization.slug}/releases/`,
  17. {
  18. query: {
  19. sort: 'date',
  20. project: projects,
  21. per_page: 50,
  22. environment: environments,
  23. query: searchTerm,
  24. },
  25. },
  26. ],
  27. {staleTime: Infinity}
  28. );
  29. }
  30. export function useReleaseSelection() {
  31. const location = useLocation();
  32. const {data: releases, isLoading} = useReleases();
  33. const primaryRelease =
  34. decodeScalar(location.query.primaryRelease) ?? releases?.[0]?.version ?? undefined;
  35. const secondaryRelease =
  36. decodeScalar(location.query.secondaryRelease) ??
  37. (releases && releases.length > 1 ? releases?.[1]?.version : undefined);
  38. return {primaryRelease, secondaryRelease, isLoading};
  39. }
  40. export function useReleaseStats() {
  41. const organization = useOrganization();
  42. const {selection} = usePageFilters();
  43. const {environments, projects} = selection;
  44. const {start, end, statsPeriod} = normalizeDateTimeParams(selection.datetime, {
  45. allowEmptyPeriod: true,
  46. });
  47. // The sessions endpoint does not support wildcard search.
  48. // So we're just getting top 250 values ordered by count.
  49. // Hopefully this is enough to populate session count for
  50. // any releases searched in the release selector.
  51. const urlQuery = Object.fromEntries(
  52. Object.entries({
  53. project: projects,
  54. environment: environments,
  55. field: ['sum(session)'],
  56. groupBy: ['release', 'project'],
  57. orderBy: '-sum(session)',
  58. start,
  59. end,
  60. statsPeriod,
  61. per_page: 250,
  62. interval: getInterval({start, end, period: statsPeriod}, 'low'),
  63. }).filter(([, value]) => defined(value) && value !== '')
  64. );
  65. const result = useApiQuery<any>(
  66. [
  67. `/organizations/${organization.slug}/sessions/`,
  68. {
  69. query: urlQuery,
  70. },
  71. ],
  72. {staleTime: Infinity}
  73. );
  74. const releaseStatsMap: {[release: string]: {project: number; 'sum(session)': number}} =
  75. {};
  76. if (result.data && result.data.groups) {
  77. result.data.groups.forEach(group => {
  78. const release = group.by.release;
  79. const project = group.by.project;
  80. const sessionCount = group.totals['sum(session)'];
  81. releaseStatsMap[release] = {project, 'sum(session)': sessionCount};
  82. });
  83. }
  84. return {
  85. ...result,
  86. data: releaseStatsMap,
  87. };
  88. }