From b7b4f895b7ca64aef00d346cefae3819f63a17cf Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Tue, 25 Aug 2026 16:54:37 -0300 Subject: [PATCH 1/4] fix(usage): only claim a percentage the allowance can support max_api_calls is a 30 day figure, so Last 90 days measured three months of usage against one month of allowance and read about three times too high. The meter reports a count for that window instead, and names the allowance as a 30 day one, and the chart drops its ceiling with it. The headline also stopped repeating the fraction beside it, and stopped taking its colour from a percentage it was no longer showing. Fixes #8353 Co-Authored-By: Claude Opus 5 (1M context) --- .../components/pages/usage/UsageDashboard.tsx | 6 ++- .../pages/usage/UsageDashboardPage.tsx | 5 +- .../pages/usage/__tests__/utils.test.ts | 12 +++++ .../components/UsageMeter/UsageMeter.tsx | 47 ++++++++++-------- .../UsageMeter/__tests__/utils.test.ts | 39 +++++++++++++-- .../usage/components/UsageMeter/utils.ts | 49 ++++++++++++++----- frontend/web/components/pages/usage/utils.ts | 3 ++ 7 files changed, 122 insertions(+), 39 deletions(-) diff --git a/frontend/web/components/pages/usage/UsageDashboard.tsx b/frontend/web/components/pages/usage/UsageDashboard.tsx index a0f8589195de..c22ba4748e40 100644 --- a/frontend/web/components/pages/usage/UsageDashboard.tsx +++ b/frontend/web/components/pages/usage/UsageDashboard.tsx @@ -9,6 +9,7 @@ export type UsageDashboardProps = { data: Res['organisationUsage'] | undefined total: number limit: PlanLimit + comparable?: boolean hasBillingPeriod: boolean isError?: boolean isLoading?: boolean @@ -16,6 +17,7 @@ export type UsageDashboardProps = { } const UsageDashboard: FC = ({ + comparable, data, filters, hasBillingPeriod, @@ -43,11 +45,11 @@ const UsageDashboard: FC = ({ } else { content = ( <> - + diff --git a/frontend/web/components/pages/usage/UsageDashboardPage.tsx b/frontend/web/components/pages/usage/UsageDashboardPage.tsx index 090669720815..33119943145a 100644 --- a/frontend/web/components/pages/usage/UsageDashboardPage.tsx +++ b/frontend/web/components/pages/usage/UsageDashboardPage.tsx @@ -10,6 +10,7 @@ import { PeriodOption } from 'common/types/requests' import UsageDashboard from './UsageDashboard' import { isBillingPeriodSelected, + isComparableToAllowance, periodsFor, PeriodSelection, planHasBillingPeriod, @@ -25,6 +26,7 @@ const UsageDashboardPage: FC = ({ organisationId, }) => { const [project, setProject] = useState() + const selectedProjectId = project ? Number(project) : undefined const { data: organisation, @@ -50,7 +52,7 @@ const UsageDashboardPage: FC = ({ ? { billing_period: billingPeriod, organisationId, - projectId: project ? Number(project) : undefined, + projectId: selectedProjectId, } : skipToken, ) @@ -71,6 +73,7 @@ const UsageDashboardPage: FC = ({ total={data?.totals?.total ?? 0} limit={subscriptionMeta?.max_api_calls} hasBillingPeriod={isBillingPeriodSelected(billingPeriod)} + comparable={isComparableToAllowance(billingPeriod)} isError={organisationFailed || usageFailed} isLoading={loadingOrganisation || loadingUsage || loadingLimit} filters={ diff --git a/frontend/web/components/pages/usage/__tests__/utils.test.ts b/frontend/web/components/pages/usage/__tests__/utils.test.ts index f8b795a205ca..fe3aa29a009e 100644 --- a/frontend/web/components/pages/usage/__tests__/utils.test.ts +++ b/frontend/web/components/pages/usage/__tests__/utils.test.ts @@ -1,5 +1,6 @@ import { Subscription } from 'common/types/responses' import { + isComparableToAllowance, isBillingPeriodSelected, planHasBillingPeriod, periodsFor, @@ -81,6 +82,17 @@ describe('UsageDashboard utils', () => { }) }) + describe('isComparableToAllowance', () => { + it('compares the 30 day window and the billing periods', () => { + expect(isComparableToAllowance(undefined)).toBe(true) + expect(isComparableToAllowance('current_billing_period')).toBe(true) + }) + + it('refuses the 90 day window against a 30 day allowance', () => { + expect(isComparableToAllowance('90_day_period')).toBe(false) + }) + }) + describe('periodsFor', () => { it('offers the billing periods only when there is a term', () => { expect(periodsFor(true).map((period) => period.value)).toContain( diff --git a/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx b/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx index 1643de2d4fef..11ad3c4016b6 100644 --- a/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx +++ b/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx @@ -1,12 +1,7 @@ import { FC, ReactNode } from 'react' -import Format from 'common/utils/format' import UsageBar from 'components/shared/UsageBar' -import { - PlanLimit, - toneFor, - usagePercent, -} from 'components/shared/UsageBar/utils' -import { meterCopy } from './utils' +import { PlanLimit } from 'components/shared/UsageBar/utils' +import { meterCopy, meterTone } from './utils' import './UsageMeter.scss' const WARN_AT = 75 @@ -15,12 +10,18 @@ const NOTIFICATION_THRESHOLDS = [WARN_AT, 100] export type UsageMeterProps = { total: number limit: PlanLimit + comparable?: boolean note?: ReactNode } -const UsageMeter: FC = ({ limit, note, total }) => { - const copy = meterCopy(total, limit) - const tone = toneFor(usagePercent(total, limit), WARN_AT) +const UsageMeter: FC = ({ + comparable = true, + limit, + note, + total, +}) => { + const copy = meterCopy(total, limit, comparable) + const tone = meterTone(total, limit, comparable, WARN_AT) return (
@@ -28,7 +29,11 @@ const UsageMeter: FC = ({ limit, note, total }) => {

Plan usage

- + {copy.headline} @@ -36,18 +41,20 @@ const UsageMeter: FC = ({ limit, note, total }) => {
-
-
- {Format.shortenNumber(total)} - {copy.fractionSuffix} + {copy.fraction && ( +
+
+ {copy.fraction.value} + {copy.fraction.suffix} +
+
+ {copy.fraction.caption} +
-
- {copy.fractionCaption} -
-
+ )}
- {!!limit && ( + {!!limit && comparable && ( { describe('meterCopy', () => { it('reads as a percentage of the limit when there is one', () => { expect(meterCopy(1500000, 2000000)).toEqual({ - fractionCaption: 'API calls used / plan limit', - fractionSuffix: ' / 2M', + fraction: { + caption: 'API calls used / plan limit', + suffix: ' / 2M', + value: '1.5M', + }, headline: '75%', headlineCaption: 'of plan consumed', }) @@ -20,17 +26,40 @@ describe('UsageMeter utils', () => { 'falls back to the raw count when the limit is %p', (limit) => { expect(meterCopy(1500000, limit)).toEqual({ - fractionCaption: 'API calls used', - fractionSuffix: '', + fraction: undefined, headline: '1.5M', headlineCaption: 'API calls', }) }, ) + it('reports the count and names the allowance window when not comparable', () => { + expect(meterCopy(1500000, 2000000, false)).toEqual({ + fraction: { caption: 'allowance per 30 days', value: '2M' }, + headline: '1.5M', + headlineCaption: 'API calls', + }) + }) + it('shows zero rather than NaN for an organisation with no calls', () => { expect(meterCopy(0, null).headline).toBe('0') expect(meterCopy(0, 2000000).headline).toBe('0%') }) }) + + describe('meterTone', () => { + it('tracks the thresholds when the comparison holds', () => { + expect(meterTone(500000, 2000000, true, 75)).toBe('success') + expect(meterTone(1600000, 2000000, true, 75)).toBe('warning') + expect(meterTone(2000000, 2000000, true, 75)).toBe('danger') + }) + + it('has no tone to give when the comparison does not hold', () => { + expect(meterTone(9000000, 2000000, false, 75)).toBeUndefined() + }) + + it('has no tone to give without a limit', () => { + expect(meterTone(9000000, null, true, 75)).toBeUndefined() + }) + }) }) diff --git a/frontend/web/components/pages/usage/components/UsageMeter/utils.ts b/frontend/web/components/pages/usage/components/UsageMeter/utils.ts index 80ddc2a5e9a2..dee226aa4de5 100644 --- a/frontend/web/components/pages/usage/components/UsageMeter/utils.ts +++ b/frontend/web/components/pages/usage/components/UsageMeter/utils.ts @@ -1,26 +1,53 @@ import Format from 'common/utils/format' -import { PlanLimit, usagePercent } from 'components/shared/UsageBar/utils' +import { + PlanLimit, + toneFor, + usagePercent, + UsageTone, +} from 'components/shared/UsageBar/utils' -export type MeterCopy = { +type MeterCopy = { headline: string headlineCaption: string - fractionSuffix: string - fractionCaption: string + fraction?: { + value: string + suffix?: string + caption: string + } } const withLimit = (total: number, limit: number): MeterCopy => ({ - fractionCaption: 'API calls used / plan limit', - fractionSuffix: ` / ${Format.shortenNumber(limit)}`, + fraction: { + caption: 'API calls used / plan limit', + suffix: ` / ${Format.shortenNumber(limit)}`, + value: Format.shortenNumber(total), + }, headline: `${usagePercent(total, limit)}%`, headlineCaption: 'of plan consumed', }) -const withoutLimit = (total: number): MeterCopy => ({ - fractionCaption: 'API calls used', - fractionSuffix: '', +const withoutLimit = (total: number, limit: PlanLimit): MeterCopy => ({ + fraction: limit + ? { + caption: 'allowance per 30 days', + value: Format.shortenNumber(limit), + } + : undefined, headline: Format.shortenNumber(total), headlineCaption: 'API calls', }) -export const meterCopy = (total: number, limit: PlanLimit): MeterCopy => - limit ? withLimit(total, limit) : withoutLimit(total) +export const meterCopy = ( + total: number, + limit: PlanLimit, + comparable = true, +): MeterCopy => + limit && comparable ? withLimit(total, limit) : withoutLimit(total, limit) + +export const meterTone = ( + total: number, + limit: PlanLimit, + comparable: boolean, + warnAt: number, +): UsageTone | undefined => + limit && comparable ? toneFor(usagePercent(total, limit), warnAt) : undefined diff --git a/frontend/web/components/pages/usage/utils.ts b/frontend/web/components/pages/usage/utils.ts index 75229f2349af..36ad86c9c09e 100644 --- a/frontend/web/components/pages/usage/utils.ts +++ b/frontend/web/components/pages/usage/utils.ts @@ -26,5 +26,8 @@ export const resolvePeriod = ( export const isBillingPeriodSelected = (period: BillingPeriod): boolean => period === 'current_billing_period' || period === 'previous_billing_period' +export const isComparableToAllowance = (period: BillingPeriod): boolean => + period !== '90_day_period' + export const periodsFor = (billingPeriodAvailable: boolean): PeriodOption[] => billingPeriodAvailable ? periodOptions : rollingPeriodOptions From d73e8c761de0cb488831d889573c183930c8f7a7 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Tue, 25 Aug 2026 16:55:09 -0300 Subject: [PATCH 2/4] fix(usage): say whose usage the meter is showing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Picking a project measured that project against the whole organisation's allowance while still calling it plan usage. The number was right, the label was not: it is that project's share of what you are allowed. The meter now reads "Plan usage · Checkout" and "of your allowance", rather than dropping the percentage and losing something useful. Fixes #8354 Co-Authored-By: Claude Opus 5 (1M context) --- .../components/pages/usage/UsageDashboard.tsx | 9 ++++++- .../pages/usage/UsageDashboardPage.tsx | 7 +++++- .../components/UsageMeter/UsageMeter.tsx | 6 +++-- .../UsageMeter/__tests__/utils.test.ts | 18 +++++++++++++ .../usage/components/UsageMeter/utils.ts | 25 ++++++++++++++++--- 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/frontend/web/components/pages/usage/UsageDashboard.tsx b/frontend/web/components/pages/usage/UsageDashboard.tsx index c22ba4748e40..d76339c8272b 100644 --- a/frontend/web/components/pages/usage/UsageDashboard.tsx +++ b/frontend/web/components/pages/usage/UsageDashboard.tsx @@ -10,6 +10,7 @@ export type UsageDashboardProps = { total: number limit: PlanLimit comparable?: boolean + projectName?: string hasBillingPeriod: boolean isError?: boolean isLoading?: boolean @@ -24,6 +25,7 @@ const UsageDashboard: FC = ({ isError, isLoading, limit, + projectName, total, }) => { let content @@ -45,7 +47,12 @@ const UsageDashboard: FC = ({ } else { content = ( <> - + = ({ organisationId, }) => { const [project, setProject] = useState() + const [projectName, setProjectName] = useState() const selectedProjectId = project ? Number(project) : undefined const { @@ -74,6 +75,7 @@ const UsageDashboardPage: FC = ({ limit={subscriptionMeta?.max_api_calls} hasBillingPeriod={isBillingPeriodSelected(billingPeriod)} comparable={isComparableToAllowance(billingPeriod)} + projectName={selectedProjectId ? projectName : undefined} isError={organisationFailed || usageFailed} isLoading={loadingOrganisation || loadingUsage || loadingLimit} filters={ @@ -93,7 +95,10 @@ const UsageDashboardPage: FC = ({ inputId='usage-project' showAll organisationId={organisationId} - onChange={setProject} + onChange={(id: string, name: string) => { + setProject(id) + setProjectName(name) + }} value={project} />
diff --git a/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx b/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx index 11ad3c4016b6..03c08ff3bcb8 100644 --- a/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx +++ b/frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx @@ -11,6 +11,7 @@ export type UsageMeterProps = { total: number limit: PlanLimit comparable?: boolean + projectName?: string note?: ReactNode } @@ -18,16 +19,17 @@ const UsageMeter: FC = ({ comparable = true, limit, note, + projectName, total, }) => { - const copy = meterCopy(total, limit, comparable) + const copy = meterCopy(total, limit, comparable, projectName) const tone = meterTone(total, limit, comparable, WARN_AT) return (
-

Plan usage

+

{copy.label}

{ }, headline: '75%', headlineCaption: 'of plan consumed', + label: 'Plan usage', }) }) @@ -29,6 +30,7 @@ describe('UsageMeter utils', () => { fraction: undefined, headline: '1.5M', headlineCaption: 'API calls', + label: 'Plan usage', }) }, ) @@ -38,9 +40,25 @@ describe('UsageMeter utils', () => { fraction: { caption: 'allowance per 30 days', value: '2M' }, headline: '1.5M', headlineCaption: 'API calls', + label: 'Plan usage', }) }) + it('names the project and what the percentage is of when one is chosen', () => { + const copy = meterCopy(500000, 2000000, true, 'Checkout') + + expect(copy.label).toBe('Plan usage · Checkout') + expect(copy.headline).toBe('25%') + expect(copy.headlineCaption).toBe('of your allowance') + }) + + it('keeps naming the project when the period rules the percentage out', () => { + const copy = meterCopy(500000, 2000000, false, 'Checkout') + + expect(copy.label).toBe('Plan usage · Checkout') + expect(copy.headline).toBe('500K') + }) + it('shows zero rather than NaN for an organisation with no calls', () => { expect(meterCopy(0, null).headline).toBe('0') expect(meterCopy(0, 2000000).headline).toBe('0%') diff --git a/frontend/web/components/pages/usage/components/UsageMeter/utils.ts b/frontend/web/components/pages/usage/components/UsageMeter/utils.ts index dee226aa4de5..1f1367e49269 100644 --- a/frontend/web/components/pages/usage/components/UsageMeter/utils.ts +++ b/frontend/web/components/pages/usage/components/UsageMeter/utils.ts @@ -7,6 +7,7 @@ import { } from 'components/shared/UsageBar/utils' type MeterCopy = { + label: string headline: string headlineCaption: string fraction?: { @@ -16,17 +17,29 @@ type MeterCopy = { } } -const withLimit = (total: number, limit: number): MeterCopy => ({ +const labelFor = (projectName?: string) => + projectName ? `Plan usage · ${projectName}` : 'Plan usage' + +const withLimit = ( + total: number, + limit: number, + projectName?: string, +): MeterCopy => ({ fraction: { caption: 'API calls used / plan limit', suffix: ` / ${Format.shortenNumber(limit)}`, value: Format.shortenNumber(total), }, headline: `${usagePercent(total, limit)}%`, - headlineCaption: 'of plan consumed', + headlineCaption: projectName ? 'of your allowance' : 'of plan consumed', + label: labelFor(projectName), }) -const withoutLimit = (total: number, limit: PlanLimit): MeterCopy => ({ +const withoutLimit = ( + total: number, + limit: PlanLimit, + projectName?: string, +): MeterCopy => ({ fraction: limit ? { caption: 'allowance per 30 days', @@ -35,14 +48,18 @@ const withoutLimit = (total: number, limit: PlanLimit): MeterCopy => ({ : undefined, headline: Format.shortenNumber(total), headlineCaption: 'API calls', + label: labelFor(projectName), }) export const meterCopy = ( total: number, limit: PlanLimit, comparable = true, + projectName?: string, ): MeterCopy => - limit && comparable ? withLimit(total, limit) : withoutLimit(total, limit) + limit && comparable + ? withLimit(total, limit, projectName) + : withoutLimit(total, limit, projectName) export const meterTone = ( total: number, From 12bf7844c6513ce652d407b03b51c95e292d3049 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Tue, 25 Aug 2026 16:55:35 -0300 Subject: [PATCH 3/4] fix(usage): keep the chart's ceiling off a filtered view The meter and the chart answer different questions, so they need different rules. A project's share of the allowance is a fact worth stating. A ceiling on the chart implies a trajectory towards a limit one project will never reach, which is the point Matt made about the per-endpoint chart back in July. Co-Authored-By: Claude Opus 5 (1M context) --- .../components/pages/usage/UsageDashboard.tsx | 4 +++- .../pages/usage/UsageDashboardPage.tsx | 2 ++ .../pages/usage/__tests__/utils.test.ts | 17 +++++++++++++++++ frontend/web/components/pages/usage/utils.ts | 5 +++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/frontend/web/components/pages/usage/UsageDashboard.tsx b/frontend/web/components/pages/usage/UsageDashboard.tsx index d76339c8272b..843d320d9bc9 100644 --- a/frontend/web/components/pages/usage/UsageDashboard.tsx +++ b/frontend/web/components/pages/usage/UsageDashboard.tsx @@ -10,6 +10,7 @@ export type UsageDashboardProps = { total: number limit: PlanLimit comparable?: boolean + showPlanCeiling?: boolean projectName?: string hasBillingPeriod: boolean isError?: boolean @@ -26,6 +27,7 @@ const UsageDashboard: FC = ({ isLoading, limit, projectName, + showPlanCeiling, total, }) => { let content @@ -56,7 +58,7 @@ const UsageDashboard: FC = ({ diff --git a/frontend/web/components/pages/usage/UsageDashboardPage.tsx b/frontend/web/components/pages/usage/UsageDashboardPage.tsx index 73dad3186dd6..8c7bcca0c74c 100644 --- a/frontend/web/components/pages/usage/UsageDashboardPage.tsx +++ b/frontend/web/components/pages/usage/UsageDashboardPage.tsx @@ -11,6 +11,7 @@ import UsageDashboard from './UsageDashboard' import { isBillingPeriodSelected, isComparableToAllowance, + showsPlanCeiling, periodsFor, PeriodSelection, planHasBillingPeriod, @@ -75,6 +76,7 @@ const UsageDashboardPage: FC = ({ limit={subscriptionMeta?.max_api_calls} hasBillingPeriod={isBillingPeriodSelected(billingPeriod)} comparable={isComparableToAllowance(billingPeriod)} + showPlanCeiling={showsPlanCeiling(billingPeriod, selectedProjectId)} projectName={selectedProjectId ? projectName : undefined} isError={organisationFailed || usageFailed} isLoading={loadingOrganisation || loadingUsage || loadingLimit} diff --git a/frontend/web/components/pages/usage/__tests__/utils.test.ts b/frontend/web/components/pages/usage/__tests__/utils.test.ts index fe3aa29a009e..66149b854064 100644 --- a/frontend/web/components/pages/usage/__tests__/utils.test.ts +++ b/frontend/web/components/pages/usage/__tests__/utils.test.ts @@ -1,6 +1,7 @@ import { Subscription } from 'common/types/responses' import { isComparableToAllowance, + showsPlanCeiling, isBillingPeriodSelected, planHasBillingPeriod, periodsFor, @@ -93,6 +94,22 @@ describe('UsageDashboard utils', () => { }) }) + describe('showsPlanCeiling', () => { + it('draws the ceiling for the organisation over a comparable period', () => { + expect(showsPlanCeiling(undefined, undefined)).toBe(true) + expect(showsPlanCeiling('current_billing_period', undefined)).toBe(true) + }) + + it('drops it for one project, which will never reach the ceiling', () => { + expect(showsPlanCeiling(undefined, 12)).toBe(false) + expect(showsPlanCeiling('current_billing_period', 12)).toBe(false) + }) + + it('drops it for the 90 day window', () => { + expect(showsPlanCeiling('90_day_period', undefined)).toBe(false) + }) + }) + describe('periodsFor', () => { it('offers the billing periods only when there is a term', () => { expect(periodsFor(true).map((period) => period.value)).toContain( diff --git a/frontend/web/components/pages/usage/utils.ts b/frontend/web/components/pages/usage/utils.ts index 36ad86c9c09e..50afe355d128 100644 --- a/frontend/web/components/pages/usage/utils.ts +++ b/frontend/web/components/pages/usage/utils.ts @@ -29,5 +29,10 @@ export const isBillingPeriodSelected = (period: BillingPeriod): boolean => export const isComparableToAllowance = (period: BillingPeriod): boolean => period !== '90_day_period' +export const showsPlanCeiling = ( + period: BillingPeriod, + projectId: number | undefined, +): boolean => isComparableToAllowance(period) && !projectId + export const periodsFor = (billingPeriodAvailable: boolean): PeriodOption[] => billingPeriodAvailable ? periodOptions : rollingPeriodOptions From bfe04943fc4df0df0019ad5a57b76a9ac3033d4c Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Tue, 25 Aug 2026 16:55:49 -0300 Subject: [PATCH 4/4] feat(usage): offer a retry when usage fails to load Failing to load left you reloading the page. The retry refetches the organisation first, since a failed organisation query leaves the usage query skipped and retrying it alone cannot recover the page. Co-Authored-By: Claude Opus 5 (1M context) --- .../components/pages/usage/UsageDashboard.tsx | 9 ++++++++ .../pages/usage/UsageDashboardPage.tsx | 21 +++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/frontend/web/components/pages/usage/UsageDashboard.tsx b/frontend/web/components/pages/usage/UsageDashboard.tsx index 843d320d9bc9..c939c059fb82 100644 --- a/frontend/web/components/pages/usage/UsageDashboard.tsx +++ b/frontend/web/components/pages/usage/UsageDashboard.tsx @@ -15,6 +15,7 @@ export type UsageDashboardProps = { hasBillingPeriod: boolean isError?: boolean isLoading?: boolean + onRetry?: () => void filters?: ReactNode } @@ -26,6 +27,7 @@ const UsageDashboard: FC = ({ isError, isLoading, limit, + onRetry, projectName, showPlanCeiling, total, @@ -44,6 +46,13 @@ const UsageDashboard: FC = ({ title='Usage could not be loaded' description='Something went wrong fetching usage for this period. Try again in a moment.' icon='bar-chart' + action={ + onRetry && ( + + ) + } /> ) } else { diff --git a/frontend/web/components/pages/usage/UsageDashboardPage.tsx b/frontend/web/components/pages/usage/UsageDashboardPage.tsx index 8c7bcca0c74c..9288e863552a 100644 --- a/frontend/web/components/pages/usage/UsageDashboardPage.tsx +++ b/frontend/web/components/pages/usage/UsageDashboardPage.tsx @@ -34,6 +34,7 @@ const UsageDashboardPage: FC = ({ data: organisation, isError: organisationFailed, isLoading: loadingOrganisation, + refetch: refetchOrganisation, } = useGetOrganisationQuery( organisationId ? { id: organisationId } : skipToken, ) @@ -49,6 +50,8 @@ const UsageDashboardPage: FC = ({ data, isError: usageFailed, isFetching: loadingUsage, + isUninitialized: usageNotStarted, + refetch: refetchUsage, } = useGetOrganisationUsageQuery( organisationId && organisation ? { @@ -58,10 +61,13 @@ const UsageDashboardPage: FC = ({ } : skipToken, ) - const { data: subscriptionMeta, isLoading: loadingLimit } = - useGetSubscriptionMetadataQuery( - organisationId ? { id: organisationId } : skipToken, - ) + const { + data: subscriptionMeta, + isLoading: loadingLimit, + refetch: refetchLimit, + } = useGetSubscriptionMetadataQuery( + organisationId ? { id: organisationId } : skipToken, + ) const periods = periodsFor(planIsBilled) @@ -80,6 +86,13 @@ const UsageDashboardPage: FC = ({ projectName={selectedProjectId ? projectName : undefined} isError={organisationFailed || usageFailed} isLoading={loadingOrganisation || loadingUsage || loadingLimit} + onRetry={() => { + refetchOrganisation() + refetchLimit() + if (!usageNotStarted) { + refetchUsage() + } + }} filters={