fix(web): animate refresh icons while checking - #9561
Conversation
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — The PR is mostly a localized refresh-feedback fix, but the Usage path now waits on per-environment queries that can remain pending during reconnect, backoff, or no-session states. This can leave refresh controls spinning and disabled indefinitely, warranting targeted human review. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 86bb529. Configure here.
| ); | ||
| }, | ||
| [environments, windowKey], | ||
| ); |
There was a problem hiding this comment.
Refresh hangs on reconnecting environments
Medium Severity
refresh now awaits executeAtomQuery on every environment's usageSummary. Those queries yield Effect.never while an environment is connecting, in backoff, or connected without a session, so the promise never settles. isRefreshing then stays true and the refresh control remains disabled and spinning until that environment leaves recovery.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 86bb529. Configure here.


Refresh controls changed their labels or disabled state while checking, but their refresh icons stayed static. That made active provider, pull-request, and usage checks look stuck.
This ties each icon's spin animation to the control's existing busy state. Usage limits now track the refresh command until it settles, and usage queries derive activity across every connected environment.
Before
After
https://pub-b182a4071edc4521829926b34990540b.r2.dev/files/0d81d599-13ce-44d3-8f65-99a8c42b44ac/provider-refresh-after.mp4
Verification
pnpm exec vp test run apps/web/src/components/pullRequest/PullRequestListEmptyState.test.tsx apps/web/src/components/settings/ProviderSettingsPanel.environment.test.tsx apps/web/src/components/usage/UsagePage.test.tsxpnpm exec vp fmt apps/web/src/components/pullRequest/PullRequestListEmptyState.tsx apps/web/src/components/settings/ProviderSettingsPanel.tsx apps/web/src/components/usage/UsagePage.tsx --checkpnpm exec vp lint apps/web/src/components/pullRequest/PullRequestListEmptyState.tsx apps/web/src/components/settings/ProviderSettingsPanel.tsx apps/web/src/components/usage/UsagePage.tsx --type-aware --type-checkanimate-spin, and rotates while the request runs.Built with GPT-5.6-Sol in T3 Code via Codex.
Note
Low Risk
Mostly UI feedback and a clearer usage refetch path; behavior change is disabling Usage refresh during in-flight requests and awaiting environment queries instead of fire-and-forget registry refresh.
Overview
Refresh actions already disabled buttons and changed labels, but refresh icons stayed static, so in-flight checks looked stuck. This PR applies
animate-spintoRefreshCwIconwherever an existing busy flag is true (pull request empty states, provider settings, usage top bar).On Usage, refresh now tracks
isRefreshing(with a ref guard against double-clicks), setsaria-busy/disabledon both desktop and mobile refresh buttons, and clears busy state when the underlying command oruseUsage().refresh()promise settles. Limits mode wires that busy state torefreshProviders; usage mode always awaitsrefresh(nextWindow)after optionally rolling the time window forward.useUsage’srefreshis nowasyncand optionally accepts a window input. Itawaits per-environment rate refresh plusexecuteAtomQuery(..., { refresh: true })instead of registry-only refresh, so the Usage button’s spinner reflects work across all connected environments.Reviewed by Cursor Bugbot for commit 86bb529. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Animate refresh icons across
UsagePage,ProviderSettingsPanel, andPullRequestListEmptyStateuseUsagesorefreshreturns a promise, accepts an optional usage window, and forces a usage-summary query per environment after its provider-rate refresh completes.UsagePageadds a local busy state and a ref-based guard to prevent overlapping refresh activations; both desktop and mobile refresh buttons disable and spin until the promise settles.UsageView.refreshchanges from a fire-and-forget() => voidto an async(window?) => Promise<void>; callers in UsagePage.tsx are updated but any out-of-tree callers of the old signature will break.Macroscope summarized 86bb529.