useSamplingProjectRates.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import type {Client} from 'sentry/api';
  2. import type {Organization} from 'sentry/types/organization';
  3. import parseLinkHeader from 'sentry/utils/parseLinkHeader';
  4. import {
  5. type ApiQueryKey,
  6. useMutation,
  7. useQuery,
  8. useQueryClient,
  9. } from 'sentry/utils/queryClient';
  10. import type RequestError from 'sentry/utils/requestError/requestError';
  11. import useApi from 'sentry/utils/useApi';
  12. import useOrganization from 'sentry/utils/useOrganization';
  13. interface SamplingProjectRate {
  14. id: number;
  15. sampleRate: number;
  16. }
  17. function getEndpoint(organization: Organization) {
  18. return `/organizations/${organization.slug}/sampling/project-rates/`;
  19. }
  20. function getQueryKey(organization: Organization): ApiQueryKey {
  21. return [getEndpoint(organization)];
  22. }
  23. /**
  24. * Fetches all sampling rates for the organization by looping through
  25. * the paginated results.
  26. */
  27. const fetchAllSamplingRates = async (
  28. api: Client,
  29. organization: Organization
  30. ): Promise<SamplingProjectRate[]> => {
  31. const endpoint = getEndpoint(organization);
  32. let cursor: string | null = '';
  33. let result: SamplingProjectRate[] = [];
  34. while (cursor !== null) {
  35. const [data, _, response] = await api.requestPromise(endpoint, {
  36. method: 'GET',
  37. includeAllArgs: true,
  38. query: {cursor},
  39. });
  40. result = result.concat(data);
  41. cursor = null;
  42. const linkHeader = response?.getResponseHeader('Link');
  43. if (linkHeader) {
  44. const links = parseLinkHeader(linkHeader);
  45. cursor = (links.next.results && links.next.cursor) || null;
  46. }
  47. }
  48. return result;
  49. };
  50. export function useGetSamplingProjectRates() {
  51. const api = useApi();
  52. const organization = useOrganization();
  53. return useQuery<SamplingProjectRate[]>({
  54. queryKey: getQueryKey(organization),
  55. queryFn: () => fetchAllSamplingRates(api, organization),
  56. staleTime: 0,
  57. });
  58. }
  59. export function useUpdateSamplingProjectRates() {
  60. const api = useApi();
  61. const queryClient = useQueryClient();
  62. const organization = useOrganization();
  63. return useMutation<SamplingProjectRate[], RequestError, SamplingProjectRate[]>({
  64. mutationFn: variables => {
  65. return api.requestPromise(getEndpoint(organization), {
  66. method: 'PUT',
  67. data: variables,
  68. });
  69. },
  70. onSuccess: data => {
  71. const queryKey = getQueryKey(organization);
  72. const previous = queryClient.getQueryData<SamplingProjectRate[]>(queryKey);
  73. if (!previous) {
  74. return;
  75. }
  76. const newDataById = data.reduce(
  77. (acc, item) => {
  78. acc[item.id] = item;
  79. return acc;
  80. },
  81. {} as Record<number, SamplingProjectRate>
  82. );
  83. queryClient.setQueryData(
  84. queryKey,
  85. previous.map(item => {
  86. const newItem = newDataById[item.id];
  87. if (newItem) {
  88. return newItem;
  89. }
  90. return item;
  91. })
  92. );
  93. },
  94. onSettled: () => {
  95. queryClient.invalidateQueries({queryKey: getQueryKey(organization)});
  96. },
  97. });
  98. }