Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions static/app/constants/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,20 @@ export const DATA_CATEGORY_INFO = {
showExternalStats: true,
},
},
[DataCategoryExact.SEER_USER]: {
name: DataCategoryExact.SEER_USER,
plural: DataCategory.SEER_USER,
singular: 'seerUser',
displayName: 'seer user',
titleName: t('Seer'),
productName: t('Seer'),
uid: 34,
isBilledCategory: true,
statsInfo: {
...DEFAULT_STATS_INFO,
showExternalStats: false, // TODO(seer): add external stats when ready
},
},
} as const satisfies Record<DataCategoryExact, DataCategoryInfo>;

// SmartSearchBar settings
Expand Down
2 changes: 2 additions & 0 deletions static/app/types/core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export enum DataCategory {
LOG_BYTE = 'logBytes',
SEER_AUTOFIX = 'seerAutofix',
SEER_SCANNER = 'seerScanner',
SEER_USER = 'seerUsers',
PREVENT_USER = 'preventUsers',
PREVENT_REVIEW = 'preventReviews',
USER_REPORT_V2 = 'feedback',
Expand Down Expand Up @@ -126,6 +127,7 @@ export enum DataCategoryExact {
LOG_BYTE = 'log_byte',
SEER_AUTOFIX = 'seer_autofix',
SEER_SCANNER = 'seer_scanner',
SEER_USER = 'seer_user',
PREVENT_USER = 'prevent_user',
PREVENT_REVIEW = 'prevent_review',
USER_REPORT_V2 = 'feedback',
Expand Down
16 changes: 9 additions & 7 deletions static/gsAdmin/components/changePlanAction.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {MetricHistoryFixture} from 'getsentry-test/fixtures/metricHistory';
import {PlanDetailsLookupFixture} from 'getsentry-test/fixtures/planDetailsLookup';
import {
SubscriptionFixture,
SubscriptionWithSeerFixture,
SubscriptionWithLegacySeerFixture,
} from 'getsentry-test/fixtures/subscription';
import {
renderGlobalModal,
Expand Down Expand Up @@ -268,17 +268,19 @@ describe('ChangePlanAction', () => {
await selectEvent.select(screen.getByRole('textbox', {name: 'Logs (GB)'}), '5');

expect(screen.getByText('Available Products')).toBeInTheDocument();
await userEvent.click(screen.getByText('Seer'));
await userEvent.click(screen.getByText('Prevent'));
const seerSelections = screen.getAllByText('Seer');
expect(seerSelections).toHaveLength(2);
await userEvent.click(seerSelections[0]!);
await userEvent.click(seerSelections[1]!);

expect(screen.getByRole('button', {name: 'Change Plan'})).toBeEnabled();
await userEvent.click(screen.getByRole('button', {name: 'Change Plan'}));

expect(putMock).toHaveBeenCalled();
const requestData = putMock.mock.calls[0][1].data;
expect(requestData).toHaveProperty('plan', 'am3_business');
expect(requestData).toHaveProperty('addOnLegacySeer', true);
expect(requestData).toHaveProperty('addOnSeer', true);
expect(requestData).toHaveProperty('addOnPrevent', true);
});

it('updates plan list when switching between tiers', async () => {
Expand Down Expand Up @@ -447,7 +449,7 @@ describe('ChangePlanAction', () => {

it('initializes Seer budget checkbox based on current subscription', async () => {
// Create subscription with Seer budget
const subscriptionWithSeer = SubscriptionWithSeerFixture({
const subscriptionWithSeer = SubscriptionWithLegacySeerFixture({
organization: mockOrg,
planTier: PlanTier.AM3,
plan: 'am3_business',
Expand Down Expand Up @@ -543,7 +545,7 @@ describe('ChangePlanAction', () => {
// Verify the PUT API was called with seer parameter
expect(putMock).toHaveBeenCalled();
const requestData = putMock.mock.calls[0][1].data;
expect(requestData).toHaveProperty('addOnSeer', true);
expect(requestData).toHaveProperty('addOnLegacySeer', true);
});

it('does not include add-on parameter in form submission when checkbox is unchecked', async () => {
Expand Down Expand Up @@ -595,7 +597,7 @@ describe('ChangePlanAction', () => {
// Verify the PUT API was called with seer parameter set to false
expect(putMock).toHaveBeenCalled();
const requestData = putMock.mock.calls[0][1].data;
expect(requestData).toHaveProperty('addOnSeer', false);
expect(requestData).toHaveProperty('addOnLegacySeer', false);
});
});
});
4 changes: 2 additions & 2 deletions static/gsAdmin/components/customers/customerOverview.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {SeerReservedBudgetFixture} from 'getsentry-test/fixtures/reservedBudget'
import {
InvoicedSubscriptionFixture,
SubscriptionFixture,
SubscriptionWithSeerFixture,
SubscriptionWithLegacySeerFixture,
} from 'getsentry-test/fixtures/subscription';
import {
render,
Expand Down Expand Up @@ -307,7 +307,7 @@ describe('CustomerOverview', () => {

it('renders reserved budget data', () => {
const organization = OrganizationFixture();
const subscription = SubscriptionWithSeerFixture({organization});
const subscription = SubscriptionWithLegacySeerFixture({organization});
subscription.reservedBudgets = [
SeerReservedBudgetFixture({
totalReservedSpend: 20_00,
Expand Down
6 changes: 3 additions & 3 deletions static/gsApp/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,11 @@ export const BILLED_DATA_CATEGORY_INFO = {
),
shortenedUnitName: 'GB',
},
[DataCategoryExact.PREVENT_USER]: {
...DEFAULT_BILLED_DATA_CATEGORY_INFO[DataCategoryExact.PREVENT_USER],
[DataCategoryExact.SEER_USER]: {
...DEFAULT_BILLED_DATA_CATEGORY_INFO[DataCategoryExact.SEER_USER],
feature: 'seer-user-billing',
canProductTrial: true,
maxAdminGift: 10_000, // TODO(prevent): Update this to the actual max admin gift
maxAdminGift: 10_000, // TODO(seer): Update this to the actual max admin gift
tallyType: 'seat',
},
} as const satisfies Record<DataCategoryExact, BilledDataCategoryInfo>;
1 change: 0 additions & 1 deletion static/gsApp/types/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ export type ReservedBudgetCategory = {

export enum AddOnCategory {
SEER = 'seer',
PREVENT = 'prevent',
LEGACY_SEER = 'legacySeer',
}

Expand Down
20 changes: 7 additions & 13 deletions static/gsApp/utils/billing.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import moment from 'moment-timezone';

import type {PromptData} from 'sentry/actionCreators/prompts';
import {IconBuilding, IconGroup, IconPrevent, IconSeer, IconUser} from 'sentry/icons';
import {IconBuilding, IconGroup, IconSeer, IconUser} from 'sentry/icons';
import {DataCategory} from 'sentry/types/core';
import type {Organization} from 'sentry/types/organization';
import {defined} from 'sentry/utils';
Expand Down Expand Up @@ -589,14 +589,10 @@ export function getPlanIcon(plan: Plan) {
}

export function getProductIcon(product: AddOnCategory, size?: IconSize) {
switch (product) {
case AddOnCategory.SEER:
return <IconSeer size={size} />;
case AddOnCategory.PREVENT:
return <IconPrevent size={size} />;
default:
return null;
if ([AddOnCategory.LEGACY_SEER, AddOnCategory.SEER].includes(product)) {
return <IconSeer size={size} />;
}
return null;
}

/**
Expand Down Expand Up @@ -783,12 +779,10 @@ export function hasSomeBillingDetails(billingDetails: BillingDetails | undefined
}

export function getReservedBudgetCategoryForAddOn(addOnCategory: AddOnCategory) {
switch (addOnCategory) {
case AddOnCategory.SEER:
return ReservedBudgetCategoryType.SEER;
default:
return null;
if (addOnCategory === AddOnCategory.LEGACY_SEER) {
return ReservedBudgetCategoryType.SEER;
}
return null;
}

// There are the data categories whose retention settings
Expand Down
6 changes: 3 additions & 3 deletions static/gsApp/views/amCheckout/components/cart.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ describe('Cart', () => {
},
onDemandMaxSpend: 50_00,
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: true,
},
},
Expand All @@ -165,7 +165,7 @@ describe('Cart', () => {
expect(planItem).toHaveTextContent('Continuous profile hours');
expect(planItem).toHaveTextContent('Available');

const seerItem = screen.getByTestId('summary-item-product-seer');
const seerItem = screen.getByTestId('summary-item-product-legacySeer');
expect(seerItem).toHaveTextContent('Seer');
expect(seerItem).toHaveTextContent('$216/yr');

Expand Down Expand Up @@ -496,7 +496,7 @@ describe('Cart', () => {
sharedMaxBudget: 1_00,
},
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: true,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('CartDiff', () => {
sharedMaxBudget: 100_00,
},
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: true,
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ describe('CheckoutOverview', () => {
plan: 'am2_team',
reserved: {errors: 100000, transactions: 500000, attachments: 25},
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: true,
},
},
Expand All @@ -197,7 +197,7 @@ describe('CheckoutOverview', () => {
/>
);

expect(screen.getByTestId('seer-reserved')).toBeInTheDocument();
expect(screen.getByTestId('legacySeer-reserved')).toBeInTheDocument();
expect(screen.getByText('Seer')).toBeInTheDocument();
});

Expand All @@ -207,7 +207,7 @@ describe('CheckoutOverview', () => {
plan: 'am2_team',
reserved: {errors: 100000, transactions: 500000, attachments: 25},
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: false,
},
},
Expand All @@ -224,7 +224,7 @@ describe('CheckoutOverview', () => {
/>
);

expect(screen.queryByTestId('seer')).not.toBeInTheDocument();
expect(screen.queryByTestId('legacySeer-reserved')).not.toBeInTheDocument();
expect(screen.queryByText('Seer')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('CheckoutOverviewV2', () => {
},
onDemandMaxSpend: 5000,
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: true,
},
},
Expand All @@ -97,7 +97,7 @@ describe('CheckoutOverviewV2', () => {
/>
);

expect(screen.getByTestId('seer-reserved')).toHaveTextContent('Seer$216/yr');
expect(screen.getByTestId('legacySeer-reserved')).toHaveTextContent('Seer$216/yr');
expect(screen.getByText('Total Annual Charges')).toBeInTheDocument();
expect(screen.getByText('$312/yr')).toBeInTheDocument();
expect(screen.getByTestId('additional-monthly-charge')).toHaveTextContent(
Expand Down Expand Up @@ -179,7 +179,7 @@ describe('CheckoutOverviewV2', () => {
},
onDemandMaxSpend: 5000,
addOns: {
[AddOnCategory.SEER]: {
[AddOnCategory.LEGACY_SEER]: {
enabled: false,
},
},
Expand All @@ -196,7 +196,7 @@ describe('CheckoutOverviewV2', () => {
/>
);

expect(screen.queryByTestId('seer-reserved')).not.toBeInTheDocument();
expect(screen.queryByTestId('legacySeer-reserved')).not.toBeInTheDocument();
});

it('does not show add-on when not included in formData', () => {
Expand Down Expand Up @@ -226,6 +226,6 @@ describe('CheckoutOverviewV2', () => {
/>
);

expect(screen.queryByTestId('seer-reserved')).not.toBeInTheDocument();
expect(screen.queryByTestId('legacySeer-reserved')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ function ScheduledChanges({
</Flex>
)}
{products.map(item => {
const addOn = utils.invoiceItemTypeToAddOn(item.type);
const addOn = utils.reservedInvoiceItemTypeToAddOn(item.type);
if (!addOn) {
return null;
}
Expand Down Expand Up @@ -515,7 +515,7 @@ function CheckoutSuccess({
const reservedVolume = invoiceItems.filter(
item => item.type.startsWith('reserved_') && !item.type.endsWith('_budget')
);
// TODO(prevent): This needs to be updated once we determine how to display Prevent enablement and PAYG changes on this page
// TODO(seer): This needs to be updated once we determine how to display Seer enablement and PAYG changes on this page
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: New Seer product excluded from checkout success add-ons list

The products filter explicitly restricts items to reserved_seer_budget, causing the new reserved_seer_users invoice item type to be excluded from the add-ons list. This forces the new Seer product to be rendered as a generic volume item instead of using the updated add-on presentation logic in reservedInvoiceItemTypeToAddOn.

Fix in Cursor Fix in Web

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine for now since we haven't finalized what it's going to look like in the success page (see TODO)

const products = invoiceItems.filter(item => item.type === 'reserved_seer_budget');
const onDemandItems = getOnDemandItems({invoiceItems});
const fees = getFees({invoiceItems});
Expand Down
4 changes: 2 additions & 2 deletions static/gsApp/views/amCheckout/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {BillingConfigFixture} from 'getsentry-test/fixtures/billingConfig';
import {MetricHistoryFixture} from 'getsentry-test/fixtures/metricHistory';
import {
SubscriptionFixture,
SubscriptionWithSeerFixture,
SubscriptionWithLegacySeerFixture,
} from 'getsentry-test/fixtures/subscription';
import {
act,
Expand Down Expand Up @@ -1119,7 +1119,7 @@ describe('AM2 Checkout', () => {

it('skips step 1 for business plan with seer', async () => {
const seerOrg = OrganizationFixture({features: ['seer-billing']});
const seerSubscription = SubscriptionWithSeerFixture({
const seerSubscription = SubscriptionWithLegacySeerFixture({
organization: seerOrg,
planTier: 'am2',
plan: 'am2_business',
Expand Down
Loading
Loading