mirror of
https://github.com/langgenius/dify.git
synced 2026-08-15 04:59:46 +08:00
refactor(web): read workflow profile from query cache (#40469)
This commit is contained in:
parent
a64a24b39c
commit
df07a0a1de
@ -1,5 +1,6 @@
|
||||
import { screen } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { renderWithAccountProfile } from '@/test/console/account-profile'
|
||||
import { render } from '@/test/console/render'
|
||||
import Tips from '../tips'
|
||||
|
||||
@ -9,11 +10,6 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
describe('Tips', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
@ -29,7 +25,10 @@ describe('Tips', () => {
|
||||
})
|
||||
|
||||
it('should render email tip in debug mode', () => {
|
||||
render(<Tips showEmailTip={true} isEmailDebugMode={true} showDebugModeTip={false} />)
|
||||
renderWithAccountProfile(
|
||||
<Tips showEmailTip={true} isEmailDebugMode={true} showDebugModeTip={false} />,
|
||||
{ accountProfile: mockConsoleState.userProfile },
|
||||
)
|
||||
|
||||
expect(screen.getByText('workflow.common.humanInputEmailTipInDebugMode')).toBeInTheDocument()
|
||||
expect(screen.queryByText('workflow.common.humanInputEmailTip')).not.toBeInTheDocument()
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { memo } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { userProfileEmailAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
|
||||
type TipsProps = {
|
||||
showEmailTip: boolean
|
||||
@ -10,9 +10,26 @@ type TipsProps = {
|
||||
showDebugModeTip: boolean
|
||||
}
|
||||
|
||||
const EmailDebugTip = () => {
|
||||
const { data: email } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.email,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="system-xs-regular text-text-secondary">
|
||||
<Trans
|
||||
i18nKey={($) => $['common.humanInputEmailTipInDebugMode']}
|
||||
ns="workflow"
|
||||
components={{ email: <span className="system-xs-semibold"></span> }}
|
||||
values={{ email }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Tips = ({ showEmailTip, isEmailDebugMode, showDebugModeTip }: TipsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const email = useAtomValue(userProfileEmailAtom)
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -23,16 +40,7 @@ const Tips = ({ showEmailTip, isEmailDebugMode, showDebugModeTip }: TipsProps) =
|
||||
{t(($) => $['common.humanInputEmailTip'], { ns: 'workflow' })}
|
||||
</div>
|
||||
)}
|
||||
{showEmailTip && isEmailDebugMode && (
|
||||
<div className="system-xs-regular text-text-secondary">
|
||||
<Trans
|
||||
i18nKey={($) => $['common.humanInputEmailTipInDebugMode']}
|
||||
ns="workflow"
|
||||
components={{ email: <span className="system-xs-semibold"></span> }}
|
||||
values={{ email }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showEmailTip && isEmailDebugMode && <EmailDebugTip />}
|
||||
{showDebugModeTip && (
|
||||
<div className="system-xs-medium text-text-warning">
|
||||
{t(($) => $['common.humanInputWebappTip'], { ns: 'workflow' })}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import type { ReactElement, ReactNode } from 'react'
|
||||
import { screen, waitFor } from '@testing-library/react'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import { AppACLPermission } from '@/utils/permission'
|
||||
import WorkflowApp from '../index'
|
||||
|
||||
@ -59,6 +60,11 @@ let appTriggersState: {
|
||||
|
||||
let searchParamsValue: string | null = null
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(consoleState.userProfile),
|
||||
})
|
||||
|
||||
const mockWorkflowStore = {
|
||||
setState: mockWorkflowStoreSetState,
|
||||
getState: () => ({
|
||||
@ -85,15 +91,6 @@ vi.mock('@/app/components/workflow/store/trigger-status', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => ({
|
||||
isLoadingCurrentWorkspace: consoleState.isLoadingCurrentWorkspace,
|
||||
currentWorkspace: consoleState.currentWorkspace,
|
||||
userProfile: consoleState.userProfile,
|
||||
workspacePermissionKeys: consoleState.workspacePermissionKeys,
|
||||
}))
|
||||
})
|
||||
vi.mock('@/context/workspace-state', async () => {
|
||||
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createWorkspaceStateModuleMock(() => ({
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import { screen } from '@testing-library/react'
|
||||
import { StrictMode } from 'react'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import WorkflowApp from '../index'
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => ({
|
||||
userProfile: { id: 'user-1' },
|
||||
}))
|
||||
})
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(),
|
||||
})
|
||||
|
||||
vi.mock('@/context/workspace-state', async () => {
|
||||
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
|
||||
@ -4,6 +4,7 @@ import type { CollaborationUpdate } from '@/app/components/workflow/collaboratio
|
||||
import type { Shape as HooksStoreShape } from '@/app/components/workflow/hooks-store/store'
|
||||
import type { Edge, Node } from '@/app/components/workflow/types'
|
||||
import type { FetchWorkflowDraftResponse } from '@/types/workflow'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -18,8 +19,8 @@ import { useSetWorkflowVarsWithValue } from '@/app/components/workflow/hooks/use
|
||||
import { useWorkflowUpdate } from '@/app/components/workflow/hooks/use-workflow-update'
|
||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { workspacePermissionKeysAtom } from '@/context/permission-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { fetchWorkflowDraft } from '@/service/workflow'
|
||||
import { getAppACLCapabilities } from '@/utils/permission'
|
||||
import { useAvailableNodesMetaData } from '../hooks/use-available-nodes-meta-data'
|
||||
@ -89,7 +90,10 @@ const WorkflowMain = ({ nodes, edges, viewport }: WorkflowMainProps) => {
|
||||
const filteredCursors = Object.fromEntries(
|
||||
Object.entries(cursors).filter(([userId]) => userId !== myUserId),
|
||||
)
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
|
||||
const appACLCapabilities = useMemo(
|
||||
() =>
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { waitFor } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { renderHook } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { renderHook as renderHookWithConsoleState } from '@/test/console/render'
|
||||
import { AppACLPermission } from '@/utils/permission'
|
||||
import { useWorkflowInit } from '../use-workflow-init'
|
||||
|
||||
@ -17,6 +18,11 @@ const mockFetchNodesDefaultConfigs = vi.fn()
|
||||
const mockFetchPublishedWorkflow = vi.fn()
|
||||
const mockSyncWorkflowDraft = vi.fn()
|
||||
|
||||
const renderHook = <Result>(callback: () => Result) =>
|
||||
renderHookWithConsoleState(callback, {
|
||||
wrapper: createAccountProfileQueryWrapper({ id: 'user-1' }),
|
||||
})
|
||||
|
||||
let appStoreState: {
|
||||
appDetail: {
|
||||
id: string
|
||||
@ -46,13 +52,6 @@ vi.mock('@/app/components/app/store', () => ({
|
||||
useStore: <T>(selector: (state: typeof appStoreState) => T): T => selector(appStoreState),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => ({
|
||||
userProfile: { id: 'user-1' },
|
||||
workspacePermissionKeys: ['app.create_and_management'],
|
||||
}))
|
||||
})
|
||||
vi.mock('@/context/permission-state', async () => {
|
||||
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createPermissionStateModuleMock(() => ({
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import type { Edge, Node } from '@/app/components/workflow/types'
|
||||
import type { FileUploadConfigResponse } from '@/models/common'
|
||||
import type { FetchWorkflowDraftResponse } from '@/types/workflow'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { workspacePermissionKeysAtom } from '@/context/permission-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useWorkflowConfig } from '@/service/use-workflow'
|
||||
import {
|
||||
fetchNodesDefaultConfigs,
|
||||
@ -61,7 +62,10 @@ export const useWorkflowInit = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const { nodes: nodesTemplate, edges: edgesTemplate } = useWorkflowTemplate()
|
||||
const appDetail = useAppStore((state) => state.appDetail)!
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
|
||||
const appACLCapabilities = useMemo(
|
||||
() =>
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import type { Features as FeaturesData } from '@/app/components/base/features/types'
|
||||
import type { InjectWorkflowStoreSliceFn } from '@/app/components/workflow/store'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
@ -12,9 +13,9 @@ import { WorkflowContextProvider } from '@/app/components/workflow/context'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { useTriggerStatusStore } from '@/app/components/workflow/store/trigger-status'
|
||||
import { initialEdges, initialNodes } from '@/app/components/workflow/utils'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { workspacePermissionKeysAtom } from '@/context/permission-state'
|
||||
import { currentWorkspaceAtom, currentWorkspaceLoadingAtom } from '@/context/workspace-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useSearchParams } from '@/next/navigation'
|
||||
import { fetchRunDetail } from '@/service/log'
|
||||
import { useAppTriggers } from '@/service/use-tools'
|
||||
@ -31,7 +32,10 @@ const WorkflowAppWithAdditionalContext = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const isLoadingCurrentWorkspace = useAtomValue(currentWorkspaceLoadingAtom)
|
||||
const currentWorkspace = useAtomValue(currentWorkspaceAtom)
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
|
||||
|
||||
// Initialize trigger status at application level
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { WorkflowCommentList } from '@/app/components/workflow/comment/types'
|
||||
import { fireEvent, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import { CommentIcon } from './comment-icon'
|
||||
|
||||
type Position = { x: number; y: number }
|
||||
@ -18,6 +20,14 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
const mockFlowToScreenPosition = vi.fn((position: Position) => position)
|
||||
const mockScreenToFlowPosition = vi.fn((position: Position) => position)
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper({
|
||||
...mockConsoleState.userProfile,
|
||||
id: mockUserId,
|
||||
}),
|
||||
})
|
||||
|
||||
vi.mock('reactflow', () => ({
|
||||
useReactFlow: () => ({
|
||||
flowToScreenPosition: mockFlowToScreenPosition,
|
||||
@ -30,17 +40,6 @@ vi.mock('reactflow', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => ({
|
||||
...mockConsoleState,
|
||||
userProfile: {
|
||||
...mockConsoleState.userProfile,
|
||||
id: mockUserId,
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
vi.mock('@/app/components/base/user-avatar-list', () => ({
|
||||
UserAvatarList: ({ users }: { users: Array<{ id: string }> }) => (
|
||||
<div data-testid="avatar-list">{users.map((user) => user.id).join(',')}</div>
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
|
||||
import type { FC, PointerEvent as ReactPointerEvent } from 'react'
|
||||
import type { WorkflowCommentList } from '@/app/components/workflow/comment/types'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { memo, useCallback, useMemo, useRef, useState } from 'react'
|
||||
import { useReactFlow, useViewport } from 'reactflow'
|
||||
import { UserAvatarList } from '@/app/components/base/user-avatar-list'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import CommentPreview from './comment-preview'
|
||||
|
||||
type CommentIconProps = {
|
||||
@ -20,7 +20,10 @@ export const CommentIcon: FC<CommentIconProps> = memo(
|
||||
({ comment, onClick, isActive = false, onPositionUpdate }) => {
|
||||
const { flowToScreenPosition, screenToFlowPosition } = useReactFlow()
|
||||
const viewport = useViewport()
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const isAuthor = comment.created_by_account?.id === currentUserId
|
||||
const [showPreview, setShowPreview] = useState(false)
|
||||
const [dragPosition, setDragPosition] = useState<{ x: number; y: number } | null>(null)
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import type { FC } from 'react'
|
||||
import type { FC, ReactElement } from 'react'
|
||||
import { fireEvent, screen } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import { CommentInput } from './comment-input'
|
||||
|
||||
type MentionInputProps = {
|
||||
@ -26,6 +27,11 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
},
|
||||
}))
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile),
|
||||
})
|
||||
|
||||
vi.mock('react-i18next', async () => {
|
||||
const { withSelectorKey } = await import('@/test/i18n-mock')
|
||||
return {
|
||||
@ -35,11 +41,6 @@ vi.mock('react-i18next', async () => {
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('./mention-input', () => ({
|
||||
MentionInput: ((props: MentionInputProps) => {
|
||||
mentionInputProps = props
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { FC, PointerEvent as ReactPointerEvent } from 'react'
|
||||
import { Avatar } from '@langgenius/dify-ui/avatar'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { MentionInput } from './mention-input'
|
||||
|
||||
type CommentInputProps = {
|
||||
@ -25,7 +25,10 @@ export const CommentInput: FC<CommentInputProps> = memo(
|
||||
({ position, onSubmit, onCancel, autoFocus = true, disabled = false, onPositionChange }) => {
|
||||
const [content, setContent] = useState('')
|
||||
const { t } = useTranslation()
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const dragStateRef = useRef<
|
||||
{
|
||||
pointerId: number | null
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { WorkflowCommentDetail } from '@/app/components/workflow/comment/types'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import { CommentThread } from './thread'
|
||||
|
||||
const mockSetCommentPreviewHovering = vi.hoisted(() => vi.fn())
|
||||
@ -16,6 +18,11 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
},
|
||||
}))
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile),
|
||||
})
|
||||
|
||||
const storeState = vi.hoisted(() => ({
|
||||
mentionableUsersCache: {
|
||||
'app-1': [
|
||||
@ -35,11 +42,6 @@ vi.mock('@/hooks/use-format-time-from-now', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('reactflow', () => ({
|
||||
useReactFlow: () => ({
|
||||
flowToScreenPosition: mockFlowToScreenPosition,
|
||||
|
||||
@ -22,14 +22,14 @@ import {
|
||||
RiDeleteBinLine,
|
||||
RiMoreFill,
|
||||
} from '@remixicon/react'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useReactFlow, useViewport } from 'reactflow'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import InlineDeleteConfirm from '@/app/components/base/inline-delete-confirm'
|
||||
import { getUserColor } from '@/app/components/workflow/collaboration/utils/user-color'
|
||||
import { userProfileAtom, userProfileIdAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
||||
import { useParams } from '@/next/navigation'
|
||||
import { useStore } from '../store'
|
||||
@ -68,7 +68,10 @@ const ThreadMessage: FC<{
|
||||
className?: string
|
||||
}> = ({ authorId, authorName, avatarUrl, createdAt, content, mentionableNames, className }) => {
|
||||
const { formatTimeFromNow } = useFormatTimeFromNow()
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const isCurrentUser = authorId === currentUserId
|
||||
const userColor = isCurrentUser ? undefined : getUserColor(authorId)
|
||||
|
||||
@ -179,7 +182,10 @@ export const CommentThread: FC<CommentThreadProps> = memo(
|
||||
const appId = params.appId as string
|
||||
const { flowToScreenPosition } = useReactFlow()
|
||||
const viewport = useViewport()
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const currentUserId = userProfile.id
|
||||
const { t } = useTranslation()
|
||||
const [replyContent, setReplyContent] = useState('')
|
||||
|
||||
@ -13,17 +13,6 @@ const mockHandleLoadBackupDraft = vi.fn()
|
||||
const mockHandleRefreshWorkflowDraft = vi.fn()
|
||||
let mockPlanType = Plan.professional
|
||||
let mockEnableBilling = true
|
||||
const mockConsoleState = vi.hoisted(() => ({
|
||||
userProfile: {
|
||||
id: '',
|
||||
name: '',
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('@/context/provider-context', () => ({
|
||||
useProviderContext: () => ({
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Shape } from '../../store/workflow'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
|
||||
import { FlowType } from '@/types/common'
|
||||
import { renderWorkflowComponent } from '../../__tests__/workflow-test-env'
|
||||
import { WorkflowVersion } from '../../types'
|
||||
@ -25,18 +26,6 @@ const mockViewHistory = vi.fn()
|
||||
|
||||
let mockNodesReadOnly = false
|
||||
let mockTheme: 'light' | 'dark' = 'light'
|
||||
const mockConsoleState = vi.hoisted(() => ({
|
||||
userProfile: {
|
||||
id: '',
|
||||
name: '',
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('reactflow', () => ({
|
||||
useNodes: () => mockUseNodes(),
|
||||
}))
|
||||
@ -298,6 +287,7 @@ describe('Header layout components', () => {
|
||||
const onRestoreSettled = vi.fn()
|
||||
const deleteAllInspectVars = vi.fn()
|
||||
const currentVersion = createCurrentVersion()
|
||||
const currentUser = { id: 'user-1', name: 'Alice' }
|
||||
|
||||
const { store } = renderWorkflowComponent(
|
||||
<HeaderInRestoring onRestoreSettled={onRestoreSettled} />,
|
||||
@ -316,6 +306,7 @@ describe('Header layout components', () => {
|
||||
fileSettings: {},
|
||||
},
|
||||
},
|
||||
queryClient: createAccountProfileQueryClient(currentUser),
|
||||
},
|
||||
)
|
||||
|
||||
@ -337,8 +328,8 @@ describe('Header layout components', () => {
|
||||
expect(mockEmitRestoreIntent).toHaveBeenCalledWith({
|
||||
versionId: currentVersion.id,
|
||||
versionName: currentVersion.marked_name,
|
||||
initiatorUserId: '',
|
||||
initiatorName: '',
|
||||
initiatorUserId: currentUser.id,
|
||||
initiatorName: currentUser.name,
|
||||
})
|
||||
expect(mockEmitRestoreComplete).toHaveBeenCalledWith({
|
||||
versionId: currentVersion.id,
|
||||
|
||||
@ -2,13 +2,13 @@ import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { RiHistoryLine } from '@remixicon/react'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { PlanUpgradeModal } from '@/app/components/billing/plan-upgrade-modal'
|
||||
import { Plan } from '@/app/components/billing/type'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import useTheme from '@/hooks/use-theme'
|
||||
import {
|
||||
useInvalidAllLastRun,
|
||||
@ -32,7 +32,10 @@ const HeaderInRestoring = ({ onRestoreSettled }: HeaderInRestoringProps) => {
|
||||
const [isRestorePlanUpgradeModalOpen, setIsRestorePlanUpgradeModalOpen] = useState(false)
|
||||
const { plan, enableBilling } = useProviderContext()
|
||||
const workflowStore = useWorkflowStore()
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const configsMap = useHooksStore((s) => s.configsMap)
|
||||
const invalidAllLastRun = useInvalidAllLastRun(configsMap?.flowType, configsMap?.flowId)
|
||||
const { deleteAllInspectVars } = workflowStore.getState()
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
'use client'
|
||||
|
||||
import type { OnlineUser } from '../collaboration/types/collaboration'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { AvatarFallback, AvatarImage, AvatarRoot } from '@langgenius/dify-ui/avatar'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { getAvatar } from '@/service/common'
|
||||
import { useCollaboration } from '../collaboration/hooks/use-collaboration'
|
||||
import { getUserColor } from '../collaboration/utils/user-color'
|
||||
@ -53,7 +54,10 @@ const OnlineUsers = () => {
|
||||
cursors,
|
||||
isEnabled: isCollaborationEnabled,
|
||||
} = useCollaboration(appId as string)
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const reactFlow = useReactFlow()
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false)
|
||||
const avatarUrls = useAvatarUrls(onlineUsers || [])
|
||||
|
||||
@ -3,6 +3,7 @@ import type {
|
||||
WorkflowCommentList,
|
||||
} from '@/app/components/workflow/comment/types'
|
||||
import { act, waitFor } from '@testing-library/react'
|
||||
import { seedAccountProfileQuery } from '@/test/console/account-profile'
|
||||
import { createConsoleQueryClient, seedSystemFeatures } from '@/test/console/query-data'
|
||||
import { renderWorkflowHook } from '../../__tests__/workflow-test-env'
|
||||
import { ControlMode } from '../../types'
|
||||
@ -54,36 +55,36 @@ vi.mock('@/next/navigation', () => ({
|
||||
useParams: () => ({ appId: 'app-1' }),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
vi.mock('@/service/client', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/service/client')>()
|
||||
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
systemFeatures: {
|
||||
get: () => ({
|
||||
enable_collaboration_mode: globalFeatureState.enableCollaboration,
|
||||
}),
|
||||
},
|
||||
apps: {
|
||||
byAppId: {
|
||||
workflow: {
|
||||
comments: {
|
||||
get: (...args: unknown[]) => mockFetchWorkflowComments(...args),
|
||||
post: (...args: unknown[]) => mockCreateWorkflowComment(...args),
|
||||
byCommentId: {
|
||||
delete: (...args: unknown[]) => mockDeleteWorkflowComment(...args),
|
||||
get: (...args: unknown[]) => mockFetchWorkflowComment(...args),
|
||||
put: (...args: unknown[]) => mockUpdateWorkflowComment(...args),
|
||||
resolve: {
|
||||
post: (...args: unknown[]) => mockResolveWorkflowComment(...args),
|
||||
},
|
||||
replies: {
|
||||
post: (...args: unknown[]) => mockCreateWorkflowCommentReply(...args),
|
||||
byReplyId: {
|
||||
delete: (...args: unknown[]) => mockDeleteWorkflowCommentReply(...args),
|
||||
put: (...args: unknown[]) => mockUpdateWorkflowCommentReply(...args),
|
||||
return {
|
||||
...actual,
|
||||
consoleClient: {
|
||||
systemFeatures: {
|
||||
get: () => ({
|
||||
enable_collaboration_mode: globalFeatureState.enableCollaboration,
|
||||
}),
|
||||
},
|
||||
apps: {
|
||||
byAppId: {
|
||||
workflow: {
|
||||
comments: {
|
||||
get: (...args: unknown[]) => mockFetchWorkflowComments(...args),
|
||||
post: (...args: unknown[]) => mockCreateWorkflowComment(...args),
|
||||
byCommentId: {
|
||||
delete: (...args: unknown[]) => mockDeleteWorkflowComment(...args),
|
||||
get: (...args: unknown[]) => mockFetchWorkflowComment(...args),
|
||||
put: (...args: unknown[]) => mockUpdateWorkflowComment(...args),
|
||||
resolve: {
|
||||
post: (...args: unknown[]) => mockResolveWorkflowComment(...args),
|
||||
},
|
||||
replies: {
|
||||
post: (...args: unknown[]) => mockCreateWorkflowCommentReply(...args),
|
||||
byReplyId: {
|
||||
delete: (...args: unknown[]) => mockDeleteWorkflowCommentReply(...args),
|
||||
put: (...args: unknown[]) => mockUpdateWorkflowCommentReply(...args),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -91,19 +92,9 @@ vi.mock('@/service/client', () => ({
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
consoleQuery: {
|
||||
systemFeatures: {
|
||||
get: {
|
||||
queryKey: () => ['console', 'systemFeatures', 'get'],
|
||||
queryOptions: (options: Record<string, unknown> = {}) => ({
|
||||
queryKey: ['console', 'systemFeatures', 'get'],
|
||||
...options,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
consoleQuery: actual.consoleQuery,
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/app/components/workflow/collaboration/core/collaboration-manager', () => ({
|
||||
collaborationManager: {
|
||||
@ -156,6 +147,7 @@ const baseCommentDetail = (): WorkflowCommentDetail => ({
|
||||
|
||||
const createSeededQueryClient = () => {
|
||||
const queryClient = createConsoleQueryClient()
|
||||
seedAccountProfileQuery(queryClient, mockConsoleState.userProfile)
|
||||
seedSystemFeatures(queryClient, {
|
||||
enable_collaboration_mode: globalFeatureState.enableCollaboration,
|
||||
})
|
||||
|
||||
@ -4,11 +4,10 @@ import type {
|
||||
WorkflowCommentList,
|
||||
} from '@/app/components/workflow/comment/types'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import { collaborationManager } from '@/app/components/workflow/collaboration/core/collaboration-manager'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
|
||||
import { useParams } from '@/next/navigation'
|
||||
import { consoleClient } from '@/service/client'
|
||||
@ -69,7 +68,10 @@ export const useWorkflowComment = () => {
|
||||
() => new Map(mentionableUsers.map((user) => [user.id, user])),
|
||||
[mentionableUsers],
|
||||
)
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const { data: isCollaborationEnabled } = useSuspenseQuery({
|
||||
...systemFeaturesQueryOptions(),
|
||||
select: (s) => s.enable_collaboration_mode,
|
||||
|
||||
@ -11,20 +11,6 @@ const mockHandleNodeIterationChildSizeChange = vi.fn()
|
||||
const mockHandleNodeLoopChildSizeChange = vi.fn()
|
||||
const mockUseNodeResizeObserver = vi.fn()
|
||||
const mockUseCollaboration = vi.fn()
|
||||
const mockConsoleState = vi.hoisted(() => ({
|
||||
userProfile: {
|
||||
id: 'user-1',
|
||||
name: 'User',
|
||||
email: 'user@example.com',
|
||||
avatar: '',
|
||||
avatar_url: '',
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('../../../hooks/use-tool-icon', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('../../../hooks/use-tool-icon')>()
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import type { ResourceVarInputs } from '../types'
|
||||
import type {
|
||||
@ -18,7 +19,7 @@ import {
|
||||
SelectItemText,
|
||||
SelectTrigger,
|
||||
} from '@langgenius/dify-ui/select'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { CheckboxList } from '@/app/components/base/checkbox-list'
|
||||
import Input from '@/app/components/base/input'
|
||||
@ -32,7 +33,7 @@ import MixedVariableTextInput from '@/app/components/workflow/nodes/tool/compone
|
||||
import ToolDatePicker from '@/app/components/workflow/nodes/tool/components/tool-date-picker'
|
||||
import ToolDateRangePicker from '@/app/components/workflow/nodes/tool/components/tool-date-range-picker'
|
||||
import { VarType } from '@/app/components/workflow/types'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useFetchDynamicOptions } from '@/service/use-plugins'
|
||||
import { useTriggerPluginDynamicOptions } from '@/service/use-triggers'
|
||||
import { VarKindType } from '../types'
|
||||
@ -94,7 +95,10 @@ const FormInputItem: FC<Props> = ({
|
||||
inPanel,
|
||||
}) => {
|
||||
const language = useLanguage()
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const timezone = userProfile.timezone ?? 'UTC'
|
||||
const [toolsOptions, setToolsOptions] = useState<FormOption[] | null>(null)
|
||||
const [isLoadingToolsOptions, setIsLoadingToolsOptions] = useState(false)
|
||||
|
||||
@ -5,8 +5,8 @@ import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Tabs, TabsList, TabsPanel, TabsTab } from '@langgenius/dify-ui/tabs'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
|
||||
import { RiCloseLine, RiPlayLargeLine } from '@remixicon/react'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { debounce } from 'es-toolkit/compat'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useQueryState } from 'nuqs'
|
||||
import * as React from 'react'
|
||||
import { cloneElement, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
@ -47,7 +47,7 @@ import {
|
||||
hasRetryNode,
|
||||
isSupportCustomRunForm,
|
||||
} from '@/app/components/workflow/utils'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useAllBuiltInTools } from '@/service/use-tools'
|
||||
import { useAllTriggerPlugins } from '@/service/use-triggers'
|
||||
import { FlowType } from '@/types/common'
|
||||
@ -96,7 +96,10 @@ const BasePanel: FC<BasePanelProps> = ({ id, data, children }) => {
|
||||
const { t } = useTranslation()
|
||||
const language = useLanguage()
|
||||
const appId = useStore((s) => s.appId)
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const { isConnected, nodePanelPresence } = useCollaboration(appId as string)
|
||||
const { showMessageLogModal } = useAppStore(
|
||||
useShallow((state) => ({
|
||||
|
||||
@ -2,7 +2,7 @@ import type { FC, ReactElement } from 'react'
|
||||
import type { WorkflowTranslator } from './node-sections'
|
||||
import type { NodeProps } from '@/app/components/workflow/types'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { cloneElement, memo, useMemo, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { UserAvatarList } from '@/app/components/base/user-avatar-list'
|
||||
@ -15,7 +15,7 @@ import CopyID from '@/app/components/workflow/nodes/tool/components/copy-id'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { BlockEnum, ControlMode, NodeRunningStatus } from '@/app/components/workflow/types'
|
||||
import { hasErrorHandleNode, hasRetryNode } from '@/app/components/workflow/utils'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
|
||||
import { useNodePluginInstallation } from '../../hooks/use-node-plugin-installation'
|
||||
import { useToolIcon } from '../../hooks/use-tool-icon'
|
||||
@ -57,7 +57,10 @@ const BaseNode: FC<BaseNodeProps> = ({ id, data, children }) => {
|
||||
const { handleNodeIterationChildSizeChange } = useNodeIterationInteractions()
|
||||
const { handleNodeLoopChildSizeChange } = useNodeLoopInteractions()
|
||||
const toolIcon = useToolIcon(data)
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const appId = useStore((s) => s.appId)
|
||||
const { nodePanelPresence } = useCollaboration(appId as string)
|
||||
const controlMode = useStore((s) => s.controlMode)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { EmailConfig } from '../../../types'
|
||||
import { fireEvent, screen } from '@testing-library/react'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import EmailConfigureModal from '../email-configure-modal'
|
||||
|
||||
const mockToastError = vi.hoisted(() => vi.fn())
|
||||
@ -10,17 +12,17 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
},
|
||||
}))
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile),
|
||||
})
|
||||
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
error: (message: string) => mockToastError(message),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('../mail-body-input', () => ({
|
||||
default: ({ value, onChange }: { value: string; onChange: (value: string) => void }) => (
|
||||
<textarea
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { EmailConfig, FormInputItem } from '../../../types'
|
||||
import type { Node, NodeOutPutVar } from '@/app/components/workflow/types'
|
||||
import { fireEvent, screen, within } from '@testing-library/react'
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import { DeliveryMethodType } from '../../../types'
|
||||
import DeliveryMethodItem from '../method-item'
|
||||
|
||||
@ -27,10 +29,10 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile),
|
||||
})
|
||||
|
||||
vi.mock('../email-configure-modal', () => ({
|
||||
default: (props: EmailConfigureModalProps) => {
|
||||
|
||||
@ -16,6 +16,7 @@ import { HooksStoreContext } from '@/app/components/workflow/hooks-store/provide
|
||||
import { createHooksStore } from '@/app/components/workflow/hooks-store/store'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import { BlockEnum, InputVarType, VarType } from '@/app/components/workflow/types'
|
||||
import { seedAccountProfileQuery } from '@/test/console/account-profile'
|
||||
import { render } from '@/test/console/render'
|
||||
import EmailSenderModal from '../test-email-sender'
|
||||
|
||||
@ -38,10 +39,6 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
vi.mock('@/context/workspace-state', async () => {
|
||||
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createWorkspaceStateModuleMock(() => mockConsoleState)
|
||||
@ -67,6 +64,7 @@ const createQueryClient = () =>
|
||||
|
||||
const renderWithProviders = (ui: ReactNode) => {
|
||||
const queryClient = createQueryClient()
|
||||
seedAccountProfileQuery(queryClient, mockConsoleState.userProfile)
|
||||
const hooksStore = createHooksStore({})
|
||||
|
||||
return render(
|
||||
|
||||
@ -5,11 +5,11 @@ import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgeni
|
||||
import { Switch } from '@langgenius/dify-ui/switch'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { RiBugLine } from '@remixicon/react'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { memo, useCallback, useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { userProfileEmailAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import MailBodyInput from './mail-body-input'
|
||||
import Recipient from './recipient'
|
||||
|
||||
@ -33,7 +33,10 @@ const EmailConfigureModal = ({
|
||||
availableNodes = [],
|
||||
}: EmailConfigureModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
const email = useAtomValue(userProfileEmailAtom)
|
||||
const { data: email } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.email,
|
||||
})
|
||||
const [recipients, setRecipients] = useState(
|
||||
config?.recipients || { whole_workspace: false, items: [] },
|
||||
)
|
||||
|
||||
@ -13,12 +13,12 @@ import {
|
||||
RiRobot2Fill,
|
||||
RiSendPlane2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
|
||||
import Badge from '@/app/components/base/badge/index'
|
||||
import { userProfileEmailAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { DeliveryMethodType } from '../../types'
|
||||
import EmailConfigureModal from './email-configure-modal'
|
||||
import TestEmailSender from './test-email-sender'
|
||||
@ -49,7 +49,10 @@ const DeliveryMethodItem: FC<DeliveryMethodItemProps> = ({
|
||||
readonly,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const email = useAtomValue(userProfileEmailAtom)
|
||||
const { data: email } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.email,
|
||||
})
|
||||
const [isHovering, setIsHovering] = useState(false)
|
||||
const [showEmailModal, setShowEmailModal] = useState(false)
|
||||
const [showTestEmailModal, setShowTestEmailModal] = useState(false)
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import { fireEvent, screen } from '@testing-library/react'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import { withSelectorKey } from '@/test/i18n-mock'
|
||||
import Recipient from '../index'
|
||||
|
||||
@ -11,14 +13,15 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
currentWorkspace: { name: "Dify's Lab" },
|
||||
}))
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile),
|
||||
})
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => mockUseTranslation(),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
vi.mock('@/context/workspace-state', async () => {
|
||||
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createWorkspaceStateModuleMock(() => mockConsoleState)
|
||||
|
||||
@ -2,12 +2,13 @@ import type { RecipientData, Recipient as RecipientItem } from '../../../types'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Switch } from '@langgenius/dify-ui/switch'
|
||||
import { RiGroupLine } from '@remixicon/react'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { produce } from 'immer'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { userProfileEmailAtom } from '@/context/account-state'
|
||||
import { currentWorkspaceAtom } from '@/context/workspace-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
import EmailInput from './email-input'
|
||||
import MemberSelector from './member-selector'
|
||||
@ -21,7 +22,10 @@ type Props = Readonly<{
|
||||
|
||||
const Recipient = ({ data, onChange }: Props) => {
|
||||
const { t } = useTranslation()
|
||||
const userProfileEmail = useAtomValue(userProfileEmailAtom)
|
||||
const { data: userProfileEmail } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.email,
|
||||
})
|
||||
const currentWorkspace = useAtomValue(currentWorkspaceAtom)
|
||||
const { data: members } = useMembers()
|
||||
const accounts = members?.accounts || []
|
||||
|
||||
@ -5,6 +5,7 @@ import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { RiArrowRightSFill } from '@remixicon/react'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { noop, unionBy } from 'es-toolkit/compat'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { memo, useCallback, useMemo, useState } from 'react'
|
||||
@ -21,8 +22,8 @@ import {
|
||||
isSystemVar,
|
||||
} from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import { InputVarType, VarType } from '@/app/components/workflow/types'
|
||||
import { userProfileEmailAtom } from '@/context/account-state'
|
||||
import { currentWorkspaceAtom } from '@/context/workspace-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
import { useTestEmailSender } from '@/service/use-workflow'
|
||||
import { getHumanInputFormDependencySelectors, isOutput } from '../../utils'
|
||||
@ -128,7 +129,10 @@ const EmailSenderModal = ({
|
||||
availableNodes = [],
|
||||
}: EmailSenderModalProps) => {
|
||||
const { t } = useTranslation()
|
||||
const userProfileEmail = useAtomValue(userProfileEmailAtom)
|
||||
const { data: userProfileEmail } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.email,
|
||||
})
|
||||
const currentWorkspace = useAtomValue(currentWorkspaceAtom)
|
||||
const appDetail = useAppStore((state) => state.appDetail)
|
||||
const { mutateAsync: testEmailSender } = useTestEmailSender()
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { ComparisonOperator, MetadataFilteringCondition, MetadataShape } from '../types'
|
||||
import type { DataSet, MetadataInDoc } from '@/models/datasets'
|
||||
import { fireEvent, screen, waitFor, within } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
|
||||
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
|
||||
import {
|
||||
createAccountProfileQueryClient,
|
||||
createAccountProfileQueryWrapper,
|
||||
} from '@/test/console/account-profile'
|
||||
import { QueryClientTestProvider } from '@/test/console/query-provider'
|
||||
import { render } from '@/test/console/render'
|
||||
import { RETRIEVE_METHOD, RETRIEVE_TYPE } from '@/types/app'
|
||||
@ -34,6 +38,11 @@ import {
|
||||
MetadataFilteringVariableType,
|
||||
} from '../types'
|
||||
|
||||
const renderWithAccountProfile = (ui: ReactElement) =>
|
||||
render(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(),
|
||||
})
|
||||
|
||||
const mockHasEditPermissionForDataset = vi.fn(
|
||||
(
|
||||
_userId: string,
|
||||
@ -136,10 +145,6 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
workspacePermissionKeys: [] as string[],
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
vi.mock('@/context/permission-state', async () => {
|
||||
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createPermissionStateModuleMock(() => mockConsoleState)
|
||||
@ -422,7 +427,7 @@ describe('knowledge-retrieval path', () => {
|
||||
it('should render empty and populated dataset lists', () => {
|
||||
const onChange = vi.fn()
|
||||
|
||||
const { rerender } = render(<DatasetList list={[]} onChange={onChange} />)
|
||||
const { rerender } = renderWithAccountProfile(<DatasetList list={[]} onChange={onChange} />)
|
||||
|
||||
expect(screen.getByText('appDebug.datasetConfig.knowledgeTip')).toBeInTheDocument()
|
||||
|
||||
@ -454,7 +459,7 @@ describe('knowledge-retrieval path', () => {
|
||||
canAccessConfig: false,
|
||||
})
|
||||
|
||||
render(<DatasetList list={[dataset]} onChange={vi.fn()} />)
|
||||
renderWithAccountProfile(<DatasetList list={[dataset]} onChange={vi.fn()} />)
|
||||
|
||||
const datasetItem = getDatasetItem()
|
||||
|
||||
@ -767,7 +772,7 @@ describe('knowledge-retrieval path', () => {
|
||||
store.getState().updateDatasetsDetail([createDataset()])
|
||||
|
||||
const renderNode = (datasetIds: string[]) =>
|
||||
render(
|
||||
renderWithAccountProfile(
|
||||
<DatasetsDetailContext.Provider value={store}>
|
||||
<Node
|
||||
id="knowledge-node"
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import type { DataSet } from '@/models/datasets'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { produce } from 'immer'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { workspacePermissionKeysAtom } from '@/context/permission-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { getDatasetACLCapabilities } from '@/utils/permission'
|
||||
import Item from './dataset-item'
|
||||
|
||||
@ -31,7 +33,10 @@ const DatasetList: FC<Props> = ({
|
||||
settingsModalHeight,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
|
||||
|
||||
const handleRemove = useCallback(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { NoteNodeType } from '../note-node/types'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { CUSTOM_NOTE_NODE } from '../note-node/constants'
|
||||
import { NoteTheme } from '../note-node/types'
|
||||
import { useWorkflowNoteShowAuthorValue } from '../persistence/local-storage-options'
|
||||
@ -10,7 +10,10 @@ import { generateNewNode } from '../utils'
|
||||
|
||||
export const useOperator = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const showAuthorStorage = useWorkflowNoteShowAuthorValue()
|
||||
|
||||
const handleAddNote = useCallback(() => {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { WorkflowCommentList } from '@/app/components/workflow/comment/types'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import { render } from '@/test/console/render'
|
||||
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
|
||||
import { render as renderWithConsoleState } from '@/test/console/render'
|
||||
import CommentsPanel from '../index'
|
||||
|
||||
const mockHandleCommentIconClick = vi.hoisted(() => vi.fn())
|
||||
@ -12,6 +14,11 @@ const mockConsoleState = vi.hoisted(() => ({
|
||||
userProfile: { id: 'user-1' },
|
||||
}))
|
||||
|
||||
const render = (ui: ReactElement) =>
|
||||
renderWithConsoleState(ui, {
|
||||
wrapper: createAccountProfileQueryWrapper(mockConsoleState.userProfile),
|
||||
})
|
||||
|
||||
const commentFixtures: WorkflowCommentList[] = [
|
||||
{
|
||||
id: 'c-1',
|
||||
@ -65,11 +72,6 @@ vi.mock('@/hooks/use-format-time-from-now', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('@/app/components/workflow/store', () => ({
|
||||
useStore: (selector: (state: WorkflowStoreSelectionState) => unknown) =>
|
||||
selector({
|
||||
|
||||
@ -8,14 +8,14 @@ import {
|
||||
RiCloseLine,
|
||||
RiFilter3Line,
|
||||
} from '@remixicon/react'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import { memo, useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { UserAvatarList } from '@/app/components/base/user-avatar-list'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { ControlMode } from '@/app/components/workflow/types'
|
||||
import { userProfileIdAtom } from '@/context/account-state'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
||||
import { useWorkflowComment } from '../../hooks/use-workflow-comment'
|
||||
|
||||
@ -39,7 +39,11 @@ const CommentsPanel = () => {
|
||||
[handleCommentIconClick],
|
||||
)
|
||||
|
||||
const currentUserId = useAtomValue(userProfileIdAtom)
|
||||
const { data: currentUserId } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
|
||||
select: (data) => data.profile.id,
|
||||
})
|
||||
|
||||
const filteredSorted = useMemo(() => {
|
||||
let data = comments
|
||||
|
||||
@ -19,12 +19,6 @@ const mockEmitRestoreComplete = vi.fn()
|
||||
const mockEmitWorkflowUpdate = vi.fn()
|
||||
let mockPlanType = Plan.professional
|
||||
let mockEnableBilling = true
|
||||
const mockConsoleState = vi.hoisted(() => ({
|
||||
userProfile: {
|
||||
id: 'test-user-id',
|
||||
name: 'Test User',
|
||||
},
|
||||
}))
|
||||
|
||||
const createVersionHistory = (overrides: Partial<VersionHistory> = {}): VersionHistory => ({
|
||||
id: 'version-id',
|
||||
@ -69,11 +63,6 @@ type MockVersionHistoryItemProps = {
|
||||
handleClickActionMenuItem: (operation: VersionHistoryContextMenuOptions) => void
|
||||
}
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => mockConsoleState)
|
||||
})
|
||||
|
||||
vi.mock('@/context/provider-context', () => ({
|
||||
useProviderContext: () => ({
|
||||
plan: { type: mockPlanType },
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import type { VersionHistory } from '@/types/workflow'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { RiArrowDownDoubleLine, RiCloseLine, RiLoader2Line } from '@remixicon/react'
|
||||
import { useSuspenseQuery } from '@tanstack/react-query'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import { useAtomValue } from 'jotai'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -11,8 +12,8 @@ import VersionInfoModal from '@/app/components/app/app-publisher/version-info-mo
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { PlanUpgradeModal } from '@/app/components/billing/plan-upgrade-modal'
|
||||
import { Plan } from '@/app/components/billing/type'
|
||||
import { userProfileAtom } from '@/context/account-state'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { userProfileQueryOptions } from '@/features/account-profile/client'
|
||||
import {
|
||||
useDeleteWorkflow,
|
||||
useInvalidAllLastRun,
|
||||
@ -72,7 +73,10 @@ export const VersionHistoryPanel = ({
|
||||
const setShowWorkflowVersionHistoryPanel = useStore((s) => s.setShowWorkflowVersionHistoryPanel)
|
||||
const currentVersion = useStore((s) => s.currentVersion)
|
||||
const setCurrentVersion = useStore((s) => s.setCurrentVersion)
|
||||
const userProfile = useAtomValue(userProfileAtom)
|
||||
const { data: userProfile } = useSuspenseQuery({
|
||||
...userProfileQueryOptions(),
|
||||
select: (data) => data.profile,
|
||||
})
|
||||
const configsMap = useHooksStore((s) => s.configsMap)
|
||||
const canImportExportDSL = useHooksStore((s) => s.accessControl.canImportExportDSL)
|
||||
const invalidAllLastRun = useInvalidAllLastRun(configsMap?.flowType, configsMap?.flowId)
|
||||
|
||||
@ -21,11 +21,6 @@ vi.mock('@/service/log', () => ({
|
||||
fetchTracingList: (...args: unknown[]) => mockFetchTracingList(...args),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/account-state', async () => {
|
||||
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
|
||||
return createAccountStateModuleMock(() => ({ userProfile: { id: 'account-1' } }))
|
||||
})
|
||||
|
||||
vi.mock('@langgenius/dify-ui/toast', async (importOriginal) => ({
|
||||
...(await importOriginal()),
|
||||
toast: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user