11import { Sheet } from "@ui/Sheet" ;
22import { Tooltip } from "@ui/Tooltip" ;
33import { Loading } from "@ui/Loading" ;
4+ import { Spinner } from "@ui/Spinner" ;
45import { formatBytes , formatNumberCompact } from "@common/lib/format" ;
56import { UsageSummary } from "hooks/usageMetrics" ;
67import { ReactNode } from "react" ;
78import { GetTokenInfoResponse , TeamEntitlementsResponse } from "generatedApi" ;
8- import { QuestionMarkCircledIcon } from "@radix-ui/react-icons" ;
9+ import {
10+ QuestionMarkCircledIcon ,
11+ CrossCircledIcon ,
12+ } from "@radix-ui/react-icons" ;
913import { cn } from "@ui/cn" ;
1014import Link from "next/link" ;
1115import { Donut } from "@ui/Donut" ;
@@ -17,13 +21,15 @@ export function PlanSummary({
1721 hasSubscription,
1822 showEntitlements,
1923 hasFilter,
24+ error,
2025} : {
2126 chefTokenUsage ?: GetTokenInfoResponse ;
2227 teamSummary ?: UsageSummary ;
2328 entitlements ?: TeamEntitlementsResponse ;
2429 hasSubscription : boolean ;
2530 showEntitlements : boolean ;
2631 hasFilter : boolean ;
32+ error ?: any ;
2733} ) {
2834 return (
2935 < PlanSummaryForTeam
@@ -33,6 +39,7 @@ export function PlanSummary({
3339 hasSubscription = { hasSubscription }
3440 showEntitlements = { showEntitlements }
3541 hasFilter = { hasFilter }
42+ error = { error }
3643 />
3744 ) ;
3845}
@@ -138,6 +145,7 @@ export type PlanSummaryForTeamProps = {
138145 showEntitlements : boolean ;
139146 hasSubscription : boolean ;
140147 hasFilter : boolean ;
148+ error ?: any ;
141149} ;
142150
143151export function PlanSummaryForTeam ( {
@@ -147,6 +155,7 @@ export function PlanSummaryForTeam({
147155 hasSubscription,
148156 showEntitlements,
149157 hasFilter,
158+ error,
150159} : PlanSummaryForTeamProps ) {
151160 return (
152161 < Sheet
@@ -192,42 +201,73 @@ export function PlanSummaryForTeam({
192201 </ div >
193202 ) }
194203 </ div >
195- { sections . map ( ( section , index ) => (
196- < UsageSection
197- key = { index }
198- metric = {
199- section . metric === "chefTokens"
200- ? chefTokenUsage
201- ? chefTokenUsage . centitokensUsed / 100
202- : undefined
203- : teamSummary
204- ? teamSummary [ section . metric ]
205- : undefined
206- }
207- entitlement = {
208- section . metric === "chefTokens"
209- ? chefTokenUsage
210- ? chefTokenUsage . centitokensQuota / 100
211- : undefined
212- : entitlements
213- ? ( entitlements [ section . entitlement ] ?? 0 )
214- : undefined
215- }
216- isNotSubjectToFilter = { section . metric === "chefTokens" && hasFilter }
217- hasSubscription = { hasSubscription }
218- metricName = { section . metric }
219- format = { section . format }
220- detail = { section . detail }
221- title = { section . title }
222- suffix = { section . suffix }
223- showEntitlements = { showEntitlements }
224- />
225- ) ) }
204+ { error ? (
205+ < PlanSummaryError />
206+ ) : ! teamSummary ? (
207+ < PlanSummaryLoading />
208+ ) : (
209+ sections . map ( ( section , index ) => (
210+ < UsageSection
211+ key = { index }
212+ metric = {
213+ section . metric === "chefTokens"
214+ ? chefTokenUsage
215+ ? chefTokenUsage . centitokensUsed / 100
216+ : undefined
217+ : teamSummary
218+ ? teamSummary [ section . metric ]
219+ : undefined
220+ }
221+ entitlement = {
222+ section . metric === "chefTokens"
223+ ? chefTokenUsage
224+ ? chefTokenUsage . centitokensQuota / 100
225+ : undefined
226+ : entitlements
227+ ? ( entitlements [ section . entitlement ] ?? 0 )
228+ : undefined
229+ }
230+ isNotSubjectToFilter = {
231+ section . metric === "chefTokens" && hasFilter
232+ }
233+ hasSubscription = { hasSubscription }
234+ metricName = { section . metric }
235+ format = { section . format }
236+ detail = { section . detail }
237+ title = { section . title }
238+ suffix = { section . suffix }
239+ showEntitlements = { showEntitlements }
240+ />
241+ ) )
242+ ) }
226243 </ div >
227244 </ Sheet >
228245 ) ;
229246}
230247
248+ function PlanSummaryError ( ) {
249+ return (
250+ < div className = "flex h-56 flex-col items-center justify-center p-4 text-center" >
251+ < CrossCircledIcon className = "h-6 w-6 text-content-error" />
252+ < h5 className = "mt-2" > Error fetching Usage summary data</ h5 >
253+ < p className = "mt-1 text-sm text-content-secondary" >
254+ An error occurred while fetching usage summary data. Please try again
255+ later.
256+ </ p >
257+ </ div >
258+ ) ;
259+ }
260+
261+ function PlanSummaryLoading ( ) {
262+ return (
263+ < div className = "flex h-56 items-center justify-center p-4" >
264+ < div className = "flex items-center justify-center" >
265+ < Spinner className = "size-12" />
266+ </ div >
267+ </ div >
268+ ) ;
269+ }
270+
231271export function UsageOverview ( props : {
232272 metric ?: number ;
233273 entitlement ?: number ;
@@ -267,17 +307,16 @@ function UsageAmount({
267307 < >
268308 < div className = "flex items-center gap-2" >
269309 { showEntitlements &&
270- ( metric !== undefined && entitlement !== undefined ? (
310+ metric !== undefined &&
311+ entitlement !== undefined && (
271312 < Tooltip
272313 side = "bottom"
273314 tip = { `Your team has used ${ Math . floor ( 100 * ( metric / entitlement ) ) } % of the included amount${ title ? ` of ${ title } ` : `` } .` }
274315 className = "flex animate-fadeInFromLoading items-center"
275316 >
276317 < Donut current = { metric } max = { entitlement } />
277318 </ Tooltip >
278- ) : (
279- < Loading className = "h-6 w-6" />
280- ) ) }
319+ ) }
281320 { title && < SectionLabel detail = { detail } > { title } </ SectionLabel > }
282321 </ div >
283322 { metric === undefined || entitlement === undefined ? (
0 commit comments