From 6805d9bfc0acc96435d085b42169bd8f72ed9e28 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Sat, 30 May 2026 22:34:04 +0800 Subject: [PATCH] fix(auth): reset profile query after login (#36851) --- web/app/device/page.tsx | 2 +- web/app/install/installForm.spec.tsx | 4 ++-- web/app/install/installForm.tsx | 8 ++++++-- web/app/signin/check-code/page.tsx | 6 +++++- .../components/mail-and-password-auth.tsx | 6 +++++- .../invite-settings/__tests__/page.spec.tsx | 3 +++ web/app/signin/invite-settings/page.tsx | 9 ++++++--- web/app/signin/normal-form.tsx | 4 ++-- web/app/signin/one-more-step.tsx | 6 +++++- .../set-password/__tests__/page.spec.tsx | 18 +++++++++++++++++- web/app/signup/set-password/page.tsx | 8 ++++++-- 11 files changed, 58 insertions(+), 16 deletions(-) diff --git a/web/app/device/page.tsx b/web/app/device/page.tsx index aa09936b1f..ccfbbca427 100644 --- a/web/app/device/page.tsx +++ b/web/app/device/page.tsx @@ -196,7 +196,7 @@ export default function DevicePage() {

You're signed in

Return to your terminal to continue.

- diff --git a/web/app/install/installForm.spec.tsx b/web/app/install/installForm.spec.tsx index 65ad0b0df1..0b22c1cc70 100644 --- a/web/app/install/installForm.spec.tsx +++ b/web/app/install/installForm.spec.tsx @@ -59,7 +59,7 @@ describe('InstallForm', () => { expect(mockSetup).not.toHaveBeenCalled() }) - it('should submit and redirect to apps on successful login', async () => { + it('should submit and redirect to the console root on successful login', async () => { mockSetup.mockResolvedValue({ result: 'success' } as any) mockLogin.mockResolvedValue({ result: 'success', data: { access_token: 'token' } } as any) @@ -96,7 +96,7 @@ describe('InstallForm', () => { }) await waitFor(() => { - expect(mockReplace).toHaveBeenCalledWith('/apps') + expect(mockReplace).toHaveBeenCalledWith('/') }) }) diff --git a/web/app/install/installForm.tsx b/web/app/install/installForm.tsx index 20d2b26769..ccf01c9601 100644 --- a/web/app/install/installForm.tsx +++ b/web/app/install/installForm.tsx @@ -4,6 +4,7 @@ import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { useStore } from '@tanstack/react-form' +import { useQueryClient } from '@tanstack/react-query' import * as React from 'react' import { useEffect } from 'react' import { useTranslation } from 'react-i18next' @@ -17,6 +18,7 @@ import { LICENSE_LINK } from '@/constants/link' import useDocumentTitle from '@/hooks/use-document-title' import Link from '@/next/link' import { useRouter } from '@/next/navigation' +import { consoleQuery } from '@/service/client' import { fetchInitValidateStatus, fetchSetupStatus, login, setup } from '@/service/common' import { encryptPassword as encodePassword } from '@/utils/encryption' import Loading from '../components/base/loading' @@ -38,6 +40,7 @@ const InstallForm = () => { useDocumentTitle('') const { t, i18n } = useTranslation() const router = useRouter() + const queryClient = useQueryClient() const [showPassword, setShowPassword] = React.useState(false) const [loading, setLoading] = React.useState(true) @@ -68,9 +71,10 @@ const InstallForm = () => { }, }) - // Store tokens and redirect to apps if login successful + // Store tokens and redirect if login successful if (loginRes.result === 'success') { - router.replace('/apps') + await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) + router.replace('/') } else { // Fallback to signin page if auto-login fails diff --git a/web/app/signin/check-code/page.tsx b/web/app/signin/check-code/page.tsx index 80e6d01f5d..27724e0c02 100644 --- a/web/app/signin/check-code/page.tsx +++ b/web/app/signin/check-code/page.tsx @@ -3,6 +3,7 @@ import type { FormEvent } from 'react' import { Button } from '@langgenius/dify-ui/button' import { toast } from '@langgenius/dify-ui/toast' import { RiArrowLeftLine, RiMailSendFill } from '@remixicon/react' +import { useQueryClient } from '@tanstack/react-query' import { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { trackEvent } from '@/app/components/base/amplitude' @@ -11,6 +12,7 @@ import Countdown from '@/app/components/signin/countdown' import { useLocale } from '@/context/i18n' import { useRouter, useSearchParams } from '@/next/navigation' +import { consoleQuery } from '@/service/client' import { emailLoginWithCode, sendEMailLoginCode } from '@/service/common' import { encryptVerificationCode } from '@/utils/encryption' import { getBrowserTimezone } from '@/utils/timezone' @@ -19,6 +21,7 @@ import { resolvePostLoginRedirect } from '../utils/post-login-redirect' export default function CheckCode() { const { t, i18n } = useTranslation() const router = useRouter() + const queryClient = useQueryClient() const searchParams = useSearchParams() const email = decodeURIComponent(searchParams.get('email') as string) const token = decodeURIComponent(searchParams.get('token') as string) @@ -58,8 +61,9 @@ export default function CheckCode() { router.replace(`/signin/invite-settings?${searchParams.toString()}`) } else { + await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) const redirectUrl = resolvePostLoginRedirect(searchParams) - router.replace(redirectUrl || '/apps') + router.replace(redirectUrl || '/') } } } diff --git a/web/app/signin/components/mail-and-password-auth.tsx b/web/app/signin/components/mail-and-password-auth.tsx index 30bc78666c..e695f72b9a 100644 --- a/web/app/signin/components/mail-and-password-auth.tsx +++ b/web/app/signin/components/mail-and-password-auth.tsx @@ -1,6 +1,7 @@ import type { ResponseError } from '@/service/fetch' import { Button } from '@langgenius/dify-ui/button' import { toast } from '@langgenius/dify-ui/toast' +import { useQueryClient } from '@tanstack/react-query' import { noop } from 'es-toolkit/function' import { useState } from 'react' import { useTranslation } from 'react-i18next' @@ -10,6 +11,7 @@ import { emailRegex } from '@/config' import { useLocale } from '@/context/i18n' import Link from '@/next/link' import { useRouter, useSearchParams } from '@/next/navigation' +import { consoleQuery } from '@/service/client' import { login } from '@/service/common' import { setWebAppAccessToken } from '@/service/webapp-auth' import { encryptPassword } from '@/utils/encryption' @@ -25,6 +27,7 @@ export default function MailAndPasswordAuth({ isInvite, isEmailSetup, allowRegis const { t } = useTranslation() const locale = useLocale() const router = useRouter() + const queryClient = useQueryClient() const searchParams = useSearchParams() const [showPassword, setShowPassword] = useState(false) const emailFromLink = decodeURIComponent(searchParams.get('email') || '') @@ -75,8 +78,9 @@ export default function MailAndPasswordAuth({ isInvite, isEmailSetup, allowRegis router.replace(`/signin/invite-settings?${searchParams.toString()}`) } else { + await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) const redirectUrl = resolvePostLoginRedirect(searchParams) - router.replace(redirectUrl || '/apps') + router.replace(redirectUrl || '/') } } else { diff --git a/web/app/signin/invite-settings/__tests__/page.spec.tsx b/web/app/signin/invite-settings/__tests__/page.spec.tsx index 12e6f4dfb7..6990e71a67 100644 --- a/web/app/signin/invite-settings/__tests__/page.spec.tsx +++ b/web/app/signin/invite-settings/__tests__/page.spec.tsx @@ -12,6 +12,9 @@ vi.mock('@tanstack/react-query', async () => { const actual = await vi.importActual('@tanstack/react-query') return { ...actual, + useQueryClient: vi.fn(() => ({ + resetQueries: vi.fn(), + })), useSuspenseQuery: vi.fn(() => ({ data: { branding: { diff --git a/web/app/signin/invite-settings/page.tsx b/web/app/signin/invite-settings/page.tsx index 8b5a51782c..86dcf64194 100644 --- a/web/app/signin/invite-settings/page.tsx +++ b/web/app/signin/invite-settings/page.tsx @@ -4,7 +4,7 @@ import { Button } from '@langgenius/dify-ui/button' import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select' import { toast } from '@langgenius/dify-ui/toast' import { RiAccountCircleLine } from '@remixicon/react' -import { useSuspenseQuery } from '@tanstack/react-query' +import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query' import { noop } from 'es-toolkit/function' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -16,6 +16,7 @@ import { i18n, setLocaleOnClient } from '@/i18n-config' import { languages } from '@/i18n-config/language' import Link from '@/next/link' import { useRouter, useSearchParams } from '@/next/navigation' +import { consoleQuery } from '@/service/client' import { activateMember } from '@/service/common' import { systemFeaturesQueryOptions } from '@/service/system-features' import { useInvitationCheck } from '@/service/use-common' @@ -55,6 +56,7 @@ export default function InviteSettingsPage() { const { t } = useTranslation() const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) const router = useRouter() + const queryClient = useQueryClient() const searchParams = useSearchParams() const token = decodeURIComponent(searchParams.get('invite_token') as string) const locale = useLocale() @@ -102,14 +104,15 @@ export default function InviteSettingsPage() { if (res.result === 'success') { // Tokens are now stored in cookies by the backend await setLocaleOnClient(language!, false) + await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) const redirectUrl = resolvePostLoginRedirect(searchParams) - router.replace(redirectUrl || '/apps') + router.replace(redirectUrl || '/') } } catch { recheck() } - }, [language, name, recheck, timezone, token, router, t]) + }, [language, name, queryClient, recheck, searchParams, timezone, token, router, t]) if (!checkRes) return diff --git a/web/app/signin/normal-form.tsx b/web/app/signin/normal-form.tsx index 23576837c0..fb4e9f872c 100644 --- a/web/app/signin/normal-form.tsx +++ b/web/app/signin/normal-form.tsx @@ -50,7 +50,7 @@ const NormalForm = () => { if (isLoggedIn) { setIsRedirecting(true) const redirectUrl = resolvePostLoginRedirect(searchParams) - router.replace(redirectUrl || '/apps') + router.replace(redirectUrl || '/') return } @@ -75,7 +75,7 @@ const NormalForm = () => { setAllMethodsAreDisabled(true) } finally { setInitCheckLoading(false) } - }, [isLoggedIn, message, router, invite_token, isInviteLink, systemFeatures]) + }, [isLoggedIn, message, router, searchParams, invite_token, isInviteLink, systemFeatures]) useEffect(() => { init() }, [init]) diff --git a/web/app/signin/one-more-step.tsx b/web/app/signin/one-more-step.tsx index bb86a8675d..7c32dc879d 100644 --- a/web/app/signin/one-more-step.tsx +++ b/web/app/signin/one-more-step.tsx @@ -4,12 +4,14 @@ import { Button } from '@langgenius/dify-ui/button' import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select' import { toast } from '@langgenius/dify-ui/toast' +import { useQueryClient } from '@tanstack/react-query' import { useReducer } from 'react' import { useTranslation } from 'react-i18next' import { LICENSE_LINK } from '@/constants/link' import { languages } from '@/i18n-config/language' import Link from '@/next/link' import { useRouter, useSearchParams } from '@/next/navigation' +import { consoleQuery } from '@/service/client' import { useOneMoreStep } from '@/service/use-common' import { timezones } from '@/utils/timezone' import Input from '../components/base/input' @@ -66,6 +68,7 @@ const hasStatus = (error: unknown): error is { status: number } => { const OneMoreStep = () => { const { t } = useTranslation() const router = useRouter() + const queryClient = useQueryClient() const searchParams = useSearchParams() const [state, dispatch] = useReducer(reducer, { @@ -98,7 +101,8 @@ const OneMoreStep = () => { interface_language: state.interface_language, timezone: state.timezone, }) - router.push('/apps') + await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) + router.replace('/') } catch (error: unknown) { if (hasStatus(error) && error.status === 400) diff --git a/web/app/signup/set-password/__tests__/page.spec.tsx b/web/app/signup/set-password/__tests__/page.spec.tsx index e68694db15..b8d2ae34a8 100644 --- a/web/app/signup/set-password/__tests__/page.spec.tsx +++ b/web/app/signup/set-password/__tests__/page.spec.tsx @@ -1,4 +1,6 @@ +import type { ReactElement } from 'react' import type { MockedFunction } from 'vitest' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { useLocale } from '@/context/i18n' @@ -45,6 +47,20 @@ const mockUseRouter = useRouter as unknown as MockedFunction const mockUseMailRegister = useMailRegister as unknown as MockedFunction const mockGetBrowserTimezone = getBrowserTimezone as unknown as MockedFunction +const renderWithQueryClient = (ui: ReactElement) => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + mutations: { retry: false }, + }, + }) + return render( + + {ui} + , + ) +} + describe('Signup Set Password Page', () => { beforeEach(() => { vi.clearAllMocks() @@ -61,7 +77,7 @@ describe('Signup Set Password Page', () => { describe('Registration payload', () => { it('should submit locale and browser timezone when setting password', async () => { - render() + renderWithQueryClient() fireEvent.change(screen.getByLabelText('common.account.newPassword'), { target: { value: 'ValidPass123!' }, diff --git a/web/app/signup/set-password/page.tsx b/web/app/signup/set-password/page.tsx index 534b6b55d4..f3937116e5 100644 --- a/web/app/signup/set-password/page.tsx +++ b/web/app/signup/set-password/page.tsx @@ -3,6 +3,7 @@ import type { MailRegisterResponse } from '@/service/use-common' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { toast } from '@langgenius/dify-ui/toast' +import { useQueryClient } from '@tanstack/react-query' import Cookies from 'js-cookie' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -11,6 +12,7 @@ import Input from '@/app/components/base/input' import { validPassword } from '@/config' import { useLocale } from '@/context/i18n' import { useRouter, useSearchParams } from '@/next/navigation' +import { consoleQuery } from '@/service/client' import { useMailRegister } from '@/service/use-common' import { rememberCreateAppExternalAttribution } from '@/utils/create-app-tracking' import { sendGAEvent } from '@/utils/gtag' @@ -32,6 +34,7 @@ const parseUtmInfo = () => { const ChangePasswordForm = () => { const { t } = useTranslation() const router = useRouter() + const queryClient = useQueryClient() const searchParams = useSearchParams() const token = decodeURIComponent(searchParams.get('token') || '') const locale = useLocale() @@ -87,13 +90,14 @@ const ChangePasswordForm = () => { Cookies.remove('utm_info') // Clean up: remove utm_info cookie toast.success(t('api.actionSuccess', { ns: 'common' })) - router.replace('/apps') + await queryClient.resetQueries({ queryKey: consoleQuery.account.profile.get.key() }) + router.replace('/') } } catch (error) { console.error(error) } - }, [password, token, valid, confirmPassword, register, locale]) + }, [password, token, valid, confirmPassword, register, locale, queryClient, router, t]) return (