@@ -7,7 +7,15 @@ import { type AccountQuota, normalizeQuotaForPlan } from "../codex-quota-utils";
77/* Helpers are co-located with QuotaBars for overview sorting / stacked layout. */
88/* eslint-disable react-refresh/only-export-components */
99
10- export type QuotaBarRow = { label : string ; limitLabel : string ; percent : number ; resetAt ?: number } ;
10+ export type QuotaWindowKey = "fiveHour" | "weekly" | "monthly" ;
11+ export type QuotaBarRow = {
12+ windowKey ?: QuotaWindowKey ;
13+ customLabel ?: string ;
14+ label : string ;
15+ limitLabel : string ;
16+ percent : number ;
17+ resetAt ?: number ;
18+ } ;
1119
1220/**
1321 * Window ordering is computed from RAW wire identities BEFORE localization
@@ -43,6 +51,7 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
4351 ranked . push ( {
4452 rank : 0 ,
4553 row : {
54+ windowKey : "fiveHour" ,
4655 label : t ( "codexAuth.fiveHour" ) ,
4756 limitLabel : t ( "quota.fiveHourLimit" ) ,
4857 percent : displayQuota . fiveHourPercent ,
@@ -54,6 +63,7 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
5463 ranked . push ( {
5564 rank : 1 ,
5665 row : {
66+ windowKey : "weekly" ,
5767 label : t ( "codexAuth.weekly" ) ,
5868 limitLabel : t ( "quota.weeklyLimit" ) ,
5969 percent : displayQuota . weeklyPercent ,
@@ -65,6 +75,7 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
6575 ranked . push ( {
6676 rank : 4 ,
6777 row : {
78+ windowKey : "monthly" ,
6879 label : t ( "codexAuth.monthly" ) ,
6980 limitLabel : t ( "quota.monthlyLimit" ) ,
7081 percent : displayQuota . monthlyPercent ,
@@ -76,7 +87,13 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
7687 const localized = localizeCustomQuotaLabel ( w . label , t ) ;
7788 ranked . push ( {
7889 rank : rawCustomWindowRank ( w . label ) ,
79- row : { label : localized , limitLabel : localized , percent : w . percent , resetAt : w . resetAt } ,
90+ row : {
91+ customLabel : w . label ,
92+ label : localized ,
93+ limitLabel : localized ,
94+ percent : w . percent ,
95+ resetAt : w . resetAt ,
96+ } ,
8097 } ) ;
8198 }
8299 return ranked . sort ( ( a , b ) => a . rank - b . rank ) . map ( entry => entry . row ) ;
@@ -138,7 +155,17 @@ function barFillStyle(percent: number): CSSProperties {
138155 return { [ "--bar-scale" as string ] : String ( barWidth ( percent ) / 100 ) } ;
139156}
140157
141- export default function QuotaBars ( { quota, plan, threshold, t, className, layout = "compact" , pending = false } : {
158+ export default function QuotaBars ( {
159+ quota,
160+ plan,
161+ threshold,
162+ t,
163+ className,
164+ layout = "compact" ,
165+ pending = false ,
166+ incompleteWindowKeys,
167+ incompleteCustomWindowLabels,
168+ } : {
142169 quota : AccountQuota | null ;
143170 plan ?: string | null ;
144171 threshold : number ;
@@ -151,6 +178,9 @@ export default function QuotaBars({ quota, plan, threshold, t, className, layout
151178 * bar slot so deferred fill does not shove the page down.
152179 */
153180 pending ?: boolean ;
181+ /** Optional overview-only coverage status. Other quota surfaces remain unchanged when omitted. */
182+ incompleteWindowKeys ?: ReadonlySet < QuotaWindowKey > ;
183+ incompleteCustomWindowLabels ?: ReadonlySet < string > ;
154184} ) {
155185 const { locale } = useI18n ( ) ;
156186 const rows = buildQuotaRows ( quota , plan , t ) ;
@@ -201,7 +231,16 @@ export default function QuotaBars({ quota, plan, threshold, t, className, layout
201231 return (
202232 < div className = { `quota-stacked${ className ? ` ${ className } ` : "" } ` } >
203233 { rows . map ( row => (
204- < StackedQuotaRow key = { row . limitLabel } row = { row } threshold = { threshold } t = { t } locale = { locale } />
234+ < StackedQuotaRow
235+ key = { row . limitLabel }
236+ row = { row }
237+ threshold = { threshold }
238+ t = { t }
239+ locale = { locale }
240+ incomplete = { row . windowKey
241+ ? incompleteWindowKeys ?. has ( row . windowKey ) === true
242+ : row . customLabel !== undefined && incompleteCustomWindowLabels ?. has ( row . customLabel ) === true }
243+ />
205244 ) ) }
206245 </ div >
207246 ) ;
@@ -254,11 +293,12 @@ function QuotaRow({ label, percent, resetAt, threshold, t, locale }: {
254293 ) ;
255294}
256295
257- function StackedQuotaRow ( { row, threshold, t, locale } : {
296+ function StackedQuotaRow ( { row, threshold, t, locale, incomplete } : {
258297 row : QuotaBarRow ;
259298 threshold : number ;
260299 t : TFn ;
261300 locale : Locale ;
301+ incomplete : boolean ;
262302} ) {
263303 const exhausted = isQuotaExhausted ( row . percent ) ;
264304 const warn = isQuotaWarn ( row . percent , threshold ) ;
@@ -267,7 +307,18 @@ function StackedQuotaRow({ row, threshold, t, locale }: {
267307 return (
268308 < div className = { `quota-stacked-row${ warn ? " quota-stacked-row--warn" : "" } ${ exhausted ? " quota-stacked-row--exhausted" : "" } ` } >
269309 < div className = "quota-stacked-head" >
270- < span className = "quota-stacked-limit" > { row . limitLabel } </ span >
310+ < span className = "quota-stacked-limit-group" >
311+ < span className = "quota-stacked-limit" > { row . limitLabel } </ span >
312+ { incomplete && (
313+ < span
314+ className = "quota-window-partial"
315+ aria-label = { t ( "pws.capacity.windowPartialA11y" , { window : row . limitLabel } ) }
316+ title = { t ( "pws.capacity.windowPartialA11y" , { window : row . limitLabel } ) }
317+ >
318+ { t ( "pws.capacity.windowPartial" ) }
319+ </ span >
320+ ) }
321+ </ span >
271322 < span className = "quota-stacked-reset muted" > { resetText } </ span >
272323 </ div >
273324 < div className = "quota-stacked-bar-row" >
0 commit comments