mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 10:28:10 +08:00
refactor(web): align MCP availability context migration
- move MCP availability context to block-selector/context and update imports - preserve sandbox gating, parent-provider inheritance, and blockedBy semantics - add context tests on top of refactor baseline cases - regenerate and prune eslint suppressions
This commit is contained in:
@ -7,7 +7,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|||||||
|
|
||||||
// ==================== Imports (after mocks) ====================
|
// ==================== Imports (after mocks) ====================
|
||||||
|
|
||||||
import { MCPToolAvailabilityProvider } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
|
import { MCPToolAvailabilityProvider } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
import MultipleToolSelector from '../index'
|
import MultipleToolSelector from '../index'
|
||||||
|
|
||||||
// ==================== Mock Setup ====================
|
// ==================== Mock Setup ====================
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import Divider from '@/app/components/base/divider'
|
|||||||
import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general'
|
import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
|
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
|
||||||
import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
|
import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
import { useAllMCPTools } from '@/service/use-tools'
|
import { useAllMCPTools } from '@/service/use-tools'
|
||||||
import { cn } from '@/utils/classnames'
|
import { cn } from '@/utils/classnames'
|
||||||
|
|
||||||
|
|||||||
@ -208,7 +208,7 @@ vi.mock('../components/reasoning-config-form', () => ({
|
|||||||
// Track MCP availability mock state
|
// Track MCP availability mock state
|
||||||
let mockMCPToolAllowed = true
|
let mockMCPToolAllowed = true
|
||||||
|
|
||||||
vi.mock('@/app/components/workflow/nodes/_base/components/mcp-tool-availability', () => ({
|
vi.mock('@/app/components/workflow/block-selector/context/mcp-tool-availability-context', () => ({
|
||||||
useMCPToolAvailability: () => ({ allowed: mockMCPToolAllowed }),
|
useMCPToolAvailability: () => ({ allowed: mockMCPToolAllowed }),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,8 @@ import Switch from '@/app/components/base/switch'
|
|||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import { ToolTipContent } from '@/app/components/base/tooltip/content'
|
import { ToolTipContent } from '@/app/components/base/tooltip/content'
|
||||||
import Indicator from '@/app/components/header/indicator'
|
import Indicator from '@/app/components/header/indicator'
|
||||||
|
import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
|
import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
|
||||||
import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
|
|
||||||
import McpToolNotSupportTooltip from '@/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip'
|
import McpToolNotSupportTooltip from '@/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip'
|
||||||
import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
|
import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
|
||||||
import { cn } from '@/utils/classnames'
|
import { cn } from '@/utils/classnames'
|
||||||
|
|||||||
@ -15,9 +15,9 @@ import { useReactFlow } from 'reactflow'
|
|||||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||||
import { WorkflowWithInnerContext } from '@/app/components/workflow'
|
import { WorkflowWithInnerContext } from '@/app/components/workflow'
|
||||||
|
import { MCPToolAvailabilityProvider } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
import { collaborationManager, useCollaboration } from '@/app/components/workflow/collaboration'
|
import { collaborationManager, useCollaboration } from '@/app/components/workflow/collaboration'
|
||||||
import { useWorkflowUpdate } from '@/app/components/workflow/hooks/use-workflow-interactions'
|
import { useWorkflowUpdate } from '@/app/components/workflow/hooks/use-workflow-interactions'
|
||||||
import { MCPToolAvailabilityProvider } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
|
|
||||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||||
import { fetchWorkflowDraft } from '@/service/workflow'
|
import { fetchWorkflowDraft } from '@/service/workflow'
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { renderHook } from '@testing-library/react'
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { MCPToolAvailabilityProvider, useMCPToolAvailability } from '../mcp-tool-availability-context'
|
||||||
|
|
||||||
|
describe('useMCPToolAvailability', () => {
|
||||||
|
it('returns allowed=true without provider', () => {
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability())
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns allowed=true when version is not provided to provider', () => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MCPToolAvailabilityProvider>
|
||||||
|
{children}
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
)
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns allowed=false when version is not supported', () => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MCPToolAvailabilityProvider versionSupported={false}>
|
||||||
|
{children}
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
)
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: false, blockedBy: 'version' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns allowed=true when version is supported', () => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MCPToolAvailabilityProvider versionSupported={true}>
|
||||||
|
{children}
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
)
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns allowed=false when sandbox is not enabled', () => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MCPToolAvailabilityProvider sandboxEnabled={false}>
|
||||||
|
{children}
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
)
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: false, blockedBy: 'sandbox' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('inherits parent provider values when child omits them', () => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MCPToolAvailabilityProvider sandboxEnabled={false}>
|
||||||
|
<MCPToolAvailabilityProvider versionSupported={true}>
|
||||||
|
{children}
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
)
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: false, blockedBy: 'sandbox' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows access when child provider overrides parent sandbox value', () => {
|
||||||
|
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
|
<MCPToolAvailabilityProvider sandboxEnabled={false}>
|
||||||
|
<MCPToolAvailabilityProvider versionSupported={true} sandboxEnabled={true}>
|
||||||
|
{children}
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
</MCPToolAvailabilityProvider>
|
||||||
|
)
|
||||||
|
|
||||||
|
const { result } = renderHook(() => useMCPToolAvailability(), { wrapper })
|
||||||
|
|
||||||
|
expect(result.current).toEqual({ allowed: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -39,6 +39,7 @@ export function MCPToolAvailabilityProvider({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-refresh/only-export-components
|
||||||
export function useMCPToolAvailability(): MCPToolAvailability {
|
export function useMCPToolAvailability(): MCPToolAvailability {
|
||||||
const context = useContext(MCPToolAvailabilityContext)
|
const context = useContext(MCPToolAvailabilityContext)
|
||||||
|
|
||||||
@ -55,5 +56,8 @@ export function useMCPToolAvailability(): MCPToolAvailability {
|
|||||||
else if (!sandboxAllowed)
|
else if (!sandboxAllowed)
|
||||||
blockedBy = 'sandbox'
|
blockedBy = 'sandbox'
|
||||||
|
|
||||||
return { allowed, blockedBy }
|
if (blockedBy)
|
||||||
|
return { allowed, blockedBy }
|
||||||
|
|
||||||
|
return { allowed }
|
||||||
}
|
}
|
||||||
@ -9,7 +9,7 @@ import * as React from 'react'
|
|||||||
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Mcp } from '@/app/components/base/icons/src/vender/other'
|
import { Mcp } from '@/app/components/base/icons/src/vender/other'
|
||||||
import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
|
import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
import { useGetLanguage } from '@/context/i18n'
|
import { useGetLanguage } from '@/context/i18n'
|
||||||
import useTheme from '@/hooks/use-theme'
|
import useTheme from '@/hooks/use-theme'
|
||||||
import { Theme } from '@/types/app'
|
import { Theme } from '@/types/app'
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { RiAlertFill } from '@remixicon/react'
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import { useMCPToolAvailability } from './mcp-tool-availability'
|
import { useMCPToolAvailability } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
|
|
||||||
const McpToolNotSupportTooltip: FC = () => {
|
const McpToolNotSupportTooltip: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|||||||
@ -6,11 +6,11 @@ import type { StrategyParamItem } from '@/app/components/plugins/types'
|
|||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { toType } from '@/app/components/tools/utils/to-form-schema'
|
import { toType } from '@/app/components/tools/utils/to-form-schema'
|
||||||
|
import { MCPToolAvailabilityProvider } from '@/app/components/workflow/block-selector/context/mcp-tool-availability-context'
|
||||||
import { isSupportMCP } from '@/utils/plugin-version-feature'
|
import { isSupportMCP } from '@/utils/plugin-version-feature'
|
||||||
import { useStore } from '../../store'
|
import { useStore } from '../../store'
|
||||||
import { AgentStrategy } from '../_base/components/agent-strategy'
|
import { AgentStrategy } from '../_base/components/agent-strategy'
|
||||||
import Field from '../_base/components/field'
|
import Field from '../_base/components/field'
|
||||||
import { MCPToolAvailabilityProvider } from '../_base/components/mcp-tool-availability'
|
|
||||||
import MemoryConfig from '../_base/components/memory-config'
|
import MemoryConfig from '../_base/components/memory-config'
|
||||||
import OutputVars, { VarItem } from '../_base/components/output-vars'
|
import OutputVars, { VarItem } from '../_base/components/output-vars'
|
||||||
import Split from '../_base/components/split'
|
import Split from '../_base/components/split'
|
||||||
|
|||||||
@ -2970,11 +2970,6 @@
|
|||||||
"count": 7
|
"count": 7
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx": {
|
|
||||||
"react-refresh/only-export-components": {
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"app/components/workflow/nodes/_base/components/memory-config.tsx": {
|
"app/components/workflow/nodes/_base/components/memory-config.tsx": {
|
||||||
"unicorn/prefer-number-properties": {
|
"unicorn/prefer-number-properties": {
|
||||||
"count": 1
|
"count": 1
|
||||||
|
|||||||
Reference in New Issue
Block a user