mirror of https://github.com/langgenius/dify.git
available nodes
This commit is contained in:
parent
8d9c86ac4c
commit
5fbf8ee6c6
|
|
@ -19,10 +19,12 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||
type BlocksProps = {
|
||||
searchText: string
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
availableBlocksTypes?: BlockEnum[]
|
||||
}
|
||||
const Blocks = ({
|
||||
searchText,
|
||||
onSelect,
|
||||
availableBlocksTypes = [],
|
||||
}: BlocksProps) => {
|
||||
const { t } = useTranslation()
|
||||
const isChatMode = useIsChatMode()
|
||||
|
|
@ -35,7 +37,7 @@ const Blocks = ({
|
|||
if (block.type === BlockEnum.Answer && !isChatMode)
|
||||
return false
|
||||
|
||||
return block.title.toLowerCase().includes(searchText.toLowerCase())
|
||||
return block.title.toLowerCase().includes(searchText.toLowerCase()) && availableBlocksTypes.includes(block.type)
|
||||
})
|
||||
|
||||
return {
|
||||
|
|
@ -43,7 +45,7 @@ const Blocks = ({
|
|||
[classification]: list,
|
||||
}
|
||||
}, {} as Record<string, typeof blocks>)
|
||||
}, [blocks, isChatMode, searchText])
|
||||
}, [blocks, isChatMode, searchText, availableBlocksTypes])
|
||||
const isEmpty = Object.values(groups).every(list => !list.length)
|
||||
|
||||
const renderGroup = useCallback((classification: string) => {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import type {
|
|||
OffsetOptions,
|
||||
Placement,
|
||||
} from '@floating-ui/react'
|
||||
import type { BlockEnum, OnSelectBlock } from '../types'
|
||||
import Tabs from './tabs'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
|
|
@ -22,7 +23,6 @@ import {
|
|||
Plus02,
|
||||
SearchLg,
|
||||
} from '@/app/components/base/icons/src/vender/line/general'
|
||||
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||
import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
|
||||
|
||||
type NodeSelectorProps = {
|
||||
|
|
@ -36,6 +36,7 @@ type NodeSelectorProps = {
|
|||
triggerClassName?: (open: boolean) => string
|
||||
popupClassName?: string
|
||||
asChild?: boolean
|
||||
availableBlocksTypes?: BlockEnum[]
|
||||
}
|
||||
const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
open: openFromProps,
|
||||
|
|
@ -48,6 +49,7 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
|||
triggerStyle,
|
||||
popupClassName,
|
||||
asChild,
|
||||
availableBlocksTypes,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [searchText, setSearchText] = useState('')
|
||||
|
|
@ -125,6 +127,7 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
|||
<Tabs
|
||||
onSelect={handleSelect}
|
||||
searchText={searchText}
|
||||
availableBlocksTypes={availableBlocksTypes}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ import Blocks from './blocks'
|
|||
export type TabsProps = {
|
||||
searchText: string
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
availableBlocksTypes?: BlockEnum[]
|
||||
}
|
||||
const Tabs: FC<TabsProps> = ({
|
||||
searchText,
|
||||
onSelect,
|
||||
availableBlocksTypes,
|
||||
}) => {
|
||||
const tabs = useTabs()
|
||||
const [activeTab, setActiveTab] = useState(tabs[0].key)
|
||||
|
|
@ -46,6 +48,7 @@ const Tabs: FC<TabsProps> = ({
|
|||
<Blocks
|
||||
searchText={searchText}
|
||||
onSelect={onSelect}
|
||||
availableBlocksTypes={availableBlocksTypes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,59 +13,128 @@ import ToolDefault from './nodes/tool/default'
|
|||
import VariableAssignerDefault from './nodes/variable-assigner/default'
|
||||
import EndNodeDefault from './nodes/end/default'
|
||||
|
||||
export const NODES_EXTRA_DATA = {
|
||||
type NodesExtraData = {
|
||||
author: string
|
||||
about: string
|
||||
availablePrevNodes: BlockEnum[]
|
||||
availableNextNodes: BlockEnum[]
|
||||
getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[]
|
||||
getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[]
|
||||
checkValid: any
|
||||
}
|
||||
export const NODES_EXTRA_DATA: Record<BlockEnum, NodesExtraData> = {
|
||||
[BlockEnum.Start]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: StartNodeDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: StartNodeDefault.getAvailableNextNodes,
|
||||
checkValid: StartNodeDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.End]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: EndNodeDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: EndNodeDefault.getAvailableNextNodes,
|
||||
checkValid: EndNodeDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.Answer]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: AnswerDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: AnswerDefault.getAvailableNextNodes,
|
||||
checkValid: AnswerDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.LLM]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: LLMDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: LLMDefault.getAvailableNextNodes,
|
||||
checkValid: LLMDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.KnowledgeRetrieval]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: KnowledgeRetrievalDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: KnowledgeRetrievalDefault.getAvailableNextNodes,
|
||||
checkValid: KnowledgeRetrievalDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.IfElse]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: IfElseDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: IfElseDefault.getAvailableNextNodes,
|
||||
checkValid: IfElseDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.Code]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: CodeDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: CodeDefault.getAvailableNextNodes,
|
||||
checkValid: CodeDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.TemplateTransform]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: TemplateTransformDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: TemplateTransformDefault.getAvailableNextNodes,
|
||||
checkValid: TemplateTransformDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.QuestionClassifier]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: QuestionClassifierDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: QuestionClassifierDefault.getAvailableNextNodes,
|
||||
checkValid: QuestionClassifierDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.HttpRequest]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: HttpRequestDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: HttpRequestDefault.getAvailableNextNodes,
|
||||
checkValid: HttpRequestDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.VariableAssigner]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: VariableAssignerDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: VariableAssignerDefault.getAvailableNextNodes,
|
||||
checkValid: VariableAssignerDefault.checkValid,
|
||||
},
|
||||
[BlockEnum.Tool]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
availablePrevNodes: [],
|
||||
availableNextNodes: [],
|
||||
getAvailablePrevNodes: ToolDefault.getAvailablePrevNodes,
|
||||
getAvailableNextNodes: ToolDefault.getAvailableNextNodes,
|
||||
checkValid: ToolDefault.checkValid,
|
||||
},
|
||||
}
|
||||
|
||||
export const ALL_CHAT_AVAILABLE_BLOCKS = Object.keys(NODES_EXTRA_DATA).filter(key => key !== BlockEnum.End) as BlockEnum[]
|
||||
export const ALL_COMPLETION_AVAILABLE_BLOCKS = Object.keys(NODES_EXTRA_DATA).filter(key => key !== BlockEnum.Answer) as BlockEnum[]
|
||||
export const ALL_CHAT_AVAILABLE_BLOCKS = Object.keys(NODES_EXTRA_DATA).filter(key => key !== BlockEnum.End && key !== BlockEnum.Start) as BlockEnum[]
|
||||
export const ALL_COMPLETION_AVAILABLE_BLOCKS = Object.keys(NODES_EXTRA_DATA).filter(key => key !== BlockEnum.Answer && key !== BlockEnum.Start) as BlockEnum[]
|
||||
|
||||
export const NODES_INITIAL_DATA = {
|
||||
[BlockEnum.Start]: {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
NODES_INITIAL_DATA,
|
||||
} from '../constants'
|
||||
import { useStore } from '../store'
|
||||
import { useIsChatMode } from './use-workflow'
|
||||
|
||||
export const useNodesInitialData = () => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -28,10 +29,13 @@ export const useNodesInitialData = () => {
|
|||
|
||||
export const useNodesExtraData = () => {
|
||||
const { t } = useTranslation()
|
||||
const isChatMode = useIsChatMode()
|
||||
|
||||
return useMemo(() => produce(NODES_EXTRA_DATA, (draft) => {
|
||||
Object.keys(draft).forEach((key) => {
|
||||
draft[key as BlockEnum].about = t(`workflow.blocksAbout.${key}`)
|
||||
draft[key as BlockEnum].availablePrevNodes = draft[key as BlockEnum].getAvailablePrevNodes(isChatMode)
|
||||
draft[key as BlockEnum].availableNextNodes = draft[key as BlockEnum].getAvailableNextNodes(isChatMode)
|
||||
})
|
||||
}), [t])
|
||||
}), [t, isChatMode])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,13 +96,7 @@ export const useWorkflow = () => {
|
|||
list.push(...incomers)
|
||||
|
||||
return list.filter((item) => {
|
||||
if (item.data.type === BlockEnum.IfElse)
|
||||
return false
|
||||
|
||||
if (item.data.type === BlockEnum.QuestionClassifier)
|
||||
return false
|
||||
|
||||
return true
|
||||
return SUPPORT_OUTPUT_VARS_NODE.includes(item.data.type)
|
||||
})
|
||||
}, [store])
|
||||
|
||||
|
|
@ -175,21 +169,16 @@ export const useWorkflow = () => {
|
|||
return list
|
||||
}, [store])
|
||||
|
||||
const getIncomersNodes = useCallback((currentNode: Node) => {
|
||||
const {
|
||||
getNodes,
|
||||
edges,
|
||||
} = store.getState()
|
||||
|
||||
return getIncomers(currentNode, getNodes(), edges)
|
||||
}, [store])
|
||||
const isValidConnection = useCallback(() => {
|
||||
return true
|
||||
}, [])
|
||||
|
||||
return {
|
||||
handleLayout,
|
||||
getTreeLeafNodes,
|
||||
getBeforeNodesInSameBranch,
|
||||
getAfterNodesInSameBranch,
|
||||
getIncomersNodes,
|
||||
isValidConnection,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import ReactFlow, {
|
|||
Background,
|
||||
ReactFlowProvider,
|
||||
useOnViewportChange,
|
||||
useStoreApi,
|
||||
} from 'reactflow'
|
||||
import type { Viewport } from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
|
|
@ -21,6 +22,7 @@ import {
|
|||
useEdgesInteractions,
|
||||
useNodesInteractions,
|
||||
useNodesSyncDraft,
|
||||
useWorkflow,
|
||||
useWorkflowInit,
|
||||
} from './hooks'
|
||||
import Header from './header'
|
||||
|
|
@ -60,6 +62,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||
const runningStatus = useStore(s => s.runningStatus)
|
||||
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
const store = useStoreApi()
|
||||
|
||||
useEffect(() => {
|
||||
setAutoFreeze(false)
|
||||
|
|
@ -84,6 +87,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
handleEdgeDelete,
|
||||
handleEdgesChange,
|
||||
} = useEdgesInteractions()
|
||||
const { isValidConnection } = useWorkflow()
|
||||
|
||||
useOnViewportChange({
|
||||
onEnd: () => handleSyncWorkflowDraft(),
|
||||
|
|
@ -130,6 +134,7 @@ const Workflow: FC<WorkflowProps> = memo(({
|
|||
zoomOnPinch={!runningStatus}
|
||||
zoomOnScroll={!runningStatus}
|
||||
zoomOnDoubleClick={!runningStatus}
|
||||
isValidConnection={isValidConnection}
|
||||
>
|
||||
<Background
|
||||
gap={[14, 14]}
|
||||
|
|
|
|||
|
|
@ -3,23 +3,33 @@ import {
|
|||
useCallback,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useNodesInteractions } from '@/app/components/workflow/hooks'
|
||||
import {
|
||||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||
import type {
|
||||
BlockEnum,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type AddProps = {
|
||||
nodeId: string
|
||||
nodeType: BlockEnum
|
||||
sourceHandle: string
|
||||
branchName?: string
|
||||
}
|
||||
const Add = ({
|
||||
nodeId,
|
||||
nodeType,
|
||||
sourceHandle,
|
||||
branchName,
|
||||
}: AddProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeAdd } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availableNextNodes = nodesExtraData[nodeType].availableNextNodes
|
||||
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
handleNodeAdd(
|
||||
|
|
@ -65,6 +75,7 @@ const Add = ({
|
|||
offset={0}
|
||||
trigger={renderTrigger}
|
||||
popupClassName='!w-[328px]'
|
||||
availableBlocksTypes={availableNextNodes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ const NextStep = ({
|
|||
!nodeWithBranches && !outgoers.length && (
|
||||
<Add
|
||||
nodeId={selectedNode!.id}
|
||||
nodeType={selectedNode!.data.type}
|
||||
sourceHandle='source'
|
||||
/>
|
||||
)
|
||||
|
|
@ -81,6 +82,7 @@ const NextStep = ({
|
|||
<Add
|
||||
key={branch.id}
|
||||
nodeId={selectedNode!.id}
|
||||
nodeType={selectedNode!.data.type}
|
||||
sourceHandle={branch.id}
|
||||
branchName={branch.name}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,17 @@ import {
|
|||
useCallback,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { union } from 'lodash-es'
|
||||
import type {
|
||||
CommonNodeType,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import { useNodesInteractions } from '@/app/components/workflow/hooks'
|
||||
import {
|
||||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
type ItemProps = {
|
||||
|
|
@ -26,6 +30,9 @@ const Item = ({
|
|||
}: ItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeChange } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availablePrevNodes = nodesExtraData[data.type].availablePrevNodes
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||
}, [nodeId, sourceHandle, handleNodeChange])
|
||||
|
|
@ -68,6 +75,7 @@ const Item = ({
|
|||
}}
|
||||
trigger={renderTrigger}
|
||||
popupClassName='!w-[328px]'
|
||||
availableBlocksTypes={union(availablePrevNodes, availableNextNodes)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ import { BlockEnum } from '../../../types'
|
|||
import type { Node } from '../../../types'
|
||||
import BlockSelector from '../../../block-selector'
|
||||
import type { ToolDefaultValue } from '../../../block-selector/types'
|
||||
import { useNodesInteractions } from '../../../hooks'
|
||||
import {
|
||||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
} from '../../../hooks'
|
||||
import { useStore } from '../../../store'
|
||||
|
||||
type NodeHandleProps = {
|
||||
|
|
@ -31,7 +34,10 @@ export const NodeTargetHandle = memo(({
|
|||
}: NodeHandleProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAdd } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const connected = data._connectedTargetHandleIds?.includes(handleId)
|
||||
const availablePrevNodes = nodesExtraData[data.type].availablePrevNodes
|
||||
const isConnectable = !!availablePrevNodes.length
|
||||
|
||||
const handleOpenChange = useCallback((v: boolean) => {
|
||||
setOpen(v)
|
||||
|
|
@ -67,11 +73,11 @@ export const NodeTargetHandle = memo(({
|
|||
${data.type === BlockEnum.Start && 'opacity-0'}
|
||||
${handleClassName}
|
||||
`}
|
||||
isConnectable={data.type !== BlockEnum.Start}
|
||||
isConnectable={isConnectable}
|
||||
onClick={handleHandleClick}
|
||||
>
|
||||
{
|
||||
!connected && data.type !== BlockEnum.Start && (
|
||||
!connected && isConnectable && (
|
||||
<BlockSelector
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
|
|
@ -84,6 +90,7 @@ export const NodeTargetHandle = memo(({
|
|||
group-hover:flex
|
||||
${open && '!flex'}
|
||||
`}
|
||||
availableBlocksTypes={availablePrevNodes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -103,6 +110,9 @@ export const NodeSourceHandle = memo(({
|
|||
const notInitialWorkflow = useStore(s => s.notInitialWorkflow)
|
||||
const [open, setOpen] = useState(false)
|
||||
const { handleNodeAdd } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
const isConnectable = !!availableNextNodes.length
|
||||
const connected = data._connectedSourceHandleIds?.includes(handleId)
|
||||
const handleOpenChange = useCallback((v: boolean) => {
|
||||
setOpen(v)
|
||||
|
|
@ -142,10 +152,11 @@ export const NodeSourceHandle = memo(({
|
|||
${!connected && 'after:opacity-0'}
|
||||
${handleClassName}
|
||||
`}
|
||||
isConnectable={isConnectable}
|
||||
onClick={handleHandleClick}
|
||||
>
|
||||
{
|
||||
!connected && (
|
||||
!connected && isConnectable && (
|
||||
<BlockSelector
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
|
|
@ -157,6 +168,7 @@ export const NodeSourceHandle = memo(({
|
|||
group-hover:flex
|
||||
${open && '!flex'}
|
||||
`}
|
||||
availableBlocksTypes={availableNextNodes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,20 +3,32 @@ import {
|
|||
useCallback,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { union } from 'lodash-es'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import { useNodesInteractions } from '@/app/components/workflow/hooks'
|
||||
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||
import {
|
||||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import type {
|
||||
BlockEnum,
|
||||
OnSelectBlock,
|
||||
} from '@/app/components/workflow/types'
|
||||
|
||||
type ChangeBlockProps = {
|
||||
nodeId: string
|
||||
nodeType: BlockEnum
|
||||
sourceHandle: string
|
||||
}
|
||||
const ChangeBlock = ({
|
||||
nodeId,
|
||||
nodeType,
|
||||
sourceHandle,
|
||||
}: ChangeBlockProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeChange } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availablePrevNodes = nodesExtraData[nodeType].availablePrevNodes
|
||||
const availableNextNodes = nodesExtraData[nodeType].availableNextNodes
|
||||
|
||||
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||
|
|
@ -39,6 +51,7 @@ const ChangeBlock = ({
|
|||
}}
|
||||
onSelect={handleSelect}
|
||||
trigger={renderTrigger}
|
||||
availableBlocksTypes={union(availablePrevNodes, availableNextNodes)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ const PanelOperator = ({
|
|||
data.type !== BlockEnum.Start && (
|
||||
<ChangeBlock
|
||||
nodeId={id}
|
||||
nodeType={data.type}
|
||||
sourceHandle={edge?.sourceHandle || 'source'}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||
import {
|
||||
useNodeDataUpdate,
|
||||
useNodesExtraData,
|
||||
useNodesInteractions,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { canRunBySingle } from '@/app/components/workflow/utils'
|
||||
|
|
@ -27,7 +28,6 @@ import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/develop
|
|||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
type BasePanelProps = {
|
||||
children: ReactElement
|
||||
|
|
@ -40,6 +40,9 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { handleNodeSelect } = useNodesInteractions()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
|
||||
const {
|
||||
handleNodeDataUpdate,
|
||||
handleNodeDataUpdateWithSyncDraft,
|
||||
|
|
@ -102,7 +105,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||
{cloneElement(children, { id, data })}
|
||||
</div>
|
||||
{
|
||||
data.type !== BlockEnum.End && (
|
||||
!!availableNextNodes.length && (
|
||||
<div className='p-4 border-t-[0.5px] border-t-black/5'>
|
||||
<div className='flex items-center mb-1 text-gray-700 text-[13px] font-semibold'>
|
||||
<GitBranch01 className='mr-1 w-4 h-4' />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import { BlockEnum, type NodeDefault } from '../../types'
|
||||
import { type IfElseNodeType, LogicalOperator } from './types'
|
||||
import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/constants'
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ const nodeDefault: NodeDefault<IfElseNodeType> = {
|
|||
},
|
||||
getAvailableNextNodes(isChatMode: boolean) {
|
||||
const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
|
||||
return nodes
|
||||
return nodes.filter(type => type !== BlockEnum.VariableAssigner)
|
||||
},
|
||||
checkValid(payload: IfElseNodeType) {
|
||||
let isValid = true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { NodeDefault } from '../../types'
|
||||
import { BlockEnum } from '../../types'
|
||||
import type { QuestionClassifierNodeType } from './types'
|
||||
import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/constants'
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ const nodeDefault: NodeDefault<QuestionClassifierNodeType> = {
|
|||
},
|
||||
getAvailableNextNodes(isChatMode: boolean) {
|
||||
const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
|
||||
return nodes
|
||||
return nodes.filter(type => type !== BlockEnum.VariableAssigner)
|
||||
},
|
||||
checkValid(payload: QuestionClassifierNodeType) {
|
||||
let isValid = true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { type NodeDefault, VarType } from '../../types'
|
||||
import { BlockEnum } from '../../types'
|
||||
import type { VariableAssignerNodeType } from './types'
|
||||
import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/constants'
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ const nodeDefault: NodeDefault<VariableAssignerNodeType> = {
|
|||
},
|
||||
getAvailablePrevNodes(isChatMode: boolean) {
|
||||
const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
|
||||
return nodes
|
||||
return nodes.filter(type => type !== BlockEnum.IfElse && type !== BlockEnum.QuestionClassifier)
|
||||
},
|
||||
getAvailableNextNodes(isChatMode: boolean) {
|
||||
const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
|
||||
|
|
|
|||
Loading…
Reference in New Issue