useMetricsMeta.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import {useMemo} from 'react';
  2. import type {PageFilters} from 'sentry/types/core';
  3. import {formatMRI, getUseCaseFromMRI} from 'sentry/utils/metrics/mri';
  4. import type {ApiQueryKey} from 'sentry/utils/queryClient';
  5. import {useApiQueries} from 'sentry/utils/queryClient';
  6. import useOrganization from 'sentry/utils/useOrganization';
  7. import type {MetricMeta, MRI, UseCase} from '../../types/metrics';
  8. const DEFAULT_USE_CASES: UseCase[] = ['sessions', 'transactions', 'custom', 'spans'];
  9. export function getMetricsMetaQueryKey(
  10. orgSlug: string,
  11. {projects}: Partial<PageFilters>,
  12. useCase?: UseCase[]
  13. ): ApiQueryKey {
  14. const queryParams = projects?.length ? {useCase, project: projects} : {useCase};
  15. return [`/organizations/${orgSlug}/metrics/meta/`, {query: queryParams}];
  16. }
  17. export function useMetricsMeta(
  18. pageFilters: Partial<PageFilters>,
  19. useCases: UseCase[] = DEFAULT_USE_CASES,
  20. filterBlockedMetrics = true,
  21. enabled: boolean = true
  22. ): {data: MetricMeta[]; isLoading: boolean; isRefetching: boolean; refetch: () => void} {
  23. const {slug} = useOrganization();
  24. const queryKeys = useMemo(() => {
  25. return useCases.map(useCase => getMetricsMetaQueryKey(slug, pageFilters, [useCase]));
  26. }, [slug, pageFilters, useCases]);
  27. const results = useApiQueries<MetricMeta[]>(queryKeys, {
  28. enabled,
  29. staleTime: 2000, // 2 seconds to cover page load
  30. });
  31. const {data, isLoading, isRefetching, refetch} = useMemo(() => {
  32. const mergedResult: {
  33. data: MetricMeta[];
  34. isLoading: boolean;
  35. isRefetching: boolean;
  36. refetch: () => void;
  37. } = {
  38. data: [],
  39. isLoading: false,
  40. isRefetching: false,
  41. refetch: () => {
  42. results.forEach(result => result.refetch());
  43. },
  44. };
  45. for (const useCaseResult of results) {
  46. mergedResult.isLoading ||= useCaseResult.isLoading;
  47. mergedResult.isRefetching ||= useCaseResult.isRefetching;
  48. const useCaseData = useCaseResult.data ?? [];
  49. mergedResult.data.push(...useCaseData);
  50. }
  51. return mergedResult;
  52. }, [results]);
  53. const meta = (data ?? []).sort((a, b) =>
  54. formatMRI(a.mri).localeCompare(formatMRI(b.mri))
  55. );
  56. if (!filterBlockedMetrics) {
  57. return {data: meta, isLoading, isRefetching, refetch};
  58. }
  59. return {
  60. data: data.filter(entry => {
  61. return entry.blockingStatus?.every(({isBlocked}) => !isBlocked) ?? true;
  62. }),
  63. isLoading,
  64. isRefetching,
  65. refetch,
  66. };
  67. }
  68. export function useProjectMetric(mri: MRI, projectId: number) {
  69. const useCase = getUseCaseFromMRI(mri);
  70. const res = useMetricsMeta({projects: [projectId]}, [useCase ?? 'custom'], false);
  71. const metricMeta = res.data?.find(({mri: metaMri}) => metaMri === mri);
  72. const blockingStatus = metricMeta?.blockingStatus?.[0];
  73. return {...res, data: {...metricMeta, blockingStatus}};
  74. }