Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,150 +1,44 @@
import OptionSelector from 'sentry/components/charts/optionSelector';
import {ChartControls, InlineContainer} from 'sentry/components/charts/styles';
import {Container, Flex} from 'sentry/components/core/layout';
import {DrawerBody, DrawerHeader} from 'sentry/components/globalDrawer/components';
import {t} from 'sentry/locale';
import {DataCategory} from 'sentry/types/core';
import {useLocation} from 'sentry/utils/useLocation';
import {useNavigate} from 'sentry/utils/useNavigate';
import useOrganization from 'sentry/utils/useOrganization';
import {CHART_OPTIONS_DATA_TRANSFORM} from 'sentry/views/organizationStats/usageChart';

import {useProductBillingMetadata} from 'getsentry/hooks/useProductBillingMetadata';
import {
PlanTier,
type BillingMetricHistory,
type BillingStats,
type BillingStatTotal,
type CustomerUsage,
type Subscription,
} from 'getsentry/types';
import {addBillingStatTotals, isAm2Plan} from 'getsentry/utils/billing';
import {
getChunkCategoryFromDuration,
isContinuousProfiling,
} from 'getsentry/utils/dataCategory';
import trackGetsentryAnalytics from 'getsentry/utils/trackGetsentryAnalytics';
import {
ProductUsageChart,
selectedTransform,
} from 'getsentry/views/subscriptionPage/reservedUsageChart';
import {EMPTY_STAT_TOTAL} from 'getsentry/views/subscriptionPage/usageTotals';
import UsageTotalsTable from 'getsentry/views/subscriptionPage/usageTotalsTable';
import UsageCharts from 'getsentry/views/subscriptionPage/usageOverview/charts';

interface CategoryUsageDrawerProps {
categoryInfo: BillingMetricHistory;
eventTotals: Record<string, BillingStatTotal>;
periodEnd: string;
periodStart: string;
stats: BillingStats;
subscription: Subscription;
totals: BillingStatTotal;
usageData: CustomerUsage;
}

