From 4fae40f66a1e201cc9210baacd02501d63b48805 Mon Sep 17 00:00:00 2001 From: balibabu Date: Fri, 19 Sep 2025 11:11:22 +0800 Subject: [PATCH] Feat: Translate the splitter operator field #9869 (#10166) ### What problem does this PR solve? Feat: Translate the splitter operator field #9869 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/locales/en.ts | 5 + web/src/locales/zh.ts | 5 + web/src/pages/data-flow/canvas/index.tsx | 32 -- .../data-flow/canvas/node/agent-node.tsx | 116 ------- .../data-flow/canvas/node/categorize-node.tsx | 62 ---- .../data-flow/canvas/node/chunker-node.tsx | 49 --- .../data-flow/canvas/node/email-node.tsx | 80 ----- .../data-flow/canvas/node/generate-node.tsx | 60 ---- .../data-flow/canvas/node/invoke-node.tsx | 62 ---- .../data-flow/canvas/node/iteration-node.tsx | 93 ----- .../data-flow/canvas/node/keyword-node.tsx | 60 ---- .../data-flow/canvas/node/message-node.tsx | 65 ---- .../data-flow/canvas/node/relevant-node.tsx | 73 ---- .../data-flow/canvas/node/retrieval-node.tsx | 84 ----- .../data-flow/canvas/node/rewrite-node.tsx | 60 ---- .../data-flow/canvas/node/switch-node.tsx | 118 ------- .../data-flow/canvas/node/template-node.tsx | 78 ----- .../pages/data-flow/canvas/node/tool-node.tsx | 83 ----- .../pages/data-flow/canvas/node/toolbar.tsx | 12 +- web/src/pages/data-flow/constant.tsx | 55 +-- .../data-flow/form-sheet/form-config-map.tsx | 78 ----- web/src/pages/data-flow/form-sheet/next.tsx | 58 +--- .../data-flow/form/agent-form/agent-tools.tsx | 191 ---------- .../form/agent-form/dynamic-prompt.tsx | 93 ----- .../form/agent-form/dynamic-tool.tsx | 63 ---- .../pages/data-flow/form/agent-form/index.tsx | 280 --------------- .../form/agent-form/tool-popover/index.tsx | 89 ----- .../agent-form/tool-popover/tool-command.tsx | 178 ---------- .../agent-form/tool-popover/use-update-mcp.ts | 74 ---- .../tool-popover/use-update-tools.ts | 66 ---- .../form/agent-form/use-get-tools.ts | 26 -- .../data-flow/form/agent-form/use-values.ts | 33 -- .../form/agent-form/use-watch-change.ts | 22 -- .../categorize-form/dynamic-categorize.tsx | 249 ------------- .../form/categorize-form/dynamic-example.tsx | 68 ---- .../data-flow/form/categorize-form/index.tsx | 48 --- .../form/categorize-form/use-form-schema.ts | 32 -- .../form/categorize-form/use-values.ts | 34 -- .../form/categorize-form/use-watch-change.ts | 17 - .../data-flow/form/chunker-form/index.tsx | 140 -------- .../pages/data-flow/form/code-form/index.tsx | 168 --------- .../form/code-form/next-variable.tsx | 128 ------- .../pages/data-flow/form/code-form/schema.ts | 14 - .../data-flow/form/code-form/use-values.ts | 47 --- .../form/code-form/use-watch-change.ts | 95 ----- .../data-flow/form/crawler-form/index.tsx | 105 ------ .../pages/data-flow/form/email-form/index.tsx | 161 --------- .../data-flow/form/exesql-form/index.tsx | 167 --------- .../form/exesql-form/use-submit-form.ts | 31 -- .../form/hierarchical-merger-form/index.tsx | 98 ++++-- .../pages/data-flow/form/invoke-form/hooks.ts | 97 ------ .../data-flow/form/invoke-form/index.tsx | 226 ------------ .../data-flow/form/invoke-form/schema.ts | 21 -- .../form/invoke-form/use-edit-variable.ts | 70 ---- .../form/invoke-form/variable-dialog.tsx | 143 -------- .../form/invoke-form/variable-table.tsx | 199 ----------- .../form/iteration-form/dynamic-output.tsx | 128 ------- .../data-flow/form/iteration-form/index.tsx | 57 --- .../form/iteration-form/interface.ts | 2 - .../form/iteration-form/use-build-options.ts | 31 -- .../form/iteration-form/use-values.ts | 27 -- .../iteration-form/use-watch-form-change.ts | 30 -- .../form/iteration-start-from/index.tsx | 23 -- .../form/keyword-extract-form/index.tsx | 48 --- .../data-flow/form/message-form/index.tsx | 101 ------ .../data-flow/form/message-form/use-values.ts | 22 -- .../form/message-form/use-watch-change.ts | 24 -- .../data-flow/form/relevant-form/hooks.ts | 41 --- .../data-flow/form/relevant-form/index.tsx | 49 --- .../data-flow/form/retrieval-form/next.tsx | 126 ------- .../form/retrieval-form/use-values.ts | 25 -- .../form/rewrite-question-form/index.tsx | 68 ---- .../data-flow/form/splitter-form/index.tsx | 73 ++-- .../form/string-transform-form/index.tsx | 166 --------- .../form/string-transform-form/use-values.ts | 33 -- .../use-watch-form-change.ts | 26 -- .../data-flow/form/switch-form/index.tsx | 328 ------------------ .../data-flow/form/switch-form/use-values.ts | 17 - .../form/switch-form/use-watch-change.ts | 24 -- .../data-flow/form/tokenizer-form/index.tsx | 7 +- .../form/user-fill-up-form/index.tsx | 168 --------- .../form/user-fill-up-form/use-values.ts | 21 -- .../user-fill-up-form/use-watch-change.ts | 35 -- .../pages/data-flow/hooks/use-show-drawer.tsx | 9 +- web/src/pages/data-flow/operator-icon.tsx | 18 +- 85 files changed, 146 insertions(+), 6442 deletions(-) delete mode 100644 web/src/pages/data-flow/canvas/node/agent-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/categorize-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/chunker-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/email-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/generate-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/invoke-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/iteration-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/keyword-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/message-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/relevant-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/retrieval-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/rewrite-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/switch-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/template-node.tsx delete mode 100644 web/src/pages/data-flow/canvas/node/tool-node.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/agent-tools.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/dynamic-prompt.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/dynamic-tool.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/tool-popover/index.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/tool-popover/tool-command.tsx delete mode 100644 web/src/pages/data-flow/form/agent-form/tool-popover/use-update-mcp.ts delete mode 100644 web/src/pages/data-flow/form/agent-form/tool-popover/use-update-tools.ts delete mode 100644 web/src/pages/data-flow/form/agent-form/use-get-tools.ts delete mode 100644 web/src/pages/data-flow/form/agent-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/agent-form/use-watch-change.ts delete mode 100644 web/src/pages/data-flow/form/categorize-form/dynamic-categorize.tsx delete mode 100644 web/src/pages/data-flow/form/categorize-form/dynamic-example.tsx delete mode 100644 web/src/pages/data-flow/form/categorize-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/categorize-form/use-form-schema.ts delete mode 100644 web/src/pages/data-flow/form/categorize-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/categorize-form/use-watch-change.ts delete mode 100644 web/src/pages/data-flow/form/chunker-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/code-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/code-form/next-variable.tsx delete mode 100644 web/src/pages/data-flow/form/code-form/schema.ts delete mode 100644 web/src/pages/data-flow/form/code-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/code-form/use-watch-change.ts delete mode 100644 web/src/pages/data-flow/form/crawler-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/email-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/exesql-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/exesql-form/use-submit-form.ts delete mode 100644 web/src/pages/data-flow/form/invoke-form/hooks.ts delete mode 100644 web/src/pages/data-flow/form/invoke-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/invoke-form/schema.ts delete mode 100644 web/src/pages/data-flow/form/invoke-form/use-edit-variable.ts delete mode 100644 web/src/pages/data-flow/form/invoke-form/variable-dialog.tsx delete mode 100644 web/src/pages/data-flow/form/invoke-form/variable-table.tsx delete mode 100644 web/src/pages/data-flow/form/iteration-form/dynamic-output.tsx delete mode 100644 web/src/pages/data-flow/form/iteration-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/iteration-form/interface.ts delete mode 100644 web/src/pages/data-flow/form/iteration-form/use-build-options.ts delete mode 100644 web/src/pages/data-flow/form/iteration-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/iteration-form/use-watch-form-change.ts delete mode 100644 web/src/pages/data-flow/form/iteration-start-from/index.tsx delete mode 100644 web/src/pages/data-flow/form/keyword-extract-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/message-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/message-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/message-form/use-watch-change.ts delete mode 100644 web/src/pages/data-flow/form/relevant-form/hooks.ts delete mode 100644 web/src/pages/data-flow/form/relevant-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/retrieval-form/next.tsx delete mode 100644 web/src/pages/data-flow/form/retrieval-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/rewrite-question-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/string-transform-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/string-transform-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/string-transform-form/use-watch-form-change.ts delete mode 100644 web/src/pages/data-flow/form/switch-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/switch-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/switch-form/use-watch-change.ts delete mode 100644 web/src/pages/data-flow/form/user-fill-up-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/user-fill-up-form/use-values.ts delete mode 100644 web/src/pages/data-flow/form/user-fill-up-form/use-watch-change.ts diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index c5ad7c3ae..cafa7c753 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1663,6 +1663,11 @@ This delimiter is used to split the input text into several text pieces echo of fileFormats: 'File formats', fields: 'Fields', addParser: 'Add Parser', + hierarchy: 'Hierarchy', + regularExpressions: 'Regular Expressions', + overlappedPercent: 'Overlapped percent', + searchMethod: 'Search method', + filenameEmbdWeight: 'Filename embd weight', }, }, }; diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 0e37060e6..9f93c221a 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1573,6 +1573,11 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 fileFormats: '文件格式', fields: '字段', addParser: '增加解析器', + hierarchy: '层次结构', + regularExpressions: '正则表达式', + overlappedPercent: '重叠百分比', + searchMethod: '搜索方法', + filenameEmbdWeight: '文件名嵌入权重', }, }, }; diff --git a/web/src/pages/data-flow/canvas/index.tsx b/web/src/pages/data-flow/canvas/index.tsx index fd3b88c50..87fc9bef0 100644 --- a/web/src/pages/data-flow/canvas/index.tsx +++ b/web/src/pages/data-flow/canvas/index.tsx @@ -38,51 +38,19 @@ import RunSheet from '../run-sheet'; import { ButtonEdge } from './edge'; import styles from './index.less'; import { RagNode } from './node'; -import { AgentNode } from './node/agent-node'; import { BeginNode } from './node/begin-node'; -import { CategorizeNode } from './node/categorize-node'; -import ChunkerNode from './node/chunker-node'; import { InnerNextStepDropdown } from './node/dropdown/next-step-dropdown'; -import { GenerateNode } from './node/generate-node'; import { HierarchicalMergerNode } from './node/hierarchical-merger-node'; -import { InvokeNode } from './node/invoke-node'; -import { IterationNode, IterationStartNode } from './node/iteration-node'; -import { KeywordNode } from './node/keyword-node'; -import { LogicNode } from './node/logic-node'; -import { MessageNode } from './node/message-node'; import NoteNode from './node/note-node'; import ParserNode from './node/parser-node'; -import { RelevantNode } from './node/relevant-node'; -import { RetrievalNode } from './node/retrieval-node'; -import { RewriteNode } from './node/rewrite-node'; import { SplitterNode } from './node/splitter-node'; -import { SwitchNode } from './node/switch-node'; -import { TemplateNode } from './node/template-node'; import TokenizerNode from './node/tokenizer-node'; -import { ToolNode } from './node/tool-node'; export const nodeTypes: NodeTypes = { ragNode: RagNode, - categorizeNode: CategorizeNode, beginNode: BeginNode, - relevantNode: RelevantNode, - logicNode: LogicNode, noteNode: NoteNode, - switchNode: SwitchNode, - generateNode: GenerateNode, - retrievalNode: RetrievalNode, - messageNode: MessageNode, - rewriteNode: RewriteNode, - keywordNode: KeywordNode, - invokeNode: InvokeNode, - templateNode: TemplateNode, - // emailNode: EmailNode, - group: IterationNode, - iterationStartNode: IterationStartNode, - agentNode: AgentNode, - toolNode: ToolNode, parserNode: ParserNode, - chunkerNode: ChunkerNode, tokenizerNode: TokenizerNode, splitterNode: SplitterNode, hierarchicalMergerNode: HierarchicalMergerNode, diff --git a/web/src/pages/data-flow/canvas/node/agent-node.tsx b/web/src/pages/data-flow/canvas/node/agent-node.tsx deleted file mode 100644 index 42b489a41..000000000 --- a/web/src/pages/data-flow/canvas/node/agent-node.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import LLMLabel from '@/components/llm-select/llm-label'; -import { IAgentNode } from '@/interfaces/database/flow'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import { get } from 'lodash'; -import { memo, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { AgentExceptionMethod, NodeHandleId } from '../../constant'; -import useGraphStore from '../../store'; -import { isBottomSubAgent } from '../../utils'; -import { CommonHandle } from './handle'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; - -function InnerAgentNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const edges = useGraphStore((state) => state.edges); - const { t } = useTranslation(); - - const isHeadAgent = useMemo(() => { - return !isBottomSubAgent(edges, id); - }, [edges, id]); - - const exceptionMethod = useMemo(() => { - return get(data, 'form.exception_method'); - }, [data]); - - const isGotoMethod = useMemo(() => { - return exceptionMethod === AgentExceptionMethod.Goto; - }, [exceptionMethod]); - - return ( - - - {isHeadAgent && ( - <> - - - - )} - - - - - -
-
- -
- {(isGotoMethod || - exceptionMethod === AgentExceptionMethod.Comment) && ( -
- {t('flow.onFailure')} - - {t(`flow.${exceptionMethod}`)} - -
- )} -
- {isGotoMethod && ( - - )} -
-
- ); -} - -export const AgentNode = memo(InnerAgentNode); diff --git a/web/src/pages/data-flow/canvas/node/categorize-node.tsx b/web/src/pages/data-flow/canvas/node/categorize-node.tsx deleted file mode 100644 index a54136b5a..000000000 --- a/web/src/pages/data-flow/canvas/node/categorize-node.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import LLMLabel from '@/components/llm-select/llm-label'; -import { ICategorizeNode } from '@/interfaces/database/flow'; -import { NodeProps, Position } from '@xyflow/react'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { NodeHandleId } from '../../constant'; -import { CommonHandle } from './handle'; -import { RightHandleStyle } from './handle-icon'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; -import { useBuildCategorizeHandlePositions } from './use-build-categorize-handle-positions'; - -export function InnerCategorizeNode({ - id, - data, - selected, -}: NodeProps) { - const { positions } = useBuildCategorizeHandlePositions({ data, id }); - return ( - - - - - - -
-
- -
- {positions.map((position) => { - return ( -
-
- {position.name} -
- -
- ); - })} -
-
-
- ); -} - -export const CategorizeNode = memo(InnerCategorizeNode); diff --git a/web/src/pages/data-flow/canvas/node/chunker-node.tsx b/web/src/pages/data-flow/canvas/node/chunker-node.tsx deleted file mode 100644 index a6866b442..000000000 --- a/web/src/pages/data-flow/canvas/node/chunker-node.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { IRagNode } from '@/interfaces/database/flow'; -import { NodeProps, Position } from '@xyflow/react'; -import { memo } from 'react'; -import { NodeHandleId } from '../../constant'; -import { needsSingleStepDebugging } from '../../utils'; -import { CommonHandle } from './handle'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; - -function ChunkerNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - return ( - - - - - - - - ); -} - -export default memo(ChunkerNode); diff --git a/web/src/pages/data-flow/canvas/node/email-node.tsx b/web/src/pages/data-flow/canvas/node/email-node.tsx deleted file mode 100644 index 9482194f3..000000000 --- a/web/src/pages/data-flow/canvas/node/email-node.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { IEmailNode } from '@/interfaces/database/flow'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import { Flex } from 'antd'; -import classNames from 'classnames'; -import { memo, useState } from 'react'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; - -export function InnerEmailNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const [showDetails, setShowDetails] = useState(false); - - return ( -
- - - - - -
setShowDetails(!showDetails)} - > -
- SMTP: - {data.form?.smtp_server} -
-
- Port: - {data.form?.smtp_port} -
-
- From: - {data.form?.email} -
-
{showDetails ? '▼' : '▶'}
-
- - {showDetails && ( -
-
Expected Input JSON:
-
-              {`{
-  "to_email": "...",
-  "cc_email": "...", 
-  "subject": "...",
-  "content": "..."
-}`}
-            
-
- )} -
-
- ); -} - -export const EmailNode = memo(InnerEmailNode); diff --git a/web/src/pages/data-flow/canvas/node/generate-node.tsx b/web/src/pages/data-flow/canvas/node/generate-node.tsx deleted file mode 100644 index 8ffbbd79c..000000000 --- a/web/src/pages/data-flow/canvas/node/generate-node.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import LLMLabel from '@/components/llm-select/llm-label'; -import { useTheme } from '@/components/theme-provider'; -import { IGenerateNode } from '@/interfaces/database/flow'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; - -export function InnerGenerateNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const { theme } = useTheme(); - return ( -
- - - - - -
- -
-
- ); -} - -export const GenerateNode = memo(InnerGenerateNode); diff --git a/web/src/pages/data-flow/canvas/node/invoke-node.tsx b/web/src/pages/data-flow/canvas/node/invoke-node.tsx deleted file mode 100644 index cf1e28d02..000000000 --- a/web/src/pages/data-flow/canvas/node/invoke-node.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useTheme } from '@/components/theme-provider'; -import { IInvokeNode } from '@/interfaces/database/flow'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import { Flex } from 'antd'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; - -function InnerInvokeNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const { t } = useTranslation(); - const { theme } = useTheme(); - const url = get(data, 'form.url'); - return ( -
- - - - -
{t('flow.url')}
-
{url}
-
-
- ); -} - -export const InvokeNode = memo(InnerInvokeNode); diff --git a/web/src/pages/data-flow/canvas/node/iteration-node.tsx b/web/src/pages/data-flow/canvas/node/iteration-node.tsx deleted file mode 100644 index 3bdbae590..000000000 --- a/web/src/pages/data-flow/canvas/node/iteration-node.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { - IIterationNode, - IIterationStartNode, -} from '@/interfaces/database/flow'; -import { cn } from '@/lib/utils'; -import { NodeProps, NodeResizeControl, Position } from '@xyflow/react'; -import { memo } from 'react'; -import { NodeHandleId, Operator } from '../../constant'; -import OperatorIcon from '../../operator-icon'; -import { CommonHandle } from './handle'; -import { RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ResizeIcon, controlStyle } from './resize-icon'; -import { ToolBar } from './toolbar'; - -export function InnerIterationNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - return ( - -
- - - - - - - -
-
- ); -} - -function InnerIterationStartNode({ - isConnectable = true, - id, - selected, -}: NodeProps) { - return ( - - -
- -
-
- ); -} - -export const IterationStartNode = memo(InnerIterationStartNode); - -export const IterationNode = memo(InnerIterationNode); diff --git a/web/src/pages/data-flow/canvas/node/keyword-node.tsx b/web/src/pages/data-flow/canvas/node/keyword-node.tsx deleted file mode 100644 index 012dcf26c..000000000 --- a/web/src/pages/data-flow/canvas/node/keyword-node.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import LLMLabel from '@/components/llm-select/llm-label'; -import { useTheme } from '@/components/theme-provider'; -import { IKeywordNode } from '@/interfaces/database/flow'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; - -export function InnerKeywordNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const { theme } = useTheme(); - return ( -
- - - - - -
- -
-
- ); -} - -export const KeywordNode = memo(InnerKeywordNode); diff --git a/web/src/pages/data-flow/canvas/node/message-node.tsx b/web/src/pages/data-flow/canvas/node/message-node.tsx deleted file mode 100644 index 057845a63..000000000 --- a/web/src/pages/data-flow/canvas/node/message-node.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { IMessageNode } from '@/interfaces/database/flow'; -import { NodeProps, Position } from '@xyflow/react'; -import { Flex } from 'antd'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { NodeHandleId } from '../../constant'; -import { CommonHandle } from './handle'; -import { LeftHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; - -function InnerMessageNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const messages: string[] = get(data, 'form.messages', []); - return ( - - - - {/* */} - 0, - })} - > - - - {messages.map((message, idx) => { - return ( -
- {message} -
- ); - })} -
-
-
- ); -} - -export const MessageNode = memo(InnerMessageNode); diff --git a/web/src/pages/data-flow/canvas/node/relevant-node.tsx b/web/src/pages/data-flow/canvas/node/relevant-node.tsx deleted file mode 100644 index 410a7accd..000000000 --- a/web/src/pages/data-flow/canvas/node/relevant-node.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Handle, NodeProps, Position } from '@xyflow/react'; -import { Flex } from 'antd'; -import classNames from 'classnames'; -import { RightHandleStyle } from './handle-icon'; - -import { useTheme } from '@/components/theme-provider'; -import { IRelevantNode } from '@/interfaces/database/flow'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { useReplaceIdWithName } from '../../hooks'; -import styles from './index.less'; -import NodeHeader from './node-header'; - -function InnerRelevantNode({ id, data, selected }: NodeProps) { - const yes = get(data, 'form.yes'); - const no = get(data, 'form.no'); - const replaceIdWithName = useReplaceIdWithName(); - const { theme } = useTheme(); - return ( -
- - - - - - - -
Yes
-
{replaceIdWithName(yes)}
-
- -
No
-
{replaceIdWithName(no)}
-
-
-
- ); -} - -export const RelevantNode = memo(InnerRelevantNode); diff --git a/web/src/pages/data-flow/canvas/node/retrieval-node.tsx b/web/src/pages/data-flow/canvas/node/retrieval-node.tsx deleted file mode 100644 index 5703ec1f4..000000000 --- a/web/src/pages/data-flow/canvas/node/retrieval-node.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { RAGFlowAvatar } from '@/components/ragflow-avatar'; -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; -import { IRetrievalNode } from '@/interfaces/database/flow'; -import { NodeProps, Position } from '@xyflow/react'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { NodeHandleId } from '../../constant'; -import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; -import { CommonHandle } from './handle'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; - -function InnerRetrievalNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []); - const { list: knowledgeList } = useFetchKnowledgeList(true); - - const getLabel = useGetVariableLabelByValue(id); - - return ( - - - - - 0, - })} - > -
- {knowledgeBaseIds.map((id) => { - const item = knowledgeList.find((y) => id === y.id); - const label = getLabel(id); - - return ( -
-
- - -
{label || item?.name}
-
-
- ); - })} -
-
-
- ); -} - -export const RetrievalNode = memo(InnerRetrievalNode); diff --git a/web/src/pages/data-flow/canvas/node/rewrite-node.tsx b/web/src/pages/data-flow/canvas/node/rewrite-node.tsx deleted file mode 100644 index 134899c8b..000000000 --- a/web/src/pages/data-flow/canvas/node/rewrite-node.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import LLMLabel from '@/components/llm-select/llm-label'; -import { useTheme } from '@/components/theme-provider'; -import { IRewriteNode } from '@/interfaces/database/flow'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { memo } from 'react'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import styles from './index.less'; -import NodeHeader from './node-header'; - -function InnerRewriteNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const { theme } = useTheme(); - return ( -
- - - - - -
- -
-
- ); -} - -export const RewriteNode = memo(InnerRewriteNode); diff --git a/web/src/pages/data-flow/canvas/node/switch-node.tsx b/web/src/pages/data-flow/canvas/node/switch-node.tsx deleted file mode 100644 index b62e45adb..000000000 --- a/web/src/pages/data-flow/canvas/node/switch-node.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { Card, CardContent } from '@/components/ui/card'; -import { ISwitchCondition, ISwitchNode } from '@/interfaces/database/flow'; -import { NodeProps, Position } from '@xyflow/react'; -import { memo, useCallback } from 'react'; -import { NodeHandleId, SwitchOperatorOptions } from '../../constant'; -import { LogicalOperatorIcon } from '../../form/switch-form'; -import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; -import { CommonHandle } from './handle'; -import { RightHandleStyle } from './handle-icon'; -import NodeHeader from './node-header'; -import { NodeWrapper } from './node-wrapper'; -import { ToolBar } from './toolbar'; -import { useBuildSwitchHandlePositions } from './use-build-switch-handle-positions'; - -const getConditionKey = (idx: number, length: number) => { - if (idx === 0 && length !== 1) { - return 'If'; - } else if (idx === length - 1) { - return 'Else'; - } - - return 'ElseIf'; -}; - -const ConditionBlock = ({ - condition, - nodeId, -}: { condition: ISwitchCondition } & { nodeId: string }) => { - const items = condition?.items ?? []; - const getLabel = useGetVariableLabelByValue(nodeId); - - const renderOperatorIcon = useCallback((operator?: string) => { - const item = SwitchOperatorOptions.find((x) => x.value === operator); - if (item) { - return ( - - ); - } - return <>; - }, []); - - return ( - - - {items.map((x, idx) => ( -
-
-
- {getLabel(x?.cpn_id)} -
- {renderOperatorIcon(x?.operator)} -
{x?.value}
-
-
- ))} -
-
- ); -}; - -function InnerSwitchNode({ id, data, selected }: NodeProps) { - const { positions } = useBuildSwitchHandlePositions({ data, id }); - return ( - - - - -
- {positions.map((position, idx) => { - return ( -
-
-
- {getConditionKey(idx, positions.length)} -
- {idx < positions.length - 1 && position.text} -
-
- - {idx < positions.length - 1 && - position.condition?.logical_operator?.toUpperCase()} - - {position.condition && ( - - )} -
- -
- ); - })} -
-
-
- ); -} - -export const SwitchNode = memo(InnerSwitchNode); diff --git a/web/src/pages/data-flow/canvas/node/template-node.tsx b/web/src/pages/data-flow/canvas/node/template-node.tsx deleted file mode 100644 index b204717ab..000000000 --- a/web/src/pages/data-flow/canvas/node/template-node.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { useTheme } from '@/components/theme-provider'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import { Flex } from 'antd'; -import classNames from 'classnames'; -import { get } from 'lodash'; -import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query'; -import { IGenerateParameter } from '../../interface'; -import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; -import NodeHeader from './node-header'; - -import { ITemplateNode } from '@/interfaces/database/flow'; -import { memo } from 'react'; -import styles from './index.less'; - -function InnerTemplateNode({ - id, - data, - isConnectable = true, - selected, -}: NodeProps) { - const parameters: IGenerateParameter[] = get(data, 'form.parameters', []); - const getLabel = useGetComponentLabelByValue(id); - const { theme } = useTheme(); - return ( -
- - - - - - - {parameters.map((x) => ( - - - - {getLabel(x.component_id)} - - - ))} - -
- ); -} - -export const TemplateNode = memo(InnerTemplateNode); diff --git a/web/src/pages/data-flow/canvas/node/tool-node.tsx b/web/src/pages/data-flow/canvas/node/tool-node.tsx deleted file mode 100644 index 42c7bf3b5..000000000 --- a/web/src/pages/data-flow/canvas/node/tool-node.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { IAgentForm, IToolNode } from '@/interfaces/database/agent'; -import { Handle, NodeProps, Position } from '@xyflow/react'; -import { get } from 'lodash'; -import { MouseEventHandler, memo, useCallback } from 'react'; -import { NodeHandleId, Operator } from '../../constant'; -import { ToolCard } from '../../form/agent-form/agent-tools'; -import { useFindMcpById } from '../../hooks/use-find-mcp-by-id'; -import OperatorIcon from '../../operator-icon'; -import useGraphStore from '../../store'; -import { NodeWrapper } from './node-wrapper'; - -function InnerToolNode({ - id, - isConnectable = true, - selected, -}: NodeProps) { - const { edges, getNode } = useGraphStore((state) => state); - const upstreamAgentNodeId = edges.find((x) => x.target === id)?.source; - const upstreamAgentNode = getNode(upstreamAgentNodeId); - const { findMcpById } = useFindMcpById(); - - const handleClick = useCallback( - (operator: string): MouseEventHandler => - (e) => { - if (operator === Operator.Code) { - e.preventDefault(); - e.stopPropagation(); - } - }, - [], - ); - - const tools: IAgentForm['tools'] = get( - upstreamAgentNode, - 'data.form.tools', - [], - ); - - const mcpList: IAgentForm['mcp'] = get( - upstreamAgentNode, - 'data.form.mcp', - [], - ); - - return ( - - -
    - {tools.map((x) => ( - -
    - - {x.component_name} -
    -
    - ))} - - {mcpList.map((x) => ( - - {findMcpById(x.mcp_id)?.name} - - ))} -
-
- ); -} - -export const ToolNode = memo(InnerToolNode); diff --git a/web/src/pages/data-flow/canvas/node/toolbar.tsx b/web/src/pages/data-flow/canvas/node/toolbar.tsx index a8b5cd13c..63076c4c4 100644 --- a/web/src/pages/data-flow/canvas/node/toolbar.tsx +++ b/web/src/pages/data-flow/canvas/node/toolbar.tsx @@ -11,7 +11,6 @@ import { PropsWithChildren, useCallback, } from 'react'; -import { Operator } from '../../constant'; import { useDuplicateNode } from '../../hooks'; import useGraphStore from '../../store'; @@ -38,20 +37,13 @@ export function ToolBar({ showRun = true, }: ToolBarProps) { const deleteNodeById = useGraphStore((store) => store.deleteNodeById); - const deleteIterationNodeById = useGraphStore( - (store) => store.deleteIterationNodeById, - ); const deleteNode: MouseEventHandler = useCallback( (e) => { e.stopPropagation(); - if (label === Operator.Iteration) { - deleteIterationNodeById(id); - } else { - deleteNodeById(id); - } + deleteNodeById(id); }, - [deleteIterationNodeById, deleteNodeById, id, label], + [deleteNodeById, id], ); const duplicateNode = useDuplicateNode(); diff --git a/web/src/pages/data-flow/constant.tsx b/web/src/pages/data-flow/constant.tsx index df83d8429..9d1bc0f90 100644 --- a/web/src/pages/data-flow/constant.tsx +++ b/web/src/pages/data-flow/constant.tsx @@ -42,29 +42,8 @@ export const BeginId = 'begin'; export enum Operator { Begin = 'Begin', - Retrieval = 'Retrieval', - Categorize = 'Categorize', - Message = 'Message', - Relevant = 'Relevant', - RewriteQuestion = 'RewriteQuestion', - KeywordExtract = 'KeywordExtract', - ExeSQL = 'ExeSQL', - Switch = 'Switch', - Concentrator = 'Concentrator', Note = 'Note', - Crawler = 'Crawler', - Invoke = 'Invoke', - Email = 'Email', - Iteration = 'Iteration', - IterationStart = 'IterationItem', - Code = 'CodeExec', - WaitingDialogue = 'WaitingDialogue', - Agent = 'Agent', - Tool = 'Tool', - UserFillUp = 'UserFillUp', - StringTransform = 'StringTransform', Parser = 'Parser', - Chunker = 'Chunker', Tokenizer = 'Tokenizer', Splitter = 'Splitter', HierarchicalMerger = 'HierarchicalMerger', @@ -404,7 +383,7 @@ export const CategorizeAnchorPointPositions = [ // key is the source of the edge, value is the target of the edge // no connection lines are allowed between key and value export const RestrictedUpstreamMap = { - [Operator.Begin]: [Operator.Relevant], + [Operator.Begin]: [], [Operator.Parser]: [Operator.Begin], [Operator.Splitter]: [Operator.Begin], [Operator.HierarchicalMerger]: [Operator.Begin], @@ -413,29 +392,8 @@ export const RestrictedUpstreamMap = { export const NodeMap = { [Operator.Begin]: 'beginNode', - [Operator.Categorize]: 'categorizeNode', - [Operator.Retrieval]: 'retrievalNode', - [Operator.Message]: 'messageNode', - [Operator.Relevant]: 'relevantNode', - [Operator.RewriteQuestion]: 'rewriteNode', - [Operator.KeywordExtract]: 'keywordNode', - [Operator.ExeSQL]: 'ragNode', - [Operator.Switch]: 'switchNode', - [Operator.Concentrator]: 'logicNode', [Operator.Note]: 'noteNode', - [Operator.Crawler]: 'ragNode', - [Operator.Invoke]: 'ragNode', - [Operator.Email]: 'ragNode', - [Operator.Iteration]: 'group', - [Operator.IterationStart]: 'iterationStartNode', - [Operator.Code]: 'ragNode', - [Operator.WaitingDialogue]: 'ragNode', - [Operator.Agent]: 'agentNode', - [Operator.Tool]: 'toolNode', - [Operator.UserFillUp]: 'ragNode', - [Operator.StringTransform]: 'ragNode', [Operator.Parser]: 'parserNode', - [Operator.Chunker]: 'chunkerNode', [Operator.Tokenizer]: 'tokenizerNode', [Operator.Splitter]: 'splitterNode', [Operator.HierarchicalMerger]: 'hierarchicalMergerNode', @@ -459,16 +417,7 @@ export const BeginQueryTypeIconMap = { [BeginQueryType.Boolean]: ToggleLeft, }; -export const NoDebugOperatorsList = [ - Operator.Begin, - Operator.Concentrator, - Operator.Message, - Operator.RewriteQuestion, - Operator.Switch, - Operator.Iteration, - Operator.UserFillUp, - Operator.IterationStart, -]; +export const NoDebugOperatorsList = [Operator.Begin]; export enum NodeHandleId { Start = 'start', diff --git a/web/src/pages/data-flow/form-sheet/form-config-map.tsx b/web/src/pages/data-flow/form-sheet/form-config-map.tsx index 20caee379..ac8ff52f2 100644 --- a/web/src/pages/data-flow/form-sheet/form-config-map.tsx +++ b/web/src/pages/data-flow/form-sheet/form-config-map.tsx @@ -1,98 +1,20 @@ import { Operator } from '../constant'; -import AgentForm from '../form/agent-form'; import BeginForm from '../form/begin-form'; -import CategorizeForm from '../form/categorize-form'; -import ChunkerForm from '../form/chunker-form'; -import CodeForm from '../form/code-form'; -import CrawlerForm from '../form/crawler-form'; -import EmailForm from '../form/email-form'; -import ExeSQLForm from '../form/exesql-form'; import HierarchicalMergerForm from '../form/hierarchical-merger-form'; -import InvokeForm from '../form/invoke-form'; -import IterationForm from '../form/iteration-form'; -import IterationStartForm from '../form/iteration-start-from'; -import KeywordExtractForm from '../form/keyword-extract-form'; -import MessageForm from '../form/message-form'; import ParserForm from '../form/parser-form'; -import RelevantForm from '../form/relevant-form'; -import RetrievalForm from '../form/retrieval-form/next'; -import RewriteQuestionForm from '../form/rewrite-question-form'; import SplitterForm from '../form/splitter-form'; -import StringTransformForm from '../form/string-transform-form'; -import SwitchForm from '../form/switch-form'; import TokenizerForm from '../form/tokenizer-form'; -import UserFillUpForm from '../form/user-fill-up-form'; export const FormConfigMap = { [Operator.Begin]: { component: BeginForm, }, - [Operator.Retrieval]: { - component: RetrievalForm, - }, - [Operator.Categorize]: { - component: CategorizeForm, - }, - [Operator.Message]: { - component: MessageForm, - }, - [Operator.Relevant]: { - component: RelevantForm, - }, - [Operator.RewriteQuestion]: { - component: RewriteQuestionForm, - }, - [Operator.Code]: { - component: CodeForm, - }, - [Operator.WaitingDialogue]: { - component: CodeForm, - }, - [Operator.Agent]: { - component: AgentForm, - }, - [Operator.KeywordExtract]: { - component: KeywordExtractForm, - }, - [Operator.ExeSQL]: { - component: ExeSQLForm, - }, - [Operator.Switch]: { - component: SwitchForm, - }, - [Operator.Crawler]: { - component: CrawlerForm, - }, - [Operator.Invoke]: { - component: InvokeForm, - }, - [Operator.Concentrator]: { - component: () => <>, - }, [Operator.Note]: { component: () => <>, }, - [Operator.Email]: { - component: EmailForm, - }, - [Operator.Iteration]: { - component: IterationForm, - }, - [Operator.IterationStart]: { - component: IterationStartForm, - }, - [Operator.UserFillUp]: { - component: UserFillUpForm, - }, - [Operator.StringTransform]: { - component: StringTransformForm, - }, [Operator.Parser]: { component: ParserForm, }, - [Operator.Chunker]: { - component: ChunkerForm, - }, [Operator.Tokenizer]: { component: TokenizerForm, }, diff --git a/web/src/pages/data-flow/form-sheet/next.tsx b/web/src/pages/data-flow/form-sheet/next.tsx index 545c08ac4..aedd01b1b 100644 --- a/web/src/pages/data-flow/form-sheet/next.tsx +++ b/web/src/pages/data-flow/form-sheet/next.tsx @@ -8,17 +8,12 @@ import { import { IModalProps } from '@/interfaces/common'; import { RAGFlowNodeType } from '@/interfaces/database/flow'; import { cn } from '@/lib/utils'; -import { lowerFirst } from 'lodash'; -import { Play, X } from 'lucide-react'; -import { useMemo } from 'react'; +import { X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { BeginId, Operator } from '../constant'; import { AgentFormContext } from '../context'; -import { RunTooltip } from '../flow-tooltip'; import { useHandleNodeNameChange } from '../hooks/use-change-node-name'; import OperatorIcon from '../operator-icon'; -import useGraphStore from '../store'; -import { needsSingleStepDebugging } from '../utils'; import { FormConfigMap } from './form-config-map'; import SingleDebugSheet from './single-debug-sheet'; @@ -39,10 +34,9 @@ const FormSheet = ({ singleDebugDrawerVisible, chatVisible, hideSingleDebugDrawer, - showSingleDebugDrawer, }: IModalProps & IProps) => { const operatorName: Operator = node?.data.label as Operator; - const clickedToolId = useGraphStore((state) => state.clickedToolId); + // const clickedToolId = useGraphStore((state) => state.clickedToolId); const currentFormMap = FormConfigMap[operatorName]; @@ -53,13 +47,6 @@ const FormSheet = ({ data: node?.data, }); - const isMcp = useMemo(() => { - return ( - operatorName === Operator.Tool && - Object.values(Operator).every((x) => x !== clickedToolId) - ); - }, [clickedToolId, operatorName]); - const { t } = useTranslation(); return ( @@ -75,41 +62,28 @@ const FormSheet = ({
- - {isMcp ? ( -
MCP Config
- ) : ( -
- - {node?.id === BeginId ? ( - {t(BeginId)} - ) : ( - - )} -
- )} - - {needsSingleStepDebugging(operatorName) && ( +
+ + {node?.id === BeginId ? ( + {t(BeginId)} + ) : ( + + )} +
+ {/* {needsSingleStepDebugging(operatorName) && ( - )} + )} */}
- {isMcp || ( - - {t( - `dataflow.${lowerFirst(operatorName === Operator.Tool ? clickedToolId : operatorName)}Description`, - )} - - )}
diff --git a/web/src/pages/data-flow/form/agent-form/agent-tools.tsx b/web/src/pages/data-flow/form/agent-form/agent-tools.tsx deleted file mode 100644 index 9e5620823..000000000 --- a/web/src/pages/data-flow/form/agent-form/agent-tools.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import { BlockButton } from '@/components/ui/button'; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from '@/components/ui/tooltip'; -import { cn } from '@/lib/utils'; -import { Position } from '@xyflow/react'; -import { t } from 'i18next'; -import { PencilLine, X } from 'lucide-react'; -import { - MouseEventHandler, - PropsWithChildren, - useCallback, - useContext, - useMemo, -} from 'react'; -import { Operator } from '../../constant'; -import { AgentInstanceContext } from '../../context'; -import { useFindMcpById } from '../../hooks/use-find-mcp-by-id'; -import { INextOperatorForm } from '../../interface'; -import OperatorIcon from '../../operator-icon'; -import useGraphStore from '../../store'; -import { filterDownstreamAgentNodeIds } from '../../utils/filter-downstream-nodes'; -import { ToolPopover } from './tool-popover'; -import { useDeleteAgentNodeMCP } from './tool-popover/use-update-mcp'; -import { useDeleteAgentNodeTools } from './tool-popover/use-update-tools'; -import { useGetAgentMCPIds, useGetAgentToolNames } from './use-get-tools'; - -export function ToolCard({ - children, - className, - ...props -}: PropsWithChildren & React.HTMLAttributes) { - const element = useMemo(() => { - return ( -
  • - {children} -
  • - ); - }, [children, className, props]); - - if (children === Operator.Code) { - return ( - - {element} - -

    It doesn't have any config.

    -
    -
    - ); - } - - return element; -} - -type ActionButtonProps = { - record: T; - deleteRecord(record: T): void; - edit: MouseEventHandler; -}; - -function ActionButton({ deleteRecord, record, edit }: ActionButtonProps) { - const handleDelete = useCallback(() => { - deleteRecord(record); - }, [deleteRecord, record]); - - return ( -
    - - -
    - ); -} - -export function AgentTools() { - const { toolNames } = useGetAgentToolNames(); - const { deleteNodeTool } = useDeleteAgentNodeTools(); - const { mcpIds } = useGetAgentMCPIds(); - const { findMcpById } = useFindMcpById(); - const { deleteNodeMCP } = useDeleteAgentNodeMCP(); - const { showFormDrawer } = useContext(AgentInstanceContext); - const { clickedNodeId, findAgentToolNodeById, selectNodeIds } = useGraphStore( - (state) => state, - ); - - const handleEdit: MouseEventHandler = useCallback( - (e) => { - const toolNodeId = findAgentToolNodeById(clickedNodeId); - if (toolNodeId) { - selectNodeIds([toolNodeId]); - showFormDrawer(e, toolNodeId); - } - }, - [clickedNodeId, findAgentToolNodeById, selectNodeIds, showFormDrawer], - ); - - return ( -
    - {t('flow.tools')} -
      - {toolNames.map((x) => ( - -
      - - {x} -
      - -
      - ))} - {mcpIds.map((id) => ( - - {findMcpById(id)?.name} - - - ))} -
    - - {t('flow.addTools')} - -
    - ); -} - -export function Agents({ node }: INextOperatorForm) { - const { addCanvasNode } = useContext(AgentInstanceContext); - const { deleteAgentDownstreamNodesById, edges, getNode, selectNodeIds } = - useGraphStore((state) => state); - const { showFormDrawer } = useContext(AgentInstanceContext); - - const handleEdit = useCallback( - (nodeId: string): MouseEventHandler => - (e) => { - selectNodeIds([nodeId]); - showFormDrawer(e, nodeId); - }, - [selectNodeIds, showFormDrawer], - ); - - const subBottomAgentNodeIds = useMemo(() => { - return filterDownstreamAgentNodeIds(edges, node?.id); - }, [edges, node?.id]); - - return ( -
    - {t('flow.agent')} -
      - {subBottomAgentNodeIds.map((id) => { - const currentNode = getNode(id); - - return ( - - {currentNode?.data.name} - - - ); - })} -
    - - {t('flow.addAgent')} - -
    - ); -} diff --git a/web/src/pages/data-flow/form/agent-form/dynamic-prompt.tsx b/web/src/pages/data-flow/form/agent-form/dynamic-prompt.tsx deleted file mode 100644 index 1cda9fbd5..000000000 --- a/web/src/pages/data-flow/form/agent-form/dynamic-prompt.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { BlockButton, Button } from '@/components/ui/button'; -import { - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { RAGFlowSelect } from '@/components/ui/select'; -import { X } from 'lucide-react'; -import { memo } from 'react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { PromptRole } from '../../constant'; -import { PromptEditor } from '../components/prompt-editor'; - -const options = [ - { label: 'User', value: PromptRole.User }, - { label: 'Assistant', value: PromptRole.Assistant }, -]; - -const DynamicPrompt = () => { - const { t } = useTranslation(); - const form = useFormContext(); - const name = 'prompts'; - - const { fields, append, remove } = useFieldArray({ - name: name, - control: form.control, - }); - - return ( - - {t('flow.msg')} -
    - {fields.map((field, index) => ( -
    -
    - ( - - - - - - - - )} - /> - - ( - - -
    - -
    -
    -
    - )} - /> -
    - -
    - ))} -
    - - append({ content: '', role: PromptRole.User })} - > - Add - -
    - ); -}; - -export default memo(DynamicPrompt); diff --git a/web/src/pages/data-flow/form/agent-form/dynamic-tool.tsx b/web/src/pages/data-flow/form/agent-form/dynamic-tool.tsx deleted file mode 100644 index afda465b6..000000000 --- a/web/src/pages/data-flow/form/agent-form/dynamic-tool.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { BlockButton, Button } from '@/components/ui/button'; -import { - FormControl, - FormField, - FormItem, - FormMessage, -} from '@/components/ui/form'; -import { X } from 'lucide-react'; -import { memo } from 'react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; -import { PromptEditor } from '../components/prompt-editor'; - -const DynamicTool = () => { - const form = useFormContext(); - const name = 'tools'; - - const { fields, append, remove } = useFieldArray({ - name: name, - control: form.control, - }); - - return ( - -
    - {fields.map((field, index) => ( -
    -
    - ( - - -
    - -
    -
    -
    - )} - /> -
    - -
    - ))} -
    - - append({ component_name: '' })}> - Add - -
    - ); -}; - -export default memo(DynamicTool); diff --git a/web/src/pages/data-flow/form/agent-form/index.tsx b/web/src/pages/data-flow/form/agent-form/index.tsx deleted file mode 100644 index 9ca0fb69c..000000000 --- a/web/src/pages/data-flow/form/agent-form/index.tsx +++ /dev/null @@ -1,280 +0,0 @@ -import { Collapse } from '@/components/collapse'; -import { FormContainer } from '@/components/form-container'; -import { - LargeModelFilterFormSchema, - LargeModelFormField, -} from '@/components/large-model-form-field'; -import { LlmSettingSchema } from '@/components/llm-setting-items/next'; -import { MessageHistoryWindowSizeFormField } from '@/components/message-history-window-size-item'; -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, -} from '@/components/ui/form'; -import { Input, NumberInput } from '@/components/ui/input'; -import { Switch } from '@/components/ui/switch'; -import { LlmModelType } from '@/constants/knowledge'; -import { useFindLlmByUuid } from '@/hooks/use-llm-request'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo, useEffect, useMemo } from 'react'; -import { useForm, useWatch } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; -import { - AgentExceptionMethod, - NodeHandleId, - VariableType, - initialAgentValues, -} from '../../constant'; -import { INextOperatorForm } from '../../interface'; -import useGraphStore from '../../store'; -import { isBottomSubAgent } from '../../utils'; -import { buildOutputList } from '../../utils/build-output-list'; -import { DescriptionField } from '../components/description-field'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { PromptEditor } from '../components/prompt-editor'; -import { QueryVariable } from '../components/query-variable'; -import { AgentTools, Agents } from './agent-tools'; -import { useValues } from './use-values'; -import { useWatchFormChange } from './use-watch-change'; - -const FormSchema = z.object({ - sys_prompt: z.string(), - description: z.string().optional(), - user_prompt: z.string().optional(), - prompts: z.string().optional(), - // prompts: z - // .array( - // z.object({ - // role: z.string(), - // content: z.string(), - // }), - // ) - // .optional(), - message_history_window_size: z.coerce.number(), - tools: z - .array( - z.object({ - component_name: z.string(), - }), - ) - .optional(), - ...LlmSettingSchema, - max_retries: z.coerce.number(), - delay_after_error: z.coerce.number().optional(), - visual_files_var: z.string().optional(), - max_rounds: z.coerce.number().optional(), - exception_method: z.string().optional(), - exception_goto: z.array(z.string()).optional(), - exception_default_value: z.string().optional(), - ...LargeModelFilterFormSchema, - cite: z.boolean().optional(), -}); - -const outputList = buildOutputList(initialAgentValues.outputs); - -function AgentForm({ node }: INextOperatorForm) { - const { t } = useTranslation(); - const { edges, deleteEdgesBySourceAndSourceHandle } = useGraphStore( - (state) => state, - ); - - const defaultValues = useValues(node); - - const ExceptionMethodOptions = Object.values(AgentExceptionMethod).map( - (x) => ({ - label: t(`flow.${x}`), - value: x, - }), - ); - - const isSubAgent = useMemo(() => { - return isBottomSubAgent(edges, node?.id); - }, [edges, node?.id]); - - const form = useForm>({ - defaultValues: defaultValues, - resolver: zodResolver(FormSchema), - }); - - const llmId = useWatch({ control: form.control, name: 'llm_id' }); - - const findLlmByUuid = useFindLlmByUuid(); - - const exceptionMethod = useWatch({ - control: form.control, - name: 'exception_method', - }); - - useEffect(() => { - if (exceptionMethod !== AgentExceptionMethod.Goto) { - if (node?.id) { - deleteEdgesBySourceAndSourceHandle( - node?.id, - NodeHandleId.AgentException, - ); - } - } - }, [deleteEdgesBySourceAndSourceHandle, exceptionMethod, node?.id]); - - useWatchFormChange(node?.id, form); - - return ( -
    - - - {isSubAgent && } - - {findLlmByUuid(llmId)?.model_type === LlmModelType.Image2text && ( - - )} - - - - ( - - {t('flow.systemPrompt')} - - - - - )} - /> - - {isSubAgent || ( - - {/* */} - ( - - {t('flow.userPrompt')} - -
    - -
    -
    -
    - )} - /> -
    - )} - - - - - - {t('flow.advancedSettings')}}> - - - ( - - - {t('flow.cite')} - - - - - - )} - /> - ( - - {t('flow.maxRetries')} - - - - - )} - /> - ( - - {t('flow.delayEfterError')} - - - - - )} - /> - ( - - {t('flow.maxRounds')} - - - - - )} - /> - ( - - {t('flow.exceptionMethod')} - - - - - )} - /> - {exceptionMethod === AgentExceptionMethod.Comment && ( - ( - - {t('flow.ExceptionDefaultValue')} - - - - - )} - /> - )} - - - -
    -
    - ); -} - -export default memo(AgentForm); diff --git a/web/src/pages/data-flow/form/agent-form/tool-popover/index.tsx b/web/src/pages/data-flow/form/agent-form/tool-popover/index.tsx deleted file mode 100644 index 84f1ed46a..000000000 --- a/web/src/pages/data-flow/form/agent-form/tool-popover/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '@/components/ui/popover'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { Operator } from '@/pages/agent/constant'; -import { AgentFormContext, AgentInstanceContext } from '@/pages/agent/context'; -import useGraphStore from '@/pages/agent/store'; -import { Position } from '@xyflow/react'; -import { t } from 'i18next'; -import { PropsWithChildren, useCallback, useContext, useEffect } from 'react'; -import { useGetAgentMCPIds, useGetAgentToolNames } from '../use-get-tools'; -import { MCPCommand, ToolCommand } from './tool-command'; -import { useUpdateAgentNodeMCP } from './use-update-mcp'; -import { useUpdateAgentNodeTools } from './use-update-tools'; - -enum ToolType { - Common = 'common', - MCP = 'mcp', -} - -export function ToolPopover({ children }: PropsWithChildren) { - const { addCanvasNode } = useContext(AgentInstanceContext); - const node = useContext(AgentFormContext); - const { updateNodeTools } = useUpdateAgentNodeTools(); - const { toolNames } = useGetAgentToolNames(); - const deleteAgentToolNodeById = useGraphStore( - (state) => state.deleteAgentToolNodeById, - ); - const { mcpIds } = useGetAgentMCPIds(); - const { updateNodeMCP } = useUpdateAgentNodeMCP(); - - const handleChange = useCallback( - (value: string[]) => { - if (Array.isArray(value) && node?.id) { - updateNodeTools(value); - } - }, - [node?.id, updateNodeTools], - ); - - useEffect(() => { - const total = toolNames.length + mcpIds.length; - if (node?.id) { - if (total > 0) { - addCanvasNode(Operator.Tool, { - position: Position.Bottom, - nodeId: node?.id, - })(); - } else { - deleteAgentToolNodeById(node.id); - } - } - }, [ - addCanvasNode, - deleteAgentToolNodeById, - mcpIds.length, - node?.id, - toolNames.length, - ]); - - return ( - - {children} - - - - - {t('flow.builtIn')} - - - MCP - - - - - - - - - - - - ); -} diff --git a/web/src/pages/data-flow/form/agent-form/tool-popover/tool-command.tsx b/web/src/pages/data-flow/form/agent-form/tool-popover/tool-command.tsx deleted file mode 100644 index 6118c43ab..000000000 --- a/web/src/pages/data-flow/form/agent-form/tool-popover/tool-command.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { CheckIcon } from 'lucide-react'; - -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, -} from '@/components/ui/command'; -import { useListMcpServer } from '@/hooks/use-mcp-request'; -import { cn } from '@/lib/utils'; -import { Operator } from '@/pages/agent/constant'; -import OperatorIcon from '@/pages/agent/operator-icon'; -import { t } from 'i18next'; -import { lowerFirst } from 'lodash'; -import { PropsWithChildren, useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -const Menus = [ - { - label: t('flow.search'), - list: [ - Operator.TavilySearch, - Operator.TavilyExtract, - Operator.Google, - // Operator.Bing, - Operator.DuckDuckGo, - Operator.Wikipedia, - Operator.SearXNG, - Operator.YahooFinance, - Operator.PubMed, - Operator.GoogleScholar, - Operator.ArXiv, - Operator.WenCai, - ], - }, - { - label: t('flow.communication'), - list: [Operator.Email], - }, - // { - // label: 'Productivity', - // list: [], - // }, - { - label: t('flow.developer'), - list: [Operator.GitHub, Operator.ExeSQL, Operator.Code, Operator.Retrieval], - }, -]; - -type ToolCommandProps = { - value?: string[]; - onChange?(values: string[]): void; -}; - -type ToolCommandItemProps = { - toggleOption(id: string): void; - id: string; - isSelected: boolean; -} & ToolCommandProps; - -function ToolCommandItem({ - toggleOption, - id, - isSelected, - children, -}: ToolCommandItemProps & PropsWithChildren) { - return ( - toggleOption(id)}> -
    - -
    - {children} -
    - ); -} - -function useHandleSelectChange({ onChange, value }: ToolCommandProps) { - const [currentValue, setCurrentValue] = useState([]); - - const toggleOption = useCallback( - (option: string) => { - const newSelectedValues = currentValue.includes(option) - ? currentValue.filter((value) => value !== option) - : [...currentValue, option]; - setCurrentValue(newSelectedValues); - onChange?.(newSelectedValues); - }, - [currentValue, onChange], - ); - - useEffect(() => { - if (Array.isArray(value)) { - setCurrentValue(value); - } - }, [value]); - - return { - toggleOption, - currentValue, - }; -} - -export function ToolCommand({ value, onChange }: ToolCommandProps) { - const { t } = useTranslation(); - const { toggleOption, currentValue } = useHandleSelectChange({ - onChange, - value, - }); - - return ( - - - - No results found. - {Menus.map((x) => ( - - {x.list.map((y) => { - const isSelected = currentValue.includes(y); - return ( - - <> - - {t(`flow.${lowerFirst(y)}`)} - - - ); - })} - - ))} - - - ); -} - -export function MCPCommand({ onChange, value }: ToolCommandProps) { - const { data } = useListMcpServer(); - const { toggleOption, currentValue } = useHandleSelectChange({ - onChange, - value, - }); - - return ( - - - - No results found. - {data.mcp_servers.map((item) => { - const isSelected = currentValue.includes(item.id); - - return ( - - {item.name} - - ); - })} - - - ); -} diff --git a/web/src/pages/data-flow/form/agent-form/tool-popover/use-update-mcp.ts b/web/src/pages/data-flow/form/agent-form/tool-popover/use-update-mcp.ts deleted file mode 100644 index 827b9f9e1..000000000 --- a/web/src/pages/data-flow/form/agent-form/tool-popover/use-update-mcp.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useListMcpServer } from '@/hooks/use-mcp-request'; -import { IAgentForm } from '@/interfaces/database/agent'; -import { AgentFormContext } from '@/pages/agent/context'; -import useGraphStore from '@/pages/agent/store'; -import { get } from 'lodash'; -import { useCallback, useContext, useMemo } from 'react'; - -export function useGetNodeMCP() { - const node = useContext(AgentFormContext); - - return useMemo(() => { - const mcp: IAgentForm['mcp'] = get(node, 'data.form.mcp'); - return mcp; - }, [node]); -} - -export function useUpdateAgentNodeMCP() { - const { updateNodeForm } = useGraphStore((state) => state); - const node = useContext(AgentFormContext); - const mcpList = useGetNodeMCP(); - const { data } = useListMcpServer(); - const mcpServers = data.mcp_servers; - - const findMcpTools = useCallback( - (mcpId: string) => { - const mcp = mcpServers.find((x) => x.id === mcpId); - return mcp?.variables.tools; - }, - [mcpServers], - ); - - const updateNodeMCP = useCallback( - (value: string[]) => { - if (node?.id) { - const nextValue = value.reduce((pre, cur) => { - const mcp = mcpList.find((x) => x.mcp_id === cur); - const tools = findMcpTools(cur); - if (mcp) { - pre.push(mcp); - } else if (tools) { - pre.push({ - mcp_id: cur, - tools: {}, - }); - } - return pre; - }, []); - - updateNodeForm(node?.id, nextValue, ['mcp']); - } - }, - [node?.id, updateNodeForm, mcpList, findMcpTools], - ); - - return { updateNodeMCP }; -} - -export function useDeleteAgentNodeMCP() { - const { updateNodeForm } = useGraphStore((state) => state); - const mcpList = useGetNodeMCP(); - const node = useContext(AgentFormContext); - - const deleteNodeMCP = useCallback( - (value: string) => () => { - const nextMCP = mcpList.filter((x) => x.mcp_id !== value); - if (node?.id) { - updateNodeForm(node?.id, nextMCP, ['mcp']); - } - }, - [node?.id, mcpList, updateNodeForm], - ); - - return { deleteNodeMCP }; -} diff --git a/web/src/pages/data-flow/form/agent-form/tool-popover/use-update-tools.ts b/web/src/pages/data-flow/form/agent-form/tool-popover/use-update-tools.ts deleted file mode 100644 index db579561a..000000000 --- a/web/src/pages/data-flow/form/agent-form/tool-popover/use-update-tools.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { IAgentForm } from '@/interfaces/database/agent'; -import { Operator } from '@/pages/agent/constant'; -import { AgentFormContext } from '@/pages/agent/context'; -import { useAgentToolInitialValues } from '@/pages/agent/hooks/use-agent-tool-initial-values'; -import useGraphStore from '@/pages/agent/store'; -import { get } from 'lodash'; -import { useCallback, useContext, useMemo } from 'react'; - -export function useGetNodeTools() { - const node = useContext(AgentFormContext); - - return useMemo(() => { - const tools: IAgentForm['tools'] = get(node, 'data.form.tools'); - return tools; - }, [node]); -} - -export function useUpdateAgentNodeTools() { - const { updateNodeForm } = useGraphStore((state) => state); - const node = useContext(AgentFormContext); - const tools = useGetNodeTools(); - const { initializeAgentToolValues } = useAgentToolInitialValues(); - - const updateNodeTools = useCallback( - (value: string[]) => { - if (node?.id) { - const nextValue = value.reduce((pre, cur) => { - const tool = tools.find((x) => x.component_name === cur); - pre.push( - tool - ? tool - : { - component_name: cur, - name: cur, - params: initializeAgentToolValues(cur as Operator), - }, - ); - return pre; - }, []); - - updateNodeForm(node?.id, nextValue, ['tools']); - } - }, - [initializeAgentToolValues, node?.id, tools, updateNodeForm], - ); - - return { updateNodeTools }; -} - -export function useDeleteAgentNodeTools() { - const { updateNodeForm } = useGraphStore((state) => state); - const tools = useGetNodeTools(); - const node = useContext(AgentFormContext); - - const deleteNodeTool = useCallback( - (value: string) => () => { - const nextTools = tools.filter((x) => x.component_name !== value); - if (node?.id) { - updateNodeForm(node?.id, nextTools, ['tools']); - } - }, - [node?.id, tools, updateNodeForm], - ); - - return { deleteNodeTool }; -} diff --git a/web/src/pages/data-flow/form/agent-form/use-get-tools.ts b/web/src/pages/data-flow/form/agent-form/use-get-tools.ts deleted file mode 100644 index 32bf3f0ef..000000000 --- a/web/src/pages/data-flow/form/agent-form/use-get-tools.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IAgentForm } from '@/interfaces/database/agent'; -import { get } from 'lodash'; -import { useContext, useMemo } from 'react'; -import { AgentFormContext } from '../../context'; - -export function useGetAgentToolNames() { - const node = useContext(AgentFormContext); - - const toolNames = useMemo(() => { - const tools: IAgentForm['tools'] = get(node, 'data.form.tools', []); - return tools.map((x) => x.component_name); - }, [node]); - - return { toolNames }; -} - -export function useGetAgentMCPIds() { - const node = useContext(AgentFormContext); - - const mcpIds = useMemo(() => { - const ids: IAgentForm['mcp'] = get(node, 'data.form.mcp', []); - return ids.map((x) => x.mcp_id); - }, [node]); - - return { mcpIds }; -} diff --git a/web/src/pages/data-flow/form/agent-form/use-values.ts b/web/src/pages/data-flow/form/agent-form/use-values.ts deleted file mode 100644 index b2d61dc9f..000000000 --- a/web/src/pages/data-flow/form/agent-form/use-values.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useFetchModelId } from '@/hooks/logic-hooks'; -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { get, isEmpty } from 'lodash'; -import { useMemo } from 'react'; -import { initialAgentValues } from '../../constant'; - -export function useValues(node?: RAGFlowNodeType) { - const llmId = useFetchModelId(); - - const defaultValues = useMemo( - () => ({ - ...initialAgentValues, - llm_id: llmId, - prompts: '', - }), - [llmId], - ); - - const values = useMemo(() => { - const formData = node?.data?.form; - - if (isEmpty(formData)) { - return defaultValues; - } - - return { - ...formData, - prompts: get(formData, 'prompts.0.content', ''), - }; - }, [defaultValues, node?.data?.form]); - - return values; -} diff --git a/web/src/pages/data-flow/form/agent-form/use-watch-change.ts b/web/src/pages/data-flow/form/agent-form/use-watch-change.ts deleted file mode 100644 index 98b0ecf31..000000000 --- a/web/src/pages/data-flow/form/agent-form/use-watch-change.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useEffect } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import { PromptRole } from '../../constant'; -import useGraphStore from '../../store'; - -export function useWatchFormChange(id?: string, form?: UseFormReturn) { - let values = useWatch({ control: form?.control }); - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - useEffect(() => { - // Manually triggered form updates are synchronized to the canvas - if (id && form?.formState.isDirty) { - values = form?.getValues(); - let nextValues: any = { - ...values, - prompts: [{ role: PromptRole.User, content: values.prompts }], - }; - - updateNodeForm(id, nextValues); - } - }, [form?.formState.isDirty, id, updateNodeForm, values]); -} diff --git a/web/src/pages/data-flow/form/categorize-form/dynamic-categorize.tsx b/web/src/pages/data-flow/form/categorize-form/dynamic-categorize.tsx deleted file mode 100644 index 0807f7bfa..000000000 --- a/web/src/pages/data-flow/form/categorize-form/dynamic-categorize.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import { Button } from '@/components/ui/button'; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from '@/components/ui/collapsible'; -import { - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { BlurTextarea } from '@/components/ui/textarea'; -import { useTranslate } from '@/hooks/common-hooks'; -import { PlusOutlined } from '@ant-design/icons'; -import { useUpdateNodeInternals } from '@xyflow/react'; -import humanId from 'human-id'; -import trim from 'lodash/trim'; -import { ChevronsUpDown, X } from 'lucide-react'; -import { - ChangeEventHandler, - FocusEventHandler, - memo, - useCallback, - useEffect, - useState, -} from 'react'; -import { UseFormReturn, useFieldArray, useFormContext } from 'react-hook-form'; -import { v4 as uuid } from 'uuid'; -import { z } from 'zod'; -import useGraphStore from '../../store'; -import DynamicExample from './dynamic-example'; -import { useCreateCategorizeFormSchema } from './use-form-schema'; - -interface IProps { - nodeId?: string; -} - -interface INameInputProps { - value?: string; - onChange?: (value: string) => void; - otherNames?: string[]; - validate(error?: string): void; -} - -const getOtherFieldValues = ( - form: UseFormReturn, - formListName: string = 'items', - index: number, - latestField: string, -) => - (form.getValues(formListName) ?? []) - .map((x: any) => x[latestField]) - .filter( - (x: string) => - x !== form.getValues(`${formListName}.${index}.${latestField}`), - ); - -const InnerNameInput = ({ - value, - onChange, - otherNames, - validate, -}: INameInputProps) => { - const [name, setName] = useState(); - const { t } = useTranslate('flow'); - - const handleNameChange: ChangeEventHandler = useCallback( - (e) => { - const val = e.target.value; - setName(val); - const trimmedVal = trim(val); - // trigger validation - if (otherNames?.some((x) => x === trimmedVal)) { - validate(t('nameRepeatedMsg')); - } else if (trimmedVal === '') { - validate(t('nameRequiredMsg')); - } else { - validate(''); - } - }, - [otherNames, validate, t], - ); - - const handleNameBlur: FocusEventHandler = useCallback( - (e) => { - const val = e.target.value; - if (otherNames?.every((x) => x !== val) && trim(val) !== '') { - onChange?.(val); - } - }, - [onChange, otherNames], - ); - - useEffect(() => { - setName(value); - }, [value]); - - return ( - - ); -}; - -const NameInput = memo(InnerNameInput); - -const InnerFormSet = ({ index }: IProps & { index: number }) => { - const form = useFormContext(); - const { t } = useTranslate('flow'); - - const buildFieldName = useCallback( - (name: string) => { - return `items.${index}.${name}`; - }, - [index], - ); - - return ( -
    - ( - - {t('categoryName')} - - { - const fieldName = buildFieldName('name'); - if (error) { - form.setError(fieldName, { message: error }); - } else { - form.clearErrors(fieldName); - } - }} - > - - - - )} - /> - ( - - {t('description')} - - - - - - )} - /> - {/* Create a hidden field to make Form instance record this */} -
    } - /> - -
    - ); -}; - -const FormSet = memo(InnerFormSet); - -const DynamicCategorize = ({ nodeId }: IProps) => { - const updateNodeInternals = useUpdateNodeInternals(); - const FormSchema = useCreateCategorizeFormSchema(); - - const deleteCategorizeCaseEdges = useGraphStore( - (state) => state.deleteEdgesBySourceAndSourceHandle, - ); - const form = useFormContext>(); - const { t } = useTranslate('flow'); - const { fields, remove, append } = useFieldArray({ - name: 'items', - control: form.control, - }); - - const handleAdd = useCallback(() => { - append({ - name: humanId(), - description: '', - uuid: uuid(), - examples: [{ value: '' }], - }); - if (nodeId) updateNodeInternals(nodeId); - }, [append, nodeId, updateNodeInternals]); - - const handleRemove = useCallback( - (index: number) => () => { - remove(index); - if (nodeId) { - const uuid = fields[index].uuid; - deleteCategorizeCaseEdges(nodeId, uuid); - } - }, - [deleteCategorizeCaseEdges, fields, nodeId, remove], - ); - - return ( -
    - {fields.map((field, index) => ( - -
    -

    - {form.getValues(`items.${index}.name`)} -

    - -
    - - -
    -
    -
    - - - -
    - ))} - - -
    - ); -}; - -export default memo(DynamicCategorize); diff --git a/web/src/pages/data-flow/form/categorize-form/dynamic-example.tsx b/web/src/pages/data-flow/form/categorize-form/dynamic-example.tsx deleted file mode 100644 index 35d95cbc6..000000000 --- a/web/src/pages/data-flow/form/categorize-form/dynamic-example.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Button } from '@/components/ui/button'; -import { - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Textarea } from '@/components/ui/textarea'; -import { Plus, X } from 'lucide-react'; -import { memo } from 'react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; - -type DynamicExampleProps = { name: string }; - -const DynamicExample = ({ name }: DynamicExampleProps) => { - const { t } = useTranslation(); - const form = useFormContext(); - - const { fields, append, remove } = useFieldArray({ - name: name, - control: form.control, - }); - - return ( - - {t('flow.examples')} -
    - {fields.map((field, index) => ( -
    - ( - - - - - - )} - /> - {index === 0 ? ( - - ) : ( - - )} -
    - ))} -
    - -
    - ); -}; - -export default memo(DynamicExample); diff --git a/web/src/pages/data-flow/form/categorize-form/index.tsx b/web/src/pages/data-flow/form/categorize-form/index.tsx deleted file mode 100644 index c36ff4529..000000000 --- a/web/src/pages/data-flow/form/categorize-form/index.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { FormContainer } from '@/components/form-container'; -import { LargeModelFormField } from '@/components/large-model-form-field'; -import { MessageHistoryWindowSizeFormField } from '@/components/message-history-window-size-item'; -import { Form } from '@/components/ui/form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo } from 'react'; -import { useForm } from 'react-hook-form'; -import { initialCategorizeValues } from '../../constant'; -import { INextOperatorForm } from '../../interface'; -import { buildOutputList } from '../../utils/build-output-list'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { QueryVariable } from '../components/query-variable'; -import DynamicCategorize from './dynamic-categorize'; -import { useCreateCategorizeFormSchema } from './use-form-schema'; -import { useValues } from './use-values'; -import { useWatchFormChange } from './use-watch-change'; - -const outputList = buildOutputList(initialCategorizeValues.outputs); - -function CategorizeForm({ node }: INextOperatorForm) { - const values = useValues(node); - - const FormSchema = useCreateCategorizeFormSchema(); - - const form = useForm({ - defaultValues: values, - resolver: zodResolver(FormSchema), - }); - - useWatchFormChange(node?.id, form); - - return ( -
    - - - - - - - - - -
    - ); -} - -export default memo(CategorizeForm); diff --git a/web/src/pages/data-flow/form/categorize-form/use-form-schema.ts b/web/src/pages/data-flow/form/categorize-form/use-form-schema.ts deleted file mode 100644 index 9e56bb18b..000000000 --- a/web/src/pages/data-flow/form/categorize-form/use-form-schema.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { LlmSettingSchema } from '@/components/llm-setting-items/next'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; - -export function useCreateCategorizeFormSchema() { - const { t } = useTranslation(); - - const FormSchema = z.object({ - query: z.string().optional(), - parameter: z.string().optional(), - ...LlmSettingSchema, - message_history_window_size: z.coerce.number(), - items: z.array( - z - .object({ - name: z.string().min(1, t('flow.nameMessage')).trim(), - description: z.string().optional(), - uuid: z.string(), - examples: z - .array( - z.object({ - value: z.string(), - }), - ) - .optional(), - }) - .optional(), - ), - }); - - return FormSchema; -} diff --git a/web/src/pages/data-flow/form/categorize-form/use-values.ts b/web/src/pages/data-flow/form/categorize-form/use-values.ts deleted file mode 100644 index a920ec4cc..000000000 --- a/web/src/pages/data-flow/form/categorize-form/use-values.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ModelVariableType } from '@/constants/knowledge'; -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { isEmpty, isPlainObject } from 'lodash'; -import { useMemo } from 'react'; - -const defaultValues = { - parameter: ModelVariableType.Precise, - message_history_window_size: 1, - temperatureEnabled: true, - topPEnabled: true, - presencePenaltyEnabled: true, - frequencyPenaltyEnabled: true, - maxTokensEnabled: true, - items: [], -}; - -export function useValues(node?: RAGFlowNodeType) { - const values = useMemo(() => { - const formData = node?.data?.form; - if (isEmpty(formData)) { - return defaultValues; - } - if (isPlainObject(formData)) { - // const nextValues = { - // ...omit(formData, 'category_description'), - // items, - // }; - - return formData; - } - }, [node]); - - return values; -} diff --git a/web/src/pages/data-flow/form/categorize-form/use-watch-change.ts b/web/src/pages/data-flow/form/categorize-form/use-watch-change.ts deleted file mode 100644 index a97b80a77..000000000 --- a/web/src/pages/data-flow/form/categorize-form/use-watch-change.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import useGraphStore from '../../store'; - -export function useWatchFormChange(id?: string, form?: UseFormReturn) { - let values = useWatch({ control: form?.control }); - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - useEffect(() => { - // Manually triggered form updates are synchronized to the canvas - if (id) { - values = form?.getValues(); - - updateNodeForm(id, { ...values, items: values.items?.slice() || [] }); - } - }, [id, updateNodeForm, values]); -} diff --git a/web/src/pages/data-flow/form/chunker-form/index.tsx b/web/src/pages/data-flow/form/chunker-form/index.tsx deleted file mode 100644 index cfc32e82f..000000000 --- a/web/src/pages/data-flow/form/chunker-form/index.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { FormContainer } from '@/components/form-container'; -import NumberInput from '@/components/originui/number-input'; -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { useTranslate } from '@/hooks/common-hooks'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo } from 'react'; -import { useForm, useFormContext } from 'react-hook-form'; -import { z } from 'zod'; -import { initialChunkerValues } from '../../constant'; -import { useFormValues } from '../../hooks/use-form-values'; -import { useWatchFormChange } from '../../hooks/use-watch-form-change'; -import { INextOperatorForm } from '../../interface'; -import { GoogleCountryOptions, GoogleLanguageOptions } from '../../options'; -import { buildOutputList } from '../../utils/build-output-list'; -import { ApiKeyField } from '../components/api-key-field'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { QueryVariable } from '../components/query-variable'; - -const outputList = buildOutputList(initialChunkerValues.outputs); - -export const GoogleFormPartialSchema = { - api_key: z.string(), - country: z.string(), - language: z.string(), -}; - -export const FormSchema = z.object({ - ...GoogleFormPartialSchema, - q: z.string(), - start: z.number(), - num: z.number(), -}); - -export function GoogleFormWidgets() { - const form = useFormContext(); - const { t } = useTranslate('flow'); - - return ( - <> - ( - - {t('country')} - - - - - - )} - /> - ( - - {t('language')} - - - - - - )} - /> - - ); -} - -const ChunkerForm = ({ node }: INextOperatorForm) => { - const { t } = useTranslate('flow'); - const defaultValues = useFormValues(initialChunkerValues, node); - - const form = useForm>({ - defaultValues, - resolver: zodResolver(FormSchema), - }); - - useWatchFormChange(node?.id, form); - - return ( -
    - - - - - - - ( - - {t('flowStart')} - - - - - - )} - /> - ( - - {t('flowNum')} - - - - - - )} - /> - - - -
    - -
    -
    - ); -}; - -export default memo(ChunkerForm); diff --git a/web/src/pages/data-flow/form/code-form/index.tsx b/web/src/pages/data-flow/form/code-form/index.tsx deleted file mode 100644 index 2883fdf46..000000000 --- a/web/src/pages/data-flow/form/code-form/index.tsx +++ /dev/null @@ -1,168 +0,0 @@ -import Editor, { loader } from '@monaco-editor/react'; -import { INextOperatorForm } from '../../interface'; - -import { FormContainer } from '@/components/form-container'; -import { useIsDarkTheme } from '@/components/theme-provider'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { RAGFlowSelect } from '@/components/ui/select'; -import { ProgrammingLanguage } from '@/constants/agent'; -import { ICodeForm } from '@/interfaces/database/agent'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo } from 'react'; -import { useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { buildOutputList } from '../../utils/build-output-list'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { - DynamicInputVariable, - TypeOptions, - VariableTitle, -} from './next-variable'; -import { FormSchema, FormSchemaType } from './schema'; -import { useValues } from './use-values'; -import { - useHandleLanguageChange, - useWatchFormChange, -} from './use-watch-change'; - -loader.config({ paths: { vs: '/vs' } }); - -const options = [ - ProgrammingLanguage.Python, - ProgrammingLanguage.Javascript, -].map((x) => ({ value: x, label: x })); - -const DynamicFieldName = 'outputs'; - -function CodeForm({ node }: INextOperatorForm) { - const formData = node?.data.form as ICodeForm; - const { t } = useTranslation(); - const values = useValues(node); - const isDarkTheme = useIsDarkTheme(); - - const form = useForm({ - defaultValues: values, - resolver: zodResolver(FormSchema), - }); - - useWatchFormChange(node?.id, form); - - const handleLanguageChange = useHandleLanguageChange(node?.id, form); - - return ( -
    - - - ( - - - Code - ( - - - { - field.onChange(val); - handleLanguageChange(val); - }} - options={options} - /> - - - - )} - /> - - - - - - - )} - /> - - {formData.lang === ProgrammingLanguage.Python ? ( - - ) : ( -
    - - - ( - - Name - - - - - - )} - /> - ( - - Type - - - - - - )} - /> - -
    - )} -
    -
    - -
    -
    - ); -} - -export default memo(CodeForm); diff --git a/web/src/pages/data-flow/form/code-form/next-variable.tsx b/web/src/pages/data-flow/form/code-form/next-variable.tsx deleted file mode 100644 index 39a2dd4a4..000000000 --- a/web/src/pages/data-flow/form/code-form/next-variable.tsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client'; - -import { FormContainer } from '@/components/form-container'; -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { BlockButton, Button } from '@/components/ui/button'; -import { - FormControl, - FormField, - FormItem, - FormMessage, -} from '@/components/ui/form'; -import { BlurInput } from '@/components/ui/input'; -import { RAGFlowSelect } from '@/components/ui/select'; -import { Separator } from '@/components/ui/separator'; -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { X } from 'lucide-react'; -import { ReactNode } from 'react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { useBuildQueryVariableOptions } from '../../hooks/use-get-begin-query'; - -interface IProps { - node?: RAGFlowNodeType; - name?: string; - isOutputs: boolean; -} - -export const TypeOptions = [ - 'String', - 'Number', - 'Boolean', - 'Array', - 'Array', - 'Object', -].map((x) => ({ label: x, value: x })); - -export function DynamicVariableForm({ name = 'arguments', isOutputs }: IProps) { - const { t } = useTranslation(); - const form = useFormContext(); - - const { fields, remove, append } = useFieldArray({ - name: name, - control: form.control, - }); - - const nextOptions = useBuildQueryVariableOptions(); - - return ( -
    - {fields.map((field, index) => { - const typeField = `${name}.${index}.name`; - return ( -
    - ( - - - - - - - )} - /> - - ( - - - {isOutputs ? ( - - ) : ( - - )} - - - - )} - /> - -
    - ); - })} - append({ name: '', type: undefined })}> - {t('flow.addVariable')} - -
    - ); -} - -export function VariableTitle({ title }: { title: ReactNode }) { - return
    {title}
    ; -} - -export function DynamicInputVariable({ - node, - name, - title, - isOutputs = false, -}: IProps & { title: ReactNode }) { - return ( -
    - - - - -
    - ); -} diff --git a/web/src/pages/data-flow/form/code-form/schema.ts b/web/src/pages/data-flow/form/code-form/schema.ts deleted file mode 100644 index fe694444e..000000000 --- a/web/src/pages/data-flow/form/code-form/schema.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ProgrammingLanguage } from '@/constants/agent'; -import { z } from 'zod'; - -export const FormSchema = z.object({ - lang: z.enum([ProgrammingLanguage.Python, ProgrammingLanguage.Javascript]), - script: z.string(), - arguments: z.array(z.object({ name: z.string(), type: z.string() })), - outputs: z.union([ - z.array(z.object({ name: z.string(), type: z.string() })).optional(), - z.object({ name: z.string(), type: z.string() }), - ]), -}); - -export type FormSchemaType = z.infer; diff --git a/web/src/pages/data-flow/form/code-form/use-values.ts b/web/src/pages/data-flow/form/code-form/use-values.ts deleted file mode 100644 index ea6f2d67c..000000000 --- a/web/src/pages/data-flow/form/code-form/use-values.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ProgrammingLanguage } from '@/constants/agent'; -import { ICodeForm } from '@/interfaces/database/agent'; -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { isEmpty } from 'lodash'; -import { useMemo } from 'react'; -import { initialCodeValues } from '../../constant'; - -function convertToArray(args: Record) { - return Object.entries(args).map(([key, value]) => ({ - name: key, - type: value, - })); -} - -type OutputsFormType = { name: string; type: string }; - -function convertOutputsToArray({ lang, outputs = {} }: ICodeForm) { - if (lang === ProgrammingLanguage.Python) { - return Object.entries(outputs).map(([key, val]) => ({ - name: key, - type: val.type, - })); - } - return Object.entries(outputs).reduce((pre, [key, val]) => { - pre.name = key; - pre.type = val.type; - return pre; - }, {} as OutputsFormType); -} - -export function useValues(node?: RAGFlowNodeType) { - const values = useMemo(() => { - const formData = node?.data?.form; - - if (isEmpty(formData)) { - return initialCodeValues; - } - - return { - ...formData, - arguments: convertToArray(formData.arguments), - outputs: convertOutputsToArray(formData), - }; - }, [node?.data?.form]); - - return values; -} diff --git a/web/src/pages/data-flow/form/code-form/use-watch-change.ts b/web/src/pages/data-flow/form/code-form/use-watch-change.ts deleted file mode 100644 index 80e0c8b15..000000000 --- a/web/src/pages/data-flow/form/code-form/use-watch-change.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { CodeTemplateStrMap, ProgrammingLanguage } from '@/constants/agent'; -import { ICodeForm } from '@/interfaces/database/agent'; -import { isEmpty } from 'lodash'; -import { useCallback, useEffect } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import useGraphStore from '../../store'; -import { FormSchemaType } from './schema'; - -function convertToObject(list: FormSchemaType['arguments'] = []) { - return list.reduce>((pre, cur) => { - pre[cur.name] = cur.type; - - return pre; - }, {}); -} - -type ArrayOutputs = Extract>; - -type ObjectOutputs = Exclude>; - -function convertOutputsToObject({ lang, outputs }: FormSchemaType) { - if (lang === ProgrammingLanguage.Python) { - return (outputs as ArrayOutputs).reduce( - (pre, cur) => { - pre[cur.name] = { - value: '', - type: cur.type, - }; - - return pre; - }, - {}, - ); - } - const outputsObject = outputs as ObjectOutputs; - if (isEmpty(outputsObject)) { - return {}; - } - return { - [outputsObject.name]: { - value: '', - type: outputsObject.type, - }, - }; -} - -export function useWatchFormChange( - id?: string, - form?: UseFormReturn, -) { - let values = useWatch({ control: form?.control }); - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - useEffect(() => { - // Manually triggered form updates are synchronized to the canvas - if (id) { - values = form?.getValues() || {}; - let nextValues: any = { - ...values, - arguments: convertToObject( - values?.arguments as FormSchemaType['arguments'], - ), - outputs: convertOutputsToObject(values as FormSchemaType), - }; - - updateNodeForm(id, nextValues); - } - }, [form?.formState.isDirty, id, updateNodeForm, values]); -} - -export function useHandleLanguageChange( - id?: string, - form?: UseFormReturn, -) { - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - const handleLanguageChange = useCallback( - (lang: string) => { - if (id) { - const script = CodeTemplateStrMap[lang as ProgrammingLanguage]; - form?.setValue('script', script); - form?.setValue( - 'outputs', - (lang === ProgrammingLanguage.Python - ? [] - : {}) as FormSchemaType['outputs'], - ); - updateNodeForm(id, script, ['script']); - } - }, - [form, id, updateNodeForm], - ); - - return handleLanguageChange; -} diff --git a/web/src/pages/data-flow/form/crawler-form/index.tsx b/web/src/pages/data-flow/form/crawler-form/index.tsx deleted file mode 100644 index 8c8da6b08..000000000 --- a/web/src/pages/data-flow/form/crawler-form/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { useTranslate } from '@/hooks/common-hooks'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo, useMemo } from 'react'; -import { useForm, useFormContext } from 'react-hook-form'; -import { z } from 'zod'; -import { initialCrawlerValues } from '../../constant'; -import { useWatchFormChange } from '../../hooks/use-watch-form-change'; -import { INextOperatorForm } from '../../interface'; -import { CrawlerResultOptions } from '../../options'; -import { QueryVariable } from '../components/query-variable'; - -export function CrawlerProxyFormField() { - const { t } = useTranslate('flow'); - const form = useFormContext(); - - return ( - ( - - {t('proxy')} - - - - - - )} - /> - ); -} - -export function CrawlerExtractTypeFormField() { - const { t } = useTranslate('flow'); - const form = useFormContext(); - const crawlerResultOptions = useMemo(() => { - return CrawlerResultOptions.map((x) => ({ - value: x, - label: t(`crawlerResultOptions.${x}`), - })); - }, [t]); - - return ( - ( - - {t('extractType')} - - - - - - )} - /> - ); -} - -export const CrawlerFormSchema = { - proxy: z.string().url(), - extract_type: z.string(), -}; - -const FormSchema = z.object({ - query: z.string().optional(), - ...CrawlerFormSchema, -}); - -function CrawlerForm({ node }: INextOperatorForm) { - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: initialCrawlerValues, - mode: 'onChange', - }); - - useWatchFormChange(node?.id, form); - - return ( -
    - { - e.preventDefault(); - }} - > - - - -
    - - ); -} - -export default memo(CrawlerForm); diff --git a/web/src/pages/data-flow/form/email-form/index.tsx b/web/src/pages/data-flow/form/email-form/index.tsx deleted file mode 100644 index b142dae76..000000000 --- a/web/src/pages/data-flow/form/email-form/index.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { FormContainer } from '@/components/form-container'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { useTranslate } from '@/hooks/common-hooks'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { ReactNode } from 'react'; -import { useForm, useFormContext } from 'react-hook-form'; -import { z } from 'zod'; -import { initialEmailValues } from '../../constant'; -import { useFormValues } from '../../hooks/use-form-values'; -import { useWatchFormChange } from '../../hooks/use-watch-form-change'; -import { INextOperatorForm } from '../../interface'; -import { buildOutputList } from '../../utils/build-output-list'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { PromptEditor } from '../components/prompt-editor'; - -interface InputFormFieldProps { - name: string; - label: ReactNode; - type?: string; -} - -function InputFormField({ name, label, type }: InputFormFieldProps) { - const form = useFormContext(); - - return ( - ( - - {label} - - - - - - )} - /> - ); -} - -function PromptFormField({ name, label }: InputFormFieldProps) { - const form = useFormContext(); - - return ( - ( - - {label} - - - - - - )} - /> - ); -} -export function EmailFormWidgets() { - const { t } = useTranslate('flow'); - - return ( - <> - - - - - - - ); -} - -export const EmailFormPartialSchema = { - smtp_server: z.string(), - smtp_port: z.number(), - email: z.string(), - password: z.string(), - sender_name: z.string(), -}; - -const FormSchema = z.object({ - to_email: z.string(), - cc_email: z.string(), - content: z.string(), - subject: z.string(), - ...EmailFormPartialSchema, -}); - -const outputList = buildOutputList(initialEmailValues.outputs); - -const EmailForm = ({ node }: INextOperatorForm) => { - const { t } = useTranslate('flow'); - const defaultValues = useFormValues(initialEmailValues, node); - - const form = useForm>({ - defaultValues, - resolver: zodResolver(FormSchema), - }); - - useWatchFormChange(node?.id, form); - - return ( -
    - - - - - - - - - -
    - -
    -
    - ); -}; - -export default EmailForm; diff --git a/web/src/pages/data-flow/form/exesql-form/index.tsx b/web/src/pages/data-flow/form/exesql-form/index.tsx deleted file mode 100644 index 5a6cb5ba6..000000000 --- a/web/src/pages/data-flow/form/exesql-form/index.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import NumberInput from '@/components/originui/number-input'; -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { ButtonLoading } from '@/components/ui/button'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { useTranslate } from '@/hooks/common-hooks'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo } from 'react'; -import { useForm, useFormContext } from 'react-hook-form'; -import { z } from 'zod'; -import { initialExeSqlValues } from '../../constant'; -import { useFormValues } from '../../hooks/use-form-values'; -import { useWatchFormChange } from '../../hooks/use-watch-form-change'; -import { INextOperatorForm } from '../../interface'; -import { ExeSQLOptions } from '../../options'; -import { buildOutputList } from '../../utils/build-output-list'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { QueryVariable } from '../components/query-variable'; -import { FormSchema, useSubmitForm } from './use-submit-form'; - -const outputList = buildOutputList(initialExeSqlValues.outputs); - -export function ExeSQLFormWidgets({ loading }: { loading: boolean }) { - const form = useFormContext(); - const { t } = useTranslate('flow'); - - return ( - <> - ( - - {t('dbType')} - - - - - - )} - /> - ( - - {t('database')} - - - - - - )} - /> - ( - - {t('username')} - - - - - - )} - /> - ( - - {t('host')} - - - - - - )} - /> - ( - - {t('port')} - - - - - - )} - /> - ( - - {t('password')} - - - - - - )} - /> - - ( - - {t('maxRecords')} - - - - - - )} - /> - -
    - - {t('test')} - -
    - - ); -} - -function ExeSQLForm({ node }: INextOperatorForm) { - const defaultValues = useFormValues(initialExeSqlValues, node); - - const { onSubmit, loading } = useSubmitForm(); - - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues, - }); - - useWatchFormChange(node?.id, form); - - return ( -
    - - - - -
    - -
    -
    - ); -} - -export default memo(ExeSQLForm); diff --git a/web/src/pages/data-flow/form/exesql-form/use-submit-form.ts b/web/src/pages/data-flow/form/exesql-form/use-submit-form.ts deleted file mode 100644 index 8be69c7b0..000000000 --- a/web/src/pages/data-flow/form/exesql-form/use-submit-form.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { useTestDbConnect } from '@/hooks/use-agent-request'; -import { useCallback } from 'react'; -import { z } from 'zod'; - -export const ExeSQLFormSchema = { - db_type: z.string().min(1), - database: z.string().min(1), - username: z.string().min(1), - host: z.string().min(1), - port: z.number(), - password: z.string().min(1), - max_records: z.number(), -}; - -export const FormSchema = z.object({ - sql: z.string().optional(), - ...ExeSQLFormSchema, -}); - -export function useSubmitForm() { - const { testDbConnect, loading } = useTestDbConnect(); - - const onSubmit = useCallback( - async (data: z.infer) => { - testDbConnect(data); - }, - [testDbConnect], - ); - - return { loading, onSubmit }; -} diff --git a/web/src/pages/data-flow/form/hierarchical-merger-form/index.tsx b/web/src/pages/data-flow/form/hierarchical-merger-form/index.tsx index ebeab72d0..15cf11aeb 100644 --- a/web/src/pages/data-flow/form/hierarchical-merger-form/index.tsx +++ b/web/src/pages/data-flow/form/hierarchical-merger-form/index.tsx @@ -1,13 +1,14 @@ import { SelectWithSearch } from '@/components/originui/select-with-search'; import { RAGFlowFormItem } from '@/components/ragflow-form'; import { BlockButton, Button } from '@/components/ui/button'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Form } from '@/components/ui/form'; +import { Card, CardContent, CardHeader } from '@/components/ui/card'; +import { Form, FormLabel } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { zodResolver } from '@hookform/resolvers/zod'; -import { X } from 'lucide-react'; +import { Plus, Trash2 } from 'lucide-react'; import { memo } from 'react'; import { useFieldArray, useForm, useFormContext } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { z } from 'zod'; import { initialHierarchicalMergerValues } from '../../constant'; import { useFormValues } from '../../hooks/use-form-values'; @@ -39,7 +40,24 @@ export const FormSchema = z.object({ hierarchy: z.number(), levels: z.array( z.object({ - expressions: z.array(z.object({ expression: z.string() })), + expressions: z.array( + z.object({ + expression: z.string().refine( + (val) => { + try { + // Try converting the string to a RegExp + new RegExp(val); + return true; + } catch { + return false; + } + }, + { + message: 'Must be a valid regular expression string', + }, + ), + }), + ), }), ), }); @@ -50,13 +68,16 @@ type RegularExpressionsProps = { index: number; parentName: string; removeParent: (index: number) => void; + isLatest: boolean; }; export function RegularExpressions({ index, parentName, + isLatest, removeParent, }: RegularExpressionsProps) { + const { t } = useTranslation(); const form = useFormContext(); const name = `${parentName}.${index}.expressions`; @@ -69,16 +90,21 @@ export function RegularExpressions({ return ( - H{index + 1} - + H{index + 1} + {isLatest && ( + + )} + + {t('dataflow.regularExpressions')} +
    {fields.map((field, index) => (
    @@ -91,33 +117,38 @@ export function RegularExpressions({
    - + {index === 0 ? ( + + ) : ( + + )} ))}
    - append({ expression: '' })} - className="mt-6" - > - Add -
    ); } const HierarchicalMergerForm = ({ node }: INextOperatorForm) => { + const { t } = useTranslation(); const defaultValues = useFormValues(initialHierarchicalMergerValues, node); const form = useForm({ defaultValues, resolver: zodResolver(FormSchema), + mode: 'onChange', }); const name = 'levels'; @@ -132,23 +163,28 @@ const HierarchicalMergerForm = ({ node }: INextOperatorForm) => { return (
    - + {fields.map((field, index) => ( -
    -
    +
    +
    ))} - append({ expressions: [] })}> - Add - + {fields.length < 5 && ( + append({ expressions: [{ expression: '' }] })} + > + {t('common.add')} + + )}
    diff --git a/web/src/pages/data-flow/form/invoke-form/hooks.ts b/web/src/pages/data-flow/form/invoke-form/hooks.ts deleted file mode 100644 index 951cd42ae..000000000 --- a/web/src/pages/data-flow/form/invoke-form/hooks.ts +++ /dev/null @@ -1,97 +0,0 @@ -import get from 'lodash/get'; -import { - ChangeEventHandler, - MouseEventHandler, - useCallback, - useMemo, -} from 'react'; -import { v4 as uuid } from 'uuid'; -import { IGenerateParameter, IInvokeVariable } from '../../interface'; -import useGraphStore from '../../store'; - -export const useHandleOperateParameters = (nodeId: string) => { - const { getNode, updateNodeForm } = useGraphStore((state) => state); - const node = getNode(nodeId); - const dataSource: IGenerateParameter[] = useMemo( - () => get(node, 'data.form.variables', []) as IGenerateParameter[], - [node], - ); - - const changeValue = useCallback( - (row: IInvokeVariable, field: string, value: string) => { - const newData = [...dataSource]; - const index = newData.findIndex((item) => row.id === item.id); - const item = newData[index]; - newData.splice(index, 1, { - ...item, - [field]: value, - }); - - updateNodeForm(nodeId, { variables: newData }); - }, - [dataSource, nodeId, updateNodeForm], - ); - - const handleComponentIdChange = useCallback( - (row: IInvokeVariable) => (value: string) => { - changeValue(row, 'component_id', value); - }, - [changeValue], - ); - - const handleValueChange = useCallback( - (row: IInvokeVariable): ChangeEventHandler => - (e) => { - changeValue(row, 'value', e.target.value); - }, - [changeValue], - ); - - const handleRemove = useCallback( - (id?: string) => () => { - const newData = dataSource.filter((item) => item.id !== id); - updateNodeForm(nodeId, { variables: newData }); - }, - [updateNodeForm, nodeId, dataSource], - ); - - const handleAdd: MouseEventHandler = useCallback( - (e) => { - e.preventDefault(); - e.stopPropagation(); - updateNodeForm(nodeId, { - variables: [ - ...dataSource, - { - id: uuid(), - key: '', - component_id: undefined, - value: '', - }, - ], - }); - }, - [dataSource, nodeId, updateNodeForm], - ); - - const handleSave = (row: IGenerateParameter) => { - const newData = [...dataSource]; - const index = newData.findIndex((item) => row.id === item.id); - const item = newData[index]; - newData.splice(index, 1, { - ...item, - ...row, - }); - - updateNodeForm(nodeId, { variables: newData }); - }; - - return { - handleAdd, - handleRemove, - handleComponentIdChange, - handleValueChange, - handleSave, - dataSource, - }; -}; diff --git a/web/src/pages/data-flow/form/invoke-form/index.tsx b/web/src/pages/data-flow/form/invoke-form/index.tsx deleted file mode 100644 index 3d67ec030..000000000 --- a/web/src/pages/data-flow/form/invoke-form/index.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import { Collapse } from '@/components/collapse'; -import { FormContainer } from '@/components/form-container'; -import NumberInput from '@/components/originui/number-input'; -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { Button } from '@/components/ui/button'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { Switch } from '@/components/ui/switch'; -import { zodResolver } from '@hookform/resolvers/zod'; -import Editor, { loader } from '@monaco-editor/react'; -import { Plus } from 'lucide-react'; -import { memo } from 'react'; -import { useForm, useWatch } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { initialInvokeValues } from '../../constant'; -import { useFormValues } from '../../hooks/use-form-values'; -import { useWatchFormChange } from '../../hooks/use-watch-form-change'; -import { INextOperatorForm } from '../../interface'; -import { buildOutputList } from '../../utils/build-output-list'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { FormSchema, FormSchemaType } from './schema'; -import { useEditVariableRecord } from './use-edit-variable'; -import { VariableDialog } from './variable-dialog'; -import { VariableTable } from './variable-table'; - -loader.config({ paths: { vs: '/vs' } }); - -enum Method { - GET = 'GET', - POST = 'POST', - PUT = 'PUT', -} - -const MethodOptions = [Method.GET, Method.POST, Method.PUT].map((x) => ({ - label: x, - value: x, -})); - -interface TimeoutInputProps { - value?: number; - onChange?: (value: number | null) => void; -} - -const TimeoutInput = ({ value, onChange }: TimeoutInputProps) => { - const { t } = useTranslation(); - return ( -
    - {t('flow.seconds')} -
    - ); -}; - -const outputList = buildOutputList(initialInvokeValues.outputs); - -function InvokeForm({ node }: INextOperatorForm) { - const { t } = useTranslation(); - const defaultValues = useFormValues(initialInvokeValues, node); - - const form = useForm({ - defaultValues, - resolver: zodResolver(FormSchema), - mode: 'onChange', - }); - - const { - visible, - hideModal, - showModal, - ok, - currentRecord, - otherThanCurrentQuery, - handleDeleteRecord, - } = useEditVariableRecord({ - form, - node, - }); - - const variables = useWatch({ control: form.control, name: 'variables' }); - - useWatchFormChange(node?.id, form); - - return ( - - - - ( - - {t('flow.url')} - - - - - - )} - /> - ( - - {t('flow.method')} - - - - - - )} - /> - ( - - {t('flow.timeout')} - - - - - - )} - /> - ( - - {t('flow.headers')} - - - - - - )} - /> - ( - - {t('flow.proxy')} - - - - - - )} - /> - ( - - - {t('flow.cleanHtml')} - - - - - - - )} - /> - {/* Create a hidden field to make Form instance record this */} -
    } - /> -
    - {t('flow.parameter')}
    } - rightContent={ - - } - > - - - {visible && ( - - )} - -
    - -
    - - ); -} - -export default memo(InvokeForm); diff --git a/web/src/pages/data-flow/form/invoke-form/schema.ts b/web/src/pages/data-flow/form/invoke-form/schema.ts deleted file mode 100644 index a3b11aff2..000000000 --- a/web/src/pages/data-flow/form/invoke-form/schema.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { z } from 'zod'; - -export const VariableFormSchema = z.object({ - key: z.string(), - ref: z.string(), - value: z.string(), -}); - -export const FormSchema = z.object({ - url: z.string().url(), - method: z.string(), - timeout: z.number(), - headers: z.string(), - proxy: z.string().url(), - clean_html: z.boolean(), - variables: z.array(VariableFormSchema), -}); - -export type FormSchemaType = z.infer; - -export type VariableFormSchemaType = z.infer; diff --git a/web/src/pages/data-flow/form/invoke-form/use-edit-variable.ts b/web/src/pages/data-flow/form/invoke-form/use-edit-variable.ts deleted file mode 100644 index 40b371894..000000000 --- a/web/src/pages/data-flow/form/invoke-form/use-edit-variable.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { useSetModalState } from '@/hooks/common-hooks'; -import { useSetSelectedRecord } from '@/hooks/logic-hooks'; -import { useCallback, useMemo, useState } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import { INextOperatorForm } from '../../interface'; -import { FormSchemaType, VariableFormSchemaType } from './schema'; - -export const useEditVariableRecord = ({ - form, -}: INextOperatorForm & { form: UseFormReturn }) => { - const { setRecord, currentRecord } = - useSetSelectedRecord(); - - const { visible, hideModal, showModal } = useSetModalState(); - const [index, setIndex] = useState(-1); - const variables = useWatch({ - control: form.control, - name: 'variables', - }); - - const otherThanCurrentQuery = useMemo(() => { - return variables.filter((item, idx) => idx !== index); - }, [index, variables]); - - const handleEditRecord = useCallback( - (record: VariableFormSchemaType) => { - const variables = form?.getValues('variables') || []; - - const nextVaribales = - index > -1 - ? variables.toSpliced(index, 1, record) - : [...variables, record]; - - form.setValue('variables', nextVaribales); - - hideModal(); - }, - [form, hideModal, index], - ); - - const handleShowModal = useCallback( - (idx?: number, record?: VariableFormSchemaType) => { - setIndex(idx ?? -1); - setRecord(record ?? ({} as VariableFormSchemaType)); - showModal(); - }, - [setRecord, showModal], - ); - - const handleDeleteRecord = useCallback( - (idx: number) => { - const variables = form?.getValues('variables') || []; - const nextVariables = variables.filter((item, index) => index !== idx); - - form.setValue('variables', nextVariables); - }, - [form], - ); - - return { - ok: handleEditRecord, - currentRecord, - setRecord, - visible, - hideModal, - showModal: handleShowModal, - otherThanCurrentQuery, - handleDeleteRecord, - }; -}; diff --git a/web/src/pages/data-flow/form/invoke-form/variable-dialog.tsx b/web/src/pages/data-flow/form/invoke-form/variable-dialog.tsx deleted file mode 100644 index 03c4d83b0..000000000 --- a/web/src/pages/data-flow/form/invoke-form/variable-dialog.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { Button } from '@/components/ui/button'; -import { - Dialog, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { IModalProps } from '@/interfaces/common'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { isEmpty } from 'lodash'; -import { useEffect } from 'react'; -import { useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; -import { QueryVariable } from '../components/query-variable'; -import { VariableFormSchemaType } from './schema'; - -type ModalFormProps = { - initialValue: VariableFormSchemaType; - otherThanCurrentQuery: VariableFormSchemaType[]; - submit(values: any): void; -}; - -const FormId = 'BeginParameterForm'; - -function VariableForm({ - initialValue, - otherThanCurrentQuery, - submit, -}: ModalFormProps) { - const { t } = useTranslation(); - const FormSchema = z.object({ - key: z - .string() - .trim() - .min(1) - .refine( - (value) => - !value || !otherThanCurrentQuery.some((x) => x.key === value), - { message: 'The key cannot be repeated!' }, - ), - ref: z.string(), - value: z.string(), - }); - - const form = useForm>({ - resolver: zodResolver(FormSchema), - mode: 'onChange', - defaultValues: { - key: '', - value: '', - ref: '', - }, - }); - - useEffect(() => { - if (!isEmpty(initialValue)) { - form.reset(initialValue); - } - }, [form, initialValue]); - - function onSubmit(data: z.infer) { - submit(data); - } - - return ( -
    - - ( - - {t('flow.key')} - - - - - - )} - /> - - ( - - {t('flow.value')} - - - - - - )} - /> - - - ); -} - -export function VariableDialog({ - initialValue, - hideModal, - otherThanCurrentQuery, - submit, -}: ModalFormProps & IModalProps) { - const { t } = useTranslation(); - - return ( - - - - {t('flow.variableSettings')} - - - - - - - - ); -} diff --git a/web/src/pages/data-flow/form/invoke-form/variable-table.tsx b/web/src/pages/data-flow/form/invoke-form/variable-table.tsx deleted file mode 100644 index 33a747670..000000000 --- a/web/src/pages/data-flow/form/invoke-form/variable-table.tsx +++ /dev/null @@ -1,199 +0,0 @@ -'use client'; - -import { - ColumnDef, - ColumnFiltersState, - SortingState, - VisibilityState, - flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from '@tanstack/react-table'; -import { Pencil, Trash2 } from 'lucide-react'; -import * as React from 'react'; - -import { TableEmpty } from '@/components/table-skeleton'; -import { Button } from '@/components/ui/button'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table'; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from '@/components/ui/tooltip'; -import { cn } from '@/lib/utils'; -import { useTranslation } from 'react-i18next'; -import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; -import { VariableFormSchemaType } from './schema'; - -interface IProps { - data: VariableFormSchemaType[]; - deleteRecord(index: number): void; - showModal(index: number, record: VariableFormSchemaType): void; - nodeId?: string; -} - -export function VariableTable({ - data = [], - deleteRecord, - showModal, - nodeId, -}: IProps) { - const { t } = useTranslation(); - const getLabel = useGetVariableLabelByValue(nodeId!); - - const [sorting, setSorting] = React.useState([]); - const [columnFilters, setColumnFilters] = React.useState( - [], - ); - const [columnVisibility, setColumnVisibility] = - React.useState({}); - - const columns: ColumnDef[] = [ - { - accessorKey: 'key', - header: t('flow.key'), - meta: { cellClassName: 'max-w-30' }, - cell: ({ row }) => { - const key: string = row.getValue('key'); - return ( - - -
    {key}
    -
    - -

    {key}

    -
    -
    - ); - }, - }, - { - accessorKey: 'ref', - header: t('flow.ref'), - meta: { cellClassName: 'max-w-30' }, - cell: ({ row }) => { - const ref: string = row.getValue('ref'); - const label = getLabel(ref); - return ( - - -
    {label}
    -
    - -

    {label}

    -
    -
    - ); - }, - }, - { - accessorKey: 'value', - header: t('flow.value'), - cell: ({ row }) =>
    {row.getValue('value')}
    , - }, - { - id: 'actions', - enableHiding: false, - header: t('common.action'), - cell: ({ row }) => { - const record = row.original; - const idx = row.index; - - return ( -
    - - -
    - ); - }, - }, - ]; - - const table = useReactTable({ - data, - columns, - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - onColumnVisibilityChange: setColumnVisibility, - state: { - sorting, - columnFilters, - columnVisibility, - }, - }); - - return ( -
    -
    - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext(), - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext(), - )} - - ))} - - )) - ) : ( - - )} - -
    -
    -
    - ); -} diff --git a/web/src/pages/data-flow/form/iteration-form/dynamic-output.tsx b/web/src/pages/data-flow/form/iteration-form/dynamic-output.tsx deleted file mode 100644 index c31be8fd0..000000000 --- a/web/src/pages/data-flow/form/iteration-form/dynamic-output.tsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client'; - -import { FormContainer } from '@/components/form-container'; -import { SelectWithSearch } from '@/components/originui/select-with-search'; -import { BlockButton, Button } from '@/components/ui/button'; -import { - FormControl, - FormField, - FormItem, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { Separator } from '@/components/ui/separator'; -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { t } from 'i18next'; -import { X } from 'lucide-react'; -import { ReactNode, useCallback, useMemo } from 'react'; -import { useFieldArray, useFormContext } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { useBuildSubNodeOutputOptions } from './use-build-options'; - -interface IProps { - node?: RAGFlowNodeType; -} - -export function DynamicOutputForm({ node }: IProps) { - const { t } = useTranslation(); - const form = useFormContext(); - const options = useBuildSubNodeOutputOptions(node?.id); - const name = 'outputs'; - - const flatOptions = useMemo(() => { - return options.reduce<{ label: string; value: string; type: string }[]>( - (pre, cur) => { - pre.push(...cur.options); - return pre; - }, - [], - ); - }, [options]); - - const findType = useCallback( - (val: string) => { - const type = flatOptions.find((x) => x.value === val)?.type; - if (type) { - return `Array<${type}>`; - } - }, - [flatOptions], - ); - - const { fields, remove, append } = useFieldArray({ - name: name, - control: form.control, - }); - - return ( -
    - {fields.map((field, index) => { - const nameField = `${name}.${index}.name`; - const typeField = `${name}.${index}.type`; - return ( -
    - ( - - - - - - - )} - /> - - ( - - - { - form.setValue(typeField, findType(val)); - field.onChange(val); - }} - > - - - - )} - /> -
    } - /> - -
    - ); - })} - append({ name: '', ref: undefined })}> - {t('common.add')} - -
    - ); -} - -export function VariableTitle({ title }: { title: ReactNode }) { - return
    {title}
    ; -} - -export function DynamicOutput({ node }: IProps) { - return ( - - - - - ); -} diff --git a/web/src/pages/data-flow/form/iteration-form/index.tsx b/web/src/pages/data-flow/form/iteration-form/index.tsx deleted file mode 100644 index c70b764fb..000000000 --- a/web/src/pages/data-flow/form/iteration-form/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { FormContainer } from '@/components/form-container'; -import { Form } from '@/components/ui/form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo, useMemo } from 'react'; -import { useForm, useWatch } from 'react-hook-form'; -import { z } from 'zod'; -import { VariableType } from '../../constant'; -import { INextOperatorForm } from '../../interface'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { QueryVariable } from '../components/query-variable'; -import { DynamicOutput } from './dynamic-output'; -import { OutputArray } from './interface'; -import { useValues } from './use-values'; -import { useWatchFormChange } from './use-watch-form-change'; - -const FormSchema = z.object({ - query: z.string().optional(), - outputs: z.array(z.object({ name: z.string(), value: z.any() })).optional(), -}); - -function IterationForm({ node }: INextOperatorForm) { - const defaultValues = useValues(node); - - const form = useForm({ - defaultValues: defaultValues, - resolver: zodResolver(FormSchema), - }); - - const outputs: OutputArray = useWatch({ - control: form?.control, - name: 'outputs', - }); - - const outputList = useMemo(() => { - return outputs.map((x) => ({ title: x.name, type: x?.type })); - }, [outputs]); - - useWatchFormChange(node?.id, form); - - return ( -
    - - - - - - - -
    - ); -} - -export default memo(IterationForm); diff --git a/web/src/pages/data-flow/form/iteration-form/interface.ts b/web/src/pages/data-flow/form/iteration-form/interface.ts deleted file mode 100644 index 25f22aab0..000000000 --- a/web/src/pages/data-flow/form/iteration-form/interface.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type OutputArray = Array<{ name: string; ref: string; type?: string }>; -export type OutputObject = Record; diff --git a/web/src/pages/data-flow/form/iteration-form/use-build-options.ts b/web/src/pages/data-flow/form/iteration-form/use-build-options.ts deleted file mode 100644 index 3439000d4..000000000 --- a/web/src/pages/data-flow/form/iteration-form/use-build-options.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { isEmpty } from 'lodash'; -import { useMemo } from 'react'; -import { Operator } from '../../constant'; -import { buildOutputOptions } from '../../hooks/use-get-begin-query'; -import useGraphStore from '../../store'; - -export function useBuildSubNodeOutputOptions(nodeId?: string) { - const { nodes } = useGraphStore((state) => state); - - const nodeOutputOptions = useMemo(() => { - if (!nodeId) { - return []; - } - - const subNodeWithOutputList = nodes.filter( - (x) => - x.parentId === nodeId && - x.data.label !== Operator.IterationStart && - !isEmpty(x.data?.form?.outputs), - ); - - return subNodeWithOutputList.map((x) => ({ - label: x.data.name, - value: x.id, - title: x.data.name, - options: buildOutputOptions(x.data.form.outputs, x.id), - })); - }, [nodeId, nodes]); - - return nodeOutputOptions; -} diff --git a/web/src/pages/data-flow/form/iteration-form/use-values.ts b/web/src/pages/data-flow/form/iteration-form/use-values.ts deleted file mode 100644 index 29cd06324..000000000 --- a/web/src/pages/data-flow/form/iteration-form/use-values.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { isEmpty } from 'lodash'; -import { useMemo } from 'react'; -import { initialIterationValues } from '../../constant'; -import { OutputObject } from './interface'; - -function convertToArray(outputObject: OutputObject) { - return Object.entries(outputObject).map(([key, value]) => ({ - name: key, - ref: value.ref, - type: value.type, - })); -} - -export function useValues(node?: RAGFlowNodeType) { - const values = useMemo(() => { - const formData = node?.data?.form; - - if (isEmpty(formData)) { - return { ...initialIterationValues, outputs: [] }; - } - - return { ...formData, outputs: convertToArray(formData.outputs) }; - }, [node?.data?.form]); - - return values; -} diff --git a/web/src/pages/data-flow/form/iteration-form/use-watch-form-change.ts b/web/src/pages/data-flow/form/iteration-form/use-watch-form-change.ts deleted file mode 100644 index 4a780667e..000000000 --- a/web/src/pages/data-flow/form/iteration-form/use-watch-form-change.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { useEffect } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import useGraphStore from '../../store'; -import { OutputArray, OutputObject } from './interface'; - -export function transferToObject(list: OutputArray) { - return list.reduce((pre, cur) => { - pre[cur.name] = { ref: cur.ref, type: cur.type }; - return pre; - }, {}); -} - -export function useWatchFormChange(id?: string, form?: UseFormReturn) { - let values = useWatch({ control: form?.control }); - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - useEffect(() => { - // Manually triggered form updates are synchronized to the canvas - if (id && form?.formState.isDirty) { - values = form?.getValues(); - console.log('🚀 ~ useEffect ~ values:', values); - let nextValues: any = { - ...values, - outputs: transferToObject(values.outputs), - }; - - updateNodeForm(id, nextValues); - } - }, [form?.formState.isDirty, id, updateNodeForm, values]); -} diff --git a/web/src/pages/data-flow/form/iteration-start-from/index.tsx b/web/src/pages/data-flow/form/iteration-start-from/index.tsx deleted file mode 100644 index ba58b92d1..000000000 --- a/web/src/pages/data-flow/form/iteration-start-from/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Output, OutputType } from '@/pages/agent/form/components/output'; -import { memo } from 'react'; -import { initialIterationStartValues } from '../../constant'; - -const outputs = initialIterationStartValues.outputs; - -const outputList = Object.entries(outputs).reduce( - (pre, [key, value]) => { - pre.push({ title: key, type: value.type }); - - return pre; - }, - [], -); -function IterationStartForm() { - return ( -
    - -
    - ); -} - -export default memo(IterationStartForm); diff --git a/web/src/pages/data-flow/form/keyword-extract-form/index.tsx b/web/src/pages/data-flow/form/keyword-extract-form/index.tsx deleted file mode 100644 index bda5d44f5..000000000 --- a/web/src/pages/data-flow/form/keyword-extract-form/index.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { NextLLMSelect } from '@/components/llm-select/next'; -import { TopNFormField } from '@/components/top-n-item'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { useTranslation } from 'react-i18next'; -import { INextOperatorForm } from '../../interface'; -import { DynamicInputVariable } from '../components/next-dynamic-input-variable'; - -const KeywordExtractForm = ({ form, node }: INextOperatorForm) => { - const { t } = useTranslation(); - - return ( -
    - { - e.preventDefault(); - }} - > - - ( - - - {t('chat.model')} - - - - - - - )} - /> - - - - ); -}; - -export default KeywordExtractForm; diff --git a/web/src/pages/data-flow/form/message-form/index.tsx b/web/src/pages/data-flow/form/message-form/index.tsx deleted file mode 100644 index 05c831a84..000000000 --- a/web/src/pages/data-flow/form/message-form/index.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { FormContainer } from '@/components/form-container'; -import { BlockButton, Button } from '@/components/ui/button'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { X } from 'lucide-react'; -import { memo } from 'react'; -import { useFieldArray, useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; -import { INextOperatorForm } from '../../interface'; -import { FormWrapper } from '../components/form-wrapper'; -import { PromptEditor } from '../components/prompt-editor'; -import { useValues } from './use-values'; -import { useWatchFormChange } from './use-watch-change'; - -function MessageForm({ node }: INextOperatorForm) { - const { t } = useTranslation(); - - const values = useValues(node); - - const FormSchema = z.object({ - content: z - .array( - z.object({ - value: z.string(), - }), - ) - .optional(), - }); - - const form = useForm({ - defaultValues: values, - resolver: zodResolver(FormSchema), - }); - - useWatchFormChange(node?.id, form); - - const { fields, append, remove } = useFieldArray({ - name: 'content', - control: form.control, - }); - - return ( -
    - - - - {t('flow.msg')} -
    - {fields.map((field, index) => ( -
    - ( - - - {/* */} - - - - )} - /> - {fields.length > 1 && ( - - )} -
    - ))} - - append({ value: '' })} // "" will cause the inability to add, refer to: https://github.com/orgs/react-hook-form/discussions/8485#discussioncomment-2961861 - > - {t('flow.addMessage')} - -
    - -
    -
    -
    -
    - ); -} - -export default memo(MessageForm); diff --git a/web/src/pages/data-flow/form/message-form/use-values.ts b/web/src/pages/data-flow/form/message-form/use-values.ts deleted file mode 100644 index 6a90881be..000000000 --- a/web/src/pages/data-flow/form/message-form/use-values.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { isEmpty } from 'lodash'; -import { useMemo } from 'react'; -import { initialMessageValues } from '../../constant'; -import { convertToObjectArray } from '../../utils'; - -export function useValues(node?: RAGFlowNodeType) { - const values = useMemo(() => { - const formData = node?.data?.form; - - if (isEmpty(formData)) { - return initialMessageValues; - } - - return { - ...formData, - content: convertToObjectArray(formData.content), - }; - }, [node]); - - return values; -} diff --git a/web/src/pages/data-flow/form/message-form/use-watch-change.ts b/web/src/pages/data-flow/form/message-form/use-watch-change.ts deleted file mode 100644 index 10c35c653..000000000 --- a/web/src/pages/data-flow/form/message-form/use-watch-change.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { useEffect } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import useGraphStore from '../../store'; -import { convertToStringArray } from '../../utils'; - -export function useWatchFormChange(id?: string, form?: UseFormReturn) { - let values = useWatch({ control: form?.control }); - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - useEffect(() => { - // Manually triggered form updates are synchronized to the canvas - if (id && form?.formState.isDirty) { - values = form?.getValues(); - let nextValues: any = values; - - nextValues = { - ...values, - content: convertToStringArray(values.content), - }; - - updateNodeForm(id, nextValues); - } - }, [form?.formState.isDirty, id, updateNodeForm, values]); -} diff --git a/web/src/pages/data-flow/form/relevant-form/hooks.ts b/web/src/pages/data-flow/form/relevant-form/hooks.ts deleted file mode 100644 index 413a0ac38..000000000 --- a/web/src/pages/data-flow/form/relevant-form/hooks.ts +++ /dev/null @@ -1,41 +0,0 @@ -import pick from 'lodash/pick'; -import { useCallback, useEffect } from 'react'; -import { IOperatorForm } from '../../interface'; -import useGraphStore from '../../store'; - -export const useBuildRelevantOptions = () => { - const nodes = useGraphStore((state) => state.nodes); - - const buildRelevantOptions = useCallback( - (toList: string[]) => { - return nodes - .filter( - (x) => !toList.some((y) => y === x.id), // filter out selected values ​​in other to fields from the current drop-down box options - ) - .map((x) => ({ label: x.data.name, value: x.id })); - }, - [nodes], - ); - - return buildRelevantOptions; -}; - -/** - * monitor changes in the connection and synchronize the target to the yes and no fields of the form - * similar to the categorize-form's useHandleFormValuesChange method - * @param param0 - */ -export const useWatchConnectionChanges = ({ nodeId, form }: IOperatorForm) => { - const getNode = useGraphStore((state) => state.getNode); - const node = getNode(nodeId); - - const watchFormChanges = useCallback(() => { - if (node) { - form?.setFieldsValue(pick(node, ['yes', 'no'])); - } - }, [node, form]); - - useEffect(() => { - watchFormChanges(); - }, [watchFormChanges]); -}; diff --git a/web/src/pages/data-flow/form/relevant-form/index.tsx b/web/src/pages/data-flow/form/relevant-form/index.tsx deleted file mode 100644 index e2366f6f0..000000000 --- a/web/src/pages/data-flow/form/relevant-form/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import LLMSelect from '@/components/llm-select'; -import { useTranslate } from '@/hooks/common-hooks'; -import { Form, Select } from 'antd'; -import { Operator } from '../../constant'; -import { useBuildFormSelectOptions } from '../../form-hooks'; -import { IOperatorForm } from '../../interface'; -import { useWatchConnectionChanges } from './hooks'; - -const RelevantForm = ({ onValuesChange, form, node }: IOperatorForm) => { - const { t } = useTranslate('flow'); - const buildRelevantOptions = useBuildFormSelectOptions( - Operator.Relevant, - node?.id, - ); - useWatchConnectionChanges({ nodeId: node?.id, form }); - - return ( -
    - - - - - - -
    - ); -}; - -export default RelevantForm; diff --git a/web/src/pages/data-flow/form/retrieval-form/next.tsx b/web/src/pages/data-flow/form/retrieval-form/next.tsx deleted file mode 100644 index 425d08e4b..000000000 --- a/web/src/pages/data-flow/form/retrieval-form/next.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { Collapse } from '@/components/collapse'; -import { CrossLanguageFormField } from '@/components/cross-language-form-field'; -import { FormContainer } from '@/components/form-container'; -import { KnowledgeBaseFormField } from '@/components/knowledge-base-item'; -import { RAGFlowFormItem } from '@/components/ragflow-form'; -import { RerankFormFields } from '@/components/rerank'; -import { SimilaritySliderFormField } from '@/components/similarity-slider'; -import { TopNFormField } from '@/components/top-n-item'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Textarea } from '@/components/ui/textarea'; -import { UseKnowledgeGraphFormField } from '@/components/use-knowledge-graph-item'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { memo, useMemo } from 'react'; -import { useForm, useFormContext } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; -import { initialRetrievalValues } from '../../constant'; -import { useWatchFormChange } from '../../hooks/use-watch-form-change'; -import { INextOperatorForm } from '../../interface'; -import { FormWrapper } from '../components/form-wrapper'; -import { Output } from '../components/output'; -import { PromptEditor } from '../components/prompt-editor'; -import { useValues } from './use-values'; - -export const RetrievalPartialSchema = { - similarity_threshold: z.coerce.number(), - keywords_similarity_weight: z.coerce.number(), - top_n: z.coerce.number(), - top_k: z.coerce.number(), - kb_ids: z.array(z.string()), - rerank_id: z.string(), - empty_response: z.string(), - cross_languages: z.array(z.string()), - use_kg: z.boolean(), -}; - -export const FormSchema = z.object({ - query: z.string().optional(), - ...RetrievalPartialSchema, -}); - -export function EmptyResponseField() { - const { t } = useTranslation(); - const form = useFormContext(); - - return ( - ( - - - {t('chat.emptyResponse')} - - - - - - - )} - /> - - {/* Create a hidden field to make Form instance record this */} -
    } - /> - - {t('flow.input')} - -
    - } - rightContent={ - - } - > - - - - {visible && ( - - )} - - -
    - ); -} - -export default memo(UserFillUpForm); diff --git a/web/src/pages/data-flow/form/user-fill-up-form/use-values.ts b/web/src/pages/data-flow/form/user-fill-up-form/use-values.ts deleted file mode 100644 index 0af1c78c3..000000000 --- a/web/src/pages/data-flow/form/user-fill-up-form/use-values.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { isEmpty } from 'lodash'; -import { useMemo } from 'react'; -import { initialUserFillUpValues } from '../../constant'; -import { buildBeginInputListFromObject } from '../begin-form/utils'; - -export function useValues(node?: RAGFlowNodeType) { - const values = useMemo(() => { - const formData = node?.data?.form; - - if (isEmpty(formData)) { - return initialUserFillUpValues; - } - - const inputs = buildBeginInputListFromObject(formData?.inputs); - - return { ...(formData || {}), inputs }; - }, [node?.data?.form]); - - return values; -} diff --git a/web/src/pages/data-flow/form/user-fill-up-form/use-watch-change.ts b/web/src/pages/data-flow/form/user-fill-up-form/use-watch-change.ts deleted file mode 100644 index bdf4b9a91..000000000 --- a/web/src/pages/data-flow/form/user-fill-up-form/use-watch-change.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { omit } from 'lodash'; -import { useEffect } from 'react'; -import { UseFormReturn, useWatch } from 'react-hook-form'; -import { BeginQuery } from '../../interface'; -import useGraphStore from '../../store'; - -function transferInputsArrayToObject(inputs: BeginQuery[] = []) { - return inputs.reduce>>((pre, cur) => { - pre[cur.key] = omit(cur, 'key'); - - return pre; - }, {}); -} - -export function useWatchFormChange(id?: string, form?: UseFormReturn) { - let values = useWatch({ control: form?.control }); - const updateNodeForm = useGraphStore((state) => state.updateNodeForm); - - useEffect(() => { - // TODO: This should only be executed when the form changes - if (id) { - values = form?.getValues() || {}; - - const inputs = transferInputsArrayToObject(values.inputs); - - const nextValues = { - ...values, - inputs, - outputs: inputs, - }; - - updateNodeForm(id, nextValues); - } - }, [form?.formState.isDirty, id, updateNodeForm, values]); -} diff --git a/web/src/pages/data-flow/hooks/use-show-drawer.tsx b/web/src/pages/data-flow/hooks/use-show-drawer.tsx index 383eddd65..dd0fa5360 100644 --- a/web/src/pages/data-flow/hooks/use-show-drawer.tsx +++ b/web/src/pages/data-flow/hooks/use-show-drawer.tsx @@ -2,7 +2,7 @@ import { useSetModalState } from '@/hooks/common-hooks'; import { NodeMouseHandler } from '@xyflow/react'; import get from 'lodash/get'; import React, { useCallback, useEffect } from 'react'; -import { Operator } from '../constant'; +import { BeginId, Operator } from '../constant'; import useGraphStore from '../store'; import { useCacheChatLog } from './use-cache-chat-log'; import { useGetBeginNodeDataInputs } from './use-get-begin-query'; @@ -13,7 +13,6 @@ export const useShowFormDrawer = () => { clickedNodeId: clickNodeId, setClickedNodeId, getNode, - setClickedToolId, } = useGraphStore((state) => state); const { visible: formDrawerVisible, @@ -23,16 +22,14 @@ export const useShowFormDrawer = () => { const handleShow = useCallback( (e: React.MouseEvent, nodeId: string) => { - const tool = get(e.target, 'dataset.tool'); // TODO: Operator type judgment should be used - if (nodeId.startsWith(Operator.Tool) && !tool) { + if (nodeId === BeginId) { return; } setClickedNodeId(nodeId); - setClickedToolId(tool); showFormDrawer(); }, - [setClickedNodeId, setClickedToolId, showFormDrawer], + [setClickedNodeId, showFormDrawer], ); return { diff --git a/web/src/pages/data-flow/operator-icon.tsx b/web/src/pages/data-flow/operator-icon.tsx index 2184569d6..6db9db9d4 100644 --- a/web/src/pages/data-flow/operator-icon.tsx +++ b/web/src/pages/data-flow/operator-icon.tsx @@ -1,8 +1,9 @@ import { IconFont } from '@/components/icon-font'; import { cn } from '@/lib/utils'; import { + Blocks, FileChartColumnIncreasing, - Grid3x3, + Heading, HousePlus, ListMinus, } from 'lucide-react'; @@ -14,26 +15,15 @@ interface IProps { } export const OperatorIconMap = { - [Operator.Retrieval]: 'KR', [Operator.Begin]: 'house-plus', - [Operator.Categorize]: 'a-QuestionClassification', - [Operator.Message]: 'reply', - [Operator.Iteration]: 'loop', - [Operator.Switch]: 'condition', - [Operator.Code]: 'code-set', - [Operator.Agent]: 'agent-ai', - [Operator.UserFillUp]: 'await', - [Operator.StringTransform]: 'a-textprocessing', [Operator.Note]: 'notebook-pen', - [Operator.ExeSQL]: 'executesql-0', - [Operator.Invoke]: 'httprequest-0', - [Operator.Email]: 'sendemail-0', }; export const SVGIconMap = { [Operator.Parser]: FileChartColumnIncreasing, - [Operator.Chunker]: Grid3x3, [Operator.Tokenizer]: ListMinus, + [Operator.Splitter]: Blocks, + [Operator.HierarchicalMerger]: Heading, }; const Empty = () => {