fix(profile): stop regenerating the access token when the dialog opens - #6726
fix(profile): stop regenerating the access token when the dialog opens#6726ENCHIGO wants to merge 1 commit into
Conversation
The access token dialog regenerated on mount: token is component state, so it is always empty on open and the effect always fired. Opening the dialog was therefore enough to replace the token server-side. That is not recoverable. AccessToken is json:"-" on the user model, so the value is returned once at creation and can never be read back, and the server overwrites the old one unconditionally. A user who only wanted to look at the card broke every integration still holding the old token. Drop the auto-generate effect, explain up front that the existing token cannot be shown again, and put the regeneration behind a destructive confirmation that spells out the consequence.
WalkthroughThe access-token dialog no longer regenerates tokens on open. It now requires confirmation, shows token controls only when a token exists, and displays localized warnings about one-time visibility and invalidation. ChangesAccess Token Safety Flow
Estimated code review effort: 2 (Simple) | ~15 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ 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: 1
🧹 Nitpick comments (1)
web/src/features/profile/components/dialogs/access-token-dialog.tsx (1)
91-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMark decorative icons as
aria-hidden="true".
Loader2andRefreshCw(lines 92 and 94) sit next to the descriptive label text ("Generating..." / "Regenerate").KeyRound(line 131) sits next to the explanatory paragraph. All three icons are decorative.As per coding guidelines, "装饰性图标使用
aria-hidden="true",重要信息提供文本等价".♿️ Proposed fix
- <Loader2 className='h-4 w-4 animate-spin' /> + <Loader2 className='h-4 w-4 animate-spin' aria-hidden='true' /> ) : ( - <RefreshCw className='h-4 w-4' /> + <RefreshCw className='h-4 w-4' aria-hidden='true' />- <KeyRound className='text-muted-foreground size-5' /> + <KeyRound className='text-muted-foreground size-5' aria-hidden='true' />Also applies to: 129-138
🤖 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 `@web/src/features/profile/components/dialogs/access-token-dialog.tsx` around lines 91 - 97, Add aria-hidden="true" to the decorative Loader2 and RefreshCw icons in the generating/regenerate button and the KeyRound icon in the explanatory section of the access-token dialog, leaving their existing visual styling and labels unchanged.Source: Coding guidelines
🤖 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 `@web/src/features/profile/components/dialogs/access-token-dialog.tsx`:
- Around line 84-97: Update the access-token state handling around
useAccessToken and the regenerate Button so the first-generation empty state
uses the destructive variant, while a known existing token uses the default
variant. Base confirmation and empty-state messaging on whether a token is
present or the backend reports one exists, avoiding claims that regeneration
invalidates a current token when no token is known.
---
Nitpick comments:
In `@web/src/features/profile/components/dialogs/access-token-dialog.tsx`:
- Around line 91-97: Add aria-hidden="true" to the decorative Loader2 and
RefreshCw icons in the generating/regenerate button and the KeyRound icon in the
explanatory section of the access-token dialog, leaving their existing visual
styling and labels unchanged.
🪄 Autofix
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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 9c6940d6-109a-48b3-8519-eabbc4e04640
📒 Files selected for processing (8)
web/src/features/profile/components/dialogs/access-token-dialog.tsxweb/src/i18n/locales/en.jsonweb/src/i18n/locales/fr.jsonweb/src/i18n/locales/ja.jsonweb/src/i18n/locales/ru.jsonweb/src/i18n/locales/vi.jsonweb/src/i18n/locales/zh-TW.jsonweb/src/i18n/locales/zh.json
| <Button | ||
| type='button' | ||
| variant={token ? 'default' : 'destructive'} | ||
| onClick={() => setConfirmOpen(true)} | ||
| disabled={generating} | ||
| className='gap-2' | ||
| > | ||
| {generating ? ( | ||
| <Loader2 className='h-4 w-4 animate-spin' /> | ||
| ) : ( | ||
| <RefreshCw className='h-4 w-4' /> | ||
| )} | ||
| {generating ? t('Generating...') : t('Regenerate')} | ||
| </Button> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
fd -a 'access-token-dialog\.tsx|accessToken|useAccessToken' . | sed 's#^\./##' | head -200
echo
echo "Target file excerpt:"
cat -n web/src/features/profile/components/dialogs/access-token-dialog.tsx | sed -n '1,220p'Repository: QuantumNous/new-api
Length of output: 6698
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Search access token usages and state:"
rg -n "useAccessToken|accessToken|accessTokenMutation|token" web/src -g '*.ts' -g '*.tsx' | head -300Repository: QuantumNous/new-api
Length of output: 27609
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "use-access-token hook:"
cat -n web/src/features/profile/hooks/use-access-token.ts | sed -n '1,120p'
echo
echo "profile api token generation:"
cat -n web/src/features/profile/api.ts | sed -n '1,145p'
echo
echo "ConfirmDialog props/usages:"
fd -a 'confirm-dialog\.(tsx|ts)$' web/src | xargs -r cat -n | sed -n '1,220p'
rg -n "ConfirmDialog|destructive" web/src/components web/src/features -g '*.tsx' -g '*.ts' | head -120
echo
echo "profile context excerpt:"
cat -n web/src/features/profile/components/profile-security-card.tsx | sed -n '1,180p'Repository: QuantumNous/new-api
Length of output: 45372
🌐 Web query:
i18next conditional pluralization ifelse zero one example
💡 Result:
In i18next, pluralization is handled via suffix-based naming conventions rather than explicit if-else logic [1][2]. The framework uses the count variable to determine which suffix to select based on the language's specific plural rules (powered by Intl.PluralRules) [1][3]. To handle specific cases like zero, one, and others, you define keys in your resource file with the appropriate suffixes [1]. Resource Example: { "key_zero": "No items", "key_one": "{{count}} item", "key_other": "{{count}} items" } Usage: i18next.t('key', { count: 0 }); // -> "No items" i18next.t('key', { count: 1 }); // -> "1 item" i18next.t('key', { count: 5 }); // -> "5 items" Key Concepts: - Suffix Resolution: i18next automatically appends suffixes like _zero, _one, or _other to your base key [1][4]. If a _zero entry is provided, i18next will prioritize it when count is 0, overriding the language's default plural rules [1][2]. - Intl.PluralRules: i18next relies on the native Intl.PluralRules API [1]. In environments without this support (e.g., some legacy environments or specific versions of React Native), you must use a polyfill [1][3]. - ICU Message Format: If you require more complex conditional logic (e.g., specific messages for non-plural numbers like 42 or 13), you can use ICU Message Format within your translation strings [2][5]. This allows for syntax like {count, plural, =0 {None} =42 {Answer} one {One} other {# items}} [2][5]. For simple pluralization, stick to the _one/_other or _zero/_one/_other suffix pattern as it is the standard, optimized approach for i18next [1][4].
Citations:
- 1: https://www.i18next.com/translation-function/plurals
- 2: https://phrase.com/blog/posts/pluralization/
- 3: https://www.i18next.com/misc/json-format
- 4: https://www.i18next.com/translation-function/plurals.md
- 5: https://community.crowdin.com/t/i18next-format-zero-support/7584
Fix the access token regenerate UI state and confirmation copy.
useAccessToken() starts with token === '' and never tracks whether a token was previously created, so the empty state is ambiguous. This causes the regenerate button to use the non-destructive 'default' variant when a token is present and the destructive 'destructive' variant at the first-generation state.
Also, useAccessToken() cannot distinguish “no token was ever created” from “a token exists but is hidden”, so the confirmation and empty-state copy should not claim that regenerating invalidates a current token. If token remains the only flag, use the absence of a token for the default confirm/empty messaging, and use destruction only when a token is known to exist or the backend reports an existing token.
🤖 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 `@web/src/features/profile/components/dialogs/access-token-dialog.tsx` around
lines 84 - 97, Update the access-token state handling around useAccessToken and
the regenerate Button so the first-generation empty state uses the destructive
variant, while a known existing token uses the default variant. Base
confirmation and empty-state messaging on whether a token is present or the
backend reports one exists, avoiding claims that regeneration invalidates a
current token when no token is known.
|
问题已由 #6749 解决,实现比本 PR 更完整——多了关闭弹窗时清理内存中的令牌,以及生成过程中拦截关闭。本 PR 不再需要,关闭。感谢采纳。 |
Important
📝 变更描述 / Description
「访问令牌」弹窗在打开时会自动重新生成令牌:
token是组件内的useState,每次挂载都是空字符串,所以只要弹窗打开,generate()必然执行。而generate()会让服务端无条件覆盖旧令牌,且User.AccessToken的 json tag 是json:"-",令牌只在生成那一刻返回一次、事后无法读回 —— 也就是说这次误触不可撤销、原值也找不回来。结果是:用户只想点开看一眼,所有仍持有旧令牌的集成就全部失效了。卡片文案「生成和管理您的 API 访问令牌」也强化了"这是个查看入口"的误解。
本 PR 把这个副作用去掉,并让销毁性操作变成需要明确意图的动作:
useEffectConfirmDialog的destructive变体),确认文案说明后果未改动任何服务端逻辑与接口契约。
🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
POST /api/user/token的行为未改,只是不再被自动触发。i18n:sync流程补齐全部语言,未引入未翻译项。📸 运行证明 / Proof of Work
新增 4 条文案已提供全部 7 个语言的译文,
_sync-report.json的missingCount与untranslatedCount保持为 0,与改动前一致。行为对照
Summary by CodeRabbit
New Features
Localization