mirror of
https://github.com/langgenius/dify.git
synced 2026-05-02 16:38:04 +08:00
perf(workflow): skip unnecessary query subscriptions for non-plugin nodes
Add `enabled` parameter to tool query hooks so non-plugin nodes (LLM, Code, IfElse, etc.) avoid registering React Query observers. Extract shared matching functions into plugin-install-check utils to eliminate duplicate logic between the hook and the checklist.
This commit is contained in:
@ -16,11 +16,11 @@ import {
|
||||
useAllTriggerPlugins,
|
||||
useInvalidateAllTriggerPlugins,
|
||||
} from '@/service/use-triggers'
|
||||
import { canFindTool } from '@/utils'
|
||||
import { useStore } from '../store'
|
||||
import { BlockEnum } from '../types'
|
||||
import { matchDataSource, matchToolInCollection, matchTriggerProvider } from '../utils/plugin-install-check'
|
||||
|
||||
type InstallationState = {
|
||||
export type InstallationState = {
|
||||
isChecking: boolean
|
||||
isMissing: boolean
|
||||
uniqueIdentifier?: string
|
||||
@ -29,14 +29,25 @@ type InstallationState = {
|
||||
shouldDim: boolean
|
||||
}
|
||||
|
||||
const useToolInstallation = (data: ToolNodeType): InstallationState => {
|
||||
const builtInQuery = useAllBuiltInTools()
|
||||
const customQuery = useAllCustomTools()
|
||||
const workflowQuery = useAllWorkflowTools()
|
||||
const mcpQuery = useAllMCPTools()
|
||||
const invalidateTools = useInvalidToolsByType(data.provider_type)
|
||||
const NOOP_INSTALLATION: InstallationState = {
|
||||
isChecking: false,
|
||||
isMissing: false,
|
||||
uniqueIdentifier: undefined,
|
||||
canInstall: false,
|
||||
onInstallSuccess: () => undefined,
|
||||
shouldDim: false,
|
||||
}
|
||||
|
||||
const useToolInstallation = (data: ToolNodeType, enabled: boolean): InstallationState => {
|
||||
const builtInQuery = useAllBuiltInTools(enabled)
|
||||
const customQuery = useAllCustomTools(enabled)
|
||||
const workflowQuery = useAllWorkflowTools(enabled)
|
||||
const mcpQuery = useAllMCPTools(enabled)
|
||||
const invalidateTools = useInvalidToolsByType(enabled ? data.provider_type : undefined)
|
||||
|
||||
const collectionInfo = useMemo(() => {
|
||||
if (!enabled)
|
||||
return undefined
|
||||
switch (data.provider_type) {
|
||||
case CollectionType.builtIn:
|
||||
return {
|
||||
@ -62,6 +73,7 @@ const useToolInstallation = (data: ToolNodeType): InstallationState => {
|
||||
return undefined
|
||||
}
|
||||
}, [
|
||||
enabled,
|
||||
builtInQuery.data,
|
||||
builtInQuery.isLoading,
|
||||
customQuery.data,
|
||||
@ -80,17 +92,8 @@ const useToolInstallation = (data: ToolNodeType): InstallationState => {
|
||||
const matchedCollection = useMemo(() => {
|
||||
if (!collection || !collection.length)
|
||||
return undefined
|
||||
|
||||
return collection.find((toolWithProvider) => {
|
||||
if (data.plugin_id && toolWithProvider.plugin_id === data.plugin_id)
|
||||
return true
|
||||
if (canFindTool(toolWithProvider.id, data.provider_id))
|
||||
return true
|
||||
if (toolWithProvider.name === data.provider_name)
|
||||
return true
|
||||
return false
|
||||
})
|
||||
}, [collection, data.plugin_id, data.provider_id, data.provider_name])
|
||||
return matchToolInCollection(collection, data)
|
||||
}, [collection, data])
|
||||
|
||||
const uniqueIdentifier = data.plugin_unique_identifier || data.plugin_id || data.provider_id
|
||||
const canInstall = Boolean(data.plugin_unique_identifier)
|
||||
@ -112,8 +115,8 @@ const useToolInstallation = (data: ToolNodeType): InstallationState => {
|
||||
}
|
||||
}
|
||||
|
||||
const useTriggerInstallation = (data: PluginTriggerNodeType): InstallationState => {
|
||||
const triggerPluginsQuery = useAllTriggerPlugins()
|
||||
const useTriggerInstallation = (data: PluginTriggerNodeType, enabled: boolean): InstallationState => {
|
||||
const triggerPluginsQuery = useAllTriggerPlugins(enabled)
|
||||
const invalidateTriggers = useInvalidateAllTriggerPlugins()
|
||||
|
||||
const triggerProviders = triggerPluginsQuery.data
|
||||
@ -122,18 +125,8 @@ const useTriggerInstallation = (data: PluginTriggerNodeType): InstallationState
|
||||
const matchedProvider = useMemo(() => {
|
||||
if (!triggerProviders || !triggerProviders.length)
|
||||
return undefined
|
||||
|
||||
return triggerProviders.find(provider =>
|
||||
provider.name === data.provider_name
|
||||
|| provider.id === data.provider_id
|
||||
|| (data.plugin_id && provider.plugin_id === data.plugin_id),
|
||||
)
|
||||
}, [
|
||||
data.plugin_id,
|
||||
data.provider_id,
|
||||
data.provider_name,
|
||||
triggerProviders,
|
||||
])
|
||||
return matchTriggerProvider(triggerProviders, data)
|
||||
}, [data, triggerProviders])
|
||||
|
||||
const uniqueIdentifier = data.plugin_unique_identifier || data.plugin_id || data.provider_id
|
||||
const canInstall = Boolean(data.plugin_unique_identifier)
|
||||
@ -154,24 +147,15 @@ const useTriggerInstallation = (data: PluginTriggerNodeType): InstallationState
|
||||
}
|
||||
}
|
||||
|
||||
const useDataSourceInstallation = (data: DataSourceNodeType): InstallationState => {
|
||||
const useDataSourceInstallation = (data: DataSourceNodeType, _enabled: boolean): InstallationState => {
|
||||
const dataSourceList = useStore(s => s.dataSourceList)
|
||||
const invalidateDataSourceList = useInvalidDataSourceList()
|
||||
|
||||
const matchedPlugin = useMemo(() => {
|
||||
if (!dataSourceList || !dataSourceList.length)
|
||||
return undefined
|
||||
|
||||
return dataSourceList.find((item) => {
|
||||
if (data.plugin_unique_identifier && item.plugin_unique_identifier === data.plugin_unique_identifier)
|
||||
return true
|
||||
if (data.plugin_id && item.plugin_id === data.plugin_id)
|
||||
return true
|
||||
if (data.provider_name && item.provider === data.provider_name)
|
||||
return true
|
||||
return false
|
||||
})
|
||||
}, [data.plugin_id, data.plugin_unique_identifier, data.provider_name, dataSourceList])
|
||||
return matchDataSource(dataSourceList, data)
|
||||
}, [data, dataSourceList])
|
||||
|
||||
const uniqueIdentifier = data.plugin_unique_identifier || data.plugin_id
|
||||
const canInstall = Boolean(data.plugin_unique_identifier)
|
||||
@ -195,25 +179,19 @@ const useDataSourceInstallation = (data: DataSourceNodeType): InstallationState
|
||||
}
|
||||
|
||||
export const useNodePluginInstallation = (data: CommonNodeType): InstallationState => {
|
||||
const toolInstallation = useToolInstallation(data as ToolNodeType)
|
||||
const triggerInstallation = useTriggerInstallation(data as PluginTriggerNodeType)
|
||||
const dataSourceInstallation = useDataSourceInstallation(data as DataSourceNodeType)
|
||||
const isTool = data.type === BlockEnum.Tool
|
||||
const isTrigger = data.type === BlockEnum.TriggerPlugin
|
||||
const isDataSource = data.type === BlockEnum.DataSource
|
||||
|
||||
switch (data.type as BlockEnum) {
|
||||
case BlockEnum.Tool:
|
||||
return toolInstallation
|
||||
case BlockEnum.TriggerPlugin:
|
||||
return triggerInstallation
|
||||
case BlockEnum.DataSource:
|
||||
return dataSourceInstallation
|
||||
default:
|
||||
return {
|
||||
isChecking: false,
|
||||
isMissing: false,
|
||||
uniqueIdentifier: undefined,
|
||||
canInstall: false,
|
||||
onInstallSuccess: () => undefined,
|
||||
shouldDim: false,
|
||||
}
|
||||
}
|
||||
const toolInstallation = useToolInstallation(data as ToolNodeType, isTool)
|
||||
const triggerInstallation = useTriggerInstallation(data as PluginTriggerNodeType, isTrigger)
|
||||
const dataSourceInstallation = useDataSourceInstallation(data as DataSourceNodeType, isDataSource)
|
||||
|
||||
if (isTool)
|
||||
return toolInstallation
|
||||
if (isTrigger)
|
||||
return triggerInstallation
|
||||
if (isDataSource)
|
||||
return dataSourceInstallation
|
||||
return NOOP_INSTALLATION
|
||||
}
|
||||
|
||||
@ -7,6 +7,49 @@ import { CollectionType } from '@/app/components/tools/types'
|
||||
import { canFindTool } from '@/utils'
|
||||
import { BlockEnum } from '../types'
|
||||
|
||||
export const PLUGIN_DEPENDENT_TYPES: BlockEnum[] = [
|
||||
BlockEnum.Tool,
|
||||
BlockEnum.DataSource,
|
||||
BlockEnum.TriggerPlugin,
|
||||
]
|
||||
|
||||
export function isPluginDependentNode(type: string): boolean {
|
||||
return PLUGIN_DEPENDENT_TYPES.includes(type as BlockEnum)
|
||||
}
|
||||
|
||||
export function matchToolInCollection(
|
||||
collection: ToolWithProvider[],
|
||||
data: { plugin_id?: string, provider_id?: string, provider_name?: string },
|
||||
): ToolWithProvider | undefined {
|
||||
return collection.find(t =>
|
||||
(data.plugin_id && t.plugin_id === data.plugin_id)
|
||||
|| canFindTool(t.id, data.provider_id)
|
||||
|| t.name === data.provider_name,
|
||||
)
|
||||
}
|
||||
|
||||
export function matchTriggerProvider(
|
||||
providers: TriggerWithProvider[],
|
||||
data: { provider_name?: string, provider_id?: string, plugin_id?: string },
|
||||
): TriggerWithProvider | undefined {
|
||||
return providers.find(p =>
|
||||
p.name === data.provider_name
|
||||
|| p.id === data.provider_id
|
||||
|| (data.plugin_id && p.plugin_id === data.plugin_id),
|
||||
)
|
||||
}
|
||||
|
||||
export function matchDataSource(
|
||||
list: ToolWithProvider[],
|
||||
data: { plugin_unique_identifier?: string, plugin_id?: string, provider_name?: string },
|
||||
): ToolWithProvider | undefined {
|
||||
return list.find(item =>
|
||||
(data.plugin_unique_identifier && item.plugin_unique_identifier === data.plugin_unique_identifier)
|
||||
|| (data.plugin_id && item.plugin_id === data.plugin_id)
|
||||
|| (data.provider_name && item.provider === data.provider_name),
|
||||
)
|
||||
}
|
||||
|
||||
export type PluginInstallCheckContext = {
|
||||
builtInTools?: ToolWithProvider[]
|
||||
customTools?: ToolWithProvider[]
|
||||
@ -32,34 +75,19 @@ export function isNodePluginMissing(
|
||||
const collection = collectionMap[toolData.provider_type]
|
||||
if (!collection)
|
||||
return false
|
||||
const matched = collection.find(t =>
|
||||
(toolData.plugin_id && t.plugin_id === toolData.plugin_id)
|
||||
|| canFindTool(t.id, toolData.provider_id)
|
||||
|| t.name === toolData.provider_name,
|
||||
)
|
||||
return !matched && Boolean(toolData.plugin_unique_identifier)
|
||||
return !matchToolInCollection(collection, toolData) && Boolean(toolData.plugin_unique_identifier)
|
||||
}
|
||||
case BlockEnum.TriggerPlugin: {
|
||||
const triggerData = data as PluginTriggerNodeType
|
||||
if (!context.triggerPlugins)
|
||||
return false
|
||||
const matched = context.triggerPlugins.find(p =>
|
||||
p.name === triggerData.provider_name
|
||||
|| p.id === triggerData.provider_id
|
||||
|| (triggerData.plugin_id && p.plugin_id === triggerData.plugin_id),
|
||||
)
|
||||
return !matched && Boolean(triggerData.plugin_unique_identifier)
|
||||
return !matchTriggerProvider(context.triggerPlugins, triggerData) && Boolean(triggerData.plugin_unique_identifier)
|
||||
}
|
||||
case BlockEnum.DataSource: {
|
||||
const dsData = data as DataSourceNodeType
|
||||
if (!context.dataSourceList)
|
||||
return false
|
||||
const matched = context.dataSourceList.find(item =>
|
||||
(dsData.plugin_unique_identifier && item.plugin_unique_identifier === dsData.plugin_unique_identifier)
|
||||
|| (dsData.plugin_id && item.plugin_id === dsData.plugin_id)
|
||||
|| (dsData.provider_name && item.provider === dsData.provider_name),
|
||||
)
|
||||
return !matched && Boolean(dsData.plugin_unique_identifier)
|
||||
return !matchDataSource(context.dataSourceList, dsData) && Boolean(dsData.plugin_unique_identifier)
|
||||
}
|
||||
default:
|
||||
return false
|
||||
|
||||
@ -31,10 +31,11 @@ export const useInvalidateAllToolProviders = () => {
|
||||
}
|
||||
|
||||
const useAllBuiltInToolsKey = [NAME_SPACE, 'builtIn']
|
||||
export const useAllBuiltInTools = () => {
|
||||
export const useAllBuiltInTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllBuiltInToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/builtin'),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
@ -43,10 +44,11 @@ export const useInvalidateAllBuiltInTools = () => {
|
||||
}
|
||||
|
||||
const useAllCustomToolsKey = [NAME_SPACE, 'customTools']
|
||||
export const useAllCustomTools = () => {
|
||||
export const useAllCustomTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllCustomToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/api'),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
@ -55,10 +57,11 @@ export const useInvalidateAllCustomTools = () => {
|
||||
}
|
||||
|
||||
const useAllWorkflowToolsKey = [NAME_SPACE, 'workflowTools']
|
||||
export const useAllWorkflowTools = () => {
|
||||
export const useAllWorkflowTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllWorkflowToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/workflow'),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
@ -67,10 +70,11 @@ export const useInvalidateAllWorkflowTools = () => {
|
||||
}
|
||||
|
||||
const useAllMCPToolsKey = [NAME_SPACE, 'MCPTools']
|
||||
export const useAllMCPTools = () => {
|
||||
export const useAllMCPTools = (enabled = true) => {
|
||||
return useQuery<ToolWithProvider[]>({
|
||||
queryKey: useAllMCPToolsKey,
|
||||
queryFn: () => get<ToolWithProvider[]>('/workspaces/current/tools/mcp'),
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user