useReleases.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import chunk from 'lodash/chunk';
  2. import type {NewQuery, Release} from 'sentry/types';
  3. import type {TableData} from 'sentry/utils/discover/discoverQuery';
  4. import EventView from 'sentry/utils/discover/eventView';
  5. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  6. import type {ApiQueryKey} from 'sentry/utils/queryClient';
  7. import {useApiQuery, useQueries} from 'sentry/utils/queryClient';
  8. import {decodeScalar} from 'sentry/utils/queryString';
  9. import {escapeFilterValue} from 'sentry/utils/tokenizeSearch';
  10. import useApi from 'sentry/utils/useApi';
  11. import {useLocation} from 'sentry/utils/useLocation';
  12. import useOrganization from 'sentry/utils/useOrganization';
  13. import usePageFilters from 'sentry/utils/usePageFilters';
  14. export function useReleases(searchTerm?: string) {
  15. const organization = useOrganization();
  16. const location = useLocation();
  17. const {selection, isReady} = usePageFilters();
  18. const {environments, projects} = selection;
  19. const api = useApi();
  20. const releaseResults = useApiQuery<Release[]>(
  21. [
  22. `/organizations/${organization.slug}/releases/`,
  23. {
  24. query: {
  25. project: projects,
  26. per_page: 50,
  27. environment: environments,
  28. query: searchTerm,
  29. sort: 'date',
  30. },
  31. },
  32. ],
  33. {staleTime: Infinity, enabled: isReady, retry: false}
  34. );
  35. const chunks = releaseResults.data?.length ? chunk(releaseResults.data, 10) : [];
  36. const releaseMetrics = useQueries({
  37. queries: chunks.map(releases => {
  38. const newQuery: NewQuery = {
  39. name: '',
  40. fields: ['release', 'count()'],
  41. query: `transaction.op:ui.load ${escapeFilterValue(
  42. `release:[${releases.map(r => `"${r.version}"`).join()}]`
  43. )}`,
  44. dataset: DiscoverDatasets.METRICS,
  45. version: 2,
  46. projects: selection.projects,
  47. };
  48. const eventView = EventView.fromNewQueryWithPageFilters(newQuery, selection);
  49. const queryKey = [
  50. `/organizations/${organization.slug}/events/`,
  51. {
  52. query: {
  53. ...eventView.getEventsAPIPayload(location),
  54. referrer: 'api.starfish.mobile-release-selector',
  55. },
  56. },
  57. ] as ApiQueryKey;
  58. return {
  59. queryKey,
  60. queryFn: () =>
  61. api.requestPromise(queryKey[0], {
  62. method: 'GET',
  63. query: queryKey[1]?.query,
  64. }) as Promise<TableData>,
  65. staleTime: Infinity,
  66. enabled: isReady && !releaseResults.isLoading,
  67. retry: false,
  68. };
  69. }),
  70. });
  71. const metricsFetched = releaseMetrics.every(result => result.isFetched);
  72. const metricsStats: {[version: string]: {count: number}} = {};
  73. if (metricsFetched) {
  74. releaseMetrics.forEach(c =>
  75. c.data?.data?.forEach(release => {
  76. metricsStats[release.release] = {count: release['count()'] as number};
  77. })
  78. );
  79. }
  80. const releaseStats: {
  81. dateCreated: string;
  82. version: string;
  83. count?: number;
  84. }[] =
  85. releaseResults.data?.length && metricsFetched
  86. ? releaseResults.data.flatMap(release => {
  87. const releaseVersion = release.version;
  88. const dateCreated = release.dateCreated;
  89. if (metricsStats[releaseVersion]?.count) {
  90. return {
  91. dateCreated,
  92. version: releaseVersion,
  93. count: metricsStats[releaseVersion]?.count,
  94. };
  95. }
  96. return [];
  97. })
  98. : [];
  99. return {
  100. ...releaseResults,
  101. data: releaseStats,
  102. isLoading: !metricsFetched || releaseResults.isLoading,
  103. };
  104. }
  105. export function useReleaseSelection(): {
  106. isLoading: boolean;
  107. primaryRelease: string | undefined;
  108. secondaryRelease: string | undefined;
  109. } {
  110. const location = useLocation();
  111. const {data: releases, isLoading} = useReleases();
  112. // If there are more than 1 release, the first one should be the older one
  113. const primaryRelease =
  114. decodeScalar(location.query.primaryRelease) ??
  115. (releases && releases.length > 1 ? releases?.[1]?.version : releases?.[0]?.version);
  116. // If there are more than 1 release, the second one should be the newest one
  117. const secondaryRelease =
  118. decodeScalar(location.query.secondaryRelease) ??
  119. (releases && releases.length > 1 ? releases?.[0]?.version : undefined);
  120. return {primaryRelease, secondaryRelease, isLoading};
  121. }