useSamplingProjectRates.tsx 3.0 KB

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