mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 12:02:24 -04:00
87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
import type {
|
|
CommonNodeType,
|
|
Node,
|
|
OnSelectBlock,
|
|
} from '@/app/components/workflow/types'
|
|
import { intersection } from 'es-toolkit/array'
|
|
import { useCallback, useMemo } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
|
import {
|
|
useAvailableBlocks,
|
|
useIsChatMode,
|
|
useNodesInteractions,
|
|
} from '@/app/components/workflow/hooks'
|
|
import { useHooksStore } from '@/app/components/workflow/hooks-store'
|
|
import useNodes from '@/app/components/workflow/store/workflow/use-nodes'
|
|
import { BlockEnum, isTriggerNode } from '@/app/components/workflow/types'
|
|
import { FlowType } from '@/types/common'
|
|
|
|
type ChangeBlockMenuTriggerProps = {
|
|
nodeId: string
|
|
nodeData: Node['data']
|
|
sourceHandle: string
|
|
}
|
|
|
|
export function ChangeBlockMenuTrigger({
|
|
nodeId,
|
|
nodeData,
|
|
sourceHandle,
|
|
}: ChangeBlockMenuTriggerProps) {
|
|
const { t } = useTranslation()
|
|
const { handleNodeChange } = useNodesInteractions()
|
|
const {
|
|
availablePrevBlocks,
|
|
availableNextBlocks,
|
|
} = useAvailableBlocks(nodeData.type, nodeData.isInIteration || nodeData.isInLoop)
|
|
const isChatMode = useIsChatMode()
|
|
const flowType = useHooksStore(s => s.configsMap?.flowType)
|
|
const nodes = useNodes()
|
|
const hasStartNode = useMemo(() => {
|
|
return nodes.some(n => (n.data as CommonNodeType | undefined)?.type === BlockEnum.Start)
|
|
}, [nodes])
|
|
const showStartTab = flowType !== FlowType.ragPipeline && (!isChatMode || nodeData.type === BlockEnum.Start || !hasStartNode)
|
|
const ignoreNodeIds = useMemo(() => {
|
|
if (isTriggerNode(nodeData.type as BlockEnum) || nodeData.type === BlockEnum.Start)
|
|
return [nodeId]
|
|
return undefined
|
|
}, [nodeData.type, nodeId])
|
|
const allowStartNodeSelection = !hasStartNode
|
|
|
|
const availableNodes = useMemo(() => {
|
|
if (availablePrevBlocks.length && availableNextBlocks.length)
|
|
return intersection(availablePrevBlocks, availableNextBlocks)
|
|
if (availablePrevBlocks.length)
|
|
return availablePrevBlocks
|
|
return availableNextBlocks
|
|
}, [availablePrevBlocks, availableNextBlocks])
|
|
|
|
const handleSelect = useCallback<OnSelectBlock>((type, pluginDefaultValue) => {
|
|
handleNodeChange(nodeId, type, sourceHandle, pluginDefaultValue)
|
|
}, [handleNodeChange, nodeId, sourceHandle])
|
|
|
|
const renderTrigger = useCallback(() => {
|
|
return (
|
|
<button
|
|
type="button"
|
|
className="mx-1 flex h-8 w-[calc(100%-8px)] cursor-pointer items-center rounded-lg border-0 bg-transparent px-2 text-left text-sm text-text-secondary outline-hidden select-none hover:bg-state-base-hover focus-visible:bg-state-base-hover focus-visible:outline-hidden"
|
|
>
|
|
{t('panel.changeBlock', { ns: 'workflow' })}
|
|
</button>
|
|
)
|
|
}, [t])
|
|
|
|
return (
|
|
<BlockSelector
|
|
onSelect={handleSelect}
|
|
trigger={renderTrigger}
|
|
popupClassName="min-w-[240px]"
|
|
availableBlocksTypes={availableNodes}
|
|
showStartTab={showStartTab}
|
|
ignoreNodeIds={ignoreNodeIds}
|
|
forceEnableStartTab={nodeData.type === BlockEnum.Start}
|
|
allowUserInputSelection={allowStartNodeSelection}
|
|
/>
|
|
)
|
|
}
|