function CategoryUsageDrawer({
categoryInfo,
stats,
totals,
eventTotals,
subscription,
periodStart,
periodEnd,
usageData,
}: CategoryUsageDrawerProps) {
const organization = useOrganization();
const navigate = useNavigate();
const location = useLocation();
const transform = selectedTransform(location);
const {category, usage: billedUsage} = categoryInfo;
const {category} = categoryInfo;

// XXX(isabella): using this to make knip happy til the hook is used in other places
const {displayName} = useProductBillingMetadata(subscription, category);
const usageStats = {
[category]: stats,
};

const adjustedTotals = isContinuousProfiling(category)
? {
...addBillingStatTotals(totals, [
eventTotals[getChunkCategoryFromDuration(category)] ?? EMPTY_STAT_TOTAL,
!isAm2Plan(subscription.plan) && category === DataCategory.PROFILE_DURATION
? (eventTotals[DataCategory.PROFILES] ?? EMPTY_STAT_TOTAL)
: EMPTY_STAT_TOTAL,
]),
accepted: billedUsage,
}
: {...totals, accepted: billedUsage};

const renderFooter = () => {
return (
<ChartControls>
<InlineContainer>
<OptionSelector
title={t('Type')}
selected={transform}
options={CHART_OPTIONS_DATA_TRANSFORM}
onChange={(val: string) => {
trackGetsentryAnalytics(
'subscription_page.usage_overview.transform_changed',
{
organization,
subscription,
transform: val,
}
);
navigate({
pathname: location.pathname,
query: {...location.query, transform: val},
});
}}
/>
</InlineContainer>
</ChartControls>
);
};

const showEventBreakdown =
organization.features.includes('profiling-billing') &&
subscription.planTier === PlanTier.AM2 &&
category === DataCategory.TRANSACTIONS;

return (
<Container>
<DrawerHeader>
<Flex align="center">{displayName}</Flex>
</DrawerHeader>
<DrawerBody>
<ProductUsageChart
useDisplayModeTitle={false}
usageStats={usageStats}
shouldDisplayBudgetStats={false}
reservedBudgetCategoryInfo={{}}
displayMode="usage"
<UsageCharts
selectedProduct={category}
usageData={usageData}
subscription={subscription}
category={category}
transform={transform}
usagePeriodStart={periodStart}
usagePeriodEnd={periodEnd}
footer={renderFooter()}
organization={organization}
/>
<Flex direction="column" gap="xl">
<UsageTotalsTable
category={category}
totals={adjustedTotals}
subscription={subscription}
/>
{showEventBreakdown &&
Object.entries(eventTotals).map(([key, eventTotal]) => {
return (
<UsageTotalsTable
isEventBreakdown
key={key}
category={key as DataCategory}
totals={eventTotal}
subscription={subscription}
data-test-id={`event-breakdown-${key}`}
/>
);
})}
</Flex>
</DrawerBody>
</Container>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {OrganizationFixture} from 'sentry-fixture/organization';

import {BillingStatFixture} from 'getsentry-test/fixtures/billingStat';
import {CustomerUsageFixture} from 'getsentry-test/fixtures/customerUsage';
import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription';
import {UsageTotalFixture} from 'getsentry-test/fixtures/usageTotal';
import {act, render, screen} from 'sentry-test/reactTestingLibrary';
Expand All @@ -10,10 +11,10 @@ import {OrganizationContext} from 'sentry/views/organizationContext';

import SubscriptionStore from 'getsentry/stores/subscriptionStore';
import {PlanTier} from 'getsentry/types';
import UsageCharts from 'getsentry/views/subscriptionPage/usageOverview/charts';
import type {BreakdownPanelProps} from 'getsentry/views/subscriptionPage/usageOverview/types';

import CategoryUsageDrawer from './categoryUsageDrawer';

describe('CategoryUsageDrawer', () => {
describe('UsageCharts', () => {
const organization = OrganizationFixture();
const totals = UsageTotalFixture({
accepted: 50,
Expand All @@ -28,10 +29,10 @@ describe('CategoryUsageDrawer', () => {
organization.features.push('subscriptions-v3');
});

function renderComponent(props: any) {
function renderComponent(props: Omit<BreakdownPanelProps, 'organization'>) {
return render(
<OrganizationContext value={organization}>
<CategoryUsageDrawer {...props} />
<UsageCharts {...props} organization={organization} />
</OrganizationContext>
);
}
Expand All @@ -45,15 +46,19 @@ describe('CategoryUsageDrawer', () => {
usage: 50,
};
SubscriptionStore.set(organization.slug, subscription);
const usageData = CustomerUsageFixture({
totals: {
[DataCategory.ERRORS]: totals,
},
stats: {
[DataCategory.ERRORS]: stats,
},
});
await act(async () => {
renderComponent({
subscription,
categoryInfo: subscription.categories.errors,
eventTotals: {[DataCategory.ERRORS]: totals},
totals,
stats,
periodEnd: '2021-02-01',
periodStart: '2021-01-01',
usageData,
selectedProduct: DataCategory.ERRORS,
});

// filter values are asynchronously persisted
Expand Down Expand Up @@ -81,18 +86,27 @@ describe('CategoryUsageDrawer', () => {
usage: 50,
};
SubscriptionStore.set(organization.slug, subscription);
await act(async () => {
renderComponent({
subscription,
categoryInfo: subscription.categories.transactions,
eventTotals: {
const usageData = CustomerUsageFixture({
totals: {
[DataCategory.TRANSACTIONS]: totals,
[DataCategory.PROFILES]: totals,
},
stats: {
[DataCategory.TRANSACTIONS]: stats,
[DataCategory.PROFILES]: stats,
},
eventTotals: {
[DataCategory.TRANSACTIONS]: {
[DataCategory.TRANSACTIONS]: totals,
[DataCategory.PROFILES]: totals,
},
totals,
stats,
periodEnd: '2021-02-01',
periodStart: '2021-01-01',
},
});
await act(async () => {
renderComponent({
subscription,
selectedProduct: DataCategory.TRANSACTIONS,
usageData,
});
await tick();
});
Expand Down
Loading
Loading