Files
dify/web/app/components/workflow/nodes/_base/node.tsx
Yeuoly 4a43e165fb Plugin/merge main 20250208 (#13414)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Signed-off-by: -LAN- <laipz8200@outlook.com>
Signed-off-by: xhe <xw897002528@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: kurokobo <kuro664@gmail.com>
Co-authored-by: Hiroshi Fujita <fujita-h@users.noreply.github.com>
Co-authored-by: NFish <douxc512@gmail.com>
Co-authored-by: Gen Sato <52241300+halogen22@users.noreply.github.com>
Co-authored-by: eux <euxuuu@gmail.com>
Co-authored-by: huangzhuo1949 <167434202+huangzhuo1949@users.noreply.github.com>
Co-authored-by: huangzhuo <huangzhuo1@xiaomi.com>
Co-authored-by: lotsik <lotsik@mail.ru>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: gakkiyomi <gakkiyomi@aliyun.com>
Co-authored-by: CN-P5 <heibai2006@gmail.com>
Co-authored-by: CN-P5 <heibai2006@qq.com>
Co-authored-by: Chuehnone <1897025+chuehnone@users.noreply.github.com>
Co-authored-by: yihong <zouzou0208@gmail.com>
Co-authored-by: Kevin9703 <51311316+Kevin9703@users.noreply.github.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: Boris Feld <lothiraldan@gmail.com>
Co-authored-by: mbo <himabo@gmail.com>
Co-authored-by: mabo <mabo@aeyes.ai>
Co-authored-by: Warren Chen <warren.chen830@gmail.com>
Co-authored-by: KVOJJJin <jzongcode@gmail.com>
Co-authored-by: JzoNgKVO <27049666+JzoNgKVO@users.noreply.github.com>
Co-authored-by: jiandanfeng <chenjh3@wangsu.com>
Co-authored-by: zhu-an <70234959+xhdd123321@users.noreply.github.com>
Co-authored-by: zhaoqingyu.1075 <zhaoqingyu.1075@bytedance.com>
Co-authored-by: 海狸大師 <86974027+yenslife@users.noreply.github.com>
Co-authored-by: Xu Song <xusong.vip@gmail.com>
Co-authored-by: rayshaw001 <396301947@163.com>
Co-authored-by: Ding Jiatong <dingjiatong@gmail.com>
Co-authored-by: Bowen Liang <liangbowen@gf.com.cn>
Co-authored-by: JasonVV <jasonwangiii@outlook.com>
Co-authored-by: le0zh <newlight@qq.com>
Co-authored-by: zhuxinliang <zhuxinliang@didiglobal.com>
Co-authored-by: k-zaku <zaku99@outlook.jp>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: luckylhb90 <luckylhb90@gmail.com>
Co-authored-by: hobo.l <hobo.l@binance.com>
Co-authored-by: jiangbo721 <365065261@qq.com>
Co-authored-by: 刘江波 <jiangbo721@163.com>
Co-authored-by: Shun Miyazawa <34241526+miya@users.noreply.github.com>
Co-authored-by: EricPan <30651140+Egfly@users.noreply.github.com>
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: sino <sino2322@gmail.com>
Co-authored-by: Jhvcc <37662342+Jhvcc@users.noreply.github.com>
Co-authored-by: lowell <lowell.hu@zkteco.in>
Co-authored-by: Ademílson Tonato <ademilsonft@outlook.com>
Co-authored-by: Ademílson Tonato <ademilson.tonato@refurbed.com>
Co-authored-by: IWAI, Masaharu <iwaim.sub@gmail.com>
Co-authored-by: Yueh-Po Peng (Yabi) <94939112+y10ab1@users.noreply.github.com>
Co-authored-by: 非法操作 <hjlarry@163.com>
Co-authored-by: Jason <ggbbddjm@gmail.com>
Co-authored-by: Xin Zhang <sjhpzx@gmail.com>
Co-authored-by: yjc980121 <3898524+yjc980121@users.noreply.github.com>
Co-authored-by: heyszt <36215648+hieheihei@users.noreply.github.com>
Co-authored-by: Abdullah AlOsaimi <osaimiacc@gmail.com>
Co-authored-by: Abdullah AlOsaimi <189027247+osaimi@users.noreply.github.com>
Co-authored-by: Yingchun Lai <laiyingchun@apache.org>
Co-authored-by: Hash Brown <hi@xzd.me>
Co-authored-by: zuodongxu <192560071+zuodongxu@users.noreply.github.com>
Co-authored-by: Masashi Tomooka <tmokmss@users.noreply.github.com>
Co-authored-by: aplio <ryo.091219@gmail.com>
Co-authored-by: Obada Khalili <54270856+obadakhalili@users.noreply.github.com>
Co-authored-by: Nam Vu <zuzoovn@gmail.com>
Co-authored-by: Kei YAMAZAKI <1715090+kei-yamazaki@users.noreply.github.com>
Co-authored-by: TechnoHouse <13776377+deephbz@users.noreply.github.com>
Co-authored-by: Riddhimaan-Senapati <114703025+Riddhimaan-Senapati@users.noreply.github.com>
Co-authored-by: MaFee921 <31881301+2284730142@users.noreply.github.com>
Co-authored-by: te-chan <t-nakanome@sakura-is.co.jp>
Co-authored-by: HQidea <HQidea@users.noreply.github.com>
Co-authored-by: Joshbly <36315710+Joshbly@users.noreply.github.com>
Co-authored-by: xhe <xw897002528@gmail.com>
Co-authored-by: weiwenyan-dev <154779315+weiwenyan-dev@users.noreply.github.com>
Co-authored-by: ex_wenyan.wei <ex_wenyan.wei@tcl.com>
Co-authored-by: engchina <12236799+engchina@users.noreply.github.com>
Co-authored-by: engchina <atjapan2015@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: 呆萌闷油瓶 <253605712@qq.com>
Co-authored-by: Kemal <kemalmeler@outlook.com>
Co-authored-by: Lazy_Frog <4590648+lazyFrogLOL@users.noreply.github.com>
Co-authored-by: Novice Lee <novicelee@NoviPro.local>
Co-authored-by: Yi Xiao <54782454+YIXIAO0@users.noreply.github.com>
Co-authored-by: Steven sun <98230804+Tuyohai@users.noreply.github.com>
Co-authored-by: steven <sunzwj@digitalchina.com>
Co-authored-by: Kalo Chin <91766386+fdb02983rhy@users.noreply.github.com>
Co-authored-by: Katy Tao <34019945+KatyTao@users.noreply.github.com>
Co-authored-by: depy <42985524+h4ckdepy@users.noreply.github.com>
Co-authored-by: 胡春东 <gycm520@gmail.com>
Co-authored-by: Junjie.M <118170653@qq.com>
2025-02-08 19:12:36 +08:00

273 lines
8.7 KiB
TypeScript

import type {
FC,
ReactElement,
} from 'react'
import {
cloneElement,
memo,
useEffect,
useMemo,
useRef,
} from 'react'
import {
RiAlertFill,
RiCheckboxCircleFill,
RiErrorWarningFill,
RiLoader2Line,
} from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import type { NodeProps } from '../../types'
import {
BlockEnum,
NodeRunningStatus,
} from '../../types'
import {
useNodesReadOnly,
useToolIcon,
} from '../../hooks'
import {
hasErrorHandleNode,
hasRetryNode,
} from '../../utils'
import { useNodeIterationInteractions } from '../iteration/use-interactions'
import type { IterationNodeType } from '../iteration/types'
import {
NodeSourceHandle,
NodeTargetHandle,
} from './components/node-handle'
import NodeResizer from './components/node-resizer'
import NodeControl from './components/node-control'
import ErrorHandleOnNode from './components/error-handle/error-handle-on-node'
import RetryOnNode from './components/retry/retry-on-node'
import AddVariablePopupWithPosition from './components/add-variable-popup-with-position'
import cn from '@/utils/classnames'
import BlockIcon from '@/app/components/workflow/block-icon'
import Tooltip from '@/app/components/base/tooltip'
type BaseNodeProps = {
children: ReactElement
} & NodeProps
const BaseNode: FC<BaseNodeProps> = ({
id,
data,
children,
}) => {
const { t } = useTranslation()
const nodeRef = useRef<HTMLDivElement>(null)
const { nodesReadOnly } = useNodesReadOnly()
const { handleNodeIterationChildSizeChange } = useNodeIterationInteractions()
const toolIcon = useToolIcon(data)
useEffect(() => {
if (nodeRef.current && data.selected && data.isInIteration) {
const resizeObserver = new ResizeObserver(() => {
handleNodeIterationChildSizeChange(id)
})
resizeObserver.observe(nodeRef.current)
return () => {
resizeObserver.disconnect()
}
}
}, [data.isInIteration, data.selected, id, handleNodeIterationChildSizeChange])
const showSelectedBorder = data.selected || data._isBundled || data._isEntering
const {
showRunningBorder,
showSuccessBorder,
showFailedBorder,
showExceptionBorder,
} = useMemo(() => {
return {
showRunningBorder: data._runningStatus === NodeRunningStatus.Running && !showSelectedBorder,
showSuccessBorder: data._runningStatus === NodeRunningStatus.Succeeded && !showSelectedBorder,
showFailedBorder: data._runningStatus === NodeRunningStatus.Failed && !showSelectedBorder,
showExceptionBorder: data._runningStatus === NodeRunningStatus.Exception && !showSelectedBorder,
}
}, [data._runningStatus, showSelectedBorder])
return (
<div
className={cn(
'flex border-[2px] rounded-2xl',
showSelectedBorder ? 'border-components-option-card-option-selected-border' : 'border-transparent',
!showSelectedBorder && data._inParallelHovering && 'border-workflow-block-border-highlight',
data._waitingRun && 'opacity-70',
)}
ref={nodeRef}
style={{
width: data.type === BlockEnum.Iteration ? data.width : 'auto',
height: data.type === BlockEnum.Iteration ? data.height : 'auto',
}}
>
<div
className={cn(
'group relative pb-1 shadow-xs',
'border border-transparent rounded-[15px]',
data.type !== BlockEnum.Iteration && 'w-[240px] bg-workflow-block-bg',
data.type === BlockEnum.Iteration && 'flex flex-col w-full h-full bg-workflow-block-bg-transparent border-workflow-block-border',
!data._runningStatus && 'hover:shadow-lg',
showRunningBorder && '!border-state-accent-solid',
showSuccessBorder && '!border-state-success-solid',
showFailedBorder && '!border-state-destructive-solid',
showExceptionBorder && '!border-state-warning-solid',
data._isBundled && '!shadow-lg',
)}
>
{
data._inParallelHovering && (
<div className='absolute left-2 -top-2.5 top system-2xs-medium-uppercase text-text-tertiary z-10'>
{t('workflow.common.parallelRun')}
</div>
)
}
{
data._showAddVariablePopup && (
<AddVariablePopupWithPosition
nodeId={id}
nodeData={data}
/>
)
}
{
data.type === BlockEnum.Iteration && (
<NodeResizer
nodeId={id}
nodeData={data}
/>
)
}
{
!data._isCandidate && (
<NodeTargetHandle
id={id}
data={data}
handleClassName='!top-4 !-left-[9px] !translate-y-0'
handleId='target'
/>
)
}
{
data.type !== BlockEnum.IfElse && data.type !== BlockEnum.QuestionClassifier && !data._isCandidate && (
<NodeSourceHandle
id={id}
data={data}
handleClassName='!top-4 !-right-[9px] !translate-y-0'
handleId='source'
/>
)
}
{
!data._runningStatus && !nodesReadOnly && !data._isCandidate && (
<NodeControl
id={id}
data={data}
/>
)
}
<div className={cn(
'flex items-center px-3 pt-3 pb-2 rounded-t-2xl',
data.type === BlockEnum.Iteration && 'bg-transparent',
)}>
<BlockIcon
className='shrink-0 mr-2'
type={data.type}
size='md'
toolIcon={toolIcon}
/>
<div
title={data.title}
className='grow mr-1 system-sm-semibold-uppercase text-text-primary truncate flex items-center'
>
<div>
{data.title}
</div>
{
data.type === BlockEnum.Iteration && (data as IterationNodeType).is_parallel && (
<Tooltip popupContent={
<div className='w-[180px]'>
<div className='font-extrabold'>
{t('workflow.nodes.iteration.parallelModeEnableTitle')}
</div>
{t('workflow.nodes.iteration.parallelModeEnableDesc')}
</div>}
>
<div className='flex justify-center items-center px-[5px] py-[3px] ml-1 border-[1px] border-text-warning rounded-[5px] text-text-warning system-2xs-medium-uppercase '>
{t('workflow.nodes.iteration.parallelModeUpper')}
</div>
</Tooltip>
)
}
</div>
{
data._iterationLength && data._iterationIndex && data._runningStatus === NodeRunningStatus.Running && (
<div className='mr-1.5 text-xs font-medium text-text-accent'>
{data._iterationIndex > data._iterationLength ? data._iterationLength : data._iterationIndex}/{data._iterationLength}
</div>
)
}
{
(data._runningStatus === NodeRunningStatus.Running || data._singleRunningStatus === NodeRunningStatus.Running) && (
<RiLoader2Line className='w-3.5 h-3.5 text-text-accent animate-spin' />
)
}
{
data._runningStatus === NodeRunningStatus.Succeeded && (
<RiCheckboxCircleFill className='w-3.5 h-3.5 text-text-success' />
)
}
{
data._runningStatus === NodeRunningStatus.Failed && (
<RiErrorWarningFill className='w-3.5 h-3.5 text-text-destructive' />
)
}
{
data._runningStatus === NodeRunningStatus.Exception && (
<RiAlertFill className='w-3.5 h-3.5 text-text-warning-secondary' />
)
}
</div>
{
data.type !== BlockEnum.Iteration && (
cloneElement(children, { id, data })
)
}
{
data.type === BlockEnum.Iteration && (
<div className='grow pl-1 pr-1 pb-1'>
{cloneElement(children, { id, data })}
</div>
)
}
{
hasRetryNode(data.type) && (
<RetryOnNode
id={id}
data={data}
/>
)
}
{
hasErrorHandleNode(data.type) && (
<ErrorHandleOnNode
id={id}
data={data}
/>
)
}
{
data.desc && data.type !== BlockEnum.Iteration && (
<div className='px-3 pt-1 pb-2 system-xs-regular text-text-tertiary whitespace-pre-line break-words'>
{data.desc}
</div>
)
}
</div>
</div>
)
}
export default memo(BaseNode)