From 2bfd0a1ca1e1189c75dc799d937eb15800306b90 Mon Sep 17 00:00:00 2001 From: Alberto Leal Date: Fri, 29 Nov 2024 17:03:42 -0500 Subject: [PATCH 1/2] feat(billing): Add profile chunks to usage stats page --- static/app/constants/index.tsx | 10 ++++++++++ static/app/types/core.tsx | 1 + static/app/views/organizationStats/index.spec.tsx | 14 +++++++++++++- static/app/views/organizationStats/index.tsx | 5 +++++ .../views/organizationStats/usageChart/index.tsx | 6 ++++++ 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/static/app/constants/index.tsx b/static/app/constants/index.tsx index 0d6200f2773da9..71c91e6f6cbbbb 100644 --- a/static/app/constants/index.tsx +++ b/static/app/constants/index.tsx @@ -368,6 +368,16 @@ export const DATA_CATEGORY_INFO = { uid: 17, isBilledCategory: false, // TODO(Continuous Profiling GA): make true for launch to show spend notification toggle }, + [DataCategoryExact.PROFILE_CHUNK]: { + name: DataCategoryExact.PROFILE_CHUNK, + apiName: 'profile_chunk', + plural: 'profileChunks', + displayName: 'profile chunk', + titleName: t('Profile Chunks'), + productName: t('Continuous Profiling'), + uid: 18, + isBilledCategory: false, + }, } as const satisfies Record; // Special Search characters diff --git a/static/app/types/core.tsx b/static/app/types/core.tsx index 02d726c4fd5a7a..8f4c0c0c8e42b3 100644 --- a/static/app/types/core.tsx +++ b/static/app/types/core.tsx @@ -102,6 +102,7 @@ export enum DataCategoryExact { PROFILE_DURATION = 'profileDuration', SPAN = 'span', SPAN_INDEXED = 'span_indexed', + PROFILE_CHUNK = 'profileChunk', } export interface DataCategoryInfo { diff --git a/static/app/views/organizationStats/index.spec.tsx b/static/app/views/organizationStats/index.spec.tsx index 19a929190da3a3..ac1945f15f788f 100644 --- a/static/app/views/organizationStats/index.spec.tsx +++ b/static/app/views/organizationStats/index.spec.tsx @@ -435,6 +435,10 @@ describe('OrganizationStats', function () { expect(screen.getByRole('option', {name: 'Profile Hours'})).toBeInTheDocument(); // Should not show Profiles (transaction) option expect(screen.queryByRole('option', {name: 'Profiles'})).not.toBeInTheDocument(); + // Should not show Profile Chunks option + expect( + screen.queryByRole('option', {name: 'Profile Chunks'}) + ).not.toBeInTheDocument(); }); it('shows both profile hours and profiles categories with continuous-profiling feature', async () => { @@ -454,6 +458,8 @@ describe('OrganizationStats', function () { expect(screen.getByRole('option', {name: 'Profile Hours'})).toBeInTheDocument(); // Should show Profiles (transaction) option expect(screen.queryByRole('option', {name: 'Profiles'})).toBeInTheDocument(); + // Should show Profile Chunks option + expect(screen.getByRole('option', {name: 'Profile Chunks'})).toBeInTheDocument(); }); it('shows only profile duration category when both profiling features are enabled', async () => { @@ -478,6 +484,8 @@ describe('OrganizationStats', function () { expect(screen.getByRole('option', {name: 'Profile Hours'})).toBeInTheDocument(); // Should not show Profiles (transaction) option expect(screen.queryByRole('option', {name: 'Profiles'})).not.toBeInTheDocument(); + // Should show Profile Chunks option + expect(screen.getByRole('option', {name: 'Profile Chunks'})).toBeInTheDocument(); }); it('shows only Profiles category without profiling features', async () => { @@ -493,10 +501,14 @@ describe('OrganizationStats', function () { await userEvent.click(await screen.findByText('Category')); - // Should show Profile Hours option + // Should not show Profile Hours option expect(screen.queryByRole('option', {name: 'Profile Hours'})).not.toBeInTheDocument(); // Should show Profiles (transaction) option expect(screen.getByRole('option', {name: 'Profiles'})).toBeInTheDocument(); + // Should not show Profile Chunks option + expect( + screen.queryByRole('option', {name: 'Profile Chunks'}) + ).not.toBeInTheDocument(); }); }); diff --git a/static/app/views/organizationStats/index.tsx b/static/app/views/organizationStats/index.tsx index ad91859c178895..3dc4dd5355e191 100644 --- a/static/app/views/organizationStats/index.tsx +++ b/static/app/views/organizationStats/index.tsx @@ -245,6 +245,8 @@ export class OrganizationStats extends Component { const isSelfHostedErrorsOnly = ConfigStore.get('isSelfHostedErrorsOnly'); + // Some data categories are not applicable to some subscription plans. + // So we filter them out depending on if the organization has the necessary features. const options = CHART_OPTIONS_DATACATEGORY.filter(opt => { if (isSelfHostedErrorsOnly) { return opt.value === DATA_CATEGORY_INFO.error.plural; @@ -264,6 +266,9 @@ export class OrganizationStats extends Component { organization.features.includes('continuous-profiling') ); } + if (DATA_CATEGORY_INFO.profileChunk.plural === opt.value) { + return organization.features.includes('continuous-profiling'); + } if (DATA_CATEGORY_INFO.profile.plural === opt.value) { return !organization.features.includes('continuous-profiling-stats'); } diff --git a/static/app/views/organizationStats/usageChart/index.tsx b/static/app/views/organizationStats/usageChart/index.tsx index 02daeb9f36225c..d5573499021bc1 100644 --- a/static/app/views/organizationStats/usageChart/index.tsx +++ b/static/app/views/organizationStats/usageChart/index.tsx @@ -86,6 +86,12 @@ export const CHART_OPTIONS_DATACATEGORY: CategoryOption[] = [ disabled: false, yAxisMinInterval: 100, }, + { + label: DATA_CATEGORY_INFO.profileChunk.titleName, + value: DATA_CATEGORY_INFO.profileChunk.plural, + disabled: false, + yAxisMinInterval: 100, + }, ]; export enum ChartDataTransform { From 997920cf4ea12ca18bac20aa9f042787aed2ad55 Mon Sep 17 00:00:00 2001 From: Alberto Leal Date: Fri, 29 Nov 2024 17:08:17 -0500 Subject: [PATCH 2/2] update CODEOWNERS --- .github/CODEOWNERS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 933b585b428c33..e7bd27f2d51e06 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -584,8 +584,10 @@ tests/sentry/api/endpoints/test_organization_dashboard_widget_details.py @ge /tests/snuba/search/ @getsentry/issues ## End of Issues -## Billing -/src/sentry/api/endpoints/check_am2_compatibility.py @getsentry/revenue +## Billing/Revenue +/src/sentry/api/endpoints/check_am2_compatibility.py @getsentry/revenue +/static/app/views/organizationStats @getsentry/revenue +## End of Billing/Revenue ## ML & AI *autofix*.py @getsentry/machine-learning-ai