diff --git a/web/app/components/plugins/plugin-auth/__tests__/plugin-auth-in-agent.spec.tsx b/web/app/components/plugins/plugin-auth/__tests__/plugin-auth-in-agent.spec.tsx index 80f9e243834..4b5f22a1c39 100644 --- a/web/app/components/plugins/plugin-auth/__tests__/plugin-auth-in-agent.spec.tsx +++ b/web/app/components/plugins/plugin-auth/__tests__/plugin-auth-in-agent.spec.tsx @@ -3,6 +3,7 @@ import type { Credential, PluginPayload } from '../types' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { fireEvent, screen } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' +import { seedAccountProfileQuery } from '@/test/console/account-profile' import { render } from '@/test/console/render' import { AuthCategory, CredentialTypeEnum } from '../types' @@ -44,14 +45,6 @@ const mockUserProfile = { avatar_url: '', } -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ - userProfile: mockUserProfile, - isCurrentWorkspaceManager: mockIsCurrentWorkspaceManager(), - workspacePermissionKeys: ['credential.use', 'credential.create', 'credential.manage'], - })) -}) vi.mock('@/context/workspace-state', async () => { const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture') return createWorkspaceStateModuleMock(() => ({ @@ -90,6 +83,7 @@ const createConsoleQueryClient = () => const createWrapper = () => { const testQueryClient = createConsoleQueryClient() + seedAccountProfileQuery(testQueryClient, mockUserProfile) return ({ children }: { children: ReactNode }) => ( {children} ) diff --git a/web/app/components/plugins/plugin-auth/authorize/__tests__/api-key-modal.spec.tsx b/web/app/components/plugins/plugin-auth/authorize/__tests__/api-key-modal.spec.tsx index 42cbe046662..6490b85dc5a 100644 --- a/web/app/components/plugins/plugin-auth/authorize/__tests__/api-key-modal.spec.tsx +++ b/web/app/components/plugins/plugin-auth/authorize/__tests__/api-key-modal.spec.tsx @@ -6,7 +6,7 @@ import { fireEvent, screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { render } from '@/test/console/render' +import { renderWithAccountProfile as render } from '@/test/console/account-profile' import { AuthCategory } from '../../types' const { mockToast } = vi.hoisted(() => { @@ -32,10 +32,6 @@ vi.mock('@langgenius/dify-ui/toast', () => ({ toast: mockToast, })) -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ userProfile: {} })) -}) const mockAddPluginCredential = vi.fn().mockResolvedValue({}) const mockUpdatePluginCredential = vi.fn().mockResolvedValue({}) const defaultCredentialSchemas = [ diff --git a/web/app/components/plugins/plugin-auth/authorize/__tests__/authorize-components.spec.tsx b/web/app/components/plugins/plugin-auth/authorize/__tests__/authorize-components.spec.tsx index 02e52ab0aaf..351a1d8920c 100644 --- a/web/app/components/plugins/plugin-auth/authorize/__tests__/authorize-components.spec.tsx +++ b/web/app/components/plugins/plugin-auth/authorize/__tests__/authorize-components.spec.tsx @@ -1,22 +1,12 @@ import type { PluginPayload } from '../../types' import type { FormSchema } from '@/app/components/base/form/types' -import { QueryClient } from '@tanstack/react-query' import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' +import { createAccountProfileQueryClient } from '@/test/console/account-profile' import { createQueryClientWrapper } from '@/test/console/query-client' import { AuthCategory } from '../../types' -const createWrapper = () => - createQueryClientWrapper( - new QueryClient({ - defaultOptions: { - queries: { - retry: false, - gcTime: 0, - }, - }, - }), - ) +const createWrapper = () => createQueryClientWrapper(createAccountProfileQueryClient()) // Mock API hooks - these make network requests so must be mocked const mockGetPluginOAuthUrl = vi.fn() @@ -111,10 +101,6 @@ vi.mock('@langgenius/dify-ui/toast', () => ({ toast: mockToast, })) -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ userProfile: {} })) -}) // Factory function for creating test PluginPayload const createPluginPayload = (overrides: Partial = {}): PluginPayload => ({ category: AuthCategory.tool, diff --git a/web/app/components/plugins/plugin-auth/authorize/permission-selector.tsx b/web/app/components/plugins/plugin-auth/authorize/permission-selector.tsx index 9292ebad2e0..f38c993bb06 100644 --- a/web/app/components/plugins/plugin-auth/authorize/permission-selector.tsx +++ b/web/app/components/plugins/plugin-auth/authorize/permission-selector.tsx @@ -8,9 +8,9 @@ import { PopoverTrigger, } from '@langgenius/dify-ui/popover' import { RadioGroup, RadioItem } from '@langgenius/dify-ui/radio' -import { useAtomValue } from 'jotai' +import { useSuspenseQuery } from '@tanstack/react-query' import { useTranslation } from 'react-i18next' -import { userProfileAtom } from '@/context/account-state' +import { userProfileQueryOptions } from '@/features/account-profile/client' import { PermissionLevel } from '@/models/permission' export type CredentialPermission = @@ -28,7 +28,10 @@ const optionClassName = const PermissionSelector = ({ disabled, permission, onChange }: PermissionSelectorProps) => { const { t } = useTranslation() - const userProfile = useAtomValue(userProfileAtom) + const { data: userProfile } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile, + }) const isOnlyMe = permission === PermissionLevel.onlyMe const isAllTeamMembers = permission === PermissionLevel.allTeamMembers const permissionLabel = t(($) => $['auth.whoCanUse'], { ns: 'plugin' }) diff --git a/web/app/components/plugins/plugin-auth/authorized/__tests__/index.spec.tsx b/web/app/components/plugins/plugin-auth/authorized/__tests__/index.spec.tsx index 42e69745f7a..744bf4bd11c 100644 --- a/web/app/components/plugins/plugin-auth/authorized/__tests__/index.spec.tsx +++ b/web/app/components/plugins/plugin-auth/authorized/__tests__/index.spec.tsx @@ -3,6 +3,7 @@ import type { Credential, PluginPayload } from '../../types' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, fireEvent, screen, waitFor } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' +import { seedAccountProfileQuery } from '@/test/console/account-profile' import { render } from '@/test/console/render' import { AuthCategory, CredentialTypeEnum } from '../../types' import Authorized from '../index' @@ -87,13 +88,6 @@ const mockConsoleState = vi.hoisted(() => ({ workspacePermissionKeys: ['credential.use', 'credential.create', 'credential.manage'] as string[], })) -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ - userProfile: mockConsoleState.userProfile, - workspacePermissionKeys: mockConsoleState.workspacePermissionKeys, - })) -}) vi.mock('@/context/permission-state', async () => { const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture') return createPermissionStateModuleMock(() => ({ @@ -137,6 +131,7 @@ const createConsoleQueryClient = () => const createWrapper = () => { const testQueryClient = createConsoleQueryClient() + seedAccountProfileQuery(testQueryClient, mockConsoleState.userProfile) return ({ children }: { children: ReactNode }) => ( {children} ) diff --git a/web/app/components/plugins/plugin-auth/authorized/__tests__/item.spec.tsx b/web/app/components/plugins/plugin-auth/authorized/__tests__/item.spec.tsx index 26cf90178a0..428004e16a2 100644 --- a/web/app/components/plugins/plugin-auth/authorized/__tests__/item.spec.tsx +++ b/web/app/components/plugins/plugin-auth/authorized/__tests__/item.spec.tsx @@ -1,17 +1,10 @@ import type { Credential } from '../../types' import { cleanup, fireEvent, screen } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { render } from '@/test/console/render' +import { renderWithAccountProfile as render } from '@/test/console/account-profile' import { CredentialTypeEnum } from '../../types' import Item from '../item' -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ - userProfile: { id: 'test-user' }, - workspacePermissionKeys: ['credential.use', 'credential.create', 'credential.manage'], - })) -}) vi.mock('@/context/permission-state', async () => { const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture') return createPermissionStateModuleMock(() => ({ diff --git a/web/app/components/plugins/plugin-auth/authorized/item.tsx b/web/app/components/plugins/plugin-auth/authorized/item.tsx index f36119c14fa..a9f22472c65 100644 --- a/web/app/components/plugins/plugin-auth/authorized/item.tsx +++ b/web/app/components/plugins/plugin-auth/authorized/item.tsx @@ -4,13 +4,13 @@ import { cn } from '@langgenius/dify-ui/cn' import { StatusDot } from '@langgenius/dify-ui/status-dot' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { RiInformationLine } from '@remixicon/react' -import { useAtomValue } from 'jotai' +import { useSuspenseQuery } from '@tanstack/react-query' import { memo, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' import Badge from '@/app/components/base/badge' import Input from '@/app/components/base/input' -import { userProfileIdAtom } from '@/context/account-state' +import { userProfileQueryOptions } from '@/features/account-profile/client' import { useCredentialPermissions } from '@/hooks/use-credential-permissions' import { CredentialTypeEnum } from '../types' @@ -50,7 +50,10 @@ const Item = ({ const { canUseCredential, canManageCredential } = useCredentialPermissions() const isOAuth = credential.credential_type === CredentialTypeEnum.OAUTH2 const isPersonal = credential.visibility === 'only_me' - const currentUserId = useAtomValue(userProfileIdAtom) + const { data: currentUserId } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile.id, + }) // Borrowed-from-teammate: the backend explicitly flagged this row as another member's // only_me credential, returned only because the current node still references it. // Fallback heuristic (created_by mismatch on a selected row) is kept for backends diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.tsx index 18e24b5f278..a5031c8963d 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.tsx @@ -15,8 +15,8 @@ import { } from '@langgenius/dify-ui/select' import { Switch } from '@langgenius/dify-ui/switch' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' +import { useSuspenseQuery } from '@tanstack/react-query' import { useBoolean } from 'ahooks' -import { useAtomValue } from 'jotai' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { Infotip } from '@/app/components/base/infotip' @@ -33,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 as VarKindType } from '@/app/components/workflow/nodes/tool/types' -import { userProfileAtom } from '@/context/account-state' +import { userProfileQueryOptions } from '@/features/account-profile/client' import { createPickerProps, getFieldFlags, @@ -68,8 +68,10 @@ const ReasoningConfigForm: React.FC = ({ }) => { const { t } = useTranslation() const language = useLanguage() - const userProfile = useAtomValue(userProfileAtom) - const timezone = userProfile.timezone ?? 'UTC' + const { data: timezone } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile.timezone ?? 'UTC', + }) const handleAutomatic = (key: string, val: boolean, type: string) => { onChange(updateInputAutoState(value, key, val, type)) diff --git a/web/app/components/tools/mcp/hooks/use-mcp-service-card.ts b/web/app/components/tools/mcp/hooks/use-mcp-service-card.ts index b8acd9ff1f8..59a9c4ba132 100644 --- a/web/app/components/tools/mcp/hooks/use-mcp-service-card.ts +++ b/web/app/components/tools/mcp/hooks/use-mcp-service-card.ts @@ -1,12 +1,12 @@ 'use client' import type { AppDetailResponse } from '@/models/app' import type { AppSSO } from '@/types/app' -import { useQuery, useQueryClient } from '@tanstack/react-query' +import { useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query' import { useAtomValue } from 'jotai' import { useCallback, useMemo, useState } from 'react' 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 { fetchAppDetail } from '@/service/apps' import { useInvalidateMCPServerDetail, @@ -35,7 +35,10 @@ export const useMCPServiceCardState = (appInfo: AppInfo, triggerModeDisabled: bo const { mutateAsync: updateMCPServer } = useUpdateMCPServer() const { mutateAsync: refreshMCPServerCode, isPending: genLoading } = useRefreshMCPServerCode() const invalidateMCPServerDetail = useInvalidateMCPServerDetail() - const currentUserId = useAtomValue(userProfileIdAtom) + const { data: currentUserId } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile.id, + }) const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom) const canManageMCP = useMemo( diff --git a/web/context/account-state.ts b/web/context/account-state.ts index 06879199ace..7d883ca5fb5 100644 --- a/web/context/account-state.ts +++ b/web/context/account-state.ts @@ -10,10 +10,6 @@ export const userProfileAtom = atom((get) => { return get(accountProfileQueryAtom).data.profile }) -export const userProfileIdAtom = atom((get) => { - return get(userProfileAtom).id -}) - export const accountProfileMetaAtom = atom((get) => { return get(accountProfileQueryAtom).data.meta }) diff --git a/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx b/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx index 6d30a91dbcb..2aaff578db4 100644 --- a/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx +++ b/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx @@ -3,6 +3,7 @@ import type React from 'react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' +import { seedAccountProfileQuery } from '@/test/console/account-profile' import { seedSystemFeatures } from '@/test/console/query-data' import { render } from '@/test/console/render' import { ServiceApiAccessCard } from '../service-api-access-card' @@ -44,21 +45,6 @@ vi.mock('@/hooks/use-timestamp', () => ({ }), })) -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ - userProfile: { id: 'user-1' }, - currentWorkspace: { id: 'workspace-1' }, - workspacePermissionKeys: ['app.acl.edit'], - langGeniusVersionInfo: { - current_env: 'PRODUCTION', - current_version: '', - latest_version: '', - version: '', - release_notes: '', - }, - })) -}) vi.mock('@/context/workspace-state', async () => { const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture') return createWorkspaceStateModuleMock(() => ({ @@ -107,6 +93,13 @@ vi.mock('@/context/version-state', async () => { vi.mock('@/service/client', () => ({ consoleQuery: { + account: { + profile: { + get: { + queryKey: () => [['console', 'account', 'profile', 'get'], { type: 'query' }], + }, + }, + }, systemFeatures: { get: { queryKey: () => ['system-features'], @@ -256,6 +249,7 @@ function createConsoleQueryClient(webAppAuthEnabled = true) { enabled: webAppAuthEnabled, }, }) + seedAccountProfileQuery(queryClient, { id: 'user-1' }) return queryClient } diff --git a/web/features/agent-v2/agent-detail/access/components/web-app-access-control-button.tsx b/web/features/agent-v2/agent-detail/access/components/web-app-access-control-button.tsx index 0c954bd0386..4e53fddc851 100644 --- a/web/features/agent-v2/agent-detail/access/components/web-app-access-control-button.tsx +++ b/web/features/agent-v2/agent-detail/access/components/web-app-access-control-button.tsx @@ -6,8 +6,8 @@ import { useSuspenseQuery } from '@tanstack/react-query' import { useAtomValue } from 'jotai' import { useState } 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 { systemFeaturesQueryOptions } from '@/features/system-features/client' import { isAccessMode } from '@/models/access-control' import dynamic from '@/next/dynamic' @@ -27,7 +27,10 @@ export function WebAppAccessControlButton({ agent }: { agent?: AgentAppDetailWit ...systemFeaturesQueryOptions(), select: (systemFeatures) => systemFeatures.webapp_auth.enabled, }) - const currentUserId = useAtomValue(userProfileIdAtom) + const { data: currentUserId } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile.id, + }) const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom) const { canReleaseAndVersion: canManageWebAppAccessControl } = getAppACLCapabilities( agent?.permission_keys, diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx index 8b21b70d29a..d0ff3f728a9 100644 --- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/tools/__tests__/index.spec.tsx @@ -15,6 +15,7 @@ import { agentComposerSavedDraftAtom, isAgentComposerDirtyAtom, } from '@/features/agent-v2/agent-composer/store' +import { seedAccountProfileQuery } from '@/test/console/account-profile' import { AgentOrchestrateReadOnlyContext } from '../../read-only-context' import { AgentTools } from '../index' @@ -48,13 +49,6 @@ vi.mock('@/app/components/workflow/block-selector/tool-picker', () => ({ ToolPickerContent: () =>
Mock tool picker
, })) -vi.mock('@/context/account-state', async () => { - const { atom } = await vi.importActual('jotai') - return { - userProfileIdAtom: atom('user-1'), - } -}) - vi.mock('@/app/components/workflow/block-icon', () => ({ default: ({ toolIcon }: { toolIcon?: string | { content: string; background: string } }) => ( @@ -392,6 +386,7 @@ function renderAgentTools(initialDraft: AgentSoulConfigFormState = agentToolsDra }, }, }) + seedAccountProfileQuery(queryClient, { id: 'user-1' }) return render( @@ -410,6 +405,7 @@ function renderAgentToolsWithStore(initialDraft: AgentSoulConfigFormState = agen }, }, }) + seedAccountProfileQuery(queryClient, { id: 'user-1' }) const store = createStore() store.set(agentComposerDraftAtom, initialDraft) store.set(agentComposerSavedDraftAtom, initialDraft) @@ -436,6 +432,7 @@ function renderReadonlyAgentTools(initialDraft: AgentSoulConfigFormState = agent }, }, }) + seedAccountProfileQuery(queryClient, { id: 'user-1' }) return render( diff --git a/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/chat.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/chat.spec.tsx index 98ddc319f76..308bd5a2761 100644 --- a/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/chat.spec.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/chat.spec.tsx @@ -14,6 +14,7 @@ import { agentComposerDraftAtom } from '@/features/agent-v2/agent-composer/store import { agentComposerModelAtom } from '@/features/agent-v2/agent-composer/store-modules/model' import { agentComposerPromptAtom } from '@/features/agent-v2/agent-composer/store-modules/prompt' import { consoleQuery } from '@/service/client' +import { seedAccountProfileQuery } from '@/test/console/account-profile' import { render } from '@/test/console/render' import { seedRegisteredConsoleStateFixture } from '@/test/console/state-fixture' import { TransferMethod } from '@/types/app' @@ -188,16 +189,6 @@ vi.mock('@/app/components/base/chat/chat/hooks', () => ({ ), })) -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ - userProfile: { - avatar_url: '', - name: 'User', - }, - })) -}) - vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({ useTextGenerationCurrentProviderAndModelAndModelList: () => ({ textGenerationModelList: [ @@ -239,6 +230,13 @@ vi.mock('@/service/client', async () => { }, }, consoleQuery: { + account: { + profile: { + get: { + queryKey: () => [['console', 'account', 'profile', 'get'], { type: 'query' }], + }, + }, + }, agent: { byAgentId: { chatMessages: { @@ -275,6 +273,7 @@ function renderPreviewChat( }, }, }) + seedAccountProfileQuery(queryClient, { avatar_url: '', name: 'User' }) store.set(agentComposerModelAtom, { provider: 'openai', model: 'gpt-4', @@ -349,6 +348,7 @@ function renderPreviewChatWithConversationHarness() { }, }, }) + seedAccountProfileQuery(queryClient, { avatar_url: '', name: 'User' }) store.set(agentComposerModelAtom, { provider: 'openai', model: 'gpt-4', @@ -374,6 +374,7 @@ function renderPreviewChatWithClearCommandHarness() { }, }, }) + seedAccountProfileQuery(queryClient, { avatar_url: '', name: 'User' }) store.set(agentComposerModelAtom, { provider: 'openai', model: 'gpt-4', diff --git a/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/versions-panel.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/versions-panel.spec.tsx index 90173d2bb80..d37e7174589 100644 --- a/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/versions-panel.spec.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/preview/__tests__/versions-panel.spec.tsx @@ -1,6 +1,6 @@ import type { AgentConfigSnapshotSummaryResponse } from '@dify/contracts/api/console/agent/types.gen' import { fireEvent, screen } from '@testing-library/react' -import { render } from '@/test/console/render' +import { renderWithAccountProfile as render } from '@/test/console/account-profile' import { AgentPreviewVersionsPanel } from '../versions-panel' const versions: AgentConfigSnapshotSummaryResponse[] = [ @@ -47,6 +47,13 @@ vi.mock('@/hooks/use-timestamp', () => ({ vi.mock('@/service/client', () => ({ consoleQuery: { + account: { + profile: { + get: { + queryKey: () => [['console', 'account', 'profile', 'get'], { type: 'query' }], + }, + }, + }, agent: { byAgentId: { versions: { @@ -59,17 +66,6 @@ vi.mock('@/service/client', () => ({ }, })) -vi.mock('@/context/account-state', async () => { - const { createAccountStateModuleMock } = await import('@/test/console/state-fixture') - return createAccountStateModuleMock(() => ({ - userProfile: { - id: 'user-1', - name: 'Alice', - email: 'alice@example.com', - }, - })) -}) - describe('AgentPreviewVersionsPanel', () => { beforeEach(() => { vi.clearAllMocks() @@ -86,6 +82,7 @@ describe('AgentPreviewVersionsPanel', () => { onSelectVersion={handleSelectVersion} onClose={vi.fn()} />, + { accountProfile: { id: 'user-1', name: 'Alice', email: 'alice@example.com' } }, ) fireEvent.click(screen.getByRole('button', { name: /Initial release/i })) @@ -103,6 +100,7 @@ describe('AgentPreviewVersionsPanel', () => { onSelectVersion={handleSelectVersion} onClose={vi.fn()} />, + { accountProfile: { id: 'user-1', name: 'Alice', email: 'alice@example.com' } }, ) fireEvent.click(screen.getByRole('button', { name: /currentDraft/i })) @@ -120,6 +118,7 @@ describe('AgentPreviewVersionsPanel', () => { onSelectVersion={vi.fn()} onClose={vi.fn()} />, + { accountProfile: { id: 'user-1', name: 'Alice', email: 'alice@example.com' } }, ) fireEvent.click(screen.getByRole('button', { name: /filter/i })) @@ -137,6 +136,7 @@ describe('AgentPreviewVersionsPanel', () => { onSelectVersion={vi.fn()} onClose={vi.fn()} />, + { accountProfile: { id: 'user-1', name: 'Alice', email: 'alice@example.com' } }, ) fireEvent.click(screen.getByRole('button', { name: /filter/i })) diff --git a/web/features/agent-v2/agent-detail/configure/components/preview/chat-conversation.tsx b/web/features/agent-v2/agent-detail/configure/components/preview/chat-conversation.tsx index a8d60958fbb..9f6ea73931f 100644 --- a/web/features/agent-v2/agent-detail/configure/components/preview/chat-conversation.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/preview/chat-conversation.tsx @@ -13,8 +13,7 @@ import type { Inputs } from '@/models/debug' import { Avatar } from '@langgenius/dify-ui/avatar' import { cn } from '@langgenius/dify-ui/cn' import { toast } from '@langgenius/dify-ui/toast' -import { useQueryClient } from '@tanstack/react-query' -import { useAtomValue } from 'jotai' +import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query' import { useCallback, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { AgentRosterResponseContent } from '@/app/components/base/chat/chat/answer/agent-roster-response-content' @@ -22,8 +21,8 @@ import { useChat } from '@/app/components/base/chat/chat/hooks' import { getLastAnswer, isValidGeneratedAnswer } from '@/app/components/base/chat/utils' import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { useTextGenerationCurrentProviderAndModelAndModelList } from '@/app/components/header/account-setting/model-provider-page/hooks' -import { userProfileAtom } from '@/context/account-state' import { useDocLink } from '@/context/i18n' +import { userProfileQueryOptions } from '@/features/account-profile/client' import dynamic from '@/next/dynamic' import { consoleClient, consoleQuery } from '@/service/client' import { buildChatConfig, getAgentSoulInputs, getAgentSoulInputsForm } from './chat-config' @@ -124,7 +123,10 @@ export function AgentPreviewChatConversation({ const { t } = useTranslation('agentV2') const docLink = useDocLink() const queryClient = useQueryClient() - const userProfile = useAtomValue(userProfileAtom) + const { data: userProfile } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile, + }) const sendInterruptedRef = useRef(false) const [isSendPending, setIsSendPending] = useState(false) const notifySendInterrupted = useCallback(() => { diff --git a/web/features/agent-v2/agent-detail/configure/components/preview/versions-panel/index.tsx b/web/features/agent-v2/agent-detail/configure/components/preview/versions-panel/index.tsx index 718a61e93f6..3dc6a867964 100644 --- a/web/features/agent-v2/agent-detail/configure/components/preview/versions-panel/index.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/preview/versions-panel/index.tsx @@ -1,11 +1,10 @@ 'use client' import type { AgentVersionFilter } from './filter' -import { useQuery } from '@tanstack/react-query' -import { useAtomValue } from 'jotai' +import { useQuery, useSuspenseQuery } from '@tanstack/react-query' import { useState } from 'react' import { useTranslation } from 'react-i18next' -import { userProfileAtom } from '@/context/account-state' +import { userProfileQueryOptions } from '@/features/account-profile/client' import { consoleQuery } from '@/service/client' import { CurrentDraftItem } from './current-draft-item' import { VersionFilter } from './filter' @@ -28,7 +27,10 @@ export function AgentPreviewVersionsPanel({ const { t } = useTranslation('agentV2') const { t: tCommon } = useTranslation('common') const { t: tWorkflow } = useTranslation('workflow') - const userProfile = useAtomValue(userProfileAtom) + const { data: userProfile } = useSuspenseQuery({ + ...userProfileQueryOptions(), + select: (data) => data.profile, + }) const [filterValue, setFilterValue] = useState('all') const versionsQuery = useQuery( consoleQuery.agent.byAgentId.versions.get.queryOptions({