From 73b15fc5625dee2bdba5fbffc474a7492f470765 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Wed, 19 Aug 2026 06:30:37 +0000 Subject: [PATCH] refactor(web): compose reset password fields (#40952) --- oxlint-suppressions.json | 10 -- .../set-password/page.tsx | 108 ++++++++++-------- .../set-password/__tests__/page.spec.tsx | 31 +++++ web/app/reset-password/set-password/page.tsx | 108 ++++++++++-------- 4 files changed, 149 insertions(+), 108 deletions(-) diff --git a/oxlint-suppressions.json b/oxlint-suppressions.json index 447d378d032..0bfb65d1eb8 100644 --- a/oxlint-suppressions.json +++ b/oxlint-suppressions.json @@ -103,11 +103,6 @@ "count": 1 } }, - "web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/(shareLayout)/webapp-signin/check-code/page.tsx": { "no-restricted-imports": { "count": 1 @@ -5184,11 +5179,6 @@ "count": 1 } }, - "web/app/reset-password/set-password/page.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/signin/layout.tsx": { "typescript/no-explicit-any": { "count": 1 diff --git a/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx b/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx index 08200092f9d..204954e9e19 100644 --- a/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx +++ b/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx @@ -1,12 +1,15 @@ 'use client' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' +import { Field, FieldDescription, FieldLabel } from '@langgenius/dify-ui/field' +import { Form } from '@langgenius/dify-ui/form' +import { IconButton } from '@langgenius/dify-ui/icon-button' +import { InputGroup, InputGroupAddon, InputGroupInput } from '@langgenius/dify-ui/input-group' import { toast } from '@langgenius/dify-ui/toast' import { RiCheckboxCircleFill } from '@remixicon/react' import { useCountDown } from 'ahooks' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import Input from '@/app/components/base/input' import { validPassword } from '@/config' import useDocumentTitle from '@/hooks/use-document-title' import { useRouter, useSearchParams } from '@/next/navigation' @@ -96,68 +99,75 @@ const ChangePasswordForm = () => {
-
- {/* Password */} -
-
- {/* Confirm Password */} -
- -
- + + setConfirmPassword(e.target.value)} + onValueChange={setConfirmPassword} placeholder={t(($) => $.confirmPasswordPlaceholder, { ns: 'login' }) || ''} /> -
- -
-
-
-
- -
-
+
)} @@ -165,7 +175,7 @@ const ChangePasswordForm = () => {
- +

{t(($) => $.passwordChangedTip, { ns: 'login' })} diff --git a/web/app/reset-password/set-password/__tests__/page.spec.tsx b/web/app/reset-password/set-password/__tests__/page.spec.tsx index bf7f0463fea..2f9d96f4e6e 100644 --- a/web/app/reset-password/set-password/__tests__/page.spec.tsx +++ b/web/app/reset-password/set-password/__tests__/page.spec.tsx @@ -1,4 +1,5 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' import useDocumentTitle from '@/hooks/use-document-title' import { useRouter, useSearchParams } from '@/next/navigation' import { changePasswordWithToken } from '@/service/common' @@ -81,6 +82,36 @@ describe('Reset Password Set Password Page', () => { expect(mockUseDocumentTitle).toHaveBeenCalledWith('login.changePassword') }) + it('supports password reveal and native form submission', async () => { + const user = userEvent.setup() + render() + + const passwordInput = screen.getByLabelText('common.account.newPassword') + const confirmPasswordInput = screen.getByLabelText('common.account.confirmPassword') + + expect(passwordInput).toHaveAttribute('autocomplete', 'new-password') + expect(confirmPasswordInput).toHaveAttribute('autocomplete', 'new-password') + + await user.type(passwordInput, 'ValidPass123!') + await user.click(screen.getAllByRole('button', { name: 'login.showPassword' })[0]!) + + expect(passwordInput).toHaveAttribute('type', 'text') + expect(screen.getByRole('button', { name: 'login.hidePassword' })).toBeInTheDocument() + + await user.type(confirmPasswordInput, 'ValidPass123!{Enter}') + + await waitFor(() => { + expect(mockChangePasswordWithToken).toHaveBeenCalledWith({ + url: '/forgot-password/resets', + body: { + token: 'reset-token', + new_password: 'ValidPass123!', + password_confirm: 'ValidPass123!', + }, + }) + }) + }) + describe('Post-reset navigation', () => { it('should preserve redirect_url when the user returns to sign in manually', async () => { setSearchParams({ token: 'reset-token', redirect_url: redirectUrl }) diff --git a/web/app/reset-password/set-password/page.tsx b/web/app/reset-password/set-password/page.tsx index e5f09fc4a66..7ea375cf4a8 100644 --- a/web/app/reset-password/set-password/page.tsx +++ b/web/app/reset-password/set-password/page.tsx @@ -1,12 +1,15 @@ 'use client' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' +import { Field, FieldDescription, FieldLabel } from '@langgenius/dify-ui/field' +import { Form } from '@langgenius/dify-ui/form' +import { IconButton } from '@langgenius/dify-ui/icon-button' +import { InputGroup, InputGroupAddon, InputGroupInput } from '@langgenius/dify-ui/input-group' import { toast } from '@langgenius/dify-ui/toast' import { RiCheckboxCircleFill } from '@remixicon/react' import { useCountDown } from 'ahooks' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import Input from '@/app/components/base/input' import { validPassword } from '@/config' import useDocumentTitle from '@/hooks/use-document-title' import { useRouter, useSearchParams } from '@/next/navigation' @@ -109,68 +112,75 @@ const ChangePasswordForm = () => {

-
- {/* Password */} -
-
- {/* Confirm Password */} -
- -
- + + setConfirmPassword(e.target.value)} + onValueChange={setConfirmPassword} placeholder={t(($) => $.confirmPasswordPlaceholder, { ns: 'login' }) || ''} /> -
- -
-
-
-
- -
-
+
)} @@ -178,7 +188,7 @@ const ChangePasswordForm = () => {
- +

{t(($) => $.passwordChangedTip, { ns: 'login' })}