mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 20:48:01 +08:00
node control
This commit is contained in:
parent
173336f256
commit
16abcf082c
@ -368,6 +368,7 @@ export const useWorkflow = () => {
|
|||||||
x: currentNode.position.x,
|
x: currentNode.position.x,
|
||||||
y: currentNode.position.y,
|
y: currentNode.position.y,
|
||||||
},
|
},
|
||||||
|
targetPosition: Position.Left,
|
||||||
}
|
}
|
||||||
const newNodes = produce(nodes, (draft) => {
|
const newNodes = produce(nodes, (draft) => {
|
||||||
const index = draft.findIndex(node => node.id === currentNodeId)
|
const index = draft.findIndex(node => node.id === currentNodeId)
|
||||||
|
|||||||
@ -9,8 +9,6 @@ import { useKeyPress } from 'ahooks'
|
|||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
useEdgesState,
|
|
||||||
useNodesState,
|
|
||||||
useOnViewportChange,
|
useOnViewportChange,
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import type { Viewport } from 'reactflow'
|
import type { Viewport } from 'reactflow'
|
||||||
@ -56,13 +54,11 @@ type WorkflowProps = {
|
|||||||
viewport?: Viewport
|
viewport?: Viewport
|
||||||
}
|
}
|
||||||
const Workflow: FC<WorkflowProps> = memo(({
|
const Workflow: FC<WorkflowProps> = memo(({
|
||||||
nodes: initialNodes,
|
nodes,
|
||||||
edges: initialEdges,
|
edges,
|
||||||
viewport,
|
viewport,
|
||||||
}) => {
|
}) => {
|
||||||
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
const showFeaturesPanel = useStore(state => state.showFeaturesPanel)
|
||||||
const [nodes] = useNodesState(initialNodes)
|
|
||||||
const [edges] = useEdgesState(initialEdges)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSyncWorkflowDraft,
|
handleSyncWorkflowDraft,
|
||||||
|
|||||||
@ -21,7 +21,7 @@ const NodeControl: FC<NodeControlProps> = ({
|
|||||||
const { handleNodeDataUpdate } = useWorkflow()
|
const { handleNodeDataUpdate } = useWorkflow()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='absolute right-0 -top-7 flex items-center px-0.5 h-6 bg-white rounded-lg border-[0.5px] border-gray-100 shadow-xs text-gray-500'>
|
<div className='flex items-center px-0.5 h-6 bg-white rounded-lg border-[0.5px] border-gray-100 shadow-xs text-gray-500'>
|
||||||
{
|
{
|
||||||
isRunning && (
|
isRunning && (
|
||||||
<div className='flex items-center px-1 h-5 rounded-md bg-primary-50 text-xs font-medium text-primary-600'>
|
<div className='flex items-center px-1 h-5 rounded-md bg-primary-50 text-xs font-medium text-primary-600'>
|
||||||
|
|||||||
@ -8,10 +8,12 @@ import {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import type { NodeProps } from '../../types'
|
import type { NodeProps } from '../../types'
|
||||||
import { BlockEnum } from '../../types'
|
import { BlockEnum } from '../../types'
|
||||||
|
import { canRunBySingle } from '../../utils'
|
||||||
import {
|
import {
|
||||||
NodeSourceHandle,
|
NodeSourceHandle,
|
||||||
NodeTargetHandle,
|
NodeTargetHandle,
|
||||||
} from './components/node-handle'
|
} from './components/node-handle'
|
||||||
|
import NodeControl from './components/node-control'
|
||||||
import BlockIcon from '@/app/components/workflow/block-icon'
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
|
|
||||||
type BaseNodeProps = {
|
type BaseNodeProps = {
|
||||||
@ -26,55 +28,73 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
group relative w-[240px] bg-[#fcfdff] rounded-2xl shadow-xs
|
flex border-[2px] rounded-2xl
|
||||||
hover:shadow-lg
|
${data._selected ? 'border-primary-600' : 'border-transparent'}
|
||||||
${data._selected ? 'border-[2px] border-primary-600' : 'border border-white'}
|
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{
|
<div
|
||||||
data.type !== BlockEnum.VariableAssigner && (
|
className={`
|
||||||
<NodeTargetHandle
|
group relative w-[240px] bg-[#fcfdff] shadow-xs
|
||||||
id={id}
|
border border-transparent rounded-[15px]
|
||||||
data={data}
|
hover:shadow-lg
|
||||||
handleClassName='!top-[17px] !-left-2'
|
`}
|
||||||
handleId='target'
|
>
|
||||||
|
{
|
||||||
|
data.type !== BlockEnum.VariableAssigner && (
|
||||||
|
<NodeTargetHandle
|
||||||
|
id={id}
|
||||||
|
data={data}
|
||||||
|
handleClassName='!top-4 !-left-[9px]'
|
||||||
|
handleId='target'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
data.type !== BlockEnum.IfElse && data.type !== BlockEnum.QuestionClassifier && (
|
||||||
|
<NodeSourceHandle
|
||||||
|
id={id}
|
||||||
|
data={data}
|
||||||
|
handleClassName='!top-4 !-right-[9px]'
|
||||||
|
handleId='source'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
canRunBySingle(data.type)
|
||||||
|
&& (
|
||||||
|
<div className='hidden group-hover:flex pb-1 absolute right-0 -top-7 h-7'>
|
||||||
|
<NodeControl
|
||||||
|
nodeId={id}
|
||||||
|
isRunning={data._isSingleRun}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<div className='flex items-center px-3 pt-3 pb-2'>
|
||||||
|
<BlockIcon
|
||||||
|
className='shrink-0 mr-2'
|
||||||
|
type={data.type}
|
||||||
|
size='md'
|
||||||
|
icon={data._icon}
|
||||||
/>
|
/>
|
||||||
)
|
<div
|
||||||
}
|
title={data.title}
|
||||||
{
|
className='grow text-[13px] font-semibold text-gray-700 truncate'
|
||||||
data.type !== BlockEnum.IfElse && data.type !== BlockEnum.QuestionClassifier && (
|
>
|
||||||
<NodeSourceHandle
|
{data.title}
|
||||||
id={id}
|
|
||||||
data={data}
|
|
||||||
handleClassName='!top-[17px] !-right-2'
|
|
||||||
handleId='source'
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<div className='flex items-center px-3 pt-3 pb-2'>
|
|
||||||
<BlockIcon
|
|
||||||
className='shrink-0 mr-2'
|
|
||||||
type={data.type}
|
|
||||||
size='md'
|
|
||||||
icon={data._icon}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
title={data.title}
|
|
||||||
className='grow text-[13px] font-semibold text-gray-700 truncate'
|
|
||||||
>
|
|
||||||
{data.title}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='mb-1'>
|
|
||||||
{cloneElement(children, { id, data })}
|
|
||||||
</div>
|
|
||||||
{
|
|
||||||
data.desc && (
|
|
||||||
<div className='px-3 pt-s1 pb-2 text-xs leading-[18px] text-gray-500 whitespace-pre-line break-words'>
|
|
||||||
{data.desc}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
</div>
|
||||||
}
|
<div className='mb-1'>
|
||||||
|
{cloneElement(children, { id, data })}
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
data.desc && (
|
||||||
|
<div className='px-3 pt-s1 pb-2 text-xs leading-[18px] text-gray-500 whitespace-pre-line break-words'>
|
||||||
|
{data.desc}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +1,21 @@
|
|||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import type { NodeProps } from 'reactflow'
|
import type { NodeProps } from 'reactflow'
|
||||||
import type { Node } from '../types'
|
import type { Node } from '../types'
|
||||||
import { canRunBySingle } from '../utils'
|
|
||||||
import {
|
import {
|
||||||
NodeComponentMap,
|
NodeComponentMap,
|
||||||
PanelComponentMap,
|
PanelComponentMap,
|
||||||
} from './constants'
|
} from './constants'
|
||||||
import BaseNode from './_base/node'
|
import BaseNode from './_base/node'
|
||||||
import BasePanel from './_base/panel'
|
import BasePanel from './_base/panel'
|
||||||
import NodeControl from './_base/components/node-control'
|
|
||||||
|
|
||||||
const CustomNode = memo((props: NodeProps) => {
|
const CustomNode = memo((props: NodeProps) => {
|
||||||
const nodeId = props.id
|
|
||||||
const nodeData = props.data
|
const nodeData = props.data
|
||||||
const NodeComponent = NodeComponentMap[nodeData.type]
|
const NodeComponent = NodeComponentMap[nodeData.type]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<BaseNode { ...props }>
|
||||||
<BaseNode { ...props }>
|
<NodeComponent />
|
||||||
<NodeComponent />
|
</BaseNode>
|
||||||
</BaseNode>
|
|
||||||
{
|
|
||||||
nodeData._selected
|
|
||||||
&& canRunBySingle(nodeData.type)
|
|
||||||
&& (
|
|
||||||
<NodeControl
|
|
||||||
nodeId={nodeId}
|
|
||||||
isRunning={nodeData._isSingleRun}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
CustomNode.displayName = 'CustomNode'
|
CustomNode.displayName = 'CustomNode'
|
||||||
|
|||||||
@ -27,7 +27,6 @@ export type Branch = {
|
|||||||
|
|
||||||
export type CommonNodeType<T = {}> = {
|
export type CommonNodeType<T = {}> = {
|
||||||
_selected?: boolean
|
_selected?: boolean
|
||||||
_hovering?: boolean
|
|
||||||
_targetBranches?: Branch[]
|
_targetBranches?: Branch[]
|
||||||
_isSingleRun?: boolean
|
_isSingleRun?: boolean
|
||||||
_icon?: Collection['icon']
|
_icon?: Collection['icon']
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user