Skip to content

feat(usage): Show usage against the plan limit for the current billing period - #8320

Open
talissoncosta wants to merge 19 commits into
mainfrom
feat/usage-plan-limit-8185
Open

feat(usage): Show usage against the plan limit for the current billing period#8320
talissoncosta wants to merge 19 commits into
mainfrom
feat/usage-plan-limit-8185

Conversation

@talissoncosta

@talissoncosta talissoncosta commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Reviewing this

Every state is in Storybook under Pages > Usage Dashboard if you want to scan them quickly.

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Closes #8185

Shows usage against the plan allowance. Behind usage_dashboard, off everywhere. Replaces the old page rather than extending it, so nothing changes until the flag is on.

  • a meter: percentage consumed, used against limit, notification thresholds
  • a chart: cumulative against the limit where there is a billing period, daily bars where there is not, because a rolling window's total falls as old days leave it
  • loading, failure and empty states

Worth knowing:

  • free plans now default to 30 days rather than 90, which is the window enforcement actually measures
  • UsageBar gains thresholds, warnAt and ariaLabel. warnAt defaults to 85, so the two other pages using it are unchanged
  • also fixes Format.shortenNumber, which returned NaN for 0. OrganisationLimit had the same exposure

Not here: period dates (#8258), projection (#8188), over-limit and restricted states (#8187), breakdown (#8186). The flag should stay internal until #8186, since swapping the page loses the request-type totals and the SDK view.

How did you test this code?

99 unit tests over the period rules, the daily aggregation, the bar maths and the meter copy.

To QA, with usage_dashboard on:

  • paid org: meter shows % of plan, chart is a rising line with a red limit ceiling
  • free org: daily bars, period defaults to "Last 30 days"
  • project filter on a project with no traffic: "No usage recorded", not blank space
  • flag off: Organisation Settings > Usage behaves as today
  • Project Settings > Usage bars unchanged

@vercel

vercel Bot commented Aug 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
flagsmith-frontend-preview Ready Ready Preview Aug 24, 2026 4:16pm
flagsmith-frontend-staging Ready Ready Preview Aug 24, 2026 4:16pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Aug 24, 2026 4:16pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • No new commits to review - use @coderabbitai full review for a full pass
📝 Walkthrough

Walkthrough

The change adds a feature-flagged usage dashboard with billing-period and project filters. It introduces reusable usage bars, meters, charts, threshold markers, loading and error states, and usage aggregation utilities. It updates subscription and period types, improves nullable number formatting, replaces the previous UsageBar, and adds Storybook scenarios and unit tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🔴 Critical · up to e9d86

The replacement usage dashboard currently contains a compile-blocking reference and can also show incorrect loading or usage states in several edge cases, while some accessibility and zero-limit handling still need follow-up. Merge should be blocked until the compilation and loading correctness issues are fixed.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-api:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api-test:pr-8320 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-e2e:pr-8320 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-frontend:pr-8320 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8320 Finished ✅ Results

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe27ff58-f01f-49de-a201-6baefc45fcf3

📥 Commits

Reviewing files that changed from the base of the PR and between b7676e4 and bc0e15c.

📒 Files selected for processing (22)
  • frontend/common/types/responses.ts
  • frontend/common/utils/__tests__/format.test.ts
  • frontend/common/utils/format.ts
  • frontend/documentation/components/UsageBar.stories.tsx
  • frontend/documentation/components/UsageDashboard.stories.tsx
  • frontend/documentation/components/UsageMeter.stories.tsx
  • frontend/documentation/components/UsageOverTime.stories.tsx
  • frontend/web/components/charts/LineChart.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboard.scss
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboard.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboardView.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/index.ts
  • frontend/web/components/organisation-settings/usage/UsageMeter/UsageMeter.scss
  • frontend/web/components/organisation-settings/usage/UsageMeter/UsageMeter.tsx
  • frontend/web/components/organisation-settings/usage/UsageMeter/index.ts
  • frontend/web/components/organisation-settings/usage/UsageOverTime/UsageOverTime.tsx
  • frontend/web/components/organisation-settings/usage/UsageOverTime/index.ts
  • frontend/web/components/pages/OrganisationUsagePage.tsx
  • frontend/web/components/shared/UsageBar.tsx
  • frontend/web/components/shared/UsageBar/UsageBar.scss
  • frontend/web/components/shared/UsageBar/UsageBar.tsx
  • frontend/web/components/shared/UsageBar/index.ts
💤 Files with no reviewable changes (1)
  • frontend/web/components/shared/UsageBar.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.

Comment thread frontend/common/utils/__tests__/format.test.ts
Comment thread frontend/common/utils/format.ts Outdated
Comment thread frontend/documentation/components/UsageDashboard.stories.tsx Outdated
Comment thread frontend/documentation/components/UsageDashboard.stories.tsx Outdated
Comment thread frontend/documentation/components/UsageMeter.stories.tsx
Comment thread frontend/web/components/organisation-settings/usage/UsageMeter/UsageMeter.tsx Outdated
Comment thread frontend/web/components/pages/OrganisationUsagePage.tsx Outdated
Comment thread frontend/web/components/shared/UsageBar/UsageBar.tsx Outdated
@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor
✅ private-cloud · depot-ubuntu-latest-16 — run #19685 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  26.6 seconds
commit  b40100b
info  🔄 Run: #19685 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19685 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  38.6 seconds
commit  b40100b
info  🔄 Run: #19685 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19683 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  54.9 seconds
commit  5721594
info  🔄 Run: #19683 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19685 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  40.6 seconds
commit  b40100b
info  🔄 Run: #19685 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19683 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  36.2 seconds
commit  5721594
info  🔄 Run: #19683 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19685 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  35.6 seconds
commit  b40100b
info  🔄 Run: #19685 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19683 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  42.5 seconds
commit  5721594
info  🔄 Run: #19683 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19683 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  44.7 seconds
commit  5721594
info  🔄 Run: #19683 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19681 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  1 minute, 4 seconds
commit  256b02c
info  🔄 Run: #19681 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19681 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  45 seconds
commit  256b02c
info  🔄 Run: #19681 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19681 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  23 passed
skipped  1 skipped

Details

stats  24 tests across 18 suites
duration  1 minute, 25 seconds
commit  256b02c
info  🔄 Run: #19681 (attempt 1)

Skipped tests

firefox › tests/onboarding-tests.pw.ts › Onboarding › New user connects via the single-page onboarding flow @oss

✅ oss · depot-ubuntu-latest-16 — run #19681 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  33 seconds
commit  256b02c
info  🔄 Run: #19681 (attempt 1)

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

19 screenshots compared. See report for details.
View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboard.tsx (1)

48-56: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid rendering cached usage after filter changes.

billing_period and projectId create new query keys, but RTK Query retains data while fetching and isLoading is false after the first result. Use isFetching in UsageDashboardView, or use currentData for the active filters. Add a filter-change test.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7d514ea7-d3c3-494e-9999-de4aba7f2312

📥 Commits

Reviewing files that changed from the base of the PR and between 51e15b5 and 3b2963e.

📒 Files selected for processing (5)
  • frontend/documentation/components/UsageDashboard.stories.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboard.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboardView.tsx
  • frontend/web/components/organisation-settings/usage/UsageOverTime/UsageOverTime.tsx
  • frontend/web/components/pages/OrganisationUsagePage.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f9fbe040-8f6e-4a07-be5a-c1285f1a57bc

📥 Commits

Reviewing files that changed from the base of the PR and between aa4dc62 and ee40e96.

📒 Files selected for processing (10)
  • frontend/documentation/components/UsageDashboard.stories.tsx
  • frontend/documentation/components/UsageMeter.stories.tsx
  • frontend/documentation/components/UsageOverTime.stories.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboard.tsx
  • frontend/web/components/organisation-settings/usage/UsageMeter/utils.ts
  • frontend/web/components/organisation-settings/usage/UsageOverTime/UsageOverTime.tsx
  • frontend/web/components/pages/OrganisationUsagePage.tsx
  • frontend/web/components/shared/UsageBar/UsageBar.scss
  • frontend/web/components/shared/UsageBar/UsageBarThresholds.scss
  • frontend/web/components/shared/UsageBar/UsageBarThresholds.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.

Comment thread frontend/web/components/organisation-settings/usage/UsageMeter/utils.ts Outdated
Comment thread frontend/web/components/shared/UsageBar/UsageBarThresholds.tsx

@talissoncosta talissoncosta left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes on the parts that are not self-evident.

Comment thread frontend/web/components/pages/OrganisationUsagePage.tsx
Comment thread frontend/web/components/pages/usage/utils.ts
Comment thread frontend/web/components/shared/UsageBar/UsageBar.tsx
Comment thread frontend/common/types/requests.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3bbc8a58-9980-48b0-9ffa-e2411d5051de

📥 Commits

Reviewing files that changed from the base of the PR and between 316e61f and 6dab140.

📒 Files selected for processing (1)
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboardView.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/web/components/shared/UsageBar/UsageBar.tsx (2)

1-14: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the three relative imports in UsageBar.tsx with approved common/, components/, or project/ paths.

Source: Coding guidelines


23-33: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Require an accessible name for every progressbar.

label and ariaLabel are optional, so aria-label={label ?? ariaLabel} can be undefined. Require label or ariaLabel with a named union type.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 97e6155e-7eb1-41f0-8a02-1aeb005c9b8a

📥 Commits

Reviewing files that changed from the base of the PR and between 6dab140 and 39ee00e.

📒 Files selected for processing (1)
  • frontend/web/components/shared/UsageBar/UsageBar.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f65d6a5d-0ef0-45a9-a0fe-d83c8cb701fd

📥 Commits

Reviewing files that changed from the base of the PR and between 39ee00e and e9d8679.

📒 Files selected for processing (3)
  • frontend/web/components/ProjectFilter.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboard.tsx
  • frontend/web/components/organisation-settings/usage/UsageDashboard/UsageDashboardView.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/web/components/pages/usage/UsageDashboardPage.tsx (1)

19-113: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Move the new components to the required component-folder layout.

The new dashboard components do not consistently provide a component folder, barrel, implementation file, and co-located Sass file.

  • frontend/web/components/pages/usage/UsageDashboardPage.tsx#L19-L113: move this component to UsageDashboardPage/UsageDashboardPage.tsx and add its barrel.
  • frontend/web/components/pages/usage/UsageDashboard.tsx#L24-L80: move this component to UsageDashboard/UsageDashboard.tsx, add its barrel, and co-locate its Sass file.
  • frontend/web/components/pages/usage/components/UsageOverTime/UsageOverTime.tsx#L26-L85: add and import UsageOverTime.scss in this component folder.
  • frontend/web/components/pages/usage/UsageDashboardPage.scss#L1-L4: move this stylesheet into the UsageDashboardPage component folder and import it from the component.

As per coding guidelines, “Each new component must live in its own folder with a barrel index.ts, a ComponentName/ComponentName.tsx file, co-located ComponentName.scss.”

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d8af2905-8555-48c2-914b-06c4079a2636

📥 Commits

Reviewing files that changed from the base of the PR and between e9d8679 and 26f0e05.

📒 Files selected for processing (19)
  • frontend/documentation/components/UsageDashboard.stories.tsx
  • frontend/documentation/components/UsageMeter.stories.tsx
  • frontend/documentation/components/UsageOverTime.stories.tsx
  • frontend/web/components/pages/OrganisationUsagePage.tsx
  • frontend/web/components/pages/usage/UsageDashboard.tsx
  • frontend/web/components/pages/usage/UsageDashboardPage.scss
  • frontend/web/components/pages/usage/UsageDashboardPage.tsx
  • frontend/web/components/pages/usage/__tests__/utils.test.ts
  • frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.scss
  • frontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsx
  • frontend/web/components/pages/usage/components/UsageMeter/__tests__/utils.test.ts
  • frontend/web/components/pages/usage/components/UsageMeter/index.ts
  • frontend/web/components/pages/usage/components/UsageMeter/utils.ts
  • frontend/web/components/pages/usage/components/UsageOverTime/UsageOverTime.tsx
  • frontend/web/components/pages/usage/components/UsageOverTime/__tests__/utils.test.ts
  • frontend/web/components/pages/usage/components/UsageOverTime/index.ts
  • frontend/web/components/pages/usage/components/UsageOverTime/utils.ts
  • frontend/web/components/pages/usage/index.ts
  • frontend/web/components/pages/usage/utils.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@Zaimwa9 Zaimwa9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall good, a couple of comments as I think there is a sort of conflict related to the billing periods.
If I understand correctly, this is just the first step of a ~5/6 other PRs right ?

atLimit ? 'danger' : 'warning'
}`}
>
Notify {threshold}%

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Can we ensure a bit of margin on the right there please ?

And a bit of vertical space against the ticker
Image

organisationId: number | undefined
}

/** Behind `usage_dashboard`. Owns the fetching; the view draws the result. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this kind of comments? Same goes for the one L20 that would otherwise be valid for half the props type definition

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed it. thanks. Removed. 482f03a

import { PeriodOption } from 'common/types/requests'
import UsageDashboard from './UsageDashboard'
import {
hasBillingPeriod as deriveHasBillingPeriod,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO something is wrong with the naming if we need to always use an alias to use the function. In the downstream variable or in the function name

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Renamed to planHasBillingPeriod. 482f03a

const hasBillingPeriod = deriveHasBillingPeriod(subscription, isFreePlan)

const [chosenPeriod, setChosenPeriod] = useState<PeriodSelection>('default')
const billingPeriod = resolvePeriod(chosenPeriod, hasBillingPeriod)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something looks wrong to me here. The hasBillingPeriod is derived from the organisation subscription right ?
Meaning that as long as the organisation as a billing period, it will be shown the 4 period options, including last 30/90 days (rolling window).
So if you select one of those 2, the data will be drawn against the wrong plan limit (90 days usage against monthly limit)

It's actually also visible without a billing period:

Image Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Split in two: planHasBillingPeriod decides which options are offered, isBillingPeriodSelected decides whether the chart draws against the limit. Rolling windows no longer get a limit line. 482f03a

const {
data,
isError: usageFailed,
isLoading: loadingUsage,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isFetching would allow to show the loader again on period updates while isLoading will be true only during the initial fetch if I recall well.
Is it intentional?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intentional. Switched to isFetching. 482f03a

<div className='p-4 border border-default rounded-lg bg-surface-default'>
<div className='d-flex align-items-baseline justify-content-between gap-3 mb-3'>
<strong>
{isBillingPeriod ? 'Usage vs plan limit' : 'Daily usage'}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For self hosted there is no limit, so maybe we could fallback to plain Usage or Cumulative usage if limit is null ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 482f03a

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Falls back to Cumulative usage when there's no limit

import { useGetSubscriptionMetadataQuery } from 'common/services/useSubscriptionMetadata'
import UsageChartFilters from 'components/organisation-settings/usage/components/UsageChartFilters'
import UsageChartTotals from 'components/organisation-settings/usage/components/UsageChartTotals'
import UsageDashboard from './usage'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to nitpick on the import naming but that is a bit confusing versus UsageDashboardPage

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Renamed to UsageDashboardPage. 482f03a

talissoncosta and others added 17 commits August 24, 2026 12:25
Math.log10(0) is -Infinity, so a count of zero came back as NaN rather than
'0'. Any surface rendering a total while its query is in flight showed it,
including OrganisationLimit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Moves the flat file into a folder and separates the header and the threshold
strip, each with its own stylesheet. The percentage, clamping and tone maths
move to utils and are tested.

Adds thresholds, warnAt and ariaLabel. warnAt defaults to 85, so ProjectUsageTab
and EnvironmentOverrideUsage render exactly as before. The fill now reads its
colour from the border tokens instead of Bootstrap's theme colours: the values
are identical, but the tokens follow the theme.

aria-valuenow is clamped to the declared range, since usage can exceed the limit
while a progressbar cannot report past its maximum.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The y-axis grows to include it, so a threshold above the data stays in view.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
billingPeriods also held the rolling windows, and freePeriods is not free-only:
enterprise agreements without a Chargebee term use it too. Typing both arrays as
PeriodOption narrows their value from string to the billing_period union, which
is what the query actually accepts.

Also types has_active_billing_periods, which the dashboard reads to decide
whether usage accumulates towards a reset.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…g period

Closes #8185

Behind usage_dashboard, off everywhere. The new page replaces the old one
rather than extending it, so nothing changes until the flag is on.

- a meter: percentage consumed, used against limit, notification thresholds
- usage over time: cumulative against the limit where there is a billing
  period, daily volume where there is not, because a rolling window's total
  falls as old days leave it
- loading, failure and empty states, so a failed query no longer reads as an
  organisation that made no calls

The rules live in utils modules and are tested: whether a plan has a billing
term, how a chosen period resolves against the default, daily aggregation, and
the meter's two readings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Most cannot be reached on a dev machine: an enterprise agreement has no billing
term, so the cumulative chart and its ceiling never render locally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The usage query ran before the organisation loaded, so a billed organisation
asked for the rolling window first and corrected itself once the plan arrived:
an extra request and a visibly wrong period on the way.

The subscription metadata query was also unwatched, so while it loaded the
meter read as an organisation with no plan limit rather than as loading. Its
failure stays non-fatal, since no metadata is what self-hosted looks like.

PlanLimit replaces the nullable-number union repeated across six files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Changing the period or project filter moved the bar in one jump. Honours
prefers-reduced-motion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UsageDashboardView was eight lines of JSX and a props type it never read,
spreading everything straight through to a second component. The split cost
a duplicated contract and two names that both meant "the part that renders".

The states only needed to sit inside the layout so the heading survives them,
which a variable does as well as a component.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nineteen lines, one consumer, three props forwarded straight from UsageBar's
own, and a body of two spans in a flex row. It was a file, not a component.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The selects had no accessible name, so both announced as a bare combobox.
The page this replaces labelled all three. Uses FieldLabel with htmlFor wired
to the control's inputId, so the label is visible as well as announced.

The subscription metadata query no longer blocks the page. Its failure was
already treated as non-fatal, since no metadata means no limit, so waiting on
it was the inconsistent half.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Failure staying non-fatal was right, but the wait is not the same thing.
Until the metadata answers, limit is undefined and the meter reports "no
plan limit", which is a claim rather than an absence, then corrects itself.

Reverses the loading half of 8b04ea1; the failure half stands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It is the route once the flag is on, and OrganisationUsagePage does nothing
but render it. Follows pages/sdk-keys and pages/feature-lifecycle: a feature
folder holding the XPage.tsx route plus its own components/.

UsageDashboardView becomes UsageDashboard, since the page suffix now carries
the fetching half and the plain name can go to the part that renders.

Everything the flag still needs stays in organisation-settings/usage, so
removing the flag becomes a delete rather than another move.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two test files each carried their own event and response builders, both
casting because they omitted totals. The shared response now computes totals
from the events it was given, so the fixture cannot claim a figure its own
events disagree with, and the cast goes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cted

hasBillingPeriod came from the subscription, but it also decided whether the
chart accumulated against the plan limit. A billed organisation is still
offered the rolling windows, so picking "Last 90 days" drew 90 days of usage
against a monthly allowance. The chart now follows the period being viewed;
which options are offered still follows the subscription.

Also from review:

- isFetching rather than isLoading, so changing period shows the loader
  instead of the previous period's figures
- the chart heading no longer promises a comparison self-hosted cannot make,
  falling back to "Cumulative usage" when there is no limit
- planHasBillingPeriod, so no call site has to alias it
- the threshold labels clear the ticker and the right edge
- OrganisationUsagePage imports UsageDashboardPage under its own name

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Removes the docblocks and prop comments that described what a component is,
and the inline notes explaining decisions. The record moved to
frontend/USAGE_DASHBOARD_DECISIONS.md, which is where someone about to change
one of these should look.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@talissoncosta

Copy link
Copy Markdown
Contributor Author

Thanks for the thoughtful review @Zaimwa9
I've addressed the changes. Yes, this is 1/5 ~ .

talissoncosta and others added 2 commits August 24, 2026 13:12
Docblocks, prop comments and inline reasoning removed across the dashboard,
the meter, the chart and the shared bar. The record is in
frontend/USAGE_DASHBOARD_DECISIONS.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request front-end Issue related to the React Front End Dashboard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show usage against the plan limit for the current billing period

3 participants