diff --git a/web/app/components/rag-pipeline/hooks/use-available-nodes-meta-data.ts b/web/app/components/rag-pipeline/hooks/use-available-nodes-meta-data.ts index 3dad34f441..6ce4524c8e 100644 --- a/web/app/components/rag-pipeline/hooks/use-available-nodes-meta-data.ts +++ b/web/app/components/rag-pipeline/hooks/use-available-nodes-meta-data.ts @@ -19,26 +19,9 @@ export const useAvailableNodesMetaData = () => { ...dataSourceDefault.defaultValue, _dataSourceStartToAdd: true, }, - metaData: { - ...dataSourceDefault.metaData, - isStart: true, - isRequired: true, - }, - }, - { - ...knowledgeBaseDefault, - metaData: { - ...knowledgeBaseDefault.metaData, - isRequired: true, - }, - }, - { - ...dataSourceEmptyDefault, - metaData: { - ...dataSourceEmptyDefault.metaData, - isUndeletable: true, - }, }, + knowledgeBaseDefault, + dataSourceEmptyDefault, ], []) const prefixLink = useMemo(() => { diff --git a/web/app/components/workflow-app/hooks/use-available-nodes-meta-data.ts b/web/app/components/workflow-app/hooks/use-available-nodes-meta-data.ts index 983d598573..f590c1a8ce 100644 --- a/web/app/components/workflow-app/hooks/use-available-nodes-meta-data.ts +++ b/web/app/components/workflow-app/hooks/use-available-nodes-meta-data.ts @@ -15,35 +15,11 @@ export const useAvailableNodesMetaData = () => { const mergedNodesMetaData = useMemo(() => [ ...WORKFLOW_COMMON_NODES, - { - ...StartDefault, - metaData: { - ...StartDefault.metaData, - isStart: true, - isRequired: true, - isUndeletable: true, - }, - }, + StartDefault, ...( isChatMode - ? [ - { - ...AnswerDefault, - metaData: { - ...AnswerDefault.metaData, - isRequired: true, - }, - }, - ] - : [ - { - ...EndDefault, - metaData: { - ...EndDefault.metaData, - isRequired: true, - }, - }, - ] + ? [AnswerDefault] + : [EndDefault] ), ], [isChatMode]) diff --git a/web/app/components/workflow/hooks/use-nodes-interactions.ts b/web/app/components/workflow/hooks/use-nodes-interactions.ts index 3f1fd56df1..023f3a7470 100644 --- a/web/app/components/workflow/hooks/use-nodes-interactions.ts +++ b/web/app/components/workflow/hooks/use-nodes-interactions.ts @@ -1256,15 +1256,26 @@ export const useNodesInteractions = () => { } else { // If no nodeId is provided, fall back to the current behavior - const bundledNodes = nodes.filter(node => node.data._isBundled && node.data.type !== BlockEnum.Start && node.data.type !== BlockEnum.DataSource && node.data.type !== BlockEnum.KnowledgeBase && node.data.type !== BlockEnum.DataSourceEmpty - && !node.data.isInIteration && !node.data.isInLoop) + const bundledNodes = nodes.filter((node) => { + if (!node.data._isBundled) + return false + const { metaData } = nodesMetaDataMap![node.data.type as BlockEnum] + if (metaData.isSingleton) + return false + return !node.data.isInIteration && !node.data.isInLoop + }) if (bundledNodes.length) { setClipboardElements(bundledNodes) return } - const selectedNode = nodes.find(node => node.data.selected && node.data.type !== BlockEnum.Start && node.data.type !== BlockEnum.LoopEnd && node.data.type !== BlockEnum.DataSource) + const selectedNode = nodes.find((node) => { + if (!node.data.selected) + return false + const { metaData } = nodesMetaDataMap![node.data.type as BlockEnum] + return !metaData.isSingleton + }) if (selectedNode) setClipboardElements([selectedNode]) diff --git a/web/app/components/workflow/nodes/_base/components/panel-operator/panel-operator-popup.tsx b/web/app/components/workflow/nodes/_base/components/panel-operator/panel-operator-popup.tsx index 75abdd6d12..a871e60e3a 100644 --- a/web/app/components/workflow/nodes/_base/components/panel-operator/panel-operator-popup.tsx +++ b/web/app/components/workflow/nodes/_base/components/panel-operator/panel-operator-popup.tsx @@ -16,7 +16,6 @@ import { } from '@/app/components/workflow/hooks' import ShortcutsName from '@/app/components/workflow/shortcuts-name' import type { Node } from '@/app/components/workflow/types' -import { BlockEnum } from '@/app/components/workflow/types' type PanelOperatorPopupProps = { id: string @@ -43,7 +42,7 @@ const PanelOperatorPopup = ({ const { nodesReadOnly } = useNodesReadOnly() const edge = edges.find(edge => edge.target === id) const nodeMetaData = useNodeMetaData({ id, data } as Node) - const showChangeBlock = data.type !== BlockEnum.Start && !nodesReadOnly && data.type !== BlockEnum.Iteration && data.type !== BlockEnum.Loop + const showChangeBlock = !nodeMetaData.isTypeFixed && !nodesReadOnly const isChildNode = !!(data.isInIteration || data.isInLoop) return ( @@ -85,31 +84,37 @@ const PanelOperatorPopup = ({ ) } { - data.type !== BlockEnum.Start && !nodesReadOnly && ( + !nodesReadOnly && ( <> -
-
{ - onClosePopup() - handleNodesCopy(id) - }} - > - {t('workflow.common.copy')} - -
-
{ - onClosePopup() - handleNodesDuplicate(id) - }} - > - {t('workflow.common.duplicate')} - -
-
-
+ { + !nodeMetaData.isSingleton && ( + <> +
+
{ + onClosePopup() + handleNodesCopy(id) + }} + > + {t('workflow.common.copy')} + +
+
{ + onClosePopup() + handleNodesDuplicate(id) + }} + > + {t('workflow.common.duplicate')} + +
+
+
+ + ) + } { !nodeMetaData.isUndeletable && ( <> @@ -117,7 +122,7 @@ const PanelOperatorPopup = ({
handleNodeDelete(id)} > diff --git a/web/app/components/workflow/nodes/answer/default.ts b/web/app/components/workflow/nodes/answer/default.ts index d3cb2c6741..f115274900 100644 --- a/web/app/components/workflow/nodes/answer/default.ts +++ b/web/app/components/workflow/nodes/answer/default.ts @@ -6,6 +6,7 @@ import { BlockEnum } from '@/app/components/workflow/types' const metaData = genNodeMetaData({ sort: 2.1, type: BlockEnum.Answer, + isRequired: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/data-source-empty/default.ts b/web/app/components/workflow/nodes/data-source-empty/default.ts index df7c5e853e..69d9904217 100644 --- a/web/app/components/workflow/nodes/data-source-empty/default.ts +++ b/web/app/components/workflow/nodes/data-source-empty/default.ts @@ -6,6 +6,8 @@ import { BlockEnum } from '@/app/components/workflow/types' const metaData = genNodeMetaData({ sort: -1, type: BlockEnum.DataSourceEmpty, + isUndeletable: true, + isSingleton: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/data-source/default.ts b/web/app/components/workflow/nodes/data-source/default.ts index f5ebb27655..82e69679a2 100644 --- a/web/app/components/workflow/nodes/data-source/default.ts +++ b/web/app/components/workflow/nodes/data-source/default.ts @@ -15,6 +15,8 @@ const i18nPrefix = 'workflow.errorMsg' const metaData = genNodeMetaData({ sort: -1, type: BlockEnum.DataSource, + isStart: true, + isRequired: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/end/default.ts b/web/app/components/workflow/nodes/end/default.ts index 32e4f1051d..cadb580c34 100644 --- a/web/app/components/workflow/nodes/end/default.ts +++ b/web/app/components/workflow/nodes/end/default.ts @@ -6,6 +6,7 @@ import { BlockEnum } from '@/app/components/workflow/types' const metaData = genNodeMetaData({ sort: 2.1, type: BlockEnum.End, + isRequired: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/iteration/default.ts b/web/app/components/workflow/nodes/iteration/default.ts index 3c348a4fe0..450379ec6b 100644 --- a/web/app/components/workflow/nodes/iteration/default.ts +++ b/web/app/components/workflow/nodes/iteration/default.ts @@ -9,6 +9,7 @@ const metaData = genNodeMetaData({ classification: BlockClassificationEnum.Logic, sort: 2, type: BlockEnum.Iteration, + isTypeFixed: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/knowledge-base/default.ts b/web/app/components/workflow/nodes/knowledge-base/default.ts index e43c08778f..8175e2ac9e 100644 --- a/web/app/components/workflow/nodes/knowledge-base/default.ts +++ b/web/app/components/workflow/nodes/knowledge-base/default.ts @@ -6,6 +6,10 @@ import { BlockEnum } from '@/app/components/workflow/types' const metaData = genNodeMetaData({ sort: 3.1, type: BlockEnum.KnowledgeBase, + isRequired: true, + isUndeletable: true, + isSingleton: true, + isTypeFixed: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/loop-end/default.ts b/web/app/components/workflow/nodes/loop-end/default.ts index c02d007cde..bb46ff1166 100644 --- a/web/app/components/workflow/nodes/loop-end/default.ts +++ b/web/app/components/workflow/nodes/loop-end/default.ts @@ -10,6 +10,7 @@ const metaData = genNodeMetaData({ classification: BlockClassificationEnum.Logic, sort: 2, type: BlockEnum.LoopEnd, + isSingleton: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/loop/default.ts b/web/app/components/workflow/nodes/loop/default.ts index 0a80763001..390545d0e2 100644 --- a/web/app/components/workflow/nodes/loop/default.ts +++ b/web/app/components/workflow/nodes/loop/default.ts @@ -14,6 +14,7 @@ const metaData = genNodeMetaData({ sort: 3, type: BlockEnum.Loop, author: 'AICT-Team', + isTypeFixed: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/nodes/start/default.ts b/web/app/components/workflow/nodes/start/default.ts index 8337c2275f..3b98b57a73 100644 --- a/web/app/components/workflow/nodes/start/default.ts +++ b/web/app/components/workflow/nodes/start/default.ts @@ -6,6 +6,11 @@ import { BlockEnum } from '@/app/components/workflow/types' const metaData = genNodeMetaData({ sort: 0.1, type: BlockEnum.Start, + isStart: true, + isRequired: true, + isUndeletable: true, + isSingleton: true, + isTypeFixed: true, }) const nodeDefault: NodeDefault = { metaData, diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index bfae195a0e..f5ff7d5ce8 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -329,6 +329,8 @@ export type NodeDefault = { isRequired?: boolean isUndeletable?: boolean isStart?: boolean + isSingleton?: boolean + isTypeFixed?: boolean } defaultValue: Partial defaultRunInputData?: Record diff --git a/web/app/components/workflow/utils/gen-node-meta-data.ts b/web/app/components/workflow/utils/gen-node-meta-data.ts index e7271cfcc4..9c4e9cabca 100644 --- a/web/app/components/workflow/utils/gen-node-meta-data.ts +++ b/web/app/components/workflow/utils/gen-node-meta-data.ts @@ -8,6 +8,11 @@ export type GenNodeMetaDataParams = { title?: string author?: string helpLinkUri?: string + isRequired?: boolean + isUndeletable?: boolean + isStart?: boolean + isSingleton?: boolean + isTypeFixed?: boolean } export const genNodeMetaData = ({ classification = BlockClassificationEnum.Default, @@ -16,6 +21,11 @@ export const genNodeMetaData = ({ title = '', author = 'Dify', helpLinkUri, + isRequired = false, + isUndeletable = false, + isStart = false, + isSingleton = false, + isTypeFixed = false, }: GenNodeMetaDataParams) => { return { classification, @@ -24,5 +34,10 @@ export const genNodeMetaData = ({ title, author, helpLinkUri: helpLinkUri || type, + isRequired, + isUndeletable, + isStart, + isSingleton, + isTypeFixed, } }