Skip to content

Commit d44991a

Browse files
authored
Merge pull request #8 from github/ui/report-guide-faq-aic-rename
feat: Report Format guide improvements, FAQ view, AIC rename, ModelsView redesign
2 parents b99752a + 1531e90 commit d44991a

7 files changed

Lines changed: 240 additions & 88 deletions

File tree

src/App.css

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,7 @@ td.cost-centers-view__num {
15981598
border: 1px solid #e2e8f0;
15991599
border-radius: 10px;
16001600
padding: 1.25rem 1.5rem 1.5rem;
1601+
margin-bottom: 1.5rem;
16011602
}
16021603

16031604
.report-guide__example-title {
@@ -1706,3 +1707,44 @@ td.cost-centers-view__num {
17061707
line-height: 1.5;
17071708
margin: 0;
17081709
}
1710+
1711+
/* ── FAQ View ────────────────────────────────────────────────── */
1712+
.faq {
1713+
max-width: 960px;
1714+
}
1715+
1716+
.faq__heading {
1717+
font-size: 1.25rem;
1718+
font-weight: 600;
1719+
color: #0f172a;
1720+
margin: 0 0 1.5rem;
1721+
}
1722+
1723+
.faq__list {
1724+
display: flex;
1725+
flex-direction: column;
1726+
gap: 1rem;
1727+
margin: 0;
1728+
padding: 0;
1729+
}
1730+
1731+
.faq__item {
1732+
background: #ffffff;
1733+
border: 1px solid #e2e8f0;
1734+
border-radius: 10px;
1735+
padding: 1.25rem 1.5rem;
1736+
}
1737+
1738+
.faq__question {
1739+
font-size: 0.95rem;
1740+
font-weight: 600;
1741+
color: #1e293b;
1742+
margin: 0 0 0.75rem;
1743+
}
1744+
1745+
.faq__answer {
1746+
font-size: 0.875rem;
1747+
color: #475569;
1748+
line-height: 1.65;
1749+
margin: 0;
1750+
}

src/App.tsx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CostCentersView } from './views/CostCentersView'
88
import { OrganizationsView } from './views/OrganizationsView'
99
import { ModelsView } from './views/ModelsView'
1010
import { ReportGuideView } from './views/ReportGuideView'
11+
import { FaqView } from './views/FaqView'
1112
import { QuickStatsAggregator, type QuickStatsResult } from './pipeline/aggregators/quickStatsAggregator'
1213
import { ReportContextAggregator, type ReportContextResult } from './pipeline/aggregators/reportContextAggregator'
1314
import { DailyUsageAggregator, type DailyUsageData } from './pipeline/aggregators/dailyUsageAggregator'
@@ -54,7 +55,7 @@ function App() {
5455
const [fileName, setFileName] = useState<string | null>(null)
5556
const [dragActive, setDragActive] = useState(false)
5657
const [dailyUsageData, setDailyUsageData] = useState<DailyUsageData[]>([])
57-
const [activeView, setActiveView] = useState<'overview' | 'users' | 'userDetails' | 'costCenters' | 'orgs' | 'models' | 'guide'>('overview')
58+
const [activeView, setActiveView] = useState<'overview' | 'users' | 'userDetails' | 'costCenters' | 'orgs' | 'models' | 'guide' | 'faq'>('overview')
5859
const [userUsage, setUserUsage] = useState<UserUsageResult | null>(null)
5960
const [modelUsage, setModelUsage] = useState<ModelUsageResult | null>(null)
6061
const [selectedUsername, setSelectedUsername] = useState<string>('')
@@ -331,6 +332,19 @@ function App() {
331332
</svg>
332333
<span className="sidebar__label">Report Format</span>
333334
</button>
335+
336+
<button
337+
type="button"
338+
className={`sidebar__item ${activeView === 'faq' ? 'sidebar__item--active' : ''}`}
339+
onClick={() => setActiveView('faq')}
340+
>
341+
<svg className="sidebar__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" focusable="false">
342+
<circle cx="12" cy="12" r="10" />
343+
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
344+
<circle cx="12" cy="17" r="0.5" fill="currentColor" />
345+
</svg>
346+
<span className="sidebar__label">FAQ</span>
347+
</button>
334348
</nav>
335349
</aside>
336350

@@ -350,7 +364,7 @@ function App() {
350364
<div className="context-banner">
351365
<h2 className="context-banner__title">GitHub Copilot is moving to token-based billing</h2>
352366
<p className="context-banner__body">
353-
Starting May 1, Copilot usage will be measured in AI Units (AIUs) instead of Premium Requests (PRUs). <strong className="aiu-callout">1 AIU = $0.01.</strong> This preview shows what your usage would look like under the new pricing.
367+
Starting May 1, 2026, Copilot usage will be measured in AI Credits (AICs) instead of Premium Requests (PRUs). <strong className="aiu-callout">1 AIC = $0.01.</strong> This preview shows what your usage would look like under the new pricing.
354368
</p>
355369
{fileName && (
356370
<p className="context-banner__note">
@@ -402,10 +416,10 @@ function App() {
402416
</div>
403417
</div>
404418
<div className="card comparison-card">
405-
<div className="comparison-card__label">Token-based billing (AIUs)</div>
419+
<div className="comparison-card__label">Token-based billing (AICs)</div>
406420
<div className="comparison-card__big-number comparison-card__big-number--aiu">{formatUsd(aicNetCost)}</div>
407-
<div className="comparison-card__period">{formatAiu(overviewTotals.aiuQuantity)} AIUs</div>
408-
<div className="comparison-card__rate">1 AIU = $0.01</div>
421+
<div className="comparison-card__period">{formatAiu(overviewTotals.aiuQuantity)} AICs</div>
422+
<div className="comparison-card__rate">1 AIC = $0.01</div>
409423
<div className="comparison-card__breakdown">
410424
<div className="comparison-card__breakdown-row">
411425
<span>Gross cost</span>
@@ -444,7 +458,7 @@ function App() {
444458
height={320}
445459
/>
446460
<DualAxisLineChart
447-
title="Daily cost: PRU cost vs AIU cost"
461+
title="Daily cost: PRU cost vs AIC cost"
448462
labels={filledDailyUsageData.map((day) => day.date)}
449463
series={[
450464
{
@@ -454,7 +468,7 @@ function App() {
454468
yAxisID: 'y',
455469
},
456470
{
457-
label: 'AIU Gross Cost',
471+
label: 'AIC Gross Cost',
458472
color: '#54aeff',
459473
data: filledDailyUsageData.map((day) => day.aiuGrossAmount),
460474
yAxisID: 'y',
@@ -544,6 +558,10 @@ function App() {
544558
<div className="view-content">
545559
<ReportGuideView />
546560
</div>
561+
) : activeView === 'faq' ? (
562+
<div className="view-content">
563+
<FaqView />
564+
</div>
547565
) : (
548566
<div className="view-content">
549567
<OrganizationsView data={orgs ?? { organizations: [] }} />

src/components/UploadPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function UploadPage({
2626
<h1 className="upload-screen__title">Copilot Billing Preview</h1>
2727
<p className="upload-screen__subtitle">
2828
GitHub is moving to <strong>token-based billing</strong> for Copilot. Starting May 2026, usage
29-
will be measured in AI Units (AIUs) instead of Premium Requests (PRUs). This tool helps you
29+
will be measured in AI Credits (AICs) instead of Premium Requests (PRUs). This tool helps you
3030
understand how the change will impact your bill.
3131
</p>
3232
<p className="upload-screen__subtitle upload-screen__subtitle--spaced">

src/views/CostCentersView.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
100100
</div>
101101
</div>
102102
<div className="card comparison-card">
103-
<div className="comparison-card__label">Token-based billing (AIUs)</div>
103+
<div className="comparison-card__label">Token-based billing (AICs)</div>
104104
<div className="comparison-card__big-number comparison-card__big-number--aiu">{formatUsd(totals.aiuGrossAmount)}</div>
105-
<div className="comparison-card__period">{formatAiu(totals.aiuQuantity)} AIUs</div>
106-
<div className="comparison-card__rate">1 AIU = $0.01</div>
105+
<div className="comparison-card__period">{formatAiu(totals.aiuQuantity)} AICs</div>
106+
<div className="comparison-card__rate">1 AIC = $0.01</div>
107107
<div className="comparison-card__breakdown">
108108
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--total">
109109
<span>Gross cost</span>
@@ -141,8 +141,8 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
141141
<th>Model</th>
142142
<th className="cost-centers-view__num">PRUs</th>
143143
<th className="cost-centers-view__num">PRU Cost</th>
144-
<th className="cost-centers-view__num">AIUs</th>
145-
<th className="cost-centers-view__num">AIU Cost</th>
144+
<th className="cost-centers-view__num">AICs</th>
145+
<th className="cost-centers-view__num">AIC Cost</th>
146146
<th className="cost-centers-view__num">Difference</th>
147147
</tr>
148148
</thead>
@@ -174,8 +174,8 @@ export function CostCentersView({ data, rangeStart }: { data: CostCenterResult;
174174
<th>User</th>
175175
<th className="cost-centers-view__num">PRUs</th>
176176
<th className="cost-centers-view__num">PRU Cost</th>
177-
<th className="cost-centers-view__num">AIUs</th>
178-
<th className="cost-centers-view__num">AIU Cost</th>
177+
<th className="cost-centers-view__num">AICs</th>
178+
<th className="cost-centers-view__num">AIC Cost</th>
179179
<th className="cost-centers-view__num">Difference</th>
180180
</tr>
181181
</thead>

src/views/FaqView.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const FAQ_ITEMS: { question: string; answer: string }[] = [
2+
{
3+
question:
4+
'Why do I see two rows with one Premium Request to the same model that cost different amounts of AI Credits?',
5+
answer:
6+
'Not every request is the same. Saying "Hi" or "Thank you" to Claude Opus 4.6 costs 3 PRUs but consumes very few tokens (AI Credits) — that\'s a waste. At the same time, a complex and detailed plan implementation can run for a long time and consume a lot of AI Credits. Token-based billing reflects the actual work done, so short trivial exchanges become cheaper while long, intensive tasks are billed by what they truly consume.',
7+
},
8+
]
9+
10+
export function FaqView() {
11+
return (
12+
<section className="faq">
13+
<h2 className="faq__heading">Frequently Asked Questions</h2>
14+
15+
<dl className="faq__list">
16+
{FAQ_ITEMS.map(({ question, answer }, i) => (
17+
<div key={i} className="faq__item">
18+
<dt className="faq__question">{question}</dt>
19+
<dd className="faq__answer">{answer}</dd>
20+
</div>
21+
))}
22+
</dl>
23+
</section>
24+
)
25+
}

src/views/ModelsView.tsx

Lines changed: 63 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState, useMemo } from 'react'
22
import type { ModelUsageResult, ModelDailyUsageData } from '../pipeline/aggregators/modelUsageAggregator'
3-
import { BillingComparisonCard, DualAxisLineChart } from '../components'
3+
import { DualAxisLineChart } from '../components'
44
import { fillDataForRange } from '../utils/fillDataForRange'
55
import { formatAiu, formatUsd } from '../utils/format'
66

@@ -41,6 +41,10 @@ export function ModelsView({ modelUsage, aicDiscountRate, rangeStart, rangeEnd }
4141
? Math.max(selectedModelTotals.aiuGrossAmount - selectedModelAicDiscount, 0)
4242
: 0
4343

44+
const periodLabel = rangeStart
45+
? new Date(rangeStart + 'T00:00:00').toLocaleString('en-US', { month: 'long', year: 'numeric' })
46+
: null
47+
4448
return (
4549
<section className="per-model" aria-label="Per-Model Breakdown">
4650
<div className="per-model__header">
@@ -61,78 +65,69 @@ export function ModelsView({ modelUsage, aicDiscountRate, rangeStart, rangeEnd }
6165
))}
6266
</select>
6367
</label>
68+
</div>
6469

65-
{selectedModelTotals && (
66-
<div className="overview-cards">
67-
<div className="per-model__summary">
68-
<h4 className="cost-breakdown-card__title">PRU Cost</h4>
69-
<div className="per-model__summary-row">
70-
<span className="per-model__summary-label">Premium Requests</span>
71-
<span className="per-model__summary-value">{selectedModelTotals.requests.toLocaleString()}</span>
72-
</div>
73-
<div className="per-model__summary-row">
74-
<span className="per-model__summary-label">PRU Gross Cost</span>
75-
<span className="per-model__summary-value">{formatUsd(selectedModelTotals.grossAmount)}</span>
76-
</div>
77-
<div className="per-model__summary-row">
78-
<span className="per-model__summary-label">PRU Discounts</span>
79-
<span className="per-model__summary-value per-model__summary-value--muted">
80-
{formatUsd(selectedModelTotals.discountAmount)}
81-
</span>
82-
</div>
83-
<div className="per-model__summary-row per-model__summary-row--highlight">
84-
<span className="per-model__summary-label">Net Cost</span>
85-
<span className="per-model__summary-value per-model__summary-value--bold">
86-
{formatUsd(selectedModelTotals.netAmount)}
87-
</span>
88-
</div>
89-
</div>
70+
{selectedModelTotals && (() => {
71+
const savings = selectedModelTotals.netAmount - selectedModelAicNetCost
72+
return (
73+
<>
74+
{periodLabel && (
75+
<p className="comparison-framing">
76+
{savings > 0 ? (
77+
<><strong>{selectedModel}</strong>'s <strong>{periodLabel}</strong> usage would cost{' '}<strong>{formatUsd(savings)} less</strong> under token-based pricing</>
78+
) : savings < 0 ? (
79+
<><strong>{selectedModel}</strong>'s <strong>{periodLabel}</strong> usage would cost{' '}<strong>{formatUsd(Math.abs(savings))} more</strong> under token-based pricing</>
80+
) : (
81+
<><strong>{selectedModel}</strong>'s <strong>{periodLabel}</strong> usage cost would be the same under token-based pricing</>
82+
)}
83+
</p>
84+
)}
9085

91-
<div className="per-model__summary">
92-
<h4 className="cost-breakdown-card__title">AIC Cost</h4>
93-
<div className="per-model__summary-row">
94-
<span className="per-model__summary-label">AI Credits</span>
95-
<span className="per-model__summary-value">{formatAiu(selectedModelTotals.aiuQuantity)}</span>
96-
</div>
97-
<div className="per-model__summary-row">
98-
<span className="per-model__summary-label">AIC Gross Cost</span>
99-
<span className="per-model__summary-value">{formatUsd(selectedModelTotals.aiuGrossAmount)}</span>
100-
</div>
101-
<div className="per-model__summary-row">
102-
<span className="per-model__summary-label">AIC Discount</span>
103-
<span className="per-model__summary-value per-model__summary-value--muted">
104-
{formatUsd(selectedModelAicDiscount)}
105-
</span>
86+
<div className="comparison-grid">
87+
<div className="card comparison-card">
88+
<div className="comparison-card__label">Current billing (PRUs)</div>
89+
<div className="comparison-card__big-number">{formatUsd(selectedModelTotals.netAmount)}</div>
90+
<div className="comparison-card__period">{selectedModelTotals.requests.toLocaleString()} PRUs</div>
91+
<div className="comparison-card__rate">1 PRU = $0.04</div>
92+
<div className="comparison-card__breakdown">
93+
<div className="comparison-card__breakdown-row">
94+
<span>Gross cost</span>
95+
<span>{formatUsd(selectedModelTotals.grossAmount)}</span>
96+
</div>
97+
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--muted">
98+
<span>Discounts</span>
99+
<span>{formatUsd(selectedModelTotals.discountAmount)}</span>
100+
</div>
101+
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--total">
102+
<span>Net cost</span>
103+
<span>{formatUsd(selectedModelTotals.netAmount)}</span>
104+
</div>
105+
</div>
106106
</div>
107-
<div className="per-model__summary-row per-model__summary-row--highlight">
108-
<span className="per-model__summary-label">Net Cost</span>
109-
<span className="per-model__summary-value per-model__summary-value--bold">
110-
{formatUsd(selectedModelAicNetCost)}
111-
</span>
107+
<div className="card comparison-card">
108+
<div className="comparison-card__label">Token-based billing (AICs)</div>
109+
<div className="comparison-card__big-number comparison-card__big-number--aiu">{formatUsd(selectedModelAicNetCost)}</div>
110+
<div className="comparison-card__period">{formatAiu(selectedModelTotals.aiuQuantity)} AICs</div>
111+
<div className="comparison-card__rate">1 AIC = $0.01</div>
112+
<div className="comparison-card__breakdown">
113+
<div className="comparison-card__breakdown-row">
114+
<span>Gross cost</span>
115+
<span>{formatUsd(selectedModelTotals.aiuGrossAmount)}</span>
116+
</div>
117+
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--muted">
118+
<span>Included credits discount</span>
119+
<span>{formatUsd(selectedModelAicDiscount)}</span>
120+
</div>
121+
<div className="comparison-card__breakdown-row comparison-card__breakdown-row--total">
122+
<span>Net cost</span>
123+
<span>{formatUsd(selectedModelAicNetCost)}</span>
124+
</div>
125+
</div>
112126
</div>
113127
</div>
114-
115-
<BillingComparisonCard
116-
title="Billing Comparison Gross"
117-
currentLabel="Current (PRU gross)"
118-
currentValue={selectedModelTotals.grossAmount}
119-
aicLabel="AIC (gross)"
120-
aicValue={selectedModelTotals.aiuGrossAmount}
121-
savingsText="AIC gross billing is cheaper for this model"
122-
overspendText="AIC gross billing is more expensive for this model"
123-
/>
124-
<BillingComparisonCard
125-
title="Billing Comparison Net"
126-
currentLabel="Current (PRU net)"
127-
currentValue={selectedModelTotals.netAmount}
128-
aicLabel="AIC (net)"
129-
aicValue={selectedModelAicNetCost}
130-
savingsText="AIC net billing is cheaper for this model"
131-
overspendText="AIC net billing is more expensive for this model"
132-
/>
133-
</div>
134-
)}
135-
</div>
128+
</>
129+
)
130+
})()}
136131

137132
{selectedModel && filledPerModelDailyData.length > 0 && (
138133
<div className="per-model__charts charts-grid">

0 commit comments

Comments
 (0)