mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 18:08:07 +08:00
fix(workflow): eliminate infinite loop in plugin install state management
Replace useEffect-based state sync (_pluginInstallLocked/_dimmed) with render-time derived computation in BaseNode, breaking the cycle of effect → node data update → re-render → effect. Extract plugin missing check into a pure utility function for checklist reuse.
This commit is contained in:
@ -25,6 +25,7 @@ import { ToolTypeEnum } from '@/app/components/workflow/block-selector/types'
|
||||
import { useCollaboration } from '@/app/components/workflow/collaboration/hooks/use-collaboration'
|
||||
import { useNodesReadOnly, useToolIcon } from '@/app/components/workflow/hooks'
|
||||
import useInspectVarsCrud from '@/app/components/workflow/hooks/use-inspect-vars-crud'
|
||||
import { useNodePluginInstallation } from '@/app/components/workflow/hooks/use-node-plugin-installation'
|
||||
import { useNodeIterationInteractions } from '@/app/components/workflow/nodes/iteration/use-interactions'
|
||||
import { useNodeLoopInteractions } from '@/app/components/workflow/nodes/loop/use-interactions'
|
||||
import CopyID from '@/app/components/workflow/nodes/tool/components/copy-id'
|
||||
@ -81,6 +82,9 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
const appId = useStore(s => s.appId)
|
||||
const { nodePanelPresence } = useCollaboration(appId as string)
|
||||
const controlMode = useStore(s => s.controlMode)
|
||||
const { shouldDim: pluginShouldDim, isChecking: pluginIsChecking, isMissing: pluginIsMissing, canInstall: pluginCanInstall, uniqueIdentifier: pluginUniqueIdentifier } = useNodePluginInstallation(data)
|
||||
const pluginInstallLocked = !pluginIsChecking && pluginIsMissing && pluginCanInstall && Boolean(pluginUniqueIdentifier)
|
||||
const pluginDimmed = pluginShouldDim
|
||||
|
||||
const currentUserPresence = useMemo(() => {
|
||||
const userId = userProfile?.id || ''
|
||||
@ -226,7 +230,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
'relative flex rounded-2xl border',
|
||||
showSelectedBorder ? 'border-components-option-card-option-selected-border' : 'border-transparent',
|
||||
data._waitingRun && 'opacity-70',
|
||||
data._pluginInstallLocked && 'cursor-not-allowed',
|
||||
pluginInstallLocked && 'cursor-not-allowed',
|
||||
)}
|
||||
ref={nodeRef}
|
||||
style={{
|
||||
@ -234,14 +238,15 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
height: (data.type === BlockEnum.Iteration || data.type === BlockEnum.Loop) ? data.height : 'auto',
|
||||
}}
|
||||
>
|
||||
{(data._dimmed || data._pluginInstallLocked) && (
|
||||
{(data._dimmed || pluginDimmed || pluginInstallLocked) && (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute inset-0 rounded-2xl transition-opacity',
|
||||
data._pluginInstallLocked
|
||||
pluginInstallLocked
|
||||
? 'pointer-events-auto z-30 bg-workflow-block-parma-bg opacity-80 backdrop-blur-[2px]'
|
||||
: 'pointer-events-none z-20 bg-workflow-block-parma-bg opacity-50',
|
||||
)}
|
||||
onClick={pluginInstallLocked ? e => e.stopPropagation() : undefined}
|
||||
data-testid="workflow-node-install-overlay"
|
||||
/>
|
||||
)}
|
||||
@ -318,6 +323,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
<NodeControl
|
||||
id={id}
|
||||
data={data}
|
||||
pluginInstallLocked={pluginInstallLocked}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user