fix(usage): meter comparability and unbounded loading - #8357
fix(usage): meter comparability and unbounded loading#8357talissoncosta wants to merge 5 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueNote Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe change adds billing-period comparability checks and project-aware usage rendering. It adds a timer hook for loading requests that exceed 20 seconds. The usage dashboard now renders stalled and error states and supports retry callbacks that refetch usage and subscription data. Usage meters now adjust copy and tone and hide the allowance bar when comparison is not valid. Tests cover period comparability, meter copy, and meter tones. Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: 🟡 Moderate · up to The dashboard now handles non-comparable usage and stalled requests, but the current head can still show inconsistent allowance behavior, hide subscription-metadata failures without a retry action, and briefly display stale timeout states after request changes. These bounded UI correctness and recovery issues should be fixed or explicitly accepted before merging. 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. Comment |
Docker builds report
|
70ec520 to
202ccf8
Compare
❌ private-cloud · depot-ubuntu-latest-16 — run #19757 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
Failed testsfirefox › tests/change-request-test.pw.ts › Change Request Tests › Change requests can be created, approved, and published with four-eyes approval @enterprise 🗂️ Previous results✅ private-cloud · depot-ubuntu-latest-16 — run #19759 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19759 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
✅ oss · depot-ubuntu-latest-16 — run #19759 (attempt 1)Playwright Test Results (oss - depot-ubuntu-latest-16)Details
✅ oss · depot-ubuntu-latest-arm-16 — run #19757 (attempt 1)Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
✅ oss · depot-ubuntu-latest-16 — run #19757 (attempt 1)Playwright Test Results (oss - depot-ubuntu-latest-16)Details
✅ private-cloud · depot-ubuntu-latest-16 — run #19746 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19746 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
✅ oss · depot-ubuntu-latest-arm-16 — run #19746 (attempt 1)Playwright Test Results (oss - depot-ubuntu-latest-arm-16)Details
✅ oss · depot-ubuntu-latest-16 — run #19746 (attempt 1)Playwright Test Results (oss - depot-ubuntu-latest-16)Details
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19743 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)Details
✅ private-cloud · depot-ubuntu-latest-16 — run #19743 (attempt 1)Playwright Test Results (private-cloud - depot-ubuntu-latest-16)Details
|
Visual Regression15 screenshots compared. See report for details. |
There was a problem hiding this comment.
Actionable comments posted: 9
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 8e46f0f1-f8fb-4bf7-be3e-438740499572
📒 Files selected for processing (13)
frontend/CHANGE_REQUEST_STUCK_BUTTON_INVESTIGATION.mdfrontend/CSS_TOKEN_GAPS_PLAN.mdfrontend/MV_IDENTITY_OVERRIDE_EDITOR_NOTES.mdfrontend/USAGE_DASHBOARD_DECISIONS.mdfrontend/USAGE_DASHBOARD_PARITY.mdfrontend/common/hooks/useTakingTooLong.tsfrontend/web/components/pages/usage/UsageDashboard.tsxfrontend/web/components/pages/usage/UsageDashboardPage.tsxfrontend/web/components/pages/usage/__tests__/utils.test.tsfrontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsxfrontend/web/components/pages/usage/components/UsageMeter/__tests__/utils.test.tsfrontend/web/components/pages/usage/components/UsageMeter/utils.tsfrontend/web/components/pages/usage/utils.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.
|
|
||
| ## How to reproduce | ||
|
|
||
| ### Symptom — deterministic, no Zoox data needed |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add blank lines after the affected headings.
markdownlint-cli2 reports MD022 warnings because these headings are not followed by a blank line. Add one blank line after each heading at Lines 52, 60, 65, and 70.
Also applies to: 60-60, 65-65, 70-70
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 52-52: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
Source: Linters/SAST tools
| a route-level component that fetches and renders. None of them is paired, so it | ||
| does not name the rendering half, but it names the fetching half exactly: | ||
|
|
||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a language to the fenced code block.
Line [186] opens a fenced code block without a language. Markdownlint MD040 reports this. Use text for this filename map, or the correct language identifier, so documentation lint passes.
This addresses the markdownlint warning reported for Line [186].
Proposed fix
-```
+```text📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ``` |
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 186-186: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
Source: Linters/SAST tools
There was a problem hiding this comment.
Actionable comments posted: 3
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: efad4046-5647-40ef-9d40-cec84cc76248
📒 Files selected for processing (6)
frontend/common/hooks/useTakingTooLong.tsfrontend/web/components/pages/usage/UsageDashboard.tsxfrontend/web/components/pages/usage/UsageDashboardPage.tsxfrontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsxfrontend/web/components/pages/usage/components/UsageMeter/__tests__/utils.test.tsfrontend/web/components/pages/usage/components/UsageMeter/utils.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.
| return () => clearTimeout(timer) | ||
| }, [active, afterMs, attempt]) | ||
|
|
||
| return tooLong |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- frontend/common/hooks/useTakingTooLong.ts ---'
cat -n frontend/common/hooks/useTakingTooLong.ts
printf '%s\n' '--- UsageDashboard references ---'
rg -n -C 8 'useTakingTooLong|tooLong' frontend --glob '*.{ts,tsx}'Repository: Flagsmith/flagsmith
Length of output: 4719
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- UsageDashboard render branches ---'
sed -n '33,125p' frontend/web/components/pages/usage/UsageDashboard.tsx
printf '%s\n' '--- directly named hook tests/usages ---'
rg -n -C 5 'useTakingTooLong|STALLED_AFTER_MS|stalled' frontend --glob '*.{test,spec}.{ts,tsx}' --glob '*.{ts,tsx}'Repository: Flagsmith/flagsmith
Length of output: 11878
Return active && tooLong from useTakingTooLong.
When active changes to false after the timer expires, the hook can return the previous tooLong state for one render. UsageDashboard can therefore render the timeout state after loading completes. Add a regression test for this transition.
| import UsageMeter from './components/UsageMeter' | ||
| import UsageOverTime from './components/UsageOverTime' |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use permitted import aliases for the changed imports.
The changed imports use relative paths in files under frontend/.
frontend/web/components/pages/usage/UsageDashboard.tsx#L6-L7: importUsageMeterandUsageOverTimethrough theircomponents/aliases.frontend/web/components/pages/usage/UsageDashboardPage.tsx#L11-L18: import the addedisComparableToAllowancesymbol throughcomponents/pages/usage/utils.
As per coding guidelines, frontend/**/*.{js,jsx,ts,tsx} must “Use only common/, components/, and project/ import paths; do not use relative imports.”
📍 Affects 2 files
frontend/web/components/pages/usage/UsageDashboard.tsx#L6-L7(this comment)frontend/web/components/pages/usage/UsageDashboardPage.tsx#L11-L18
Source: Coding guidelines
| const { | ||
| data: subscriptionMeta, | ||
| isLoading: loadingLimit, | ||
| refetch: refetchLimit, | ||
| } = useGetSubscriptionMetadataQuery( | ||
| organisationId ? { id: organisationId } : skipToken, | ||
| ) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- changed hunk ---'
git diff -- frontend/web/components/pages/usage/UsageDashboardPage.tsx
printf '%s\n' '--- page definitions and usage ---'
sed -n '1,180p' frontend/web/components/pages/usage/UsageDashboardPage.tsx
fd -i 'UsageDashboard' frontend
rg -n -C 5 'useGetSubscriptionMetadataQuery|isError=|Try again|loadingLimit|subscriptionMeta' frontend/web/components/pages/usage frontend/common frontend/components frontend/project 2>/dev/null || trueRepository: Flagsmith/flagsmith
Length of output: 17401
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- UsageDashboard contract ---'
sed -n '1,120p' frontend/web/components/pages/usage/UsageDashboard.tsx
printf '%s\n' '--- subscription metadata endpoint ---'
sed -n '1,80p' frontend/common/services/useSubscriptionMetadata.ts
printf '%s\n' '--- shared service base ---'
rg -n -C 6 'const service|createApi|fetchBaseQuery|baseQuery' frontend/common/services frontend/common | head -160Repository: Flagsmith/flagsmith
Length of output: 17024
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- RTK Query dependency and base service ---'
rg -n '"`@reduxjs/toolkit`"|reduxjs/toolkit' package.json frontend/package.json frontend/*/package.json 2>/dev/null || true
fd -i 'service' frontend/common -t f | head -40
fd -i 'package.json' . -t f -E node_modules -E dist -E build | head -30Repository: Flagsmith/flagsmith
Length of output: 334
Surface subscription metadata failures.
Destructure isError: limitFailed from useGetSubscriptionMetadataQuery and include it in UsageDashboard's isError prop. Otherwise, a failed request can render the dashboard without a plan limit or the Try again action.
67cfa22 to
838e421
Compare
There was a problem hiding this comment.
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/UsageDashboard.tsx (1)
76-85: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the
comparabledefault consistent across both children.When
comparableis omitted,UsageMeterdefaults it totrue, butUsageOverTimereceivesundefinedand omits the allowance limit. The meter can therefore show a percentage and allowance bar while the chart does not show the allowance. Normalise the value once, such asconst isComparable = comparable ?? true, and pass it to both components.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 679f84d7-0cff-4693-a17a-4f17aad50e29
📒 Files selected for processing (7)
frontend/web/components/pages/usage/UsageDashboard.tsxfrontend/web/components/pages/usage/UsageDashboardPage.tsxfrontend/web/components/pages/usage/__tests__/utils.test.tsfrontend/web/components/pages/usage/components/UsageMeter/UsageMeter.tsxfrontend/web/components/pages/usage/components/UsageMeter/__tests__/utils.test.tsfrontend/web/components/pages/usage/components/UsageMeter/utils.tsfrontend/web/components/pages/usage/utils.ts
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.
0cc95ab to
bfe0494
Compare
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, 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) <noreply@anthropic.com>
Picking a project re-pointed the meter at that project while still calling it plan usage, so the same panel meant different things depending on a control at the far side of the page. The meter now always answers for the organisation, and a note underneath says what share of that usage the chosen project accounts for. Share of usage rather than share of allowance: a project on 4M of a 50M plan is 8% of the allowance but could be 40% of everything the organisation did, and the second number is the one that says whether it matters. The organisation query carries no projectId, so RTK fetches it once and reuses it across project changes, and dedupes it with the scoped query when no project is chosen. Fixes #8354 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The meter and the chart answer different questions, so they need different rules. The meter reports the organisation, so a project filter does not touch it. The chart follows the filter, and a ceiling there implies a trajectory towards a limit one project will never reach, which is the point Matt made about the per-endpoint chart in July. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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) <noreply@anthropic.com>
The base API sets refetchOnFocus for everything, which Wadii spotted on the breakdown: switching tabs and back reloads the page behind a loader. Worse than the flicker, usage-data is throttled at five requests a minute per user, so tab switching quietly spends the budget the page needs. Off for both usage queries, since the listener is what the features page relies on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
25799fb to
0264417
Compare
docs/if required so people know about the feature.Changes
Fixes reported against the usage dashboard after #8320 merged.
The meter compared numbers that do not belong together (#8353, #8354). The total moved with both filters, the allowance never did.
max_api_callsis a 30-day, organisation-wide figure, so "Last 90 days" read about three times too high and picking a project measured that project against the whole organisation's allowance.Those turned out to be two different problems. A project filter is a labelling problem: a project's usage over the organisation's allowance is a real number, that project's share of what you are allowed, and only the wording was wrong. A 90-day window is not: ninety days against a thirty-day allowance cannot be reworded into meaning. So the meter now names the project and says the percentage is "of your allowance", and only drops to a plain count for the 90-day window.
The chart drew a ceiling a filtered view can never reach (per Matt's July design review). It keeps the plan limit line for the organisation over a comparable period, and loses it when a project is selected, since one project has no trajectory towards the organisation's limit.
Failing to load left you reloading the page. The error state now offers a retry, which refetches the organisation, the usage and the subscription metadata.
Fixes #8353, #8354
How did you test this code?
47 unit tests over the two rules and the meter copy.
Worth checking on the deploy preview: