diff --git a/web/app/components/workflow/block-selector/constants.tsx b/web/app/components/workflow/block-selector/constants.tsx
index 680cbf45b9..f10035bcfd 100644
--- a/web/app/components/workflow/block-selector/constants.tsx
+++ b/web/app/components/workflow/block-selector/constants.tsx
@@ -1,107 +1,5 @@
-import type { Block } from '../types'
-import { BlockEnum } from '../types'
import { BlockClassificationEnum } from './types'
-export const BLOCKS: Block[] = [
- {
- classification: BlockClassificationEnum.Default,
- type: BlockEnum.Start,
- title: 'Start',
- description: '',
- },
- {
- classification: BlockClassificationEnum.Default,
- type: BlockEnum.LLM,
- title: 'LLM',
- },
- {
- classification: BlockClassificationEnum.Default,
- type: BlockEnum.KnowledgeRetrieval,
- title: 'Knowledge Retrieval',
- },
- {
- classification: BlockClassificationEnum.Default,
- type: BlockEnum.End,
- title: 'End',
- },
- {
- classification: BlockClassificationEnum.Default,
- type: BlockEnum.Answer,
- title: 'Direct Answer',
- },
- {
- classification: BlockClassificationEnum.QuestionUnderstand,
- type: BlockEnum.QuestionClassifier,
- title: 'Question Classifier',
- },
- {
- classification: BlockClassificationEnum.Logic,
- type: BlockEnum.IfElse,
- title: 'IF/ELSE',
- },
- {
- classification: BlockClassificationEnum.Logic,
- type: BlockEnum.LoopEnd,
- title: 'Exit Loop',
- description: '',
- },
- {
- classification: BlockClassificationEnum.Logic,
- type: BlockEnum.Iteration,
- title: 'Iteration',
- },
- {
- classification: BlockClassificationEnum.Logic,
- type: BlockEnum.Loop,
- title: 'Loop',
- },
- {
- classification: BlockClassificationEnum.Transform,
- type: BlockEnum.Code,
- title: 'Code',
- },
- {
- classification: BlockClassificationEnum.Transform,
- type: BlockEnum.TemplateTransform,
- title: 'Templating Transform',
- },
- {
- classification: BlockClassificationEnum.Transform,
- type: BlockEnum.VariableAggregator,
- title: 'Variable Aggregator',
- },
- {
- classification: BlockClassificationEnum.Transform,
- type: BlockEnum.DocExtractor,
- title: 'Doc Extractor',
- },
- {
- classification: BlockClassificationEnum.Transform,
- type: BlockEnum.Assigner,
- title: 'Variable Assigner',
- },
- {
- classification: BlockClassificationEnum.Transform,
- type: BlockEnum.ParameterExtractor,
- title: 'Parameter Extractor',
- },
- {
- classification: BlockClassificationEnum.Utilities,
- type: BlockEnum.HttpRequest,
- title: 'HTTP Request',
- },
- {
- classification: BlockClassificationEnum.Utilities,
- type: BlockEnum.ListFilter,
- title: 'List Filter',
- },
- {
- classification: BlockClassificationEnum.Default,
- type: BlockEnum.Agent,
- title: 'Agent',
- },
-]
-
export const BLOCK_CLASSIFICATIONS: string[] = [
BlockClassificationEnum.Default,
BlockClassificationEnum.QuestionUnderstand,
diff --git a/web/app/components/workflow/block-selector/hooks.ts b/web/app/components/workflow/block-selector/hooks.ts
index a8b1759506..7f33a06e72 100644
--- a/web/app/components/workflow/block-selector/hooks.ts
+++ b/web/app/components/workflow/block-selector/hooks.ts
@@ -1,21 +1,9 @@
import { useTranslation } from 'react-i18next'
-import { BLOCKS } from './constants'
import {
TabsEnum,
ToolTypeEnum,
} from './types'
-export const useBlocks = () => {
- const { t } = useTranslation()
-
- return BLOCKS.map((block) => {
- return {
- ...block,
- title: t(`workflow.blocks.${block.type}`),
- }
- })
-}
-
export const useTabs = () => {
const { t } = useTranslation()
diff --git a/web/app/components/workflow/block-selector/index.tsx b/web/app/components/workflow/block-selector/index.tsx
index f0f57adefe..c930e4b740 100644
--- a/web/app/components/workflow/block-selector/index.tsx
+++ b/web/app/components/workflow/block-selector/index.tsx
@@ -1,171 +1,36 @@
-import type {
- FC,
- MouseEventHandler,
-} from 'react'
-import {
- memo,
- useCallback,
- useMemo,
- useState,
-} from 'react'
-import { useTranslation } from 'react-i18next'
-import type {
- OffsetOptions,
- Placement,
-} from '@floating-ui/react'
-import type { BlockEnum, OnSelectBlock } from '../types'
-import Tabs from './tabs'
-import { TabsEnum } from './types'
-import {
- PortalToFollowElem,
- PortalToFollowElemContent,
- PortalToFollowElemTrigger,
-} from '@/app/components/base/portal-to-follow-elem'
-import Input from '@/app/components/base/input'
-import SearchBox from '@/app/components/plugins/marketplace/search-box'
+import { useMemo } from 'react'
+import type { NodeSelectorProps } from './main'
+import NodeSelector from './main'
+import { useHooksStore } from '@/app/components/workflow/hooks-store/store'
+import { BlockEnum } from '@/app/components/workflow/types'
-import {
- Plus02,
-} from '@/app/components/base/icons/src/vender/line/general'
+const NodeSelectorWrapper = (props: NodeSelectorProps) => {
+ const availableNodesMetaData = useHooksStore(s => s.availableNodesMetaData)
-type NodeSelectorProps = {
- open?: boolean
- onOpenChange?: (open: boolean) => void
- onSelect: OnSelectBlock
- trigger?: (open: boolean) => React.ReactNode
- placement?: Placement
- offset?: OffsetOptions
- triggerStyle?: React.CSSProperties
- triggerClassName?: (open: boolean) => string
- triggerInnerClassName?: string
- popupClassName?: string
- asChild?: boolean
- availableBlocksTypes?: BlockEnum[]
- disabled?: boolean
- noBlocks?: boolean
-}
-const NodeSelector: FC
= ({
- open: openFromProps,
- onOpenChange,
- onSelect,
- trigger,
- placement = 'right',
- offset = 6,
- triggerClassName,
- triggerInnerClassName,
- triggerStyle,
- popupClassName,
- asChild,
- availableBlocksTypes,
- disabled,
- noBlocks = false,
-}) => {
- const { t } = useTranslation()
- const [searchText, setSearchText] = useState('')
- const [tags, setTags] = useState([])
- const [localOpen, setLocalOpen] = useState(false)
- const open = openFromProps === undefined ? localOpen : openFromProps
- const handleOpenChange = useCallback((newOpen: boolean) => {
- setLocalOpen(newOpen)
+ const blocks = useMemo(() => {
+ const result = availableNodesMetaData?.nodes || []
+ console.log(result, 'result')
- if (!newOpen)
- setSearchText('')
+ return result.filter((block) => {
+ if (block.type === BlockEnum.Start)
+ return false
- if (onOpenChange)
- onOpenChange(newOpen)
- }, [onOpenChange])
- const handleTrigger = useCallback>((e) => {
- if (disabled)
- return
- e.stopPropagation()
- handleOpenChange(!open)
- }, [handleOpenChange, open, disabled])
- const handleSelect = useCallback((type, toolDefaultValue) => {
- handleOpenChange(false)
- onSelect(type, toolDefaultValue)
- }, [handleOpenChange, onSelect])
+ if (block.type === BlockEnum.IterationStart)
+ return false
- const [activeTab, setActiveTab] = useState(noBlocks ? TabsEnum.Tools : TabsEnum.Blocks)
- const handleActiveTabChange = useCallback((newActiveTab: TabsEnum) => {
- setActiveTab(newActiveTab)
- }, [])
- const searchPlaceholder = useMemo(() => {
- if (activeTab === TabsEnum.Blocks)
- return t('workflow.tabs.searchBlock')
+ if (block.type === BlockEnum.LoopStart)
+ return false
- if (activeTab === TabsEnum.Tools)
- return t('workflow.tabs.searchTool')
- return ''
- }, [activeTab, t])
+ return true
+ })
+ }, [availableNodesMetaData?.nodes])
return (
-
-
- {
- trigger
- ? trigger(open)
- : (
-
- )
- }
-
-
-
-
e.stopPropagation()}>
- {activeTab === TabsEnum.Blocks && (
- setSearchText(e.target.value)}
- onClear={() => setSearchText('')}
- />
- )}
- {activeTab === TabsEnum.Tools && (
-
- )}
-
-
-
-
-
-
+
)
}
-export default memo(NodeSelector)
+export default NodeSelectorWrapper
diff --git a/web/app/components/workflow/block-selector/main.tsx b/web/app/components/workflow/block-selector/main.tsx
new file mode 100644
index 0000000000..88dc7d06dc
--- /dev/null
+++ b/web/app/components/workflow/block-selector/main.tsx
@@ -0,0 +1,175 @@
+import type {
+ FC,
+ MouseEventHandler,
+} from 'react'
+import {
+ memo,
+ useCallback,
+ useMemo,
+ useState,
+} from 'react'
+import { useTranslation } from 'react-i18next'
+import type {
+ OffsetOptions,
+ Placement,
+} from '@floating-ui/react'
+import type {
+ BlockEnum,
+ NodeDefault,
+ OnSelectBlock,
+} from '../types'
+import Tabs from './tabs'
+import { TabsEnum } from './types'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Input from '@/app/components/base/input'
+import SearchBox from '@/app/components/plugins/marketplace/search-box'
+
+import {
+ Plus02,
+} from '@/app/components/base/icons/src/vender/line/general'
+
+export type NodeSelectorProps = {
+ open?: boolean
+ onOpenChange?: (open: boolean) => void
+ onSelect: OnSelectBlock
+ trigger?: (open: boolean) => React.ReactNode
+ placement?: Placement
+ offset?: OffsetOptions
+ triggerStyle?: React.CSSProperties
+ triggerClassName?: (open: boolean) => string
+ triggerInnerClassName?: string
+ popupClassName?: string
+ asChild?: boolean
+ availableBlocksTypes?: BlockEnum[]
+ disabled?: boolean
+ blocks?: NodeDefault[]
+}
+const NodeSelector: FC = ({
+ open: openFromProps,
+ onOpenChange,
+ onSelect,
+ trigger,
+ placement = 'right',
+ offset = 6,
+ triggerClassName,
+ triggerInnerClassName,
+ triggerStyle,
+ popupClassName,
+ asChild,
+ availableBlocksTypes,
+ disabled,
+ blocks = [],
+}) => {
+ const { t } = useTranslation()
+ const [searchText, setSearchText] = useState('')
+ const [tags, setTags] = useState([])
+ const [localOpen, setLocalOpen] = useState(false)
+ const open = openFromProps === undefined ? localOpen : openFromProps
+ const handleOpenChange = useCallback((newOpen: boolean) => {
+ setLocalOpen(newOpen)
+
+ if (!newOpen)
+ setSearchText('')
+
+ if (onOpenChange)
+ onOpenChange(newOpen)
+ }, [onOpenChange])
+ const handleTrigger = useCallback>((e) => {
+ if (disabled)
+ return
+ e.stopPropagation()
+ handleOpenChange(!open)
+ }, [handleOpenChange, open, disabled])
+ const handleSelect = useCallback((type, toolDefaultValue) => {
+ handleOpenChange(false)
+ onSelect(type, toolDefaultValue)
+ }, [handleOpenChange, onSelect])
+
+ const [activeTab, setActiveTab] = useState(!blocks.length ? TabsEnum.Tools : TabsEnum.Blocks)
+ const handleActiveTabChange = useCallback((newActiveTab: TabsEnum) => {
+ setActiveTab(newActiveTab)
+ }, [])
+ const searchPlaceholder = useMemo(() => {
+ if (activeTab === TabsEnum.Blocks)
+ return t('workflow.tabs.searchBlock')
+
+ if (activeTab === TabsEnum.Tools)
+ return t('workflow.tabs.searchTool')
+ return ''
+ }, [activeTab, t])
+
+ return (
+
+
+ {
+ trigger
+ ? trigger(open)
+ : (
+
+ )
+ }
+
+
+
+
e.stopPropagation()}>
+ {activeTab === TabsEnum.Blocks && (
+ setSearchText(e.target.value)}
+ onClear={() => setSearchText('')}
+ />
+ )}
+ {activeTab === TabsEnum.Tools && (
+
+ )}
+
+
+
+
+
+
+ )
+}
+
+export default memo(NodeSelector)
diff --git a/web/app/components/workflow/block-selector/tabs.tsx b/web/app/components/workflow/block-selector/tabs.tsx
index 67aaaba1a5..db2f3d8535 100644
--- a/web/app/components/workflow/block-selector/tabs.tsx
+++ b/web/app/components/workflow/block-selector/tabs.tsx
@@ -1,7 +1,10 @@
import type { FC } from 'react'
import { memo } from 'react'
import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools } from '@/service/use-tools'
-import type { BlockEnum } from '../types'
+import type {
+ BlockEnum,
+ NodeDefault,
+} from '../types'
import { useTabs } from './hooks'
import type { ToolDefaultValue } from './types'
import { TabsEnum } from './types'
@@ -16,7 +19,7 @@ export type TabsProps = {
tags: string[]
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
availableBlocksTypes?: BlockEnum[]
- noBlocks?: boolean
+ blocks: NodeDefault[]
}
const Tabs: FC = ({
activeTab,
@@ -25,7 +28,7 @@ const Tabs: FC = ({
searchText,
onSelect,
availableBlocksTypes,
- noBlocks,
+ blocks,
}) => {
const tabs = useTabs()
const { data: buildInTools } = useAllBuiltInTools()
@@ -35,7 +38,7 @@ const Tabs: FC = ({
return (
e.stopPropagation()}>
{
- !noBlocks && (
+ !!blocks.length && (
{
tabs.map(tab => (
@@ -57,11 +60,12 @@ const Tabs: FC
= ({
)
}
{
- activeTab === TabsEnum.Blocks && !noBlocks && (
+ activeTab === TabsEnum.Blocks && !!blocks.length && (
)
}
diff --git a/web/app/components/workflow/blocks.tsx b/web/app/components/workflow/blocks.tsx
deleted file mode 100644
index 334ddbf087..0000000000
--- a/web/app/components/workflow/blocks.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { BlockEnum } from './types'
-
-export const ALL_AVAILABLE_BLOCKS = Object.values(BlockEnum)
-export const ALL_CHAT_AVAILABLE_BLOCKS = ALL_AVAILABLE_BLOCKS.filter(key => key !== BlockEnum.End && key !== BlockEnum.Start) as BlockEnum[]
-export const ALL_COMPLETION_AVAILABLE_BLOCKS = ALL_AVAILABLE_BLOCKS.filter(key => key !== BlockEnum.Answer && key !== BlockEnum.Start) as BlockEnum[]
diff --git a/web/app/components/workflow/constants.ts b/web/app/components/workflow/constants.ts
index cdfd963cfa..6410192d89 100644
--- a/web/app/components/workflow/constants.ts
+++ b/web/app/components/workflow/constants.ts
@@ -1,405 +1,6 @@
import type { Var } from './types'
import { BlockEnum, VarType } from './types'
-import StartNodeDefault from './nodes/start/default'
-import AnswerDefault from './nodes/answer/default'
-import LLMDefault from './nodes/llm/default'
-import KnowledgeRetrievalDefault from './nodes/knowledge-retrieval/default'
-import QuestionClassifierDefault from './nodes/question-classifier/default'
-import IfElseDefault from './nodes/if-else/default'
-import CodeDefault from './nodes/code/default'
-import TemplateTransformDefault from './nodes/template-transform/default'
-import HttpRequestDefault from './nodes/http/default'
-import ParameterExtractorDefault from './nodes/parameter-extractor/default'
-import ToolDefault from './nodes/tool/default'
-import VariableAssignerDefault from './nodes/variable-assigner/default'
-import AssignerDefault from './nodes/assigner/default'
-import EndNodeDefault from './nodes/end/default'
-import IterationDefault from './nodes/iteration/default'
-import LoopDefault from './nodes/loop/default'
-import DocExtractorDefault from './nodes/document-extractor/default'
-import ListFilterDefault from './nodes/list-operator/default'
-import IterationStartDefault from './nodes/iteration-start/default'
-import AgentDefault from './nodes/agent/default'
-import LoopStartDefault from './nodes/loop-start/default'
-import LoopEndDefault from './nodes/loop-end/default'
-type NodesExtraData = {
- author: string
- about: string
- availablePrevNodes: BlockEnum[]
- availableNextNodes: BlockEnum[]
- getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[]
- getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[]
- checkValid: any
-}
-export const NODES_EXTRA_DATA: Record = {
- [BlockEnum.Start]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: StartNodeDefault.getAvailablePrevNodes,
- getAvailableNextNodes: StartNodeDefault.getAvailableNextNodes,
- checkValid: StartNodeDefault.checkValid,
- },
- [BlockEnum.End]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: EndNodeDefault.getAvailablePrevNodes,
- getAvailableNextNodes: EndNodeDefault.getAvailableNextNodes,
- checkValid: EndNodeDefault.checkValid,
- },
- [BlockEnum.Answer]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: AnswerDefault.getAvailablePrevNodes,
- getAvailableNextNodes: AnswerDefault.getAvailableNextNodes,
- checkValid: AnswerDefault.checkValid,
- },
- [BlockEnum.LLM]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: LLMDefault.getAvailablePrevNodes,
- getAvailableNextNodes: LLMDefault.getAvailableNextNodes,
- checkValid: LLMDefault.checkValid,
- },
- [BlockEnum.KnowledgeRetrieval]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: KnowledgeRetrievalDefault.getAvailablePrevNodes,
- getAvailableNextNodes: KnowledgeRetrievalDefault.getAvailableNextNodes,
- checkValid: KnowledgeRetrievalDefault.checkValid,
- },
- [BlockEnum.IfElse]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: IfElseDefault.getAvailablePrevNodes,
- getAvailableNextNodes: IfElseDefault.getAvailableNextNodes,
- checkValid: IfElseDefault.checkValid,
- },
- [BlockEnum.Iteration]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: IterationDefault.getAvailablePrevNodes,
- getAvailableNextNodes: IterationDefault.getAvailableNextNodes,
- checkValid: IterationDefault.checkValid,
- },
- [BlockEnum.IterationStart]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: IterationStartDefault.getAvailablePrevNodes,
- getAvailableNextNodes: IterationStartDefault.getAvailableNextNodes,
- checkValid: IterationStartDefault.checkValid,
- },
- [BlockEnum.Loop]: {
- author: 'AICT-Team',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: LoopDefault.getAvailablePrevNodes,
- getAvailableNextNodes: LoopDefault.getAvailableNextNodes,
- checkValid: LoopDefault.checkValid,
- },
- [BlockEnum.LoopStart]: {
- author: 'AICT-Team',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: LoopStartDefault.getAvailablePrevNodes,
- getAvailableNextNodes: LoopStartDefault.getAvailableNextNodes,
- checkValid: LoopStartDefault.checkValid,
- },
- [BlockEnum.LoopEnd]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: LoopEndDefault.getAvailablePrevNodes,
- getAvailableNextNodes: LoopEndDefault.getAvailableNextNodes,
- checkValid: LoopEndDefault.checkValid,
- },
- [BlockEnum.Code]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: CodeDefault.getAvailablePrevNodes,
- getAvailableNextNodes: CodeDefault.getAvailableNextNodes,
- checkValid: CodeDefault.checkValid,
- },
- [BlockEnum.TemplateTransform]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: TemplateTransformDefault.getAvailablePrevNodes,
- getAvailableNextNodes: TemplateTransformDefault.getAvailableNextNodes,
- checkValid: TemplateTransformDefault.checkValid,
- },
- [BlockEnum.QuestionClassifier]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: QuestionClassifierDefault.getAvailablePrevNodes,
- getAvailableNextNodes: QuestionClassifierDefault.getAvailableNextNodes,
- checkValid: QuestionClassifierDefault.checkValid,
- },
- [BlockEnum.HttpRequest]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: HttpRequestDefault.getAvailablePrevNodes,
- getAvailableNextNodes: HttpRequestDefault.getAvailableNextNodes,
- checkValid: HttpRequestDefault.checkValid,
- },
- [BlockEnum.VariableAssigner]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: VariableAssignerDefault.getAvailablePrevNodes,
- getAvailableNextNodes: VariableAssignerDefault.getAvailableNextNodes,
- checkValid: VariableAssignerDefault.checkValid,
- },
- [BlockEnum.Assigner]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: AssignerDefault.getAvailablePrevNodes,
- getAvailableNextNodes: AssignerDefault.getAvailableNextNodes,
- checkValid: AssignerDefault.checkValid,
- },
- [BlockEnum.VariableAggregator]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: VariableAssignerDefault.getAvailablePrevNodes,
- getAvailableNextNodes: VariableAssignerDefault.getAvailableNextNodes,
- checkValid: VariableAssignerDefault.checkValid,
- },
- [BlockEnum.ParameterExtractor]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: ParameterExtractorDefault.getAvailablePrevNodes,
- getAvailableNextNodes: ParameterExtractorDefault.getAvailableNextNodes,
- checkValid: ParameterExtractorDefault.checkValid,
- },
- [BlockEnum.Tool]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: ToolDefault.getAvailablePrevNodes,
- getAvailableNextNodes: ToolDefault.getAvailableNextNodes,
- checkValid: ToolDefault.checkValid,
- },
- [BlockEnum.DocExtractor]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: DocExtractorDefault.getAvailablePrevNodes,
- getAvailableNextNodes: DocExtractorDefault.getAvailableNextNodes,
- checkValid: DocExtractorDefault.checkValid,
- },
- [BlockEnum.ListFilter]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: ListFilterDefault.getAvailablePrevNodes,
- getAvailableNextNodes: ListFilterDefault.getAvailableNextNodes,
- checkValid: ListFilterDefault.checkValid,
- },
- [BlockEnum.Agent]: {
- author: 'Dify',
- about: '',
- availablePrevNodes: [],
- availableNextNodes: [],
- getAvailablePrevNodes: ListFilterDefault.getAvailablePrevNodes,
- getAvailableNextNodes: ListFilterDefault.getAvailableNextNodes,
- checkValid: AgentDefault.checkValid,
- },
-}
-
-export const NODES_INITIAL_DATA = {
- [BlockEnum.Start]: {
- type: BlockEnum.Start,
- title: '',
- desc: '',
- ...StartNodeDefault.defaultValue,
- },
- [BlockEnum.End]: {
- type: BlockEnum.End,
- title: '',
- desc: '',
- ...EndNodeDefault.defaultValue,
- },
- [BlockEnum.Answer]: {
- type: BlockEnum.Answer,
- title: '',
- desc: '',
- ...AnswerDefault.defaultValue,
- },
- [BlockEnum.LLM]: {
- type: BlockEnum.LLM,
- title: '',
- desc: '',
- variables: [],
- ...LLMDefault.defaultValue,
- },
- [BlockEnum.KnowledgeRetrieval]: {
- type: BlockEnum.KnowledgeRetrieval,
- title: '',
- desc: '',
- query_variable_selector: [],
- dataset_ids: [],
- retrieval_mode: 'single',
- ...KnowledgeRetrievalDefault.defaultValue,
- },
- [BlockEnum.IfElse]: {
- type: BlockEnum.IfElse,
- title: '',
- desc: '',
- ...IfElseDefault.defaultValue,
- },
- [BlockEnum.Iteration]: {
- type: BlockEnum.Iteration,
- title: '',
- desc: '',
- ...IterationDefault.defaultValue,
- },
- [BlockEnum.IterationStart]: {
- type: BlockEnum.IterationStart,
- title: '',
- desc: '',
- ...IterationStartDefault.defaultValue,
- },
- [BlockEnum.Loop]: {
- type: BlockEnum.Loop,
- title: '',
- desc: '',
- ...LoopDefault.defaultValue,
- },
- [BlockEnum.LoopStart]: {
- type: BlockEnum.LoopStart,
- title: '',
- desc: '',
- ...LoopStartDefault.defaultValue,
- },
- [BlockEnum.LoopEnd]: {
- type: BlockEnum.LoopEnd,
- title: '',
- desc: '',
- ...LoopEndDefault.defaultValue,
- },
- [BlockEnum.Code]: {
- type: BlockEnum.Code,
- title: '',
- desc: '',
- variables: [],
- code_language: 'python3',
- code: '',
- outputs: [],
- ...CodeDefault.defaultValue,
- },
- [BlockEnum.TemplateTransform]: {
- type: BlockEnum.TemplateTransform,
- title: '',
- desc: '',
- variables: [],
- template: '',
- ...TemplateTransformDefault.defaultValue,
- },
- [BlockEnum.QuestionClassifier]: {
- type: BlockEnum.QuestionClassifier,
- title: '',
- desc: '',
- query_variable_selector: [],
- topics: [],
- ...QuestionClassifierDefault.defaultValue,
- },
- [BlockEnum.HttpRequest]: {
- type: BlockEnum.HttpRequest,
- title: '',
- desc: '',
- variables: [],
- ...HttpRequestDefault.defaultValue,
- },
- [BlockEnum.ParameterExtractor]: {
- type: BlockEnum.ParameterExtractor,
- title: '',
- desc: '',
- variables: [],
- ...ParameterExtractorDefault.defaultValue,
- },
- [BlockEnum.VariableAssigner]: {
- type: BlockEnum.VariableAssigner,
- title: '',
- desc: '',
- variables: [],
- output_type: '',
- ...VariableAssignerDefault.defaultValue,
- },
- [BlockEnum.VariableAggregator]: {
- type: BlockEnum.VariableAggregator,
- title: '',
- desc: '',
- variables: [],
- output_type: '',
- ...VariableAssignerDefault.defaultValue,
- },
- [BlockEnum.Assigner]: {
- type: BlockEnum.Assigner,
- title: '',
- desc: '',
- ...AssignerDefault.defaultValue,
- },
- [BlockEnum.Tool]: {
- type: BlockEnum.Tool,
- title: '',
- desc: '',
- ...ToolDefault.defaultValue,
- },
- [BlockEnum.DocExtractor]: {
- type: BlockEnum.DocExtractor,
- title: '',
- desc: '',
- ...DocExtractorDefault.defaultValue,
- },
- [BlockEnum.ListFilter]: {
- type: BlockEnum.ListFilter,
- title: '',
- desc: '',
- ...ListFilterDefault.defaultValue,
- },
- [BlockEnum.Agent]: {
- type: BlockEnum.Agent,
- title: '',
- desc: '',
- ...AgentDefault.defaultValue,
- },
-}
export const MAX_ITERATION_PARALLEL_NUM = 10
export const MIN_ITERATION_PARALLEL_NUM = 1
export const DEFAULT_ITER_TIMES = 1
diff --git a/web/app/components/workflow/constants/node.ts b/web/app/components/workflow/constants/node.ts
new file mode 100644
index 0000000000..fee3a51f6d
--- /dev/null
+++ b/web/app/components/workflow/constants/node.ts
@@ -0,0 +1,42 @@
+import llmDefault from '@/app/components/workflow/nodes/llm/default'
+import knowledgeRetrievalDefault from '@/app/components/workflow/nodes/knowledge-retrieval/default'
+import agentDefault from '@/app/components/workflow/nodes/agent/default'
+
+import questionClassifierDefault from '@/app/components/workflow/nodes/question-classifier/default'
+
+import ifElseDefault from '@/app/components/workflow/nodes/if-else/default'
+import iterationDefault from '@/app/components/workflow/nodes/iteration/default'
+import iterationStartDefault from '@/app/components/workflow/nodes/iteration-start/default'
+import loopDefault from '@/app/components/workflow/nodes/loop/default'
+import loopStartDefault from '@/app/components/workflow/nodes/loop-start/default'
+import loopEndDefault from '@/app/components/workflow/nodes/loop-end/default'
+
+import codeDefault from '@/app/components/workflow/nodes/code/default'
+import templateTransformDefault from '@/app/components/workflow/nodes/template-transform/default'
+import variableAggregatorDefault from '@/app/components/workflow/nodes/variable-assigner/default'
+import documentExtractorDefault from '@/app/components/workflow/nodes/document-extractor/default'
+import assignerDefault from '@/app/components/workflow/nodes/assigner/default'
+import httpRequestDefault from '@/app/components/workflow/nodes/http/default'
+import parameterExtractorDefault from '@/app/components/workflow/nodes/parameter-extractor/default'
+import listOperatorDefault from '@/app/components/workflow/nodes/list-operator/default'
+
+export const WORKFLOW_COMMON_NODES = [
+ llmDefault,
+ knowledgeRetrievalDefault,
+ agentDefault,
+ questionClassifierDefault,
+ ifElseDefault,
+ iterationDefault,
+ iterationStartDefault,
+ loopDefault,
+ loopStartDefault,
+ loopEndDefault,
+ codeDefault,
+ templateTransformDefault,
+ variableAggregatorDefault,
+ documentExtractorDefault,
+ assignerDefault,
+ parameterExtractorDefault,
+ httpRequestDefault,
+ listOperatorDefault,
+]
diff --git a/web/app/components/workflow/custom-edge.tsx b/web/app/components/workflow/custom-edge.tsx
index 4467b0adb5..fa04b46fea 100644
--- a/web/app/components/workflow/custom-edge.tsx
+++ b/web/app/components/workflow/custom-edge.tsx
@@ -56,8 +56,9 @@ const CustomEdge = ({
})
const [open, setOpen] = useState(false)
const { handleNodeAdd } = useNodesInteractions()
- const { availablePrevBlocks } = useAvailableBlocks((data as Edge['data'])!.targetType, (data as Edge['data'])?.isInIteration, (data as Edge['data'])?.isInLoop)
- const { availableNextBlocks } = useAvailableBlocks((data as Edge['data'])!.sourceType, (data as Edge['data'])?.isInIteration, (data as Edge['data'])?.isInLoop)
+ const { availablePrevBlocks } = useAvailableBlocks((data as Edge['data'])!.targetType, (data as Edge['data'])?.isInIteration || (data as Edge['data'])?.isInLoop)
+ const { availableNextBlocks } = useAvailableBlocks((data as Edge['data'])!.sourceType, (data as Edge['data'])?.isInIteration || (data as Edge['data'])?.isInLoop)
+ console.log(availableNextBlocks, 'xx')
const {
_sourceRunningStatus,
_targetRunningStatus,
diff --git a/web/app/components/workflow/hooks-store/store.ts b/web/app/components/workflow/hooks-store/store.ts
index 2e40cbfbc9..775d24a3ce 100644
--- a/web/app/components/workflow/hooks-store/store.ts
+++ b/web/app/components/workflow/hooks-store/store.ts
@@ -7,8 +7,16 @@ import {
} from 'zustand'
import { createStore } from 'zustand/vanilla'
import { HooksStoreContext } from './provider'
+import type {
+ BlockEnum,
+ NodeDefault,
+} from '@/app/components/workflow/types'
-type CommonHooksFnMap = {
+export type AvailableNodesMetaData = {
+ nodes: NodeDefault[]
+ nodesMap?: Record>
+}
+export type CommonHooksFnMap = {
doSyncWorkflowDraft: (
notRefreshWhenSyncError?: boolean,
callback?: {
@@ -26,6 +34,7 @@ type CommonHooksFnMap = {
handleStartWorkflowRun: () => void
handleWorkflowStartRunInWorkflow: () => void
handleWorkflowStartRunInChatflow: () => void
+ availableNodesMetaData?: AvailableNodesMetaData
}
export type Shape = {
@@ -43,6 +52,9 @@ export const createHooksStore = ({
handleStartWorkflowRun = noop,
handleWorkflowStartRunInWorkflow = noop,
handleWorkflowStartRunInChatflow = noop,
+ availableNodesMetaData = {
+ nodes: [],
+ },
}: Partial) => {
return createStore(set => ({
refreshAll: props => set(state => ({ ...state, ...props })),
@@ -56,6 +68,7 @@ export const createHooksStore = ({
handleStartWorkflowRun,
handleWorkflowStartRunInWorkflow,
handleWorkflowStartRunInChatflow,
+ availableNodesMetaData,
}))
}
diff --git a/web/app/components/workflow/hooks/index.ts b/web/app/components/workflow/hooks/index.ts
index 20a34c69e3..2b58e20db6 100644
--- a/web/app/components/workflow/hooks/index.ts
+++ b/web/app/components/workflow/hooks/index.ts
@@ -1,7 +1,6 @@
export * from './use-edges-interactions'
export * from './use-node-data-update'
export * from './use-nodes-interactions'
-export * from './use-nodes-data'
export * from './use-nodes-sync-draft'
export * from './use-workflow'
export * from './use-workflow-run'
@@ -16,3 +15,5 @@ export * from './use-shortcuts'
export * from './use-workflow-interactions'
export * from './use-workflow-mode'
export * from './use-format-time-from-now'
+export * from './use-nodes-meta-data'
+export * from './use-available-blocks'
diff --git a/web/app/components/workflow/hooks/use-available-blocks.ts b/web/app/components/workflow/hooks/use-available-blocks.ts
new file mode 100644
index 0000000000..aa15eb3b7e
--- /dev/null
+++ b/web/app/components/workflow/hooks/use-available-blocks.ts
@@ -0,0 +1,58 @@
+import {
+ useCallback,
+ useMemo,
+} from 'react'
+import { BlockEnum } from '../types'
+import { useNodesMetaData } from './use-nodes-meta-data'
+
+const availableBlocksFilter = (nodeType: BlockEnum, inContainer?: boolean) => {
+ if (inContainer && (nodeType === BlockEnum.Iteration || nodeType === BlockEnum.Loop || nodeType === BlockEnum.End))
+ return false
+
+ if (!inContainer && nodeType === BlockEnum.LoopEnd)
+ return false
+
+ return true
+}
+
+export const useAvailableBlocks = (nodeType?: BlockEnum, inContainer?: boolean) => {
+ const {
+ nodes: availableNodes,
+ } = useNodesMetaData()
+ const availableNodesType = useMemo(() => availableNodes.map(node => node.type), [availableNodes])
+ const availablePrevBlocks = useMemo(() => {
+ if (!nodeType || nodeType === BlockEnum.Start)
+ return []
+
+ return availableNodesType
+ }, [availableNodesType, nodeType])
+ const availableNextBlocks = useMemo(() => {
+ if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd)
+ return []
+
+ return availableNodesType
+ }, [availableNodesType, nodeType])
+
+ const getAvailableBlocks = useCallback((nodeType?: BlockEnum, inContainer?: boolean) => {
+ let availablePrevBlocks = availableNodesType
+ if (!nodeType || nodeType === BlockEnum.Start)
+ availablePrevBlocks = []
+
+ let availableNextBlocks = availableNodesType
+ if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd)
+ availableNextBlocks = []
+
+ return {
+ availablePrevBlocks: availablePrevBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
+ availableNextBlocks: availableNextBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
+ }
+ }, [availableNodesType])
+
+ return useMemo(() => {
+ return {
+ getAvailableBlocks,
+ availablePrevBlocks: availablePrevBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
+ availableNextBlocks: availableNextBlocks.filter(nType => availableBlocksFilter(nType, inContainer)),
+ }
+ }, [getAvailableBlocks, availablePrevBlocks, availableNextBlocks, inContainer])
+}
diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts
index c1b0189b8b..9aebd935a5 100644
--- a/web/app/components/workflow/hooks/use-checklist.ts
+++ b/web/app/components/workflow/hooks/use-checklist.ts
@@ -22,7 +22,7 @@ import {
} from '../constants'
import type { ToolNodeType } from '../nodes/tool/types'
import { useIsChatMode } from './use-workflow'
-import { useNodesExtraData } from './use-nodes-data'
+import { useNodesMetaData } from './use-nodes-meta-data'
import { useToastContext } from '@/app/components/base/toast'
import { CollectionType } from '@/app/components/tools/types'
import { useGetLanguage } from '@/context/i18n'
@@ -37,7 +37,7 @@ import { fetchDatasets } from '@/service/datasets'
export const useChecklist = (nodes: Node[], edges: Edge[]) => {
const { t } = useTranslation()
const language = useGetLanguage()
- const nodesExtraData = useNodesExtraData()
+ const { nodesMap: nodesExtraData } = useNodesMetaData()
const isChatMode = useIsChatMode()
const buildInTools = useStore(s => s.buildInTools)
const customTools = useStore(s => s.customTools)
@@ -100,7 +100,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
if (node.type === CUSTOM_NODE) {
const checkData = getCheckData(node.data)
- const { errorMessage } = nodesExtraData[node.data.type].checkValid(checkData, t, moreDataForCheckValid)
+ const { errorMessage } = nodesExtraData![node.data.type].checkValid(checkData, t, moreDataForCheckValid)
if (errorMessage || !validNodes.find(n => n.id === node.id)) {
list.push({
@@ -148,7 +148,7 @@ export const useChecklistBeforePublish = () => {
const { notify } = useToastContext()
const isChatMode = useIsChatMode()
const store = useStoreApi()
- const nodesExtraData = useNodesExtraData()
+ const { nodesMap: nodesExtraData } = useNodesMetaData()
const { data: strategyProviders } = useStrategyProviders()
const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail)
const updateTime = useRef(0)
@@ -228,7 +228,7 @@ export const useChecklistBeforePublish = () => {
}
const checkData = getCheckData(node.data, datasets)
- const { errorMessage } = nodesExtraData[node.data.type as BlockEnum].checkValid(checkData, t, moreDataForCheckValid)
+ const { errorMessage } = nodesExtraData![node.data.type as BlockEnum].checkValid(checkData, t, moreDataForCheckValid)
if (errorMessage) {
notify({ type: 'error', message: `[${node.data.title}] ${errorMessage}` })
diff --git a/web/app/components/workflow/hooks/use-nodes-data.ts b/web/app/components/workflow/hooks/use-nodes-data.ts
deleted file mode 100644
index aeb45ddb93..0000000000
--- a/web/app/components/workflow/hooks/use-nodes-data.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import produce from 'immer'
-import { BlockEnum } from '../types'
-import {
- NODES_EXTRA_DATA,
- NODES_INITIAL_DATA,
-} from '../constants'
-import { useIsChatMode } from './use-workflow'
-
-export const useNodesInitialData = () => {
- const { t } = useTranslation()
-
- return useMemo(() => produce(NODES_INITIAL_DATA, (draft) => {
- Object.keys(draft).forEach((key) => {
- draft[key as BlockEnum].title = t(`workflow.blocks.${key}`)
- })
- }), [t])
-}
-
-export const useNodesExtraData = () => {
- const { t } = useTranslation()
- const isChatMode = useIsChatMode()
-
- return useMemo(() => produce(NODES_EXTRA_DATA, (draft) => {
- Object.keys(draft).forEach((key) => {
- draft[key as BlockEnum].about = t(`workflow.blocksAbout.${key}`)
- draft[key as BlockEnum].availablePrevNodes = draft[key as BlockEnum].getAvailablePrevNodes(isChatMode)
- draft[key as BlockEnum].availableNextNodes = draft[key as BlockEnum].getAvailableNextNodes(isChatMode)
- })
- }), [t, isChatMode])
-}
-
-export const useAvailableBlocks = (nodeType?: BlockEnum, isInIteration?: boolean, isInLoop?: boolean) => {
- const nodesExtraData = useNodesExtraData()
- const availablePrevBlocks = useMemo(() => {
- if (!nodeType)
- return []
- return nodesExtraData[nodeType].availablePrevNodes || []
- }, [nodeType, nodesExtraData])
-
- const availableNextBlocks = useMemo(() => {
- if (!nodeType)
- return []
-
- return nodesExtraData[nodeType].availableNextNodes || []
- }, [nodeType, nodesExtraData])
-
- return useMemo(() => {
- return {
- availablePrevBlocks: availablePrevBlocks.filter((nType) => {
- if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
- return false
-
- if (isInLoop && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
- return false
-
- if (!isInLoop && nType === BlockEnum.LoopEnd)
- return false
-
- return true
- }),
- availableNextBlocks: availableNextBlocks.filter((nType) => {
- if (isInIteration && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
- return false
-
- if (isInLoop && (nType === BlockEnum.Iteration || nType === BlockEnum.Loop || nType === BlockEnum.End))
- return false
-
- if (!isInLoop && nType === BlockEnum.LoopEnd)
- return false
-
- return true
- }),
- }
- }, [isInIteration, availablePrevBlocks, availableNextBlocks, isInLoop])
-}
diff --git a/web/app/components/workflow/hooks/use-nodes-interactions.ts b/web/app/components/workflow/hooks/use-nodes-interactions.ts
index 94b10c9929..b220d47a08 100644
--- a/web/app/components/workflow/hooks/use-nodes-interactions.ts
+++ b/web/app/components/workflow/hooks/use-nodes-interactions.ts
@@ -31,7 +31,6 @@ import {
ITERATION_PADDING,
LOOP_CHILDREN_Z_INDEX,
LOOP_PADDING,
- NODES_INITIAL_DATA,
NODE_WIDTH_X_OFFSET,
X_OFFSET,
Y_OFFSET,
@@ -60,6 +59,7 @@ import {
useWorkflowReadOnly,
} from './use-workflow'
import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
+import { useNodesMetaData } from './use-nodes-meta-data'
export const useNodesInteractions = () => {
const { t } = useTranslation()
@@ -84,6 +84,7 @@ export const useNodesInteractions = () => {
handleNodeLoopChildrenCopy,
} = useNodeLoopInteractions()
const dragNodeStartPosition = useRef({ x: 0, y: 0 } as { x: number; y: number })
+ const { nodesMap: nodesMetaDataMap } = useNodesMetaData()
const { saveStateToHistory, undo, redo } = useWorkflowHistory()
@@ -682,6 +683,10 @@ export const useNodesInteractions = () => {
} = store.getState()
const nodes = getNodes()
const nodesWithSameType = nodes.filter(node => node.data.type === nodeType)
+ const {
+ defaultValue,
+ title,
+ } = nodesMetaDataMap![nodeType]
const {
newNode,
newIterationStartNode,
@@ -689,8 +694,8 @@ export const useNodesInteractions = () => {
} = generateNewNode({
type: getNodeCustomTypeByNodeDataType(nodeType),
data: {
- ...NODES_INITIAL_DATA[nodeType],
- title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
+ ...(defaultValue as any),
+ title: nodesWithSameType.length > 0 ? `${title} ${nodesWithSameType.length + 1}` : title,
...(toolDefaultValue || {}),
selected: true,
_showAddVariablePopup: (nodeType === BlockEnum.VariableAssigner || nodeType === BlockEnum.VariableAggregator) && !!prevNodeId,
@@ -1093,7 +1098,7 @@ export const useNodesInteractions = () => {
}
handleSyncWorkflowDraft()
saveStateToHistory(WorkflowHistoryEvent.NodeAdd)
- }, [getNodesReadOnly, store, t, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, getAfterNodesInSameBranch, checkNestedParallelLimit])
+ }, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, getAfterNodesInSameBranch, checkNestedParallelLimit, nodesMetaDataMap])
const handleNodeChange = useCallback((
currentNodeId: string,
@@ -1114,6 +1119,10 @@ export const useNodesInteractions = () => {
const currentNode = nodes.find(node => node.id === currentNodeId)!
const connectedEdges = getConnectedEdges([currentNode], edges)
const nodesWithSameType = nodes.filter(node => node.data.type === nodeType)
+ const {
+ defaultValue,
+ title,
+ } = nodesMetaDataMap![nodeType]
const {
newNode: newCurrentNode,
newIterationStartNode,
@@ -1121,8 +1130,8 @@ export const useNodesInteractions = () => {
} = generateNewNode({
type: getNodeCustomTypeByNodeDataType(nodeType),
data: {
- ...NODES_INITIAL_DATA[nodeType],
- title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
+ ...(defaultValue as any),
+ title: nodesWithSameType.length > 0 ? `${title} ${nodesWithSameType.length + 1}` : title,
...(toolDefaultValue || {}),
_connectedSourceHandleIds: [],
_connectedTargetHandleIds: [],
@@ -1175,7 +1184,7 @@ export const useNodesInteractions = () => {
handleSyncWorkflowDraft()
saveStateToHistory(WorkflowHistoryEvent.NodeChange)
- }, [getNodesReadOnly, store, t, handleSyncWorkflowDraft, saveStateToHistory])
+ }, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, nodesMetaDataMap])
const handleNodesCancelSelected = useCallback(() => {
const {
@@ -1285,7 +1294,7 @@ export const useNodesInteractions = () => {
} = generateNewNode({
type: nodeToPaste.type,
data: {
- ...NODES_INITIAL_DATA[nodeType],
+ ...nodesMetaDataMap![nodeType].defaultValue,
...nodeToPaste.data,
selected: false,
_isBundled: false,
@@ -1361,7 +1370,7 @@ export const useNodesInteractions = () => {
saveStateToHistory(WorkflowHistoryEvent.NodePaste)
handleSyncWorkflowDraft()
}
- }, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy, handleNodeLoopChildrenCopy])
+ }, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy, handleNodeLoopChildrenCopy, nodesMetaDataMap])
const handleNodesDuplicate = useCallback((nodeId?: string) => {
if (getNodesReadOnly())
diff --git a/web/app/components/workflow/hooks/use-nodes-meta-data.ts b/web/app/components/workflow/hooks/use-nodes-meta-data.ts
new file mode 100644
index 0000000000..1e140ffaf1
--- /dev/null
+++ b/web/app/components/workflow/hooks/use-nodes-meta-data.ts
@@ -0,0 +1,14 @@
+import { useMemo } from 'react'
+import type { AvailableNodesMetaData } from '@/app/components/workflow/hooks-store'
+import { useHooksStore } from '@/app/components/workflow/hooks-store'
+
+export const useNodesMetaData = () => {
+ const availableNodesMetaData = useHooksStore(s => s.availableNodesMetaData)
+
+ return useMemo(() => {
+ return {
+ nodes: availableNodesMetaData?.nodes || [],
+ nodesMap: availableNodesMetaData?.nodesMap || {},
+ } as AvailableNodesMetaData
+ }, [availableNodesMetaData])
+}
diff --git a/web/app/components/workflow/hooks/use-workflow.ts b/web/app/components/workflow/hooks/use-workflow.ts
index 99dce4dc15..9889c42cff 100644
--- a/web/app/components/workflow/hooks/use-workflow.ts
+++ b/web/app/components/workflow/hooks/use-workflow.ts
@@ -35,7 +35,7 @@ import {
} from '../constants'
import { CUSTOM_NOTE_NODE } from '../note-node/constants'
import { findUsedVarNodes, getNodeOutputVars, updateNodeVars } from '../nodes/_base/components/variable/utils'
-import { useNodesExtraData } from './use-nodes-data'
+import { useAvailableBlocks } from './use-available-blocks'
import { useStore as useAppStore } from '@/app/components/app/store'
import {
fetchAllBuiltInTools,
@@ -58,7 +58,7 @@ export const useWorkflow = () => {
const { t } = useTranslation()
const store = useStoreApi()
const workflowStore = useWorkflowStore()
- const nodesExtraData = useNodesExtraData()
+ const { getAvailableBlocks } = useAvailableBlocks()
const setPanelWidth = useCallback((width: number) => {
localStorage.setItem('workflow-node-panel-width', `${width}`)
workflowStore.setState({ panelWidth: width })
@@ -364,8 +364,8 @@ export const useWorkflow = () => {
return false
if (sourceNode && targetNode) {
- const sourceNodeAvailableNextNodes = nodesExtraData[sourceNode.data.type].availableNextNodes
- const targetNodeAvailablePrevNodes = [...nodesExtraData[targetNode.data.type].availablePrevNodes, BlockEnum.Start]
+ const sourceNodeAvailableNextNodes = getAvailableBlocks(sourceNode.data.type, !!sourceNode.parentId).availableNextBlocks
+ const targetNodeAvailablePrevNodes = getAvailableBlocks(targetNode.data.type, !!targetNode.parentId).availablePrevBlocks
if (!sourceNodeAvailableNextNodes.includes(targetNode.data.type))
return false
@@ -389,7 +389,7 @@ export const useWorkflow = () => {
}
return !hasCycle(targetNode)
- }, [store, nodesExtraData, checkParallelLimit])
+ }, [store, checkParallelLimit, getAvailableBlocks])
const getNode = useCallback((nodeId?: string) => {
const { getNodes } = store.getState()
diff --git a/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip.tsx b/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip.tsx
index b4448855c7..dc98c4003d 100644
--- a/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip.tsx
+++ b/web/app/components/workflow/nodes/_base/components/error-handle/error-handle-tip.tsx
@@ -17,7 +17,7 @@ const ErrorHandleTip = ({
if (type === ErrorHandleTypeEnum.defaultValue)
return t('workflow.nodes.common.errorHandle.defaultValue.inLog')
- }, [])
+ }, [t, type])
if (!type)
return null
diff --git a/web/app/components/workflow/nodes/_base/components/next-step/add.tsx b/web/app/components/workflow/nodes/_base/components/next-step/add.tsx
index de5fbacfa5..474ddc78d5 100644
--- a/web/app/components/workflow/nodes/_base/components/next-step/add.tsx
+++ b/web/app/components/workflow/nodes/_base/components/next-step/add.tsx
@@ -38,7 +38,7 @@ const Add = ({
const [open, setOpen] = useState(false)
const { handleNodeAdd } = useNodesInteractions()
const { nodesReadOnly } = useNodesReadOnly()
- const { availableNextBlocks } = useAvailableBlocks(nodeData.type, nodeData.isInIteration, nodeData.isInLoop)
+ const { availableNextBlocks } = useAvailableBlocks(nodeData.type, nodeData.isInIteration || nodeData.isInLoop)
const { checkParallelLimit } = useWorkflow()
const handleSelect = useCallback((type, toolDefaultValue) => {
diff --git a/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx b/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx
index 565db02602..c54a63d8ad 100644
--- a/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx
+++ b/web/app/components/workflow/nodes/_base/components/next-step/operator.tsx
@@ -36,7 +36,7 @@ const ChangeItem = ({
const {
availablePrevBlocks,
availableNextBlocks,
- } = useAvailableBlocks(data.type, data.isInIteration, data.isInLoop)
+ } = useAvailableBlocks(data.type, data.isInIteration || data.isInLoop)
const handleSelect = useCallback((type, toolDefaultValue) => {
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
diff --git a/web/app/components/workflow/nodes/_base/components/node-handle.tsx b/web/app/components/workflow/nodes/_base/components/node-handle.tsx
index 0dc099f5a0..351fe109a4 100644
--- a/web/app/components/workflow/nodes/_base/components/node-handle.tsx
+++ b/web/app/components/workflow/nodes/_base/components/node-handle.tsx
@@ -47,7 +47,7 @@ export const NodeTargetHandle = memo(({
const { handleNodeAdd } = useNodesInteractions()
const { getNodesReadOnly } = useNodesReadOnly()
const connected = data._connectedTargetHandleIds?.includes(handleId)
- const { availablePrevBlocks } = useAvailableBlocks(data.type, data.isInIteration, data.isInLoop)
+ const { availablePrevBlocks } = useAvailableBlocks(data.type, data.isInIteration || data.isInLoop)
const isConnectable = !!availablePrevBlocks.length
const handleOpenChange = useCallback((v: boolean) => {
@@ -129,7 +129,7 @@ export const NodeSourceHandle = memo(({
const [open, setOpen] = useState(false)
const { handleNodeAdd } = useNodesInteractions()
const { getNodesReadOnly } = useNodesReadOnly()
- const { availableNextBlocks } = useAvailableBlocks(data.type, data.isInIteration, data.isInLoop)
+ const { availableNextBlocks } = useAvailableBlocks(data.type, data.isInIteration || data.isInLoop)
const isConnectable = !!availableNextBlocks.length
const isChatMode = useIsChatMode()
const { checkParallelLimit } = useWorkflow()
diff --git a/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx b/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx
index 90f9dae894..d7b2188ed5 100644
--- a/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx
+++ b/web/app/components/workflow/nodes/_base/components/panel-operator/change-block.tsx
@@ -30,7 +30,7 @@ const ChangeBlock = ({
const {
availablePrevBlocks,
availableNextBlocks,
- } = useAvailableBlocks(nodeData.type, nodeData.isInIteration, nodeData.isInLoop)
+ } = useAvailableBlocks(nodeData.type, nodeData.isInIteration || nodeData.isInLoop)
const availableNodes = useMemo(() => {
if (availablePrevBlocks.length && availableNextBlocks.length)
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 28d7358ddb..ad0f6c636f 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
@@ -12,8 +12,8 @@ import {
import { useStore } from '@/app/components/workflow/store'
import {
useNodeDataUpdate,
- useNodesExtraData,
useNodesInteractions,
+ useNodesMetaData,
useNodesReadOnly,
useNodesSyncDraft,
} from '@/app/components/workflow/hooks'
@@ -48,14 +48,14 @@ const PanelOperatorPopup = ({
const { handleNodeDataUpdate } = useNodeDataUpdate()
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
const { nodesReadOnly } = useNodesReadOnly()
- const nodesExtraData = useNodesExtraData()
+ const { nodesMap: nodesExtraData } = useNodesMetaData()
const buildInTools = useStore(s => s.buildInTools)
const customTools = useStore(s => s.customTools)
const workflowTools = useStore(s => s.workflowTools)
const edge = edges.find(edge => edge.target === id)
const author = useMemo(() => {
if (data.type !== BlockEnum.Tool)
- return nodesExtraData[data.type].author
+ return nodesExtraData![data.type].author
if (data.provider_type === CollectionType.builtIn)
return buildInTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.author
@@ -68,7 +68,7 @@ const PanelOperatorPopup = ({
const about = useMemo(() => {
if (data.type !== BlockEnum.Tool)
- return nodesExtraData[data.type].about
+ return nodesExtraData![data.type].description
if (data.provider_type === CollectionType.builtIn)
return buildInTools.find(toolWithProvider => canFindTool(toolWithProvider.id, data.provider_id))?.description[language]
diff --git a/web/app/components/workflow/nodes/_base/hooks/use-node-help-link.ts b/web/app/components/workflow/nodes/_base/hooks/use-node-help-link.ts
index 3c68fbd1fd..804d031a8e 100644
--- a/web/app/components/workflow/nodes/_base/hooks/use-node-help-link.ts
+++ b/web/app/components/workflow/nodes/_base/hooks/use-node-help-link.ts
@@ -1,69 +1,15 @@
import { useMemo } from 'react'
-import { useGetLanguage } from '@/context/i18n'
-import { BlockEnum } from '@/app/components/workflow/types'
+import type { BlockEnum } from '@/app/components/workflow/types'
+import { useNodesMetaData } from '@/app/components/workflow/hooks'
export const useNodeHelpLink = (nodeType: BlockEnum) => {
- const language = useGetLanguage()
- const prefixLink = useMemo(() => {
- if (language === 'zh_Hans')
- return 'https://docs.dify.ai/zh-hans/guides/workflow/node/'
+ const availableNodesMetaData = useNodesMetaData()
- return 'https://docs.dify.ai/guides/workflow/node/'
- }, [language])
- const linkMap = useMemo(() => {
- if (language === 'zh_Hans') {
- return {
- [BlockEnum.Start]: 'start',
- [BlockEnum.End]: 'end',
- [BlockEnum.Answer]: 'answer',
- [BlockEnum.LLM]: 'llm',
- [BlockEnum.KnowledgeRetrieval]: 'knowledge-retrieval',
- [BlockEnum.QuestionClassifier]: 'question-classifier',
- [BlockEnum.IfElse]: 'ifelse',
- [BlockEnum.Code]: 'code',
- [BlockEnum.TemplateTransform]: 'template',
- [BlockEnum.VariableAssigner]: 'variable-assigner',
- [BlockEnum.VariableAggregator]: 'variable-aggregator',
- [BlockEnum.Assigner]: 'variable-assigner',
- [BlockEnum.Iteration]: 'iteration',
- [BlockEnum.Loop]: 'loop',
- [BlockEnum.ParameterExtractor]: 'parameter-extractor',
- [BlockEnum.HttpRequest]: 'http-request',
- [BlockEnum.Tool]: 'tools',
- [BlockEnum.DocExtractor]: 'doc-extractor',
- [BlockEnum.ListFilter]: 'list-operator',
- [BlockEnum.Agent]: 'agent',
- }
- }
+ const link = useMemo(() => {
+ const result = availableNodesMetaData?.nodesMap?.[nodeType]?.helpLinkUri || ''
- return {
- [BlockEnum.Start]: 'start',
- [BlockEnum.End]: 'end',
- [BlockEnum.Answer]: 'answer',
- [BlockEnum.LLM]: 'llm',
- [BlockEnum.KnowledgeRetrieval]: 'knowledge-retrieval',
- [BlockEnum.QuestionClassifier]: 'question-classifier',
- [BlockEnum.IfElse]: 'ifelse',
- [BlockEnum.Code]: 'code',
- [BlockEnum.TemplateTransform]: 'template',
- [BlockEnum.VariableAssigner]: 'variable-assigner',
- [BlockEnum.VariableAggregator]: 'variable-aggregator',
- [BlockEnum.Assigner]: 'variable-assigner',
- [BlockEnum.Iteration]: 'iteration',
- [BlockEnum.Loop]: 'loop',
- [BlockEnum.ParameterExtractor]: 'parameter-extractor',
- [BlockEnum.HttpRequest]: 'http-request',
- [BlockEnum.Tool]: 'tools',
- [BlockEnum.DocExtractor]: 'doc-extractor',
- [BlockEnum.ListFilter]: 'list-operator',
- [BlockEnum.Agent]: 'agent',
- }
- }, [language]) as Record
+ return result
+ }, [availableNodesMetaData, nodeType])
- const link = linkMap[nodeType]
-
- if (!link)
- return ''
-
- return `${prefixLink}${link}`
+ return link
}
diff --git a/web/app/components/workflow/nodes/_base/panel.tsx b/web/app/components/workflow/nodes/_base/panel.tsx
index 2ee39a3b06..e109fafcb5 100644
--- a/web/app/components/workflow/nodes/_base/panel.tsx
+++ b/web/app/components/workflow/nodes/_base/panel.tsx
@@ -68,7 +68,7 @@ const BasePanel: FC = ({
const { handleNodeSelect } = useNodesInteractions()
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
const { nodesReadOnly } = useNodesReadOnly()
- const { availableNextBlocks } = useAvailableBlocks(data.type, data.isInIteration, data.isInLoop)
+ const { availableNextBlocks } = useAvailableBlocks(data.type, data.isInIteration || data.isInLoop)
const toolIcon = useToolIcon(data)
const handleResize = useCallback((width: number) => {
diff --git a/web/app/components/workflow/nodes/agent/default.ts b/web/app/components/workflow/nodes/agent/default.ts
index 4e7b447de8..aed97fb7c3 100644
--- a/web/app/components/workflow/nodes/agent/default.ts
+++ b/web/app/components/workflow/nodes/agent/default.ts
@@ -1,23 +1,18 @@
import type { StrategyDetail, StrategyPluginDetail } from '@/app/components/plugins/types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
import type { NodeDefault } from '../../types'
import type { AgentNodeType } from './types'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { renderI18nObject } from '@/i18n'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: 3,
+ type: BlockEnum.Agent,
+ }),
defaultValue: {
},
- getAvailablePrevNodes(isChatMode) {
- return isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS
- },
- getAvailableNextNodes(isChatMode) {
- return isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS
- },
checkValid(payload, t, moreDataForCheckValid: {
strategyProvider?: StrategyPluginDetail,
strategy?: StrategyDetail
diff --git a/web/app/components/workflow/nodes/answer/default.ts b/web/app/components/workflow/nodes/answer/default.ts
index 4ff6e49d7e..a1f0b47c5a 100644
--- a/web/app/components/workflow/nodes/answer/default.ts
+++ b/web/app/components/workflow/nodes/answer/default.ts
@@ -1,25 +1,17 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import type { AnswerNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: 2.1,
+ type: BlockEnum.Answer,
+ }),
defaultValue: {
variables: [],
answer: '',
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: AnswerNodeType, t: any) {
let errorMessages = ''
const { answer } = payload
diff --git a/web/app/components/workflow/nodes/assigner/default.ts b/web/app/components/workflow/nodes/assigner/default.ts
index f443ae1d3b..1a43d15c49 100644
--- a/web/app/components/workflow/nodes/assigner/default.ts
+++ b/web/app/components/workflow/nodes/assigner/default.ts
@@ -1,24 +1,21 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import { type AssignerNodeType, WriteMode } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Transform,
+ sort: 5,
+ type: BlockEnum.Assigner,
+ helpLinkUri: 'variable-assigner',
+ }),
defaultValue: {
version: '2',
items: [],
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: AssignerNodeType, t: any) {
let errorMessages = ''
const {
diff --git a/web/app/components/workflow/nodes/code/default.ts b/web/app/components/workflow/nodes/code/default.ts
index 5f90c18716..c66215fa99 100644
--- a/web/app/components/workflow/nodes/code/default.ts
+++ b/web/app/components/workflow/nodes/code/default.ts
@@ -1,27 +1,23 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import { CodeLanguage, type CodeNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Transform,
+ sort: 1,
+ type: BlockEnum.Code,
+ }),
defaultValue: {
code: '',
code_language: CodeLanguage.python3,
variables: [],
outputs: {},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: CodeNodeType, t: any) {
let errorMessages = ''
const { code, variables } = payload
diff --git a/web/app/components/workflow/nodes/document-extractor/default.ts b/web/app/components/workflow/nodes/document-extractor/default.ts
index e141844d19..caeb37656a 100644
--- a/web/app/components/workflow/nodes/document-extractor/default.ts
+++ b/web/app/components/workflow/nodes/document-extractor/default.ts
@@ -1,24 +1,21 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import type { DocExtractorNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Transform,
+ sort: 4,
+ type: BlockEnum.DocExtractor,
+ helpLinkUri: 'doc-extractor',
+ }),
defaultValue: {
variable_selector: [],
is_array_file: false,
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: DocExtractorNodeType, t: any) {
let errorMessages = ''
const { variable_selector: variable } = payload
diff --git a/web/app/components/workflow/nodes/end/default.ts b/web/app/components/workflow/nodes/end/default.ts
index e8fbb94bd0..e61d84d648 100644
--- a/web/app/components/workflow/nodes/end/default.ts
+++ b/web/app/components/workflow/nodes/end/default.ts
@@ -1,21 +1,16 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import type { EndNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: 2.1,
+ type: BlockEnum.End,
+ }),
defaultValue: {
outputs: [],
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes() {
- return []
- },
checkValid() {
return {
isValid: true,
diff --git a/web/app/components/workflow/nodes/http/default.ts b/web/app/components/workflow/nodes/http/default.ts
index 1bd584eeb9..b5dca4549e 100644
--- a/web/app/components/workflow/nodes/http/default.ts
+++ b/web/app/components/workflow/nodes/http/default.ts
@@ -1,13 +1,16 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import { AuthorizationType, BodyType, Method } from './types'
import type { BodyPayload, HttpNodeType } from './types'
-import {
- ALL_CHAT_AVAILABLE_BLOCKS,
- ALL_COMPLETION_AVAILABLE_BLOCKS,
-} from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Utilities,
+ sort: 1,
+ type: BlockEnum.HttpRequest,
+ }),
defaultValue: {
variables: [],
method: Method.get,
@@ -33,16 +36,6 @@ const nodeDefault: NodeDefault = {
retry_interval: 100,
},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: HttpNodeType, t: any) {
let errorMessages = ''
diff --git a/web/app/components/workflow/nodes/if-else/default.ts b/web/app/components/workflow/nodes/if-else/default.ts
index 1be80592e5..1f82c0fe29 100644
--- a/web/app/components/workflow/nodes/if-else/default.ts
+++ b/web/app/components/workflow/nodes/if-else/default.ts
@@ -1,10 +1,18 @@
-import { BlockEnum, type NodeDefault } from '../../types'
+import type { NodeDefault } from '../../types'
import { type IfElseNodeType, LogicalOperator } from './types'
import { isEmptyRelatedOperator } from './utils'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Logic,
+ sort: 1,
+ type: BlockEnum.IfElse,
+ helpLinkUri: 'ifelse',
+ }),
defaultValue: {
_targetBranches: [
{
@@ -24,16 +32,6 @@ const nodeDefault: NodeDefault = {
},
],
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: IfElseNodeType, t: any) {
let errorMessages = ''
const { cases } = payload
diff --git a/web/app/components/workflow/nodes/iteration-start/default.ts b/web/app/components/workflow/nodes/iteration-start/default.ts
index c93b472259..3bd42894f1 100644
--- a/web/app/components/workflow/nodes/iteration-start/default.ts
+++ b/web/app/components/workflow/nodes/iteration-start/default.ts
@@ -1,16 +1,14 @@
import type { NodeDefault } from '../../types'
import type { IterationStartNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: -1,
+ type: BlockEnum.IterationStart,
+ }),
defaultValue: {},
- getAvailablePrevNodes() {
- return []
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid() {
return {
isValid: true,
diff --git a/web/app/components/workflow/nodes/iteration/default.ts b/web/app/components/workflow/nodes/iteration/default.ts
index 0ef8382abe..3cc51dd340 100644
--- a/web/app/components/workflow/nodes/iteration/default.ts
+++ b/web/app/components/workflow/nodes/iteration/default.ts
@@ -1,13 +1,17 @@
-import { BlockEnum, ErrorHandleMode } from '../../types'
+import { ErrorHandleMode } from '../../types'
import type { NodeDefault } from '../../types'
import type { IterationNodeType } from './types'
-import {
- ALL_CHAT_AVAILABLE_BLOCKS,
- ALL_COMPLETION_AVAILABLE_BLOCKS,
-} from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Logic,
+ sort: 2,
+ type: BlockEnum.Iteration,
+ }),
defaultValue: {
start_node_id: '',
iterator_selector: [],
@@ -18,20 +22,6 @@ const nodeDefault: NodeDefault = {
parallel_nums: 10,
error_handle_mode: ErrorHandleMode.Terminated,
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(
- type => type !== BlockEnum.End,
- )
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: IterationNodeType, t: any) {
let errorMessages = ''
diff --git a/web/app/components/workflow/nodes/iteration/use-interactions.ts b/web/app/components/workflow/nodes/iteration/use-interactions.ts
index c294cfd6aa..b4e0540b2c 100644
--- a/web/app/components/workflow/nodes/iteration/use-interactions.ts
+++ b/web/app/components/workflow/nodes/iteration/use-interactions.ts
@@ -12,13 +12,14 @@ import {
} from '../../utils'
import {
ITERATION_PADDING,
- NODES_INITIAL_DATA,
} from '../../constants'
import { CUSTOM_ITERATION_START_NODE } from '../iteration-start/constants'
+import { useNodesMetaData } from '@/app/components/workflow/hooks'
export const useNodeIterationInteractions = () => {
const { t } = useTranslation()
const store = useStoreApi()
+ const { nodesMap: nodesMetaDataMap } = useNodesMetaData()
const handleNodeIterationRerender = useCallback((nodeId: string) => {
const {
@@ -120,7 +121,7 @@ export const useNodeIterationInteractions = () => {
const { newNode } = generateNewNode({
type: getNodeCustomTypeByNodeDataType(childNodeType),
data: {
- ...NODES_INITIAL_DATA[childNodeType],
+ ...nodesMetaDataMap![childNodeType].defaultValue,
...child.data,
selected: false,
_isBundled: false,
diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/default.ts b/web/app/components/workflow/nodes/knowledge-retrieval/default.ts
index 09da8dd789..bbb2ed6387 100644
--- a/web/app/components/workflow/nodes/knowledge-retrieval/default.ts
+++ b/web/app/components/workflow/nodes/knowledge-retrieval/default.ts
@@ -1,13 +1,17 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import type { KnowledgeRetrievalNodeType } from './types'
import { checkoutRerankModelConfigedInRetrievalSettings } from './utils'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
import { DATASET_DEFAULT } from '@/config'
import { RETRIEVE_TYPE } from '@/types/app'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const i18nPrefix = 'workflow'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: 2,
+ type: BlockEnum.KnowledgeRetrieval,
+ }),
defaultValue: {
query_variable_selector: [],
dataset_ids: [],
@@ -18,16 +22,6 @@ const nodeDefault: NodeDefault = {
reranking_enable: false,
},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: KnowledgeRetrievalNodeType, t: any) {
let errorMessages = ''
if (!errorMessages && (!payload.query_variable_selector || payload.query_variable_selector.length === 0))
diff --git a/web/app/components/workflow/nodes/list-operator/default.ts b/web/app/components/workflow/nodes/list-operator/default.ts
index 0256cb8673..a9898ac2a8 100644
--- a/web/app/components/workflow/nodes/list-operator/default.ts
+++ b/web/app/components/workflow/nodes/list-operator/default.ts
@@ -1,11 +1,18 @@
-import { BlockEnum, VarType } from '../../types'
+import { VarType } from '../../types'
import type { NodeDefault } from '../../types'
import { comparisonOperatorNotRequireValue } from '../if-else/utils'
import { type ListFilterNodeType, OrderBy } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Utilities,
+ sort: 2,
+ type: BlockEnum.ListFilter,
+ }),
defaultValue: {
variable: [],
filter_by: {
@@ -26,16 +33,6 @@ const nodeDefault: NodeDefault = {
size: 10,
},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: ListFilterNodeType, t: any) {
let errorMessages = ''
const { variable, var_type, filter_by } = payload
diff --git a/web/app/components/workflow/nodes/llm/default.ts b/web/app/components/workflow/nodes/llm/default.ts
index 92377f74b8..34b6085c9d 100644
--- a/web/app/components/workflow/nodes/llm/default.ts
+++ b/web/app/components/workflow/nodes/llm/default.ts
@@ -1,11 +1,16 @@
-import { BlockEnum, EditionType } from '../../types'
+import { EditionType } from '../../types'
import { type NodeDefault, type PromptItem, PromptRole } from '../../types'
import type { LLMNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: 1,
+ type: BlockEnum.LLM,
+ }),
defaultValue: {
model: {
provider: '',
@@ -27,16 +32,6 @@ const nodeDefault: NodeDefault = {
enabled: false,
},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: LLMNodeType, t: any) {
let errorMessages = ''
if (!errorMessages && !payload.model.provider)
diff --git a/web/app/components/workflow/nodes/loop-end/default.ts b/web/app/components/workflow/nodes/loop-end/default.ts
index c136704123..7e314ab277 100644
--- a/web/app/components/workflow/nodes/loop-end/default.ts
+++ b/web/app/components/workflow/nodes/loop-end/default.ts
@@ -1,18 +1,18 @@
import type { NodeDefault } from '../../types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
import type {
SimpleNodeType,
} from '@/app/components/workflow/simple-node/types'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Logic,
+ sort: 2,
+ type: BlockEnum.LoopEnd,
+ }),
defaultValue: {},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
- getAvailableNextNodes() {
- return []
- },
checkValid() {
return {
isValid: true,
diff --git a/web/app/components/workflow/nodes/loop-start/default.ts b/web/app/components/workflow/nodes/loop-start/default.ts
index 685f227838..17f1669111 100644
--- a/web/app/components/workflow/nodes/loop-start/default.ts
+++ b/web/app/components/workflow/nodes/loop-start/default.ts
@@ -1,16 +1,14 @@
import type { NodeDefault } from '../../types'
import type { LoopStartNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: -1,
+ type: BlockEnum.LoopStart,
+ }),
defaultValue: {},
- getAvailablePrevNodes() {
- return []
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid() {
return {
isValid: true,
diff --git a/web/app/components/workflow/nodes/loop/add-block.tsx b/web/app/components/workflow/nodes/loop/add-block.tsx
index accee12665..a9c1429269 100644
--- a/web/app/components/workflow/nodes/loop/add-block.tsx
+++ b/web/app/components/workflow/nodes/loop/add-block.tsx
@@ -32,7 +32,7 @@ const AddBlock = ({
const { t } = useTranslation()
const { nodesReadOnly } = useNodesReadOnly()
const { handleNodeAdd } = useNodesInteractions()
- const { availableNextBlocks } = useAvailableBlocks(BlockEnum.Start, false, true)
+ const { availableNextBlocks } = useAvailableBlocks(BlockEnum.Start, true)
const handleSelect = useCallback((type, toolDefaultValue) => {
handleNodeAdd(
diff --git a/web/app/components/workflow/nodes/loop/default.ts b/web/app/components/workflow/nodes/loop/default.ts
index b446432458..1e54b31122 100644
--- a/web/app/components/workflow/nodes/loop/default.ts
+++ b/web/app/components/workflow/nodes/loop/default.ts
@@ -1,13 +1,20 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import { ComparisonOperator, LogicalOperator, type LoopNodeType } from './types'
import { isEmptyRelatedOperator } from './utils'
import { TransferMethod } from '@/types/app'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
import { LOOP_NODE_MAX_COUNT } from '@/config'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Logic,
+ sort: 3,
+ type: BlockEnum.Loop,
+ // author: 'AICT-Team',
+ }),
defaultValue: {
start_node_id: '',
break_conditions: [],
@@ -15,16 +22,6 @@ const nodeDefault: NodeDefault = {
_children: [],
logical_operator: LogicalOperator.and,
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: LoopNodeType, t: any) {
let errorMessages = ''
diff --git a/web/app/components/workflow/nodes/loop/use-interactions.ts b/web/app/components/workflow/nodes/loop/use-interactions.ts
index 83a32106db..6687acb0c4 100644
--- a/web/app/components/workflow/nodes/loop/use-interactions.ts
+++ b/web/app/components/workflow/nodes/loop/use-interactions.ts
@@ -1,6 +1,5 @@
import { useCallback } from 'react'
import produce from 'immer'
-import { useTranslation } from 'react-i18next'
import { useStoreApi } from 'reactflow'
import type {
BlockEnum,
@@ -12,13 +11,13 @@ import {
} from '../../utils'
import {
LOOP_PADDING,
- NODES_INITIAL_DATA,
} from '../../constants'
import { CUSTOM_LOOP_START_NODE } from '../loop-start/constants'
+import { useNodesMetaData } from '@/app/components/workflow/hooks'
export const useNodeLoopInteractions = () => {
- const { t } = useTranslation()
const store = useStoreApi()
+ const { nodesMap: nodesMetaDataMap } = useNodesMetaData()
const handleNodeLoopRerender = useCallback((nodeId: string) => {
const {
@@ -115,17 +114,21 @@ export const useNodeLoopInteractions = () => {
return childrenNodes.map((child, index) => {
const childNodeType = child.data.type as BlockEnum
+ const {
+ defaultValue,
+ title,
+ } = nodesMetaDataMap![childNodeType]
const nodesWithSameType = nodes.filter(node => node.data.type === childNodeType)
const { newNode } = generateNewNode({
type: getNodeCustomTypeByNodeDataType(childNodeType),
data: {
- ...NODES_INITIAL_DATA[childNodeType],
+ ...defaultValue,
...child.data,
selected: false,
_isBundled: false,
_connectedSourceHandleIds: [],
_connectedTargetHandleIds: [],
- title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${childNodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${childNodeType}`),
+ title: nodesWithSameType.length > 0 ? `${title} ${nodesWithSameType.length + 1}` : title,
loop_id: newNodeId,
},
@@ -138,7 +141,7 @@ export const useNodeLoopInteractions = () => {
newNode.id = `${newNodeId}${newNode.id + index}`
return newNode
})
- }, [store, t])
+ }, [store, nodesMetaDataMap])
return {
handleNodeLoopRerender,
diff --git a/web/app/components/workflow/nodes/parameter-extractor/default.ts b/web/app/components/workflow/nodes/parameter-extractor/default.ts
index 0e3b707d30..c2c0140940 100644
--- a/web/app/components/workflow/nodes/parameter-extractor/default.ts
+++ b/web/app/components/workflow/nodes/parameter-extractor/default.ts
@@ -1,10 +1,16 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import { type ParameterExtractorNodeType, ReasoningModeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Transform,
+ sort: 6,
+ type: BlockEnum.ParameterExtractor,
+ }),
defaultValue: {
query: [],
model: {
@@ -20,16 +26,6 @@ const nodeDefault: NodeDefault = {
enabled: false,
},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: ParameterExtractorNodeType, t: any) {
let errorMessages = ''
if (!errorMessages && (!payload.query || payload.query.length === 0))
diff --git a/web/app/components/workflow/nodes/question-classifier/default.ts b/web/app/components/workflow/nodes/question-classifier/default.ts
index 2729c53f29..c404a6698b 100644
--- a/web/app/components/workflow/nodes/question-classifier/default.ts
+++ b/web/app/components/workflow/nodes/question-classifier/default.ts
@@ -1,11 +1,17 @@
import type { NodeDefault } from '../../types'
-import { BlockEnum } from '../../types'
import type { QuestionClassifierNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.QuestionUnderstand,
+ sort: 1,
+ type: BlockEnum.QuestionClassifier,
+ }),
defaultValue: {
query_variable_selector: [],
model: {
@@ -40,16 +46,6 @@ const nodeDefault: NodeDefault = {
enabled: false,
},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: QuestionClassifierNodeType, t: any) {
let errorMessages = ''
if (!errorMessages && (!payload.query_variable_selector || payload.query_variable_selector.length === 0))
diff --git a/web/app/components/workflow/nodes/start/default.ts b/web/app/components/workflow/nodes/start/default.ts
index 98f24c5d98..53ad1761a1 100644
--- a/web/app/components/workflow/nodes/start/default.ts
+++ b/web/app/components/workflow/nodes/start/default.ts
@@ -1,18 +1,16 @@
import type { NodeDefault } from '../../types'
import type { StartNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: 0.1,
+ type: BlockEnum.Start,
+ }),
defaultValue: {
variables: [],
},
- getAvailablePrevNodes() {
- return []
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid() {
return {
isValid: true,
diff --git a/web/app/components/workflow/nodes/template-transform/default.ts b/web/app/components/workflow/nodes/template-transform/default.ts
index c698680342..f68d81663a 100644
--- a/web/app/components/workflow/nodes/template-transform/default.ts
+++ b/web/app/components/workflow/nodes/template-transform/default.ts
@@ -1,23 +1,21 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import type { TemplateTransformNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Transform,
+ sort: 2,
+ type: BlockEnum.TemplateTransform,
+ helpLinkUri: 'template',
+ }),
defaultValue: {
+ template: '',
variables: [],
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: TemplateTransformNodeType, t: any) {
let errorMessages = ''
const { template, variables } = payload
diff --git a/web/app/components/workflow/nodes/tool/default.ts b/web/app/components/workflow/nodes/tool/default.ts
index f245929684..891857d6ec 100644
--- a/web/app/components/workflow/nodes/tool/default.ts
+++ b/web/app/components/workflow/nodes/tool/default.ts
@@ -1,26 +1,21 @@
-import { BlockEnum } from '../../types'
import type { NodeDefault } from '../../types'
import type { ToolNodeType } from './types'
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ sort: -1,
+ type: BlockEnum.Tool,
+ helpLinkUri: 'tools',
+ }),
defaultValue: {
tool_parameters: {},
tool_configurations: {},
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: ToolNodeType, t: any, moreDataForCheckValid: any) {
const { toolInputsSchema, toolSettingSchema, language, notAuthed } = moreDataForCheckValid
let errorMessages = ''
diff --git a/web/app/components/workflow/nodes/variable-assigner/default.ts b/web/app/components/workflow/nodes/variable-assigner/default.ts
index 60c7c27969..f7813c9258 100644
--- a/web/app/components/workflow/nodes/variable-assigner/default.ts
+++ b/web/app/components/workflow/nodes/variable-assigner/default.ts
@@ -1,25 +1,21 @@
import { type NodeDefault, VarType } from '../../types'
-import { BlockEnum } from '../../types'
import type { VariableAssignerNodeType } from './types'
-import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+import { genNodeMetaData } from '@/app/components/workflow/utils'
+import { BlockEnum } from '@/app/components/workflow/types'
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
const i18nPrefix = 'workflow'
const nodeDefault: NodeDefault = {
+ ...genNodeMetaData({
+ classification: BlockClassificationEnum.Transform,
+ sort: 3,
+ type: BlockEnum.VariableAggregator,
+ }),
defaultValue: {
output_type: VarType.any,
variables: [],
},
- getAvailablePrevNodes(isChatMode: boolean) {
- const nodes = isChatMode
- ? ALL_CHAT_AVAILABLE_BLOCKS
- : ALL_COMPLETION_AVAILABLE_BLOCKS.filter(type => type !== BlockEnum.End)
- return nodes
- },
- getAvailableNextNodes(isChatMode: boolean) {
- const nodes = isChatMode ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS
- return nodes
- },
checkValid(payload: VariableAssignerNodeType, t: any) {
let errorMessages = ''
const { variables, advanced_settings } = payload
diff --git a/web/app/components/workflow/operator/add-block.tsx b/web/app/components/workflow/operator/add-block.tsx
index d35a5be8b4..7e6a6598e4 100644
--- a/web/app/components/workflow/operator/add-block.tsx
+++ b/web/app/components/workflow/operator/add-block.tsx
@@ -13,10 +13,10 @@ import {
} from '../utils'
import {
useAvailableBlocks,
+ useNodesMetaData,
useNodesReadOnly,
usePanelInteractions,
} from '../hooks'
-import { NODES_INITIAL_DATA } from '../constants'
import { useWorkflowStore } from '../store'
import TipPopup from './tip-popup'
import cn from '@/utils/classnames'
@@ -43,6 +43,7 @@ const AddBlock = ({
const { handlePaneContextmenuCancel } = usePanelInteractions()
const [open, setOpen] = useState(false)
const { availableNextBlocks } = useAvailableBlocks(BlockEnum.Start, false)
+ const { nodesMap: nodesMetaDataMap } = useNodesMetaData()
const handleOpenChange = useCallback((open: boolean) => {
setOpen(open)
@@ -56,11 +57,15 @@ const AddBlock = ({
} = store.getState()
const nodes = getNodes()
const nodesWithSameType = nodes.filter(node => node.data.type === type)
+ const {
+ defaultValue,
+ title,
+ } = nodesMetaDataMap![type]
const { newNode } = generateNewNode({
type: getNodeCustomTypeByNodeDataType(type),
data: {
- ...NODES_INITIAL_DATA[type],
- title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${type}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${type}`),
+ ...(defaultValue as any),
+ title: nodesWithSameType.length > 0 ? `${title} ${nodesWithSameType.length + 1}` : title,
...(toolDefaultValue || {}),
_isCandidate: true,
},
@@ -72,7 +77,7 @@ const AddBlock = ({
workflowStore.setState({
candidateNode: newNode,
})
- }, [store, workflowStore, t])
+ }, [store, workflowStore, nodesMetaDataMap])
const renderTriggerElement = useCallback((open: boolean) => {
return (
diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts
index 884bdfbd10..eded5030e2 100644
--- a/web/app/components/workflow/types.ts
+++ b/web/app/components/workflow/types.ts
@@ -15,6 +15,7 @@ import type {
} from '@/app/components/workflow/nodes/_base/components/error-handle/types'
import type { WorkflowRetryConfig } from '@/app/components/workflow/nodes/_base/components/retry/types'
import type { StructuredOutput } from '@/app/components/workflow/nodes/llm/types'
+import type { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
export enum BlockEnum {
Start = 'start',
@@ -285,17 +286,15 @@ export type NodeOutPutVar = {
isLoop?: boolean
}
-export type Block = {
- classification?: string
+export type NodeDefault = {
+ classification: BlockClassificationEnum
+ sort: number
type: BlockEnum
title: string
+ author: string
description?: string
-}
-
-export type NodeDefault = {
+ helpLinkUri?: string
defaultValue: Partial
- getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[]
- getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[]
checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string }
}
diff --git a/web/app/components/workflow/utils/gen-node-meta-data.ts b/web/app/components/workflow/utils/gen-node-meta-data.ts
new file mode 100644
index 0000000000..e7271cfcc4
--- /dev/null
+++ b/web/app/components/workflow/utils/gen-node-meta-data.ts
@@ -0,0 +1,28 @@
+import { BlockClassificationEnum } from '@/app/components/workflow/block-selector/types'
+import type { BlockEnum } from '@/app/components/workflow/types'
+
+export type GenNodeMetaDataParams = {
+ classification?: BlockClassificationEnum
+ sort: number
+ type: BlockEnum
+ title?: string
+ author?: string
+ helpLinkUri?: string
+}
+export const genNodeMetaData = ({
+ classification = BlockClassificationEnum.Default,
+ sort,
+ type,
+ title = '',
+ author = 'Dify',
+ helpLinkUri,
+}: GenNodeMetaDataParams) => {
+ return {
+ classification,
+ sort,
+ type,
+ title,
+ author,
+ helpLinkUri: helpLinkUri || type,
+ }
+}
diff --git a/web/app/components/workflow/utils/index.ts b/web/app/components/workflow/utils/index.ts
index 4a1da760d4..62f609e4b5 100644
--- a/web/app/components/workflow/utils/index.ts
+++ b/web/app/components/workflow/utils/index.ts
@@ -6,3 +6,4 @@ export * from './common'
export * from './tool'
export * from './workflow'
export * from './variable'
+export * from './gen-node-meta-data'