useReleases.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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}
  34. );
  35. const chunks =
  36. releaseResults.data && releaseResults.data.length
  37. ? chunk(releaseResults.data, 10)
  38. : [];
  39. const releaseMetrics = useQueries({
  40. queries: chunks.map(releases => {
  41. const newQuery: NewQuery = {
  42. name: '',
  43. fields: ['release', 'count()'],
  44. query: `transaction.op:ui.load ${escapeFilterValue(
  45. `release:[${releases.map(r => `"${r.version}"`).join()}]`
  46. )}`,
  47. dataset: DiscoverDatasets.METRICS,
  48. version: 2,
  49. projects: selection.projects,
  50. };
  51. const eventView = EventView.fromNewQueryWithPageFilters(newQuery, selection);
  52. const queryKey = [
  53. `/organizations/${organization.slug}/events/`,
  54. {
  55. query: {
  56. ...eventView.getEventsAPIPayload(location),
  57. referrer: 'api.starfish.mobile-release-selector',
  58. },
  59. },
  60. ] as ApiQueryKey;
  61. return {
  62. queryKey,
  63. queryFn: () =>
  64. api.requestPromise(queryKey[0], {
  65. method: 'GET',
  66. query: queryKey[1]?.query,
  67. }) as Promise<TableData>,
  68. ...{staleTime: Infinity, enabled: isReady && !releaseResults.isLoading},
  69. };
  70. }),
  71. });
  72. const metricsFetched = releaseMetrics.every(result => result.isFetched);
  73. const metricsStats: {[version: string]: {count: number}} = {};
  74. if (metricsFetched) {
  75. releaseMetrics.forEach(c =>
  76. c.data?.data?.forEach(release => {
  77. metricsStats[release.release] = {count: release['count()'] as number};
  78. })
  79. );
  80. }
  81. const releaseStats: {
  82. dateCreated: string;
  83. version: string;
  84. count?: number;
  85. }[] =
  86. releaseResults.data && releaseResults.data.length && metricsFetched
  87. ? releaseResults.data.flatMap(release => {
  88. const releaseVersion = release.version;
  89. const dateCreated = release.dateCreated;
  90. if (metricsStats[releaseVersion]?.count) {
  91. return {
  92. dateCreated,
  93. version: releaseVersion,
  94. count: metricsStats[releaseVersion]?.count,
  95. };
  96. }
  97. return [];
  98. })
  99. : [];
  100. return {
  101. ...releaseResults,
  102. data: releaseStats,
  103. isLoading: !metricsFetched || releaseResults.isLoading,
  104. };
  105. }
  106. export function useReleaseSelection(): {
  107. isLoading: boolean;
  108. primaryRelease: string | undefined;
  109. secondaryRelease: string | undefined;
  110. } {
  111. const location = useLocation();
  112. const {data: releases, isLoading} = useReleases();
  113. // If there are more than 1 release, the first one should be the older one
  114. const primaryRelease =
  115. decodeScalar(location.query.primaryRelease) ??
  116. (releases && releases.length > 1 ? releases?.[1]?.version : releases?.[0]?.version);
  117. // If there are more than 1 release, the second one should be the newest one
  118. const secondaryRelease =
  119. decodeScalar(location.query.secondaryRelease) ??
  120. (releases && releases.length > 1 ? releases?.[0]?.version : undefined);
  121. return {primaryRelease, secondaryRelease, isLoading};
  122. }