Просмотр исходного кода

feat(configurable-thresholds): Use project thresholds in project details and releases (#26564)

Use the new project level thresholds for orgs that have the
feature flag enabled. The rest will still use the organization
apdexThreshold.
Shruthi 3 лет назад
Родитель
Сommit
48de1a333b

+ 13 - 3
static/app/views/projectDetail/projectCharts.tsx

@@ -277,6 +277,16 @@ class ProjectCharts extends Component<Props, State> {
     const hasDiscover = organization.features.includes('discover-basic');
     const displayMode = this.displayMode;
 
+    let apdexYAxis: string;
+    let apdexPerformanceTerm: PERFORMANCE_TERM;
+    if (organization.features.includes('project-transaction-threshold')) {
+      apdexPerformanceTerm = PERFORMANCE_TERM.APDEX_NEW;
+      apdexYAxis = 'apdex()';
+    } else {
+      apdexPerformanceTerm = PERFORMANCE_TERM.APDEX;
+      apdexYAxis = `apdex(${organization.apdexThreshold})`;
+    }
+
     return (
       <Panel>
         <ChartContainer>
@@ -287,10 +297,10 @@ class ProjectCharts extends Component<Props, State> {
               {displayMode === DisplayModes.APDEX && (
                 <ProjectBaseEventsChart
                   title={t('Apdex')}
-                  help={getTermHelp(organization, PERFORMANCE_TERM.APDEX)}
+                  help={getTermHelp(organization, apdexPerformanceTerm)}
                   query="event.type:transaction"
-                  yAxis={`apdex(${organization.apdexThreshold})`}
-                  field={[`apdex(${organization.apdexThreshold})`]}
+                  yAxis={apdexYAxis}
+                  field={[apdexYAxis]}
                   api={api}
                   router={router}
                   organization={organization}

+ 22 - 8
static/app/views/projectDetail/projectScoreCards/projectApdexScoreCard.tsx

@@ -48,12 +48,16 @@ class ProjectApdexScoreCard extends AsyncComponent<Props, State> {
       return [];
     }
 
+    const apdexField = organization.features.includes('project-transaction-threshold')
+      ? 'apdex()'
+      : `apdex(${organization.apdexThreshold})`;
+
     const {projects, environments, datetime} = selection;
     const {period} = datetime;
     const commonQuery = {
       environment: environments,
       project: projects.map(proj => String(proj)),
-      field: [`apdex(${organization.apdexThreshold})`],
+      field: [apdexField],
       query: 'event.type:transaction count():>0',
     };
     const endpoints: ReturnType<AsyncComponent['getEndpoints']> = [
@@ -106,7 +110,13 @@ class ProjectApdexScoreCard extends AsyncComponent<Props, State> {
   }
 
   get cardHelp() {
-    const baseHelp = getTermHelp(this.props.organization, PERFORMANCE_TERM.APDEX);
+    const {organization} = this.props;
+    const performanceTerm = organization.features.includes(
+      'project-transaction-threshold'
+    )
+      ? PERFORMANCE_TERM.APDEX_NEW
+      : PERFORMANCE_TERM.APDEX;
+    const baseHelp = getTermHelp(this.props.organization, performanceTerm);
 
     if (this.trend) {
       return baseHelp + t(' This shows how it has changed since the last period.');
@@ -119,8 +129,11 @@ class ProjectApdexScoreCard extends AsyncComponent<Props, State> {
     const {organization} = this.props;
     const {currentApdex} = this.state;
 
-    const apdex =
-      currentApdex?.data[0]?.[getAggregateAlias(`apdex(${organization.apdexThreshold})`)];
+    const apdexField = organization.features.includes('project-transaction-threshold')
+      ? 'apdex()'
+      : `apdex(${organization.apdexThreshold})`;
+
+    const apdex = currentApdex?.data[0]?.[getAggregateAlias(apdexField)];
 
     return typeof apdex === 'undefined' ? undefined : Number(apdex);
   }
@@ -129,10 +142,11 @@ class ProjectApdexScoreCard extends AsyncComponent<Props, State> {
     const {organization} = this.props;
     const {previousApdex} = this.state;
 
-    const apdex =
-      previousApdex?.data[0]?.[
-        getAggregateAlias(`apdex(${organization.apdexThreshold})`)
-      ];
+    const apdexField = organization.features.includes('project-transaction-threshold')
+      ? 'apdex()'
+      : `apdex(${organization.apdexThreshold})`;
+
+    const apdex = previousApdex?.data[0]?.[getAggregateAlias(apdexField)];
 
     return typeof apdex === 'undefined' ? undefined : Number(apdex);
   }

+ 12 - 8
static/app/views/releases/detail/overview/releaseStats.tsx

@@ -99,6 +99,16 @@ function ReleaseStats({
     DisplayOption.USERS
   );
 
+  let apdexField: string;
+  let apdexPerformanceTerm: PERFORMANCE_TERM;
+  if (organization.features.includes('project-transaction-threshold')) {
+    apdexPerformanceTerm = PERFORMANCE_TERM.APDEX_NEW;
+    apdexField = 'apdex()';
+  } else {
+    apdexPerformanceTerm = PERFORMANCE_TERM.APDEX;
+    apdexField = `apdex(${organization.apdexThreshold})`;
+  }
+
   return (
     <Container>
       <div>
@@ -262,7 +272,7 @@ function ReleaseStats({
             {t('Apdex')}
             <QuestionTooltip
               position="top"
-              title={getTermHelp(organization, PERFORMANCE_TERM.APDEX)}
+              title={getTermHelp(organization, apdexPerformanceTerm)}
               size="sm"
             />
           </SectionHeading>
@@ -297,13 +307,7 @@ function ReleaseStats({
                         >
                           <Tooltip title={t('Open in Performance')}>
                             <Count
-                              value={
-                                tableData.data[0][
-                                  getAggregateAlias(
-                                    `apdex(${organization.apdexThreshold})`
-                                  )
-                                ]
-                              }
+                              value={tableData.data[0][getAggregateAlias(apdexField)]}
                             />
                           </Tooltip>
                         </GlobalSelectionLink>

+ 5 - 1
static/app/views/releases/detail/utils.tsx

@@ -108,11 +108,15 @@ export function getReleaseEventView(
   const {projects, environments, datetime} = selection;
   const {start, end, period} = datetime;
 
+  const apdexField = organization.features.includes('project-transaction-threshold')
+    ? 'apdex()'
+    : `apdex(${organization.apdexThreshold})`;
+
   const discoverQuery = {
     id: undefined,
     version: 2,
     name: `${t('Release Apdex')}`,
-    fields: [`apdex(${organization.apdexThreshold})`],
+    fields: [apdexField],
     query: stringifyQueryObject(
       new QueryResults([`release:${version}`, 'event.type:transaction', 'count():>0'])
     ),

+ 91 - 0
tests/js/spec/views/projectDetail/projectApdex.spec.jsx

@@ -0,0 +1,91 @@
+import {mountWithTheme} from 'sentry-test/enzyme';
+import {initializeOrg} from 'sentry-test/initializeOrg';
+
+import ProjectApdexScoreCard from 'app/views/projectDetail/projectScoreCards/projectApdexScoreCard';
+
+describe('ProjectDetail > ProjectApdex', function () {
+  let endpointMock;
+  const {organization} = initializeOrg({
+    organization: {
+      apdexThreshold: 500,
+    },
+  });
+
+  const selection = {
+    projects: [1],
+    environments: [],
+    datetime: {
+      period: '14d',
+    },
+  };
+
+  beforeEach(function () {
+    endpointMock = MockApiClient.addMockResponse({
+      url: `/organizations/${organization.slug}/eventsv2/`,
+      body: {
+        data: [],
+      },
+      status: 200,
+    });
+  });
+
+  afterEach(function () {
+    MockApiClient.clearMockResponses();
+  });
+
+  it('makes api calls with the correct params', function () {
+    organization.features = ['discover-basic', 'performance-view'];
+    mountWithTheme(
+      <ProjectApdexScoreCard
+        organization={organization}
+        selection={selection}
+        isProjectStabilized
+        hasTransactions
+      />
+    );
+
+    expect(endpointMock).toHaveBeenNthCalledWith(
+      1,
+      `/organizations/${organization.slug}/eventsv2/`,
+      expect.objectContaining({
+        query: {
+          environment: [],
+          field: ['apdex(500)'],
+          project: ['1'],
+          query: 'event.type:transaction count():>0',
+          statsPeriod: '14d',
+        },
+      })
+    );
+  });
+
+  it('calls api with new apdex if feature flag is enabled', function () {
+    organization.features = [
+      'discover-basic',
+      'performance-view',
+      'project-transaction-threshold',
+    ];
+    mountWithTheme(
+      <ProjectApdexScoreCard
+        organization={organization}
+        selection={selection}
+        isProjectStabilized
+        hasTransactions
+      />
+    );
+
+    expect(endpointMock).toHaveBeenNthCalledWith(
+      1,
+      `/organizations/${organization.slug}/eventsv2/`,
+      expect.objectContaining({
+        query: {
+          environment: [],
+          field: ['apdex()'],
+          project: ['1'],
+          query: 'event.type:transaction count():>0',
+          statsPeriod: '14d',
+        },
+      })
+    );
+  });
+});