Skip to content

Commit 16f3574

Browse files
asizikovCopilot
andcommitted
feat: show cumulative AIC usage on overview
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8183710 commit 16f3574

2 files changed

Lines changed: 85 additions & 36 deletions

File tree

src/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ function App() {
729729
rangeEnd={rangeEnd}
730730
licenseAmount={licenseAmount}
731731
licenseSeatCounts={licenseSeatCounts}
732+
includedAicCredits={includedAicPoolSize}
732733
reportPlanScope={reportPlanScope}
733734
upgradeRecommendation={individualUpgradeRecommendation}
734735
onAdjustSeatCounts={reportPlanScope === 'organization' && !isIndividualReport ? () => setActiveView('users') : undefined}

src/views/OverviewView.tsx

Lines changed: 84 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BillingProjectionDisclaimer, BillingTotalsCards } from '../components/u
33
import { appLinks } from '../config/links'
44
import type { ReportPlanScope } from '../pipeline/aicIncludedCredits'
55
import type { DailyUsageData } from '../pipeline/aggregators/dailyUsageAggregator'
6+
import { AIC_UNIT_PRICE_USD } from '../utils/billingConstants'
67
import { fillDataForRange } from '../utils/fillDataForRange'
78
import { formatUsd } from '../utils/format'
89
import type { IndividualPlanUpgradeRecommendation } from '../utils/individualPlanUpgrade'
@@ -18,11 +19,16 @@ type OverviewViewProps = {
1819
business: number
1920
enterprise: number
2021
}
22+
includedAicCredits: number
2123
reportPlanScope?: ReportPlanScope
2224
upgradeRecommendation?: IndividualPlanUpgradeRecommendation | null
2325
onAdjustSeatCounts?: () => void
2426
}
2527

28+
const CURRENT_AIC_COLOR = '#1a7f37'
29+
const ADDITIONAL_AIC_COLOR = '#cf222e'
30+
const INCLUDED_CREDITS_COLOR = '#0969da'
31+
2632
function createEmptyDailyUsage(date: string): DailyUsageData {
2733
return {
2834
date,
@@ -44,6 +50,7 @@ export function OverviewView({
4450
rangeEnd,
4551
licenseAmount,
4652
licenseSeatCounts,
53+
includedAicCredits,
4754
reportPlanScope = 'organization',
4855
upgradeRecommendation = null,
4956
onAdjustSeatCounts,
@@ -73,6 +80,23 @@ export function OverviewView({
7380
const usageBasedBillingDocsUrl = reportPlanScope === 'individual'
7481
? appLinks.usageBasedBillingForIndividualsDocs
7582
: appLinks.usageBasedBillingForOrganizationsDocs
83+
const includedCreditsValue = includedAicCredits * AIC_UNIT_PRICE_USD
84+
const includedCreditsLabel = 'Included value'
85+
const includedCreditsLegendLabel = reportPlanScope === 'individual' ? 'Included AI Credits' : 'Included AI Credits pool'
86+
const includedCreditsDescription = reportPlanScope === 'individual'
87+
? 'Your plan\'s included AI Credits are consumed first. Additional usage spend starts after cumulative AIC gross cost exceeds the included value.'
88+
: 'The account-wide included AI Credits pool is consumed first. Additional usage spend starts after cumulative AIC gross cost exceeds the included value.'
89+
const includedCreditsCardTitle = reportPlanScope === 'individual' ? 'Included credits are coming' : 'Pooled included credits are coming'
90+
const includedCreditsCardBody = reportPlanScope === 'individual'
91+
? 'Under usage-based billing, your Copilot plan includes AI Credits each month. Usage consumes those included credits first; additional usage is billed only after they are used.'
92+
: 'Under usage-based billing, included credits will be pooled across all licensed users in your account. No more unused capacity going to waste from idle users.'
93+
const includedCreditsDocsUrl = reportPlanScope === 'individual'
94+
? appLinks.usageBasedBillingForIndividualsDocs
95+
: appLinks.aiCreditsForOrganizationsDocs
96+
const cumulativeAicGrossAmount = filledDailyUsageData.reduce<number[]>((totals, day) => {
97+
totals.push((totals[totals.length - 1] ?? 0) + day.aicGrossAmount)
98+
return totals
99+
}, [])
76100

77101
return (
78102
<div className="max-w-[var(--width-content-max)] w-full mx-auto px-6 pt-8 pb-12 flex flex-col gap-6">
@@ -146,25 +170,51 @@ export function OverviewView({
146170
<BillingProjectionDisclaimer className="mb-6" />
147171

148172
<section className="grid grid-cols-1 gap-6 w-full">
149-
<DualAxisLineChart
150-
title="Daily Requests & AI Credits"
151-
labels={filledDailyUsageData.map((day) => day.date)}
152-
series={[
153-
{
154-
label: 'Premium Requests',
155-
color: '#6366f1',
156-
data: filledDailyUsageData.map((day) => day.requests),
157-
yAxisID: 'y',
158-
},
159-
{
160-
label: 'AI Credits',
161-
color: '#22c55e',
162-
data: filledDailyUsageData.map((day) => day.aicQuantity),
163-
yAxisID: 'y1',
164-
},
165-
]}
166-
height={320}
167-
/>
173+
<div className="flex flex-col gap-2">
174+
<DualAxisLineChart
175+
title="Cumulative AIC gross cost: included vs additional"
176+
labels={filledDailyUsageData.map((day) => day.date)}
177+
series={[
178+
{
179+
label: 'AIC gross cost',
180+
legendLabel: 'Usage - within included value',
181+
legendOrder: 1,
182+
color: CURRENT_AIC_COLOR,
183+
data: cumulativeAicGrossAmount,
184+
yAxisID: 'y',
185+
order: 1,
186+
segmentColor: (_startValue, endValue) => (
187+
endValue <= includedCreditsValue
188+
? CURRENT_AIC_COLOR
189+
: ADDITIONAL_AIC_COLOR
190+
),
191+
},
192+
{
193+
label: includedCreditsLabel,
194+
legendLabel: includedCreditsLegendLabel,
195+
legendOrder: 3,
196+
color: INCLUDED_CREDITS_COLOR,
197+
data: filledDailyUsageData.map(() => includedCreditsValue),
198+
yAxisID: 'y',
199+
borderDash: [2, 4],
200+
order: 2,
201+
pointRadius: 0,
202+
},
203+
]}
204+
extraLegendItems={[
205+
{
206+
label: 'Usage - additional spend',
207+
color: ADDITIONAL_AIC_COLOR,
208+
legendOrder: 2,
209+
},
210+
]}
211+
formatYAsCurrency
212+
height={320}
213+
/>
214+
<p className="m-0 text-center text-[13px] text-fg-muted leading-normal">
215+
{includedCreditsDescription}
216+
</p>
217+
</div>
168218
<DualAxisLineChart
169219
title="Daily cost: PRU cost vs AIC cost"
170220
labels={filledDailyUsageData.map((day) => day.date)}
@@ -213,24 +263,22 @@ export function OverviewView({
213263
/>
214264
</section>
215265

216-
{reportPlanScope === 'organization' && (
217-
<div className="bg-bg-default border border-border-default rounded-md py-5 px-6 mt-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-5">
218-
<div className="flex-1 flex flex-col gap-1">
219-
<strong className="text-sm font-semibold text-fg-default">Pooled included credits are coming</strong>
220-
<p className="m-0 text-[13px] text-fg-muted leading-normal">
221-
Under usage-based billing, included credits will be pooled across all licensed users in your account. No more unused capacity going to waste from idle users.
222-
</p>
223-
</div>
224-
<a
225-
href={appLinks.aiCreditsForOrganizationsDocs}
226-
className="text-sm font-medium text-fg-accent no-underline whitespace-nowrap hover:underline"
227-
target="_blank"
228-
rel="noopener noreferrer"
229-
>
230-
Learn more &rarr;
231-
</a>
266+
<div className="bg-bg-default border border-border-default rounded-md py-5 px-6 mt-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-5">
267+
<div className="flex-1 flex flex-col gap-1">
268+
<strong className="text-sm font-semibold text-fg-default">{includedCreditsCardTitle}</strong>
269+
<p className="m-0 text-[13px] text-fg-muted leading-normal">
270+
{includedCreditsCardBody}
271+
</p>
232272
</div>
233-
)}
273+
<a
274+
href={includedCreditsDocsUrl}
275+
className="text-sm font-medium text-fg-accent no-underline whitespace-nowrap hover:underline"
276+
target="_blank"
277+
rel="noopener noreferrer"
278+
>
279+
Learn more &rarr;
280+
</a>
281+
</div>
234282

235283
<section className="mt-8">
236284
<h2 className="text-base font-semibold text-fg-default pb-[10px] border-b border-border-default mb-4">Recommended next steps</h2>

0 commit comments

Comments
 (0)