mirror of
https://github.com/langgenius/dify.git
synced 2026-05-30 21:57:46 +08:00
Compare commits
1 Commits
main
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f19aba9d8 |
@ -196,7 +196,7 @@ export default function DevicePage() {
|
||||
<h1 className="text-xl font-semibold text-text-primary">You're signed in</h1>
|
||||
<p className="text-sm text-text-secondary">Return to your terminal to continue.</p>
|
||||
<Divider className="my-3" />
|
||||
<Button variant="ghost" className="w-full" onClick={() => router.push('/apps')}>
|
||||
<Button variant="ghost" className="w-full" onClick={() => router.push('/')}>
|
||||
Go to Dify console →
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -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('/')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 || '/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -12,6 +12,9 @@ vi.mock('@tanstack/react-query', async () => {
|
||||
const actual = await vi.importActual<typeof import('@tanstack/react-query')>('@tanstack/react-query')
|
||||
return {
|
||||
...actual,
|
||||
useQueryClient: vi.fn(() => ({
|
||||
resetQueries: vi.fn(),
|
||||
})),
|
||||
useSuspenseQuery: vi.fn(() => ({
|
||||
data: {
|
||||
branding: {
|
||||
|
||||
@ -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 <Loading />
|
||||
|
||||
@ -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])
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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<typeof useRouter>
|
||||
const mockUseMailRegister = useMailRegister as unknown as MockedFunction<typeof useMailRegister>
|
||||
const mockGetBrowserTimezone = getBrowserTimezone as unknown as MockedFunction<typeof getBrowserTimezone>
|
||||
|
||||
const renderWithQueryClient = (ui: ReactElement) => {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { retry: false },
|
||||
mutations: { retry: false },
|
||||
},
|
||||
})
|
||||
return render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{ui}
|
||||
</QueryClientProvider>,
|
||||
)
|
||||
}
|
||||
|
||||
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(<ChangePasswordForm />)
|
||||
renderWithQueryClient(<ChangePasswordForm />)
|
||||
|
||||
fireEvent.change(screen.getByLabelText('common.account.newPassword'), {
|
||||
target: { value: 'ValidPass123!' },
|
||||
|
||||
@ -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 (
|
||||
<div className={
|
||||
|
||||
Reference in New Issue
Block a user