projectsPreviewTable.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import {useMemo} from 'react';
  2. import {t} from 'sentry/locale';
  3. import {formatNumberWithDynamicDecimalPoints} from 'sentry/utils/number/formatNumberWithDynamicDecimalPoints';
  4. import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
  5. import {ProjectsTable} from 'sentry/views/settings/dynamicSampling/projectsTable';
  6. import {organizationSamplingForm} from 'sentry/views/settings/dynamicSampling/utils/organizationSamplingForm';
  7. import {balanceSampleRate} from 'sentry/views/settings/dynamicSampling/utils/rebalancing';
  8. import type {ProjectSampleCount} from 'sentry/views/settings/dynamicSampling/utils/useProjectSampleCounts';
  9. const {useFormField} = organizationSamplingForm;
  10. interface Props {
  11. isLoading: boolean;
  12. sampleCounts: ProjectSampleCount[];
  13. }
  14. export function ProjectsPreviewTable({isLoading, sampleCounts}: Props) {
  15. const {value: targetSampleRate, initialValue: initialTargetSampleRate} =
  16. useFormField('targetSampleRate');
  17. const debouncedTargetSampleRate = useDebouncedValue(
  18. targetSampleRate,
  19. // For longer lists we debounce the input to avoid too many re-renders
  20. sampleCounts.length > 100 ? 200 : 0
  21. );
  22. const balancingItems = useMemo(
  23. () =>
  24. sampleCounts.map(item => ({
  25. ...item,
  26. // Add properties to match the BalancingItem type of the balanceSampleRate function
  27. id: item.project.id,
  28. sampleRate: 1,
  29. })),
  30. [sampleCounts]
  31. );
  32. const {balancedItems} = useMemo(() => {
  33. const targetRate = Math.min(100, Math.max(0, Number(debouncedTargetSampleRate) || 0));
  34. return balanceSampleRate({
  35. targetSampleRate: targetRate / 100,
  36. items: balancingItems,
  37. });
  38. }, [debouncedTargetSampleRate, balancingItems]);
  39. const initialSampleRatesBySlug = useMemo(() => {
  40. const targetRate = Math.min(100, Math.max(0, Number(initialTargetSampleRate) || 0));
  41. const {balancedItems: initialBalancedItems} = balanceSampleRate({
  42. targetSampleRate: targetRate / 100,
  43. items: balancingItems,
  44. });
  45. return initialBalancedItems.reduce((acc, item) => {
  46. acc[item.id] = item.sampleRate;
  47. return acc;
  48. }, {});
  49. }, [initialTargetSampleRate, balancingItems]);
  50. const itemsWithFormattedNumbers = useMemo(() => {
  51. return balancedItems.map(item => ({
  52. ...item,
  53. sampleRate: formatNumberWithDynamicDecimalPoints(item.sampleRate * 100, 2),
  54. initialSampleRate: formatNumberWithDynamicDecimalPoints(
  55. initialSampleRatesBySlug[item.project.slug] * 100,
  56. 2
  57. ),
  58. }));
  59. }, [balancedItems, initialSampleRatesBySlug]);
  60. return (
  61. <ProjectsTable
  62. stickyHeaders
  63. emptyMessage={t('No active projects found in the selected period.')}
  64. isEmpty={!sampleCounts.length}
  65. isLoading={isLoading}
  66. items={itemsWithFormattedNumbers}
  67. />
  68. );
  69. }