Skip to content

feat: add password reset settings tab / 新增密码修改设置页#928

Open
WenhuaXia wants to merge 1 commit into
siteboon:mainfrom
WenhuaXia:feat/password-reset-settings
Open

feat: add password reset settings tab / 新增密码修改设置页#928
WenhuaXia wants to merge 1 commit into
siteboon:mainfrom
WenhuaXia:feat/password-reset-settings

Conversation

@WenhuaXia

@WenhuaXia WenhuaXia commented Jun 28, 2026

Copy link
Copy Markdown

feat: add password reset settings tab / 新增密码修改设置页

Add a dedicated Password Settings tab in CloudCLI settings UI, allowing users to change their authentication password directly from the web interface.

新增内容:

  • PasswordSettingsTab 组件(旧密码→新密码→确认→提交)
  • SettingsSidebar 新增 Lock 图标入口
  • SettingsMainTabs 路由注册
  • 全量 10 个 locale 的 settings.json 翻译

Files changed:

  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx (new)
  • src/components/settings/view/SettingsSidebar.tsx
  • src/components/settings/view/Settings.tsx
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/types/types.ts
  • src/i18n/locales/*/settings.json (10 files)

Summary by CodeRabbit

  • New Features
    • Added a Password tab to Settings, available from both the main tab bar and the sidebar/navigation.
    • Introduced a password change screen with current/new/confirm fields, validation, and clear save states (saving, success, and error).
  • Localization
    • Added/extended password-related Settings translations across supported languages (labels, help text, and validation/error messages).

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e03750fc-327c-4af5-8c23-01c40272450e

📥 Commits

Reviewing files that changed from the base of the PR and between 9e57ec0 and 6425101.

📒 Files selected for processing (14)
  • src/components/settings/types/types.ts
  • src/components/settings/view/Settings.tsx
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/view/SettingsSidebar.tsx
  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json
✅ Files skipped from review due to trivial changes (5)
  • src/components/settings/types/types.ts
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/zh-TW/settings.json
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/components/settings/view/Settings.tsx
  • src/i18n/locales/tr/settings.json
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/view/SettingsSidebar.tsx
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/ja/settings.json
  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx

📝 Walkthrough

Walkthrough

Adds a Password settings tab with a password-change form, navigation wiring, and locale strings. The new tab validates current, new, and confirmation fields before calling the password-change API, then shows success or error state.

Changes

Password Settings Tab

Layer / File(s) Summary
Type and navigation wiring
src/components/settings/types/types.ts, src/components/settings/view/SettingsMainTabs.tsx, src/components/settings/view/SettingsSidebar.tsx, src/components/settings/view/Settings.tsx
SettingsMainTab is updated; password is added to the main tab config and sidebar nav with the Lock icon; Settings.tsx imports and renders PasswordSettingsTab when activeTab === 'password'.
PasswordSettingsTab component
src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx
New component manages the three password fields, status and error state, client-side validation, change-password API submission, and rendered save/error/success UI.
i18n strings across all locales
src/i18n/locales/en/settings.json, src/i18n/locales/de/settings.json, src/i18n/locales/it/settings.json, src/i18n/locales/ja/settings.json, src/i18n/locales/ko/settings.json, src/i18n/locales/ru/settings.json, src/i18n/locales/tr/settings.json, src/i18n/locales/zh-CN/settings.json, src/i18n/locales/zh-TW/settings.json
mainTabs.password and the password UI string blocks are added to all supported locales; en and zh-CN also add browserSettings strings.

Possibly related PRs

  • siteboon/claudecodeui#303: Adds related settings-namespace locale keys that this PR extends with the new password tab strings.

Suggested reviewers

  • blackmammoth

🐇 A lock now hops beside the tabs,
Three fields and a save button for password grabs.
If all is right, the bunny beams,
With translated words and success-themed dreams.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding a password settings tab, with both English and Chinese wording aligned to the update.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx (1)

62-66: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Avoid matching backend errors by display text.

Checking for the exact string 'Current password is incorrect' hard-codes server copy into the client. Any wording change on the API side will bypass the translated branch and start surfacing raw backend text here. Prefer a stable error code/status from api.auth.changePassword and map that to t(...) on the client.

🤖 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 `@src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx`
around lines 62 - 66, The password change error handling in PasswordSettingsTab
should not branch on the literal backend message text. Update the
`api.auth.changePassword`/`PasswordSettingsTab` flow to rely on a stable error
code or status from the API response instead of checking for `'Current password
is incorrect'`, then map that code to `t('password.error.incorrectOld')` on the
client. Keep the fallback behavior for other errors by still using the existing
`msg`/`setErrorMessage` path when the code does not match the incorrect-password
case.
🤖 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 `@src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx`:
- Around line 20-69: Prevent duplicate password-change requests by adding a
synchronous in-flight guard in handleChangePassword inside PasswordSettingsTab.
The issue is that setStatus('saving') updates asynchronously, so a fast
double-click can enter api.auth.changePassword twice before the button disables.
Add a local guard (for example, a ref or similar immediate flag) that is checked
at the start of handleChangePassword and set before awaiting the API call, then
cleared in both success and error paths so only one mutation can run at a time.

---

Nitpick comments:
In `@src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx`:
- Around line 62-66: The password change error handling in PasswordSettingsTab
should not branch on the literal backend message text. Update the
`api.auth.changePassword`/`PasswordSettingsTab` flow to rely on a stable error
code or status from the API response instead of checking for `'Current password
is incorrect'`, then map that code to `t('password.error.incorrectOld')` on the
client. Keep the fallback behavior for other errors by still using the existing
`msg`/`setErrorMessage` path when the code does not match the incorrect-password
case.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bb8673a5-1bde-4926-b7d1-c31166c20ce0

📥 Commits

Reviewing files that changed from the base of the PR and between ed4ae31 and 9e57ec0.

📒 Files selected for processing (14)
  • src/components/settings/types/types.ts
  • src/components/settings/view/Settings.tsx
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/view/SettingsSidebar.tsx
  • src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json

Comment on lines +20 to +69
const handleChangePassword = useCallback(async () => {
setErrorMessage('');

if (!oldPassword || !newPassword || !confirmPassword) {
setStatus('error');
setErrorMessage(t('password.error.fillAllFields'));
return;
}

if (newPassword.length < 6) {
setStatus('error');
setErrorMessage(t('password.error.minLength'));
return;
}

if (newPassword !== confirmPassword) {
setStatus('error');
setErrorMessage(t('password.error.notMatch'));
return;
}

if (oldPassword === newPassword) {
setStatus('error');
setErrorMessage(t('password.error.sameAsOld'));
return;
}

setStatus('saving');

try {
const result = await api.auth.changePassword(oldPassword, newPassword);
if (result.success) {
setStatus('success');
setOldPassword('');
setNewPassword('');
setConfirmPassword('');
} else {
setStatus('error');
setErrorMessage(result.error || t('password.error.failed'));
}
} catch (err: any) {
setStatus('error');
const msg = err.response?.data?.error || err.message || t('password.error.failed');
if (msg === 'Current password is incorrect') {
setErrorMessage(t('password.error.incorrectOld'));
} else {
setErrorMessage(msg);
}
}
}, [oldPassword, newPassword, confirmPassword, t]);

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Prevent duplicate password-change requests.

setStatus('saving') disables the button only after React re-renders, so a fast double-click can still call api.auth.changePassword(...) twice. Because this mutation is not idempotent, the second request can race the first and leave the tab in an error state even though the password already changed. Add a synchronous in-flight guard around the handler.

Proposed fix
-import { useCallback, useState } from 'react';
+import { useCallback, useRef, useState } from 'react';
@@
   const [confirmPassword, setConfirmPassword] = useState('');
   const [status, setStatus] = useState<Status>('idle');
   const [errorMessage, setErrorMessage] = useState('');
+  const isSubmittingRef = useRef(false);
@@
   const handleChangePassword = useCallback(async () => {
+    if (isSubmittingRef.current) {
+      return;
+    }
+
     setErrorMessage('');
@@
     setStatus('saving');
+    isSubmittingRef.current = true;
 
     try {
       const result = await api.auth.changePassword(oldPassword, newPassword);
@@
     } catch (err: any) {
       setStatus('error');
       const msg = err.response?.data?.error || err.message || t('password.error.failed');
       if (msg === 'Current password is incorrect') {
         setErrorMessage(t('password.error.incorrectOld'));
       } else {
         setErrorMessage(msg);
       }
+    } finally {
+      isSubmittingRef.current = false;
     }
   }, [oldPassword, newPassword, confirmPassword, t]);
📝 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.

Suggested change
const handleChangePassword = useCallback(async () => {
setErrorMessage('');
if (!oldPassword || !newPassword || !confirmPassword) {
setStatus('error');
setErrorMessage(t('password.error.fillAllFields'));
return;
}
if (newPassword.length < 6) {
setStatus('error');
setErrorMessage(t('password.error.minLength'));
return;
}
if (newPassword !== confirmPassword) {
setStatus('error');
setErrorMessage(t('password.error.notMatch'));
return;
}
if (oldPassword === newPassword) {
setStatus('error');
setErrorMessage(t('password.error.sameAsOld'));
return;
}
setStatus('saving');
try {
const result = await api.auth.changePassword(oldPassword, newPassword);
if (result.success) {
setStatus('success');
setOldPassword('');
setNewPassword('');
setConfirmPassword('');
} else {
setStatus('error');
setErrorMessage(result.error || t('password.error.failed'));
}
} catch (err: any) {
setStatus('error');
const msg = err.response?.data?.error || err.message || t('password.error.failed');
if (msg === 'Current password is incorrect') {
setErrorMessage(t('password.error.incorrectOld'));
} else {
setErrorMessage(msg);
}
}
}, [oldPassword, newPassword, confirmPassword, t]);
const [confirmPassword, setConfirmPassword] = useState('');
const [status, setStatus] = useState<Status>('idle');
const [errorMessage, setErrorMessage] = useState('');
const isSubmittingRef = useRef(false);
const handleChangePassword = useCallback(async () => {
if (isSubmittingRef.current) {
return;
}
setErrorMessage('');
if (!oldPassword || !newPassword || !confirmPassword) {
setStatus('error');
setErrorMessage(t('password.error.fillAllFields'));
return;
}
if (newPassword.length < 6) {
setStatus('error');
setErrorMessage(t('password.error.minLength'));
return;
}
if (newPassword !== confirmPassword) {
setStatus('error');
setErrorMessage(t('password.error.notMatch'));
return;
}
if (oldPassword === newPassword) {
setStatus('error');
setErrorMessage(t('password.error.sameAsOld'));
return;
}
setStatus('saving');
isSubmittingRef.current = true;
try {
const result = await api.auth.changePassword(oldPassword, newPassword);
if (result.success) {
setStatus('success');
setOldPassword('');
setNewPassword('');
setConfirmPassword('');
} else {
setStatus('error');
setErrorMessage(result.error || t('password.error.failed'));
}
} catch (err: any) {
setStatus('error');
const msg = err.response?.data?.error || err.message || t('password.error.failed');
if (msg === 'Current password is incorrect') {
setErrorMessage(t('password.error.incorrectOld'));
} else {
setErrorMessage(msg);
}
} finally {
isSubmittingRef.current = false;
}
}, [oldPassword, newPassword, confirmPassword, t]);
🤖 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 `@src/components/settings/view/tabs/password-settings/PasswordSettingsTab.tsx`
around lines 20 - 69, Prevent duplicate password-change requests by adding a
synchronous in-flight guard in handleChangePassword inside PasswordSettingsTab.
The issue is that setStatus('saving') updates asynchronously, so a fast
double-click can enter api.auth.changePassword twice before the button disables.
Add a local guard (for example, a ref or similar immediate flag) that is checked
at the start of handleChangePassword and set before awaiting the API call, then
cleared in both success and error paths so only one mutation can run at a time.

@WenhuaXia WenhuaXia force-pushed the feat/password-reset-settings branch from 9e57ec0 to 6425101 Compare June 30, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant