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: '测试运行 ',