Browse Source

feat(settings-metrics): Add extrapolate metrics field (#73287)

Priscila Oliveira 3 days ago
parent
commit
03fcab02fa

+ 2 - 1
static/app/types/project.tsx

@@ -23,6 +23,7 @@ export type Project = {
   eventProcessing: {
     symbolicationDegraded: boolean;
   };
+  extrapolateMetrics: boolean;
   features: string[];
   firstEvent: string | null;
   firstTransactionEvent: boolean;
@@ -52,8 +53,8 @@ export type Project = {
   isMember: boolean;
   name: string;
   organization: Organization;
-  plugins: Plugin[];
 
+  plugins: Plugin[];
   processingIssues: number;
   relayCustomMetricCardinalityLimit: number | null;
   relayPiiConfig: string;

+ 4 - 0
static/app/utils/metrics/features.tsx

@@ -17,6 +17,10 @@ export function hasCustomMetricsExtractionRules(organization: Organization) {
   return organization.features.includes('custom-metrics-extraction-rule');
 }
 
+export function hasMetricsExtrapolationFeature(organization: Organization) {
+  return organization.features.includes('metrics-extrapolation');
+}
+
 /**
  * Returns the forceMetricsLayer query param for the alert
  * wrapped in an object so it can be spread into existing query params

+ 76 - 0
static/app/views/settings/projectMetrics/extrapolationField.tsx

@@ -0,0 +1,76 @@
+import {useEffect, useState} from 'react';
+
+import {
+  addErrorMessage,
+  addLoadingMessage,
+  addSuccessMessage,
+} from 'sentry/actionCreators/indicator';
+import BooleanField from 'sentry/components/forms/fields/booleanField';
+import ExternalLink from 'sentry/components/links/externalLink';
+import Panel from 'sentry/components/panels/panel';
+import PanelBody from 'sentry/components/panels/panelBody';
+import {t, tct} from 'sentry/locale';
+import ProjectsStore from 'sentry/stores/projectsStore';
+import type {Project} from 'sentry/types/project';
+import {useMutation} from 'sentry/utils/queryClient';
+import type RequestError from 'sentry/utils/requestError/requestError';
+import useApi from 'sentry/utils/useApi';
+import useOrganization from 'sentry/utils/useOrganization';
+
+interface ExtrapolationFieldProps {
+  project: Project;
+}
+
+export function ExtrapolationField({project}: ExtrapolationFieldProps) {
+  const organization = useOrganization();
+  const api = useApi();
+
+  const [isToggleEnabled, setIsToggleEnabled] = useState(!!project.extrapolateMetrics);
+
+  // Reload from props if new project state is received
+  useEffect(() => {
+    setIsToggleEnabled(!!project.extrapolateMetrics);
+  }, [project.extrapolateMetrics]);
+
+  const {mutate: handleToggleChange} = useMutation<Project, RequestError, boolean>({
+    mutationFn: value => {
+      return api.requestPromise(`/projects/${organization.slug}/${project.slug}/`, {
+        method: 'PUT',
+        data: {
+          extrapolateMetrics: value,
+        },
+      });
+    },
+    onMutate: () => {
+      addLoadingMessage(t('Toggling metrics extrapolation'));
+    },
+    onSuccess: updatedProject => {
+      addSuccessMessage(t('Successfully toggled metrics extrapolation'));
+      ProjectsStore.onUpdateSuccess(updatedProject);
+    },
+    onError: () => {
+      addErrorMessage(t('Failed to toggle metrics extrapolation'));
+    },
+  });
+
+  return (
+    <Panel>
+      <PanelBody>
+        <BooleanField
+          onChange={handleToggleChange}
+          value={isToggleEnabled}
+          name="metrics-extrapolation-toggle"
+          disabled={!project.access.includes('project:write')} // admin, manager and owner of an organization will be able to edit this field
+          label={t('Metrics Extrapolation')}
+          help={tct(
+            'Enables metrics extrapolation from sampled data, providing more reliable and comprehensive metrics for your project. To learn more about metrics extrapolation, [link:read the docs]',
+            {
+              // TODO(telemetry-experience): Add link to metrics extrapolation docs when available
+              link: <ExternalLink href="https://docs.sentry.io/product/metrics/" />,
+            }
+          )}
+        />
+      </PanelBody>
+    </Panel>
+  );
+}

+ 9 - 1
static/app/views/settings/projectMetrics/projectMetrics.tsx

@@ -9,7 +9,10 @@ import {t, tct} from 'sentry/locale';
 import type {Organization} from 'sentry/types/organization';
 import type {Project} from 'sentry/types/project';
 import {METRICS_DOCS_URL} from 'sentry/utils/metrics/constants';
-import {hasCustomMetricsExtractionRules} from 'sentry/utils/metrics/features';
+import {
+  hasCustomMetricsExtractionRules,
+  hasMetricsExtrapolationFeature,
+} from 'sentry/utils/metrics/features';
 import routeTitleGen from 'sentry/utils/routeTitle';
 import useOrganization from 'sentry/utils/useOrganization';
 import {useMetricsOnboardingSidebar} from 'sentry/views/metrics/ddmOnboarding/useMetricsOnboardingSidebar';
@@ -17,6 +20,7 @@ import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHea
 import TextBlock from 'sentry/views/settings/components/text/textBlock';
 import PermissionAlert from 'sentry/views/settings/project/permissionAlert';
 import {CustomMetricsTable} from 'sentry/views/settings/projectMetrics/customMetricsTable';
+import {ExtrapolationField} from 'sentry/views/settings/projectMetrics/extrapolationField';
 import {MetricsExtractionRulesTable} from 'sentry/views/settings/projectMetrics/metricsExtractionRulesTable';
 
 type Props = {
@@ -65,6 +69,10 @@ function ProjectMetrics({project}: Props) {
 
       <PermissionAlert project={project} />
 
+      {hasMetricsExtrapolationFeature(organization) ? (
+        <ExtrapolationField project={project} />
+      ) : null}
+
       {hasExtractionRules ? <MetricsExtractionRulesTable project={project} /> : null}
 
       {!hasExtractionRules || project.hasCustomMetrics ? (

+ 1 - 0
tests/js/fixtures/project.ts

@@ -59,6 +59,7 @@ export function ProjectFixture(params: Partial<Project> = {}): Project {
     sensitiveFields: [],
     subjectTemplate: '',
     verifySSL: false,
+    extrapolateMetrics: false,
     ...params,
   };
 }