diff --git a/web/app/components/workflow/hooks.ts b/web/app/components/workflow/hooks.ts index 7dba3c12ac..0f9d66920b 100644 --- a/web/app/components/workflow/hooks.ts +++ b/web/app/components/workflow/hooks.ts @@ -30,7 +30,9 @@ import { NODE_WIDTH_X_OFFSET, Y_OFFSET, } from './constants' -import { getLayoutByDagre } from './utils' +import { + getLayoutByDagre, +} from './utils' import { useStore } from './store' import type { ToolDefaultValue } from './block-selector/types' import { syncWorkflowDraft } from '@/service/workflow' diff --git a/web/app/components/workflow/nodes/_base/components/title-description-input.tsx b/web/app/components/workflow/nodes/_base/components/title-description-input.tsx index 6fd3835809..86354ef0bf 100644 --- a/web/app/components/workflow/nodes/_base/components/title-description-input.tsx +++ b/web/app/components/workflow/nodes/_base/components/title-description-input.tsx @@ -4,6 +4,7 @@ import { useState, } from 'react' import Textarea from 'rc-textarea' +import { useTranslation } from 'react-i18next' type InputProps = { value: string @@ -14,6 +15,8 @@ export const TitleInput = memo(({ value, onChange, }: InputProps) => { + const { t } = useTranslation() + return ( ) }) @@ -33,6 +36,7 @@ export const DescriptionInput = memo(({ value, onChange, }: InputProps) => { + const { t } = useTranslation() const [focus, setFocus] = useState(false) const handleFocus = useCallback(() => { setFocus(true) @@ -60,7 +64,7 @@ export const DescriptionInput = memo(({ appearance-none outline-none resize-none placeholder:text-gray-400 caret-[#295EFF] `} - placeholder='Add description...' + placeholder={t('workflow.common.addDescription') || ''} autoSize /> diff --git a/web/app/components/workflow/nodes/_base/node.tsx b/web/app/components/workflow/nodes/_base/node.tsx index 5a8e1693e5..fd781bc64e 100644 --- a/web/app/components/workflow/nodes/_base/node.tsx +++ b/web/app/components/workflow/nodes/_base/node.tsx @@ -43,7 +43,7 @@ const BaseNode: FC = ({ className={` group relative w-[240px] bg-[#fcfdff] shadow-xs border border-transparent rounded-[15px] - hover:shadow-lg + ${!data._runningStatus && 'hover:shadow-lg'} ${data._runningStatus === NodeRunningStatus.Running && '!border-primary-500'} ${data._runningStatus === NodeRunningStatus.Succeeded && '!border-[#12B76A]'} ${data._runningStatus === NodeRunningStatus.Failed && '!border-[#F04438]'} diff --git a/web/app/components/workflow/nodes/_base/panel.tsx b/web/app/components/workflow/nodes/_base/panel.tsx index 0671ec463e..bbf1aed96b 100644 --- a/web/app/components/workflow/nodes/_base/panel.tsx +++ b/web/app/components/workflow/nodes/_base/panel.tsx @@ -41,6 +41,8 @@ const BasePanel: FC = ({ handleNodeDataUpdate, } = useWorkflow() const handleTitleChange = useCallback((title: string) => { + if (!title) + return handleNodeDataUpdate({ id, data: { ...data, title } }) }, [handleNodeDataUpdate, id, data]) const handleDescriptionChange = useCallback((desc: string) => { diff --git a/web/app/components/workflow/utils.ts b/web/app/components/workflow/utils.ts index 8e40b78ffa..f8d741ac8b 100644 --- a/web/app/components/workflow/utils.ts +++ b/web/app/components/workflow/utils.ts @@ -171,6 +171,57 @@ export const canRunBySingle = (nodeType: BlockEnum) => { || nodeType === BlockEnum.Tool } -export const getVariables = (currentNodeId: string) => { +export const getTreeLeafNodes = (nodes: Node[], edges: Edge[]) => { + const startNode = nodes.find(node => node.data.type === BlockEnum.Start) + if (!startNode) + return [] + + const list: Node[] = [] + const preOrder = (root: Node, callback: (node: Node) => void) => { + const outgoers = getOutgoers(root, nodes, edges) + + if (outgoers.length) { + outgoers.forEach((outgoer) => { + preOrder(outgoer, callback) + }) + } + else { + callback(root) + } + } + preOrder(startNode, (node) => { + list.push(node) + }) + + return list +} + +export const getBeforeNodesInSameBranch = (nodeId: string, targetHandle: string, nodes: Node[], edges: Edge[]) => { + const currentNode = nodes.find(node => node.id === nodeId)! + const list: Node[] = [] + + const traverse = (root: Node, callback: (node: Node) => void) => { + const connectedEdges = getConnectedEdges([root], edges) + const sourceEdge = connectedEdges.filter(edge => edge.targetHandle === targetHandle) + const sourceEdgeLength = sourceEdge.length + + if (sourceEdgeLength === 1) { + const before = nodes.find(node => node.id === sourceEdge[0].source) + + if (before) { + callback(before) + traverse(before, callback) + } + } + } + traverse(currentNode, (node) => { + list.push(node) + }) + + const length = list.length + if (length && list[length - 1].data.type === BlockEnum.Start) + return list.reverse() + + return [] } diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index c8f627b701..a2cdd40e7c 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -21,6 +21,8 @@ const translation = { currentDraft: 'Current Draft', latestPublished: 'Latest Published', restore: 'Restore', + addTitle: 'Add title...', + addDescription: 'Add description...', }, singleRun: { testRun: 'Test Run ', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index b0cbd1c46e..57672a9509 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -21,6 +21,8 @@ const translation = { currentDraft: '当前草稿', latestPublished: '最新发布', restore: '恢复', + addTitle: '添加标题...', + addDescription: '添加描述...', }, singleRun: { testRun: '测试运行 ',