Repository navigation
feat(wework): add Wegent quota display - #2401
Conversation
📝 WalkthroughWalkthroughChangesWegent quota data and formatting
Settings and tray integration
macOS tray rendering
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant WorkbenchPage
participant WegentUsage
participant QuotaAPI
participant Tray
WorkbenchPage->>WegentUsage: refresh usage with cloud credentials
WegentUsage->>QuotaAPI: request authenticated quota data
QuotaAPI-->>WegentUsage: return quota details
WegentUsage-->>WorkbenchPage: return formatted Wegent display
WorkbenchPage->>Tray: combine Codex and Wegent titles and tooltips
Tray->>Tray: compose macOS usage text with status icon
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
wework/src/components/layout/DesktopSettingsMenu.test.tsx (1)
172-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRename the test to match its new assertions.
The test now asserts that the Codex label and the Wegent label render. The name only describes the removal of the old account and quota rows.
Rename it, for example to
renders the Codex and Wegent quota rows instead of the old account summary.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wework/src/components/layout/DesktopSettingsMenu.test.tsx` around lines 172 - 178, Rename the test case around renderMenu from “does not render the old account or quota summary row” to a name describing that the Codex and Wegent quota rows render instead of the old account summary, matching its current assertions.wework/src/components/settings/GeneralSettingsPage.test.tsx (1)
102-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the disconnected cloud connection.
The mock at lines 106-113 always returns
isConnected: true. The new code adds two branches that this suite never exercises: the early return in the fetch effect and the label fallback when the connection is inactive.Make the mock configurable, then add a test that asserts the toggle falls back to
workbench.general_settings_tray_wegent_usageand thatgetWegentUsageDisplayis not called.🧪 Proposed mock change
+const cloudConnectionMock = vi.hoisted(() => ({ + current: { + isConnected: true, + apiBaseUrl: 'https://wegent.example.com/api', + token: 'token', + serviceKey: 'test-cloud', + }, +})) + vi.mock('`@/features/cloud-connection/useCloudConnection`', () => ({ - useOptionalCloudConnection: () => ({ - isConnected: true, - apiBaseUrl: 'https://wegent.example.com/api', - token: 'token', - serviceKey: 'test-cloud', - }), + useOptionalCloudConnection: () => cloudConnectionMock.current, }))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@wework/src/components/settings/GeneralSettingsPage.test.tsx` around lines 102 - 113, Make the useOptionalCloudConnection mock configurable, then add a disconnected-connection test covering the fetch effect’s early return: assert the toggle uses the workbench.general_settings_tray_wegent_usage fallback label and getWegentUsageDisplay is not called.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@wework/src/api/wegentUsage.ts`:
- Around line 24-25: Replace the navigator.language-based isEnglishLocale check
with the selected Wework application locale, keeping quota data unlocalized in
this API module. Move user-facing quota formatting to a caller that uses the
local `@/hooks/useTranslation` wrapper, or pass the selected locale into the
formatter so manually chosen interface language controls the output.
- Around line 77-78: Update the sourceText construction in the quota usage
display to use the full data.quota_source value for settings, menu, and tooltip
text, preserving the localized quota suffix. Keep extractQuotaSourceLabel
limited to the compact tray title path so full names such as “Anthropic Cloud”
and non-ASCII sources are not truncated.
In `@wework/src/components/layout/DesktopSettingsMenu.tsx`:
- Around line 143-165: Extract the duplicated Wegent usage fetching into a
shared useWegentUsage hook: in
wework/src/components/layout/DesktopSettingsMenu.tsx lines 143-165 and
wework/src/components/settings/GeneralSettingsPage.tsx lines 98-125, replace the
effects (and GeneralSettingsPage’s cloudQuotaName state) with the hook, which
must own connection checks, getWegentUsageDisplay, cancellation, loading, and
error state; derive GeneralSettingsPage’s label from the hook’s sourceText. In
wework/src/components/layout/DesktopSettingsMenu.tsx lines 87-123, consolidate
the remaining Codex and Wegent manual-refresh logic into one helper
parameterized by the loader and state setters.
- Around line 364-381: Update the quota display conditional in
DesktopSettingsMenu around wegentUsage.status so quota_load_failed is shown only
when wegentQuotaError indicates the fetch failed. For a successful response with
no available quota source, render a separate empty-state translation, while
preserving the existing login message for disconnected users and the
available-quota display.
---
Nitpick comments:
In `@wework/src/components/layout/DesktopSettingsMenu.test.tsx`:
- Around line 172-178: Rename the test case around renderMenu from “does not
render the old account or quota summary row” to a name describing that the Codex
and Wegent quota rows render instead of the old account summary, matching its
current assertions.
In `@wework/src/components/settings/GeneralSettingsPage.test.tsx`:
- Around line 102-113: Make the useOptionalCloudConnection mock configurable,
then add a disconnected-connection test covering the fetch effect’s early
return: assert the toggle uses the workbench.general_settings_tray_wegent_usage
fallback label and getWegentUsageDisplay is not called.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a754821f-6782-45ef-afc1-047f13a9ea55
📒 Files selected for processing (21)
docs/en/wegent/user-guide/settings/desktop-app-preferences.mddocs/zh/wegent/user-guide/settings/desktop-app-preferences.mdwework/src-tauri/Cargo.tomlwework/src-tauri/src/lib.rswework/src/api/quota.tswework/src/api/wegentUsage.test.tswework/src/api/wegentUsage.tswework/src/components/layout/DesktopSettingsMenu.test.tsxwework/src/components/layout/DesktopSettingsMenu.tsxwework/src/components/settings/AppshotsSettingsPage.test.tsxwework/src/components/settings/BrowserSettingsPage.test.tsxwework/src/components/settings/ContextSettingsPage.test.tsxwework/src/components/settings/GeneralSettingsPage.test.tsxwework/src/components/settings/GeneralSettingsPage.tsxwework/src/i18n/locales/en/common.jsonwework/src/i18n/locales/zh-CN/common.jsonwework/src/pages/WorkbenchPage.tsxwework/src/tauri/appPreferences.test.tswework/src/tauri/appPreferences.tswework/src/tauri/trayUsageTitle.test.tswework/src/tauri/trayUsageTitle.ts
| function isEnglishLocale(): boolean { | ||
| return typeof navigator !== 'undefined' && navigator.language.toLowerCase().startsWith('en') |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Use the selected Wework locale for quota text.
navigator.language uses the system locale. It does not use the manually selected Wework interface language. A user who selects English in Wework on a Chinese system receives Chinese quota strings.
Keep quota data unlocalized in this API module. Format user-facing strings in a caller that uses @/hooks/useTranslation, or pass the selected application locale into the formatter.
As per coding guidelines, new wework/src/**/*.{ts,tsx} code must use the local @/hooks/useTranslation wrapper.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wework/src/api/wegentUsage.ts` around lines 24 - 25, Replace the
navigator.language-based isEnglishLocale check with the selected Wework
application locale, keeping quota data unlocalized in this API module. Move
user-facing quota formatting to a caller that uses the local
`@/hooks/useTranslation` wrapper, or pass the selected locale into the formatter
so manually chosen interface language controls the output.
Source: Coding guidelines
| const sourceLabel = extractQuotaSourceLabel(data.quota_source) | ||
| const sourceText = english ? `${sourceLabel} quota` : `${sourceLabel}额度` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Preserve the full quota source name outside the tray.
sourceText uses sourceLabel, but sourceLabel is truncated to five ASCII letters. A source such as Anthropic Cloud becomes Anthr quota. A non-ASCII source becomes Quota额度.
Use data.quota_source for settings, menu, and tooltip text. Restrict extractQuotaSourceLabel to the compact tray title only.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wework/src/api/wegentUsage.ts` around lines 77 - 78, Update the sourceText
construction in the quota usage display to use the full data.quota_source value
for settings, menu, and tooltip text, preserving the localized quota suffix.
Keep extractQuotaSourceLabel limited to the compact tray title path so full
names such as “Anthropic Cloud” and non-ASCII sources are not truncated.
| useEffect(() => { | ||
| if (!cloudConnection.isConnected) return | ||
|
|
||
| let cancelled = false | ||
| getWegentUsageDisplay({ | ||
| isConnected: cloudConnection.isConnected, | ||
| apiBaseUrl: cloudConnection.apiBaseUrl, | ||
| token: cloudConnection.token, | ||
| }) | ||
| .then(data => { | ||
| if (!cancelled) setWegentUsage(data) | ||
| }) | ||
| .catch(() => undefined) | ||
|
|
||
| return () => { | ||
| cancelled = true | ||
| } | ||
| }, [ | ||
| cloudConnection.apiBaseUrl, | ||
| cloudConnection.isConnected, | ||
| cloudConnection.serviceKey, | ||
| cloudConnection.token, | ||
| ]) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Extract the Wegent usage fetch into one shared hook. Both components copy the same effect: skip when disconnected, call getWegentUsageDisplay with the connection fields, guard the result with a cancelled flag, and depend on apiBaseUrl, isConnected, serviceKey, and token. Two copies of this logic will drift, and each copy handles errors differently.
wework/src/components/layout/DesktopSettingsMenu.tsx#L143-L165: replace this effect with a shareduseWegentUsage()hook that owns the fetch, the cancellation guard, and the loading and error state.wework/src/components/settings/GeneralSettingsPage.tsx#L98-L125: replace this effect and thecloudQuotaNamestate with the same hook, and derive the label from the returnedsourceText.wework/src/components/layout/DesktopSettingsMenu.tsx#L87-L123:loadCodexUsageandloadWegentUsagediffer only in the fetch function and the state setters. After the hook exists, collapse the remaining manual-refresh path into one helper that takes the loader and the setters.
As per coding guidelines: "Before adding code, search for and reuse existing components, services, utilities, and patterns; extract shared logic instead of duplicating it."
📍 Affects 2 files
wework/src/components/layout/DesktopSettingsMenu.tsx#L143-L165(this comment)wework/src/components/settings/GeneralSettingsPage.tsx#L98-L125wework/src/components/layout/DesktopSettingsMenu.tsx#L87-L123
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wework/src/components/layout/DesktopSettingsMenu.tsx` around lines 143 - 165,
Extract the duplicated Wegent usage fetching into a shared useWegentUsage hook:
in wework/src/components/layout/DesktopSettingsMenu.tsx lines 143-165 and
wework/src/components/settings/GeneralSettingsPage.tsx lines 98-125, replace the
effects (and GeneralSettingsPage’s cloudQuotaName state) with the hook, which
must own connection checks, getWegentUsageDisplay, cancellation, loading, and
error state; derive GeneralSettingsPage’s label from the hook’s sourceText. In
wework/src/components/layout/DesktopSettingsMenu.tsx lines 87-123, consolidate
the remaining Codex and Wegent manual-refresh logic into one helper
parameterized by the loader and state setters.
Source: Coding guidelines
| {!wegentQuotaLoading && !wegentQuotaError ? ( | ||
| wegentUsage.status === 'available' ? ( | ||
| <div className="space-y-0.5 text-xs leading-5 text-text-secondary"> | ||
| <div className="flex items-start justify-between gap-3"> | ||
| <span className="min-w-0 whitespace-nowrap">{wegentUsage.sourceText}</span> | ||
| <span className="shrink-0 whitespace-nowrap font-semibold text-text-primary"> | ||
| {wegentUsage.value} | ||
| </span> | ||
| </div> | ||
| <div className="text-text-muted">{wegentUsage.detail}</div> | ||
| </div> | ||
| ) : ( | ||
| <div className="py-1 text-sm leading-[18px] text-text-secondary"> | ||
| {cloudConnection.isConnected | ||
| ? t('workbench.quota_load_failed', '额度信息获取失败') | ||
| : t('workbench.account_cloud_login', '登录 Wegent')} | ||
| </div> | ||
| ) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not report a load failure when the quota fetch succeeded.
Lines 376-380 show quota_load_failed whenever wegentUsage.status !== 'available' and the user is connected. The fetch at line 113 can succeed and still return a non-available status, for example when the account has no quota source. In that case the panel claims that the fetch failed.
Distinguish "fetch failed" from "no quota available". Use wegentQuotaError for the failure case only, and add a separate empty-state string for a successful response without quota.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@wework/src/components/layout/DesktopSettingsMenu.tsx` around lines 364 - 381,
Update the quota display conditional in DesktopSettingsMenu around
wegentUsage.status so quota_load_failed is shown only when wegentQuotaError
indicates the fetch failed. For a successful response with no available quota
source, render a separate empty-state translation, while preserving the existing
login message for disconnected users and the available-quota display.
Summary
/quota/claude/quota, including source labels, remaining values, and usage-rate calculation.Root cause
The quota endpoint response was treated as a generic empty/zero value, the API usage-rate field was interpreted with the wrong scale, and macOS tray titles could not reliably represent the desired two-line layout. The change derives the percentage from used divided by total quota, preserves negative remaining values, and renders tray text through the existing native tray image path.
Validation
pnpm --filter wework lintpnpm --filter wework typecheckpnpm --filter wework exec vitest run(268 files, 2656 tests passed)cargo test --manifest-path wework/src-tauri/Cargo.toml --lib(122 tests passed)Summary by CodeRabbit