balibabu
		
	commited on
		
		
					Commit 
							
							·
						
						2bdad3e
	
1
								Parent(s):
							
							4496b5e
								
Feat: Add the iteration Node #4242 (#4247)
Browse files### What problem does this PR solve?
Feat: Add the iteration Node #4242
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
This view is limited to 50 files because it contains too many changes.  
							See raw diff
- web/src/assets/icon/Icon.tsx +38 -0
- web/src/components/delimiter.tsx +9 -2
- web/src/interfaces/database/flow.ts +1 -0
- web/src/less/mixins.less +20 -0
- web/src/locales/en.ts +16 -0
- web/src/locales/zh-traditional.ts +14 -0
- web/src/locales/zh.ts +14 -0
- web/src/pages/flow/canvas/edge/index.tsx +1 -0
- web/src/pages/flow/canvas/index.less +6 -0
- web/src/pages/flow/canvas/index.tsx +23 -82
- web/src/pages/flow/canvas/node/begin-node.tsx +3 -1
- web/src/pages/flow/canvas/node/dropdown.tsx +10 -2
- web/src/pages/flow/canvas/node/generate-node.tsx +1 -1
- web/src/pages/flow/canvas/node/index.less +22 -18
- web/src/pages/flow/canvas/node/iteration-node.tsx +118 -0
- web/src/pages/flow/canvas/node/node-header.tsx +16 -5
- web/src/pages/flow/canvas/node/popover.tsx +2 -1
- web/src/pages/flow/canvas/node/switch-node.tsx +1 -1
- web/src/pages/flow/canvas/node/template-node.tsx +2 -2
- web/src/pages/flow/constant.tsx +23 -0
- web/src/pages/flow/flow-drawer/index.tsx +13 -6
- web/src/pages/flow/form/akshare-form/index.tsx +1 -1
- web/src/pages/flow/form/arxiv-form/index.tsx +1 -1
- web/src/pages/flow/form/baidu-fanyi-form/index.tsx +1 -1
- web/src/pages/flow/form/baidu-form/index.tsx +1 -1
- web/src/pages/flow/form/bing-form/index.tsx +1 -1
- web/src/pages/flow/form/categorize-form/index.tsx +1 -1
- web/src/pages/flow/form/components/dynamic-input-variable.tsx +12 -7
- web/src/pages/flow/form/crawler-form/index.tsx +1 -1
- web/src/pages/flow/form/deepl-form/index.tsx +1 -1
- web/src/pages/flow/form/duckduckgo-form/index.tsx +1 -1
- web/src/pages/flow/form/email-form/index.tsx +1 -1
- web/src/pages/flow/form/exesql-form/index.tsx +1 -1
- web/src/pages/flow/form/generate-form/dynamic-parameters.tsx +8 -7
- web/src/pages/flow/form/generate-form/index.tsx +1 -1
- web/src/pages/flow/form/github-form/index.tsx +1 -1
- web/src/pages/flow/form/google-form/index.tsx +1 -1
- web/src/pages/flow/form/google-scholar-form/index.tsx +1 -1
- web/src/pages/flow/form/invoke-form/dynamic-variables.tsx +8 -6
- web/src/pages/flow/form/invoke-form/index.tsx +1 -1
- web/src/pages/flow/form/iteration-from/index.tsx +94 -0
- web/src/pages/flow/form/jin10-form/index.tsx +1 -1
- web/src/pages/flow/form/keyword-extract-form/index.tsx +1 -1
- web/src/pages/flow/form/pubmed-form/index.tsx +1 -1
- web/src/pages/flow/form/qweather-form/index.tsx +1 -1
- web/src/pages/flow/form/retrieval-form/index.tsx +1 -1
- web/src/pages/flow/form/switch-form/index.tsx +5 -2
- web/src/pages/flow/form/template-form/index.tsx +1 -1
- web/src/pages/flow/form/tushare-form/index.tsx +1 -1
- web/src/pages/flow/form/wencai-form/index.tsx +1 -1
    	
        web/src/assets/icon/Icon.tsx
    CHANGED
    
    | @@ -205,6 +205,36 @@ const QWeatherSvg = () => ( | |
| 205 | 
             
              </svg>
         | 
| 206 | 
             
            );
         | 
| 207 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 208 | 
             
            export const ApiIcon = (props: Partial<IconComponentProps>) => (
         | 
| 209 | 
             
              <Icon component={ApiSvg} {...props} />
         | 
| 210 | 
             
            );
         | 
| @@ -238,3 +268,11 @@ export const GitHubIcon = (props: Partial<IconComponentProps>) => ( | |
| 238 | 
             
            export const QWeatherIcon = (props: Partial<IconComponentProps>) => (
         | 
| 239 | 
             
              <Icon component={QWeatherSvg} {...props} />
         | 
| 240 | 
             
            );
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 205 | 
             
              </svg>
         | 
| 206 | 
             
            );
         | 
| 207 |  | 
| 208 | 
            +
            const SemicolonSvg = () => (
         | 
| 209 | 
            +
              <svg
         | 
| 210 | 
            +
                viewBox="0 0 1024 1024"
         | 
| 211 | 
            +
                version="1.1"
         | 
| 212 | 
            +
                xmlns="http://www.w3.org/2000/svg"
         | 
| 213 | 
            +
                width="200"
         | 
| 214 | 
            +
                height="200"
         | 
| 215 | 
            +
              >
         | 
| 216 | 
            +
                <path
         | 
| 217 | 
            +
                  d="M506.88 249.059556a89.884444 89.884444 0 0 0 60.074667-21.845334 87.950222 87.950222 0 0 0 23.210666-61.44 79.189333 79.189333 0 0 0-83.285333-83.285333c-24.576 0-45.056 6.826667-60.074667 23.210667-16.384 15.018667-23.210667 35.498667-23.210666 60.074666 0 24.576 6.826667 45.056 23.210666 61.44 15.018667 13.653333 35.498667 21.845333 60.074667 21.845334zM414.037333 967.224889a262.030222 262.030222 0 0 0 141.994667-88.746667c35.498667-46.421333 53.248-99.669333 53.248-159.744 0-39.594667-9.557333-70.997333-27.306667-95.573333a89.543111 89.543111 0 0 0-75.093333-38.229333c-27.306667 0-47.786667 6.826667-62.805333 23.210666-17.749333 15.018667-25.941333 35.498667-25.941334 61.44 0 23.210667 8.192 43.690667 24.576 60.074667a79.416889 79.416889 0 0 0 58.709334 24.576 78.506667 78.506667 0 0 0 30.037333-5.461333c0 32.768-9.557333 62.805333-30.037333 91.477333a190.008889 190.008889 0 0 1-87.381334 60.074667v66.901333z"
         | 
| 218 | 
            +
                  fill={currentColor}
         | 
| 219 | 
            +
                ></path>
         | 
| 220 | 
            +
              </svg>
         | 
| 221 | 
            +
            );
         | 
| 222 | 
            +
             | 
| 223 | 
            +
            const CommaSvg = () => (
         | 
| 224 | 
            +
              <svg
         | 
| 225 | 
            +
                viewBox="0 0 1024 1024"
         | 
| 226 | 
            +
                version="1.1"
         | 
| 227 | 
            +
                xmlns="http://www.w3.org/2000/svg"
         | 
| 228 | 
            +
                width="200"
         | 
| 229 | 
            +
                height="200"
         | 
| 230 | 
            +
              >
         | 
| 231 | 
            +
                <path
         | 
| 232 | 
            +
                  fill={currentColor}
         | 
| 233 | 
            +
                  d="M701.312 416.064C701.312 327.68 629.76 256 541.312 256c-88.32 0-160 71.68-160 160.064s71.68 160.064 160 160.064c10.368 0 20.352-1.216 30.144-3.072-27.136 78.592-88.32 99.392-166.4 120.32L434.688 736c228.288-40.576 269.184-268.48 266.688-266.496C707.328 452.672 701.312 434.88 701.312 416.064z"
         | 
| 234 | 
            +
                ></path>
         | 
| 235 | 
            +
              </svg>
         | 
| 236 | 
            +
            );
         | 
| 237 | 
            +
             | 
| 238 | 
             
            export const ApiIcon = (props: Partial<IconComponentProps>) => (
         | 
| 239 | 
             
              <Icon component={ApiSvg} {...props} />
         | 
| 240 | 
             
            );
         | 
|  | |
| 268 | 
             
            export const QWeatherIcon = (props: Partial<IconComponentProps>) => (
         | 
| 269 | 
             
              <Icon component={QWeatherSvg} {...props} />
         | 
| 270 | 
             
            );
         | 
| 271 | 
            +
             | 
| 272 | 
            +
            export const SemicolonIcon = (props: Partial<IconComponentProps>) => (
         | 
| 273 | 
            +
              <Icon component={SemicolonSvg} {...props} />
         | 
| 274 | 
            +
            );
         | 
| 275 | 
            +
             | 
| 276 | 
            +
            export const CommaIcon = (props: Partial<IconComponentProps>) => (
         | 
| 277 | 
            +
              <Icon component={CommaSvg} {...props} />
         | 
| 278 | 
            +
            );
         | 
    	
        web/src/components/delimiter.tsx
    CHANGED
    
    | @@ -4,16 +4,23 @@ import { useTranslation } from 'react-i18next'; | |
| 4 | 
             
            interface IProps {
         | 
| 5 | 
             
              value?: string | undefined;
         | 
| 6 | 
             
              onChange?: (val: string | undefined) => void;
         | 
|  | |
| 7 | 
             
            }
         | 
| 8 |  | 
| 9 | 
            -
            const DelimiterInput = ({ value, onChange }: IProps) => {
         | 
| 10 | 
             
              const nextValue = value?.replaceAll('\n', '\\n');
         | 
| 11 | 
             
              const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
         | 
| 12 | 
             
                const val = e.target.value;
         | 
| 13 | 
             
                const nextValue = val.replaceAll('\\n', '\n');
         | 
| 14 | 
             
                onChange?.(nextValue);
         | 
| 15 | 
             
              };
         | 
| 16 | 
            -
              return  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 17 | 
             
            };
         | 
| 18 |  | 
| 19 | 
             
            const Delimiter = () => {
         | 
|  | |
| 4 | 
             
            interface IProps {
         | 
| 5 | 
             
              value?: string | undefined;
         | 
| 6 | 
             
              onChange?: (val: string | undefined) => void;
         | 
| 7 | 
            +
              maxLength?: number;
         | 
| 8 | 
             
            }
         | 
| 9 |  | 
| 10 | 
            +
            export const DelimiterInput = ({ value, onChange, maxLength }: IProps) => {
         | 
| 11 | 
             
              const nextValue = value?.replaceAll('\n', '\\n');
         | 
| 12 | 
             
              const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
         | 
| 13 | 
             
                const val = e.target.value;
         | 
| 14 | 
             
                const nextValue = val.replaceAll('\\n', '\n');
         | 
| 15 | 
             
                onChange?.(nextValue);
         | 
| 16 | 
             
              };
         | 
| 17 | 
            +
              return (
         | 
| 18 | 
            +
                <Input
         | 
| 19 | 
            +
                  value={nextValue}
         | 
| 20 | 
            +
                  onChange={handleInputChange}
         | 
| 21 | 
            +
                  maxLength={maxLength}
         | 
| 22 | 
            +
                ></Input>
         | 
| 23 | 
            +
              );
         | 
| 24 | 
             
            };
         | 
| 25 |  | 
| 26 | 
             
            const Delimiter = () => {
         | 
    	
        web/src/interfaces/database/flow.ts
    CHANGED
    
    | @@ -17,6 +17,7 @@ export interface IOperator { | |
| 17 | 
             
              obj: IOperatorNode;
         | 
| 18 | 
             
              downstream: string[];
         | 
| 19 | 
             
              upstream: string[];
         | 
|  | |
| 20 | 
             
            }
         | 
| 21 |  | 
| 22 | 
             
            export interface IOperatorNode {
         | 
|  | |
| 17 | 
             
              obj: IOperatorNode;
         | 
| 18 | 
             
              downstream: string[];
         | 
| 19 | 
             
              upstream: string[];
         | 
| 20 | 
            +
              parent_id?: string;
         | 
| 21 | 
             
            }
         | 
| 22 |  | 
| 23 | 
             
            export interface IOperatorNode {
         | 
    	
        web/src/less/mixins.less
    CHANGED
    
    | @@ -75,3 +75,23 @@ | |
| 75 | 
             
              background-color: #eff8ff;
         | 
| 76 | 
             
              border: 1px;
         | 
| 77 | 
             
            }
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 75 | 
             
              background-color: #eff8ff;
         | 
| 76 | 
             
              border: 1px;
         | 
| 77 | 
             
            }
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            .commonNodeShadow() {
         | 
| 80 | 
            +
              box-shadow:
         | 
| 81 | 
            +
                -6px 0 12px 0 rgba(179, 177, 177, 0.08),
         | 
| 82 | 
            +
                -3px 0 6px -4px rgba(0, 0, 0, 0.12),
         | 
| 83 | 
            +
                -6px 0 16px 6px rgba(0, 0, 0, 0.05);
         | 
| 84 | 
            +
            }
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            .commonNodeRadius() {
         | 
| 87 | 
            +
              border-radius: 10px;
         | 
| 88 | 
            +
            }
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            .commonNode() {
         | 
| 91 | 
            +
              .commonNodeShadow();
         | 
| 92 | 
            +
              .commonNodeRadius();
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              padding: 10px;
         | 
| 95 | 
            +
              background: white;
         | 
| 96 | 
            +
              width: 200px;
         | 
| 97 | 
            +
            }
         | 
    	
        web/src/locales/en.ts
    CHANGED
    
    | @@ -1077,6 +1077,22 @@ The above is the content you need to summarize.`, | |
| 1077 | 
             
                  contentTip: 'content: Email content (Optional)',
         | 
| 1078 | 
             
                  jsonUploadTypeErrorMessage: 'Please upload json file',
         | 
| 1079 | 
             
                  jsonUploadContentErrorMessage: 'json file error',
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 1080 | 
             
                },
         | 
| 1081 | 
             
                footer: {
         | 
| 1082 | 
             
                  profile: 'All rights reserved @ React',
         | 
|  | |
| 1077 | 
             
                  contentTip: 'content: Email content (Optional)',
         | 
| 1078 | 
             
                  jsonUploadTypeErrorMessage: 'Please upload json file',
         | 
| 1079 | 
             
                  jsonUploadContentErrorMessage: 'json file error',
         | 
| 1080 | 
            +
                  iteration: 'Iteration',
         | 
| 1081 | 
            +
                  iterationDescription: `This component firstly split the input into array by "delimiter".
         | 
| 1082 | 
            +
            Perform the same operation steps on the elements in the array in sequence until all results are output, which can be understood as a task batch processor.
         | 
| 1083 | 
            +
             | 
| 1084 | 
            +
            For example, within the long text translation iteration node, if all content is input to the LLM node, the single conversation limit may be reached. The upstream node can first split the long text into multiple fragments, and cooperate with the iterative node to perform batch translation on each fragment to avoid reaching the LLM message limit for a single conversation.`,
         | 
| 1085 | 
            +
                  delimiterTip: `
         | 
| 1086 | 
            +
            This delimiter is used to split the input text into several text pieces echo of which will be performed as input item of each iteration.`,
         | 
| 1087 | 
            +
                  delimiterOptions: {
         | 
| 1088 | 
            +
                    comma: 'Comma',
         | 
| 1089 | 
            +
                    lineBreak: 'Line break',
         | 
| 1090 | 
            +
                    tab: 'Tab',
         | 
| 1091 | 
            +
                    underline: 'Underline',
         | 
| 1092 | 
            +
                    diagonal: 'Diagonal',
         | 
| 1093 | 
            +
                    minus: 'Minus',
         | 
| 1094 | 
            +
                    semicolon: 'Semicolon',
         | 
| 1095 | 
            +
                  },
         | 
| 1096 | 
             
                },
         | 
| 1097 | 
             
                footer: {
         | 
| 1098 | 
             
                  profile: 'All rights reserved @ React',
         | 
    	
        web/src/locales/zh-traditional.ts
    CHANGED
    
    | @@ -1016,6 +1016,20 @@ export default { | |
| 1016 | 
             
                  templateDescription: '此元件用於排版各種元件的輸出。 ',
         | 
| 1017 | 
             
                  jsonUploadTypeErrorMessage: '請上傳json檔',
         | 
| 1018 | 
             
                  jsonUploadContentErrorMessage: 'json 檔案錯誤',
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 1019 | 
             
                },
         | 
| 1020 | 
             
                footer: {
         | 
| 1021 | 
             
                  profile: '“保留所有權利 @ react”',
         | 
|  | |
| 1016 | 
             
                  templateDescription: '此元件用於排版各種元件的輸出。 ',
         | 
| 1017 | 
             
                  jsonUploadTypeErrorMessage: '請上傳json檔',
         | 
| 1018 | 
             
                  jsonUploadContentErrorMessage: 'json 檔案錯誤',
         | 
| 1019 | 
            +
                  iterationDescription: `此元件首先透過「分隔符號」將輸入拆分為陣列。
         | 
| 1020 | 
            +
            對數組中的元素依序執行相同的操作步驟,直到輸出所有結果,可以理解為任務批次處理器。
         | 
| 1021 | 
            +
             | 
| 1022 | 
            +
            例如,在長文本翻譯迭代節點內,如果所有內容都輸入到LLM節點,則可能會達到單次對話限制。上游節點可以先將長文本拆分為多個分片,並配合迭代節點對每個分片進行批次翻譯,避免達到單次對話的LLM訊息限制。`,
         | 
| 1023 | 
            +
                  delimiterTip: `此分隔符號用於將輸入文字分割成多個文字片段,其中的回顯將作為每次迭代的輸入項執行。`,
         | 
| 1024 | 
            +
                  delimiterOptions: {
         | 
| 1025 | 
            +
                    comma: '逗號',
         | 
| 1026 | 
            +
                    lineBreak: '換行',
         | 
| 1027 | 
            +
                    tab: '製表符',
         | 
| 1028 | 
            +
                    underline: '底線',
         | 
| 1029 | 
            +
                    diagonal: '斜線',
         | 
| 1030 | 
            +
                    minus: '減號',
         | 
| 1031 | 
            +
                    semicolon: '分號',
         | 
| 1032 | 
            +
                  },
         | 
| 1033 | 
             
                },
         | 
| 1034 | 
             
                footer: {
         | 
| 1035 | 
             
                  profile: '“保留所有權利 @ react”',
         | 
    	
        web/src/locales/zh.ts
    CHANGED
    
    | @@ -1060,6 +1060,20 @@ export default { | |
| 1060 | 
             
                  contentTip: 'content: 邮件内容(可选)',
         | 
| 1061 | 
             
                  jsonUploadTypeErrorMessage: '请上传json文件',
         | 
| 1062 | 
             
                  jsonUploadContentErrorMessage: 'json 文件错误',
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 1063 | 
             
                },
         | 
| 1064 | 
             
                footer: {
         | 
| 1065 | 
             
                  profile: 'All rights reserved @ React',
         | 
|  | |
| 1060 | 
             
                  contentTip: 'content: 邮件内容(可选)',
         | 
| 1061 | 
             
                  jsonUploadTypeErrorMessage: '请上传json文件',
         | 
| 1062 | 
             
                  jsonUploadContentErrorMessage: 'json 文件错误',
         | 
| 1063 | 
            +
                  iteration: '循环',
         | 
| 1064 | 
            +
                  iterationDescription: `该组件首先将输入以“分隔符”分割成数组,然后依次对数组中的元素执行相同的操作步骤,直到输出所有结果,可以理解为一个任务批处理器。
         | 
| 1065 | 
            +
             | 
| 1066 | 
            +
            例如在长文本翻译迭代节点中,如果所有内容都输入到LLM节点,可能会达到单次对话的限制,上游节点可以先将长文本分割成多个片段,配合迭代节点对每个片段进行批量翻译,避免达到单次对话的LLM消息限制。`,
         | 
| 1067 | 
            +
                  delimiterTip: `该分隔符用于将输入文本分割成几个文本片段,每个文本片段的回显将作为每次迭代的输入项。`,
         | 
| 1068 | 
            +
                  delimiterOptions: {
         | 
| 1069 | 
            +
                    comma: '逗号',
         | 
| 1070 | 
            +
                    lineBreak: '换行',
         | 
| 1071 | 
            +
                    tab: '制表符',
         | 
| 1072 | 
            +
                    underline: '下划线',
         | 
| 1073 | 
            +
                    diagonal: '斜线',
         | 
| 1074 | 
            +
                    minus: '减号',
         | 
| 1075 | 
            +
                    semicolon: '分号',
         | 
| 1076 | 
            +
                  },
         | 
| 1077 | 
             
                },
         | 
| 1078 | 
             
                footer: {
         | 
| 1079 | 
             
                  profile: 'All rights reserved @ React',
         | 
    	
        web/src/pages/flow/canvas/edge/index.tsx
    CHANGED
    
    | @@ -90,6 +90,7 @@ export function ButtonEdge({ | |
| 90 | 
             
                        // everything inside EdgeLabelRenderer has no pointer events by default
         | 
| 91 | 
             
                        // if you have an interactive element, set pointer-events: all
         | 
| 92 | 
             
                        pointerEvents: 'all',
         | 
|  | |
| 93 | 
             
                      }}
         | 
| 94 | 
             
                      className="nodrag nopan"
         | 
| 95 | 
             
                    >
         | 
|  | |
| 90 | 
             
                        // everything inside EdgeLabelRenderer has no pointer events by default
         | 
| 91 | 
             
                        // if you have an interactive element, set pointer-events: all
         | 
| 92 | 
             
                        pointerEvents: 'all',
         | 
| 93 | 
            +
                        zIndex: 1001, // https://github.com/xyflow/xyflow/discussions/3498
         | 
| 94 | 
             
                      }}
         | 
| 95 | 
             
                      className="nodrag nopan"
         | 
| 96 | 
             
                    >
         | 
    	
        web/src/pages/flow/canvas/index.less
    CHANGED
    
    | @@ -1,4 +1,10 @@ | |
| 1 | 
             
            .canvasWrapper {
         | 
| 2 | 
             
              position: relative;
         | 
| 3 | 
             
              height: 100%;
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 4 | 
             
            }
         | 
|  | |
| 1 | 
             
            .canvasWrapper {
         | 
| 2 | 
             
              position: relative;
         | 
| 3 | 
             
              height: 100%;
         | 
| 4 | 
            +
              :global(.react-flow__node-group) {
         | 
| 5 | 
            +
                .commonNode();
         | 
| 6 | 
            +
                padding: 0;
         | 
| 7 | 
            +
                border: 0;
         | 
| 8 | 
            +
                background-color: transparent;
         | 
| 9 | 
            +
              }
         | 
| 10 | 
             
            }
         | 
    	
        web/src/pages/flow/canvas/index.tsx
    CHANGED
    
    | @@ -4,32 +4,24 @@ import { | |
| 4 | 
             
              TooltipProvider,
         | 
| 5 | 
             
              TooltipTrigger,
         | 
| 6 | 
             
            } from '@/components/ui/tooltip';
         | 
| 7 | 
            -
            import { useSetModalState } from '@/hooks/common-hooks';
         | 
| 8 | 
            -
            import { get } from 'lodash';
         | 
| 9 | 
             
            import { FolderInput, FolderOutput } from 'lucide-react';
         | 
| 10 | 
            -
            import { useCallback, useEffect } from 'react';
         | 
| 11 | 
             
            import ReactFlow, {
         | 
| 12 | 
             
              Background,
         | 
| 13 | 
             
              ConnectionMode,
         | 
| 14 | 
             
              ControlButton,
         | 
| 15 | 
             
              Controls,
         | 
| 16 | 
            -
              NodeMouseHandler,
         | 
| 17 | 
             
            } from 'reactflow';
         | 
| 18 | 
             
            import 'reactflow/dist/style.css';
         | 
| 19 | 
             
            import ChatDrawer from '../chat/drawer';
         | 
| 20 | 
            -
            import { Operator } from '../constant';
         | 
| 21 | 
             
            import FormDrawer from '../flow-drawer';
         | 
| 22 | 
             
            import {
         | 
| 23 | 
            -
              useGetBeginNodeDataQuery,
         | 
| 24 | 
             
              useHandleDrop,
         | 
| 25 | 
            -
              useHandleExportOrImportJsonFile,
         | 
| 26 | 
             
              useSelectCanvasData,
         | 
| 27 | 
            -
              useShowFormDrawer,
         | 
| 28 | 
            -
              useShowSingleDebugDrawer,
         | 
| 29 | 
             
              useValidateConnection,
         | 
| 30 | 
             
              useWatchNodeFormDataChange,
         | 
| 31 | 
             
            } from '../hooks';
         | 
| 32 | 
            -
            import {  | 
|  | |
| 33 | 
             
            import JsonUploadModal from '../json-upload-modal';
         | 
| 34 | 
             
            import RunDrawer from '../run-drawer';
         | 
| 35 | 
             
            import { ButtonEdge } from './edge';
         | 
| @@ -40,6 +32,7 @@ import { CategorizeNode } from './node/categorize-node'; | |
| 40 | 
             
            import { EmailNode } from './node/email-node';
         | 
| 41 | 
             
            import { GenerateNode } from './node/generate-node';
         | 
| 42 | 
             
            import { InvokeNode } from './node/invoke-node';
         | 
|  | |
| 43 | 
             
            import { KeywordNode } from './node/keyword-node';
         | 
| 44 | 
             
            import { LogicNode } from './node/logic-node';
         | 
| 45 | 
             
            import { MessageNode } from './node/message-node';
         | 
| @@ -66,6 +59,8 @@ const nodeTypes = { | |
| 66 | 
             
              invokeNode: InvokeNode,
         | 
| 67 | 
             
              templateNode: TemplateNode,
         | 
| 68 | 
             
              emailNode: EmailNode,
         | 
|  | |
|  | |
| 69 | 
             
            };
         | 
| 70 |  | 
| 71 | 
             
            const edgeTypes = {
         | 
| @@ -87,66 +82,11 @@ function FlowCanvas({ drawerVisible, hideDrawer }: IProps) { | |
| 87 | 
             
                onSelectionChange,
         | 
| 88 | 
             
              } = useSelectCanvasData();
         | 
| 89 | 
             
              const isValidConnection = useValidateConnection();
         | 
| 90 | 
            -
              const {
         | 
| 91 | 
            -
                visible: runVisible,
         | 
| 92 | 
            -
                showModal: showRunModal,
         | 
| 93 | 
            -
                hideModal: hideRunModal,
         | 
| 94 | 
            -
              } = useSetModalState();
         | 
| 95 | 
            -
              const {
         | 
| 96 | 
            -
                visible: chatVisible,
         | 
| 97 | 
            -
                showModal: showChatModal,
         | 
| 98 | 
            -
                hideModal: hideChatModal,
         | 
| 99 | 
            -
              } = useSetModalState();
         | 
| 100 | 
            -
              const {
         | 
| 101 | 
            -
                singleDebugDrawerVisible,
         | 
| 102 | 
            -
                showSingleDebugDrawer,
         | 
| 103 | 
            -
                hideSingleDebugDrawer,
         | 
| 104 | 
            -
              } = useShowSingleDebugDrawer();
         | 
| 105 |  | 
| 106 | 
             
              const controlIconClassname = 'text-black';
         | 
| 107 |  | 
| 108 | 
            -
              const { formDrawerVisible, hideFormDrawer, showFormDrawer, clickedNode } =
         | 
| 109 | 
            -
                useShowFormDrawer();
         | 
| 110 | 
            -
             | 
| 111 | 
            -
              const onPaneClick = useCallback(() => {
         | 
| 112 | 
            -
                hideFormDrawer();
         | 
| 113 | 
            -
              }, [hideFormDrawer]);
         | 
| 114 | 
            -
             | 
| 115 | 
             
              const { onDrop, onDragOver, setReactFlowInstance } = useHandleDrop();
         | 
| 116 |  | 
| 117 | 
            -
              useWatchNodeFormDataChange();
         | 
| 118 | 
            -
             | 
| 119 | 
            -
              const hideRunOrChatDrawer = useCallback(() => {
         | 
| 120 | 
            -
                hideChatModal();
         | 
| 121 | 
            -
                hideRunModal();
         | 
| 122 | 
            -
                hideDrawer();
         | 
| 123 | 
            -
              }, [hideChatModal, hideDrawer, hideRunModal]);
         | 
| 124 | 
            -
             | 
| 125 | 
            -
              const onNodeClick: NodeMouseHandler = useCallback(
         | 
| 126 | 
            -
                (e, node) => {
         | 
| 127 | 
            -
                  if (node.data.label !== Operator.Note) {
         | 
| 128 | 
            -
                    hideSingleDebugDrawer();
         | 
| 129 | 
            -
                    hideRunOrChatDrawer();
         | 
| 130 | 
            -
                    showFormDrawer(node);
         | 
| 131 | 
            -
                  }
         | 
| 132 | 
            -
                  // handle single debug icon click
         | 
| 133 | 
            -
                  if (
         | 
| 134 | 
            -
                    get(e.target, 'dataset.play') === 'true' ||
         | 
| 135 | 
            -
                    get(e.target, 'parentNode.dataset.play') === 'true'
         | 
| 136 | 
            -
                  ) {
         | 
| 137 | 
            -
                    showSingleDebugDrawer();
         | 
| 138 | 
            -
                  }
         | 
| 139 | 
            -
                },
         | 
| 140 | 
            -
                [
         | 
| 141 | 
            -
                  hideRunOrChatDrawer,
         | 
| 142 | 
            -
                  hideSingleDebugDrawer,
         | 
| 143 | 
            -
                  showFormDrawer,
         | 
| 144 | 
            -
                  showSingleDebugDrawer,
         | 
| 145 | 
            -
                ],
         | 
| 146 | 
            -
              );
         | 
| 147 | 
            -
             | 
| 148 | 
            -
              const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
         | 
| 149 | 
            -
             | 
| 150 | 
             
              const {
         | 
| 151 | 
             
                handleExportJson,
         | 
| 152 | 
             
                handleImportJson,
         | 
| @@ -155,25 +95,25 @@ function FlowCanvas({ drawerVisible, hideDrawer }: IProps) { | |
| 155 | 
             
                hideFileUploadModal,
         | 
| 156 | 
             
              } = useHandleExportOrImportJsonFile();
         | 
| 157 |  | 
| 158 | 
            -
               | 
| 159 | 
            -
                 | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
                 | 
| 169 | 
            -
             | 
| 170 | 
            -
                hideChatModal,
         | 
| 171 | 
            -
                hideRunModal,
         | 
| 172 | 
             
                showChatModal,
         | 
| 173 | 
            -
             | 
| 174 | 
             
                drawerVisible,
         | 
| 175 | 
            -
                 | 
| 176 | 
            -
               | 
|  | |
|  | |
| 177 |  | 
| 178 | 
             
              return (
         | 
| 179 | 
             
                <div className={styles.canvasWrapper}>
         | 
| @@ -222,6 +162,7 @@ function FlowCanvas({ drawerVisible, hideDrawer }: IProps) { | |
| 222 | 
             
                        strokeWidth: 2,
         | 
| 223 | 
             
                        stroke: 'rgb(202 197 245)',
         | 
| 224 | 
             
                      },
         | 
|  | |
| 225 | 
             
                    }}
         | 
| 226 | 
             
                    deleteKeyCode={['Delete', 'Backspace']}
         | 
| 227 | 
             
                  >
         | 
|  | |
| 4 | 
             
              TooltipProvider,
         | 
| 5 | 
             
              TooltipTrigger,
         | 
| 6 | 
             
            } from '@/components/ui/tooltip';
         | 
|  | |
|  | |
| 7 | 
             
            import { FolderInput, FolderOutput } from 'lucide-react';
         | 
|  | |
| 8 | 
             
            import ReactFlow, {
         | 
| 9 | 
             
              Background,
         | 
| 10 | 
             
              ConnectionMode,
         | 
| 11 | 
             
              ControlButton,
         | 
| 12 | 
             
              Controls,
         | 
|  | |
| 13 | 
             
            } from 'reactflow';
         | 
| 14 | 
             
            import 'reactflow/dist/style.css';
         | 
| 15 | 
             
            import ChatDrawer from '../chat/drawer';
         | 
|  | |
| 16 | 
             
            import FormDrawer from '../flow-drawer';
         | 
| 17 | 
             
            import {
         | 
|  | |
| 18 | 
             
              useHandleDrop,
         | 
|  | |
| 19 | 
             
              useSelectCanvasData,
         | 
|  | |
|  | |
| 20 | 
             
              useValidateConnection,
         | 
| 21 | 
             
              useWatchNodeFormDataChange,
         | 
| 22 | 
             
            } from '../hooks';
         | 
| 23 | 
            +
            import { useHandleExportOrImportJsonFile } from '../hooks/use-export-json';
         | 
| 24 | 
            +
            import { useShowDrawer } from '../hooks/use-show-drawer';
         | 
| 25 | 
             
            import JsonUploadModal from '../json-upload-modal';
         | 
| 26 | 
             
            import RunDrawer from '../run-drawer';
         | 
| 27 | 
             
            import { ButtonEdge } from './edge';
         | 
|  | |
| 32 | 
             
            import { EmailNode } from './node/email-node';
         | 
| 33 | 
             
            import { GenerateNode } from './node/generate-node';
         | 
| 34 | 
             
            import { InvokeNode } from './node/invoke-node';
         | 
| 35 | 
            +
            import { IterationNode, IterationStartNode } from './node/iteration-node';
         | 
| 36 | 
             
            import { KeywordNode } from './node/keyword-node';
         | 
| 37 | 
             
            import { LogicNode } from './node/logic-node';
         | 
| 38 | 
             
            import { MessageNode } from './node/message-node';
         | 
|  | |
| 59 | 
             
              invokeNode: InvokeNode,
         | 
| 60 | 
             
              templateNode: TemplateNode,
         | 
| 61 | 
             
              emailNode: EmailNode,
         | 
| 62 | 
            +
              group: IterationNode,
         | 
| 63 | 
            +
              iterationStartNode: IterationStartNode,
         | 
| 64 | 
             
            };
         | 
| 65 |  | 
| 66 | 
             
            const edgeTypes = {
         | 
|  | |
| 82 | 
             
                onSelectionChange,
         | 
| 83 | 
             
              } = useSelectCanvasData();
         | 
| 84 | 
             
              const isValidConnection = useValidateConnection();
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 85 |  | 
| 86 | 
             
              const controlIconClassname = 'text-black';
         | 
| 87 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 88 | 
             
              const { onDrop, onDragOver, setReactFlowInstance } = useHandleDrop();
         | 
| 89 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 90 | 
             
              const {
         | 
| 91 | 
             
                handleExportJson,
         | 
| 92 | 
             
                handleImportJson,
         | 
|  | |
| 95 | 
             
                hideFileUploadModal,
         | 
| 96 | 
             
              } = useHandleExportOrImportJsonFile();
         | 
| 97 |  | 
| 98 | 
            +
              const {
         | 
| 99 | 
            +
                onNodeClick,
         | 
| 100 | 
            +
                onPaneClick,
         | 
| 101 | 
            +
                clickedNode,
         | 
| 102 | 
            +
                formDrawerVisible,
         | 
| 103 | 
            +
                hideFormDrawer,
         | 
| 104 | 
            +
                singleDebugDrawerVisible,
         | 
| 105 | 
            +
                hideSingleDebugDrawer,
         | 
| 106 | 
            +
                showSingleDebugDrawer,
         | 
| 107 | 
            +
                chatVisible,
         | 
| 108 | 
            +
                runVisible,
         | 
| 109 | 
            +
                hideRunOrChatDrawer,
         | 
|  | |
|  | |
| 110 | 
             
                showChatModal,
         | 
| 111 | 
            +
              } = useShowDrawer({
         | 
| 112 | 
             
                drawerVisible,
         | 
| 113 | 
            +
                hideDrawer,
         | 
| 114 | 
            +
              });
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              useWatchNodeFormDataChange();
         | 
| 117 |  | 
| 118 | 
             
              return (
         | 
| 119 | 
             
                <div className={styles.canvasWrapper}>
         | 
|  | |
| 162 | 
             
                        strokeWidth: 2,
         | 
| 163 | 
             
                        stroke: 'rgb(202 197 245)',
         | 
| 164 | 
             
                      },
         | 
| 165 | 
            +
                      zIndex: 1001, // https://github.com/xyflow/xyflow/discussions/3498
         | 
| 166 | 
             
                    }}
         | 
| 167 | 
             
                    deleteKeyCode={['Delete', 'Backspace']}
         | 
| 168 | 
             
                  >
         | 
    	
        web/src/pages/flow/canvas/node/begin-node.tsx
    CHANGED
    
    | @@ -44,7 +44,9 @@ export function BeginNode({ selected, data }: NodeProps<NodeData>) { | |
| 44 | 
             
                      fontSize={24}
         | 
| 45 | 
             
                      color={operatorMap[data.label as Operator].color}
         | 
| 46 | 
             
                    ></OperatorIcon>
         | 
| 47 | 
            -
                    <div className= | 
|  | |
|  | |
| 48 | 
             
                  </Flex>
         | 
| 49 | 
             
                  <Flex gap={8} vertical className={styles.generateParameters}>
         | 
| 50 | 
             
                    {query.map((x, idx) => {
         | 
|  | |
| 44 | 
             
                      fontSize={24}
         | 
| 45 | 
             
                      color={operatorMap[data.label as Operator].color}
         | 
| 46 | 
             
                    ></OperatorIcon>
         | 
| 47 | 
            +
                    <div className="truncate text-center font-semibold text-sm">
         | 
| 48 | 
            +
                      {t(`flow.begin`)}
         | 
| 49 | 
            +
                    </div>
         | 
| 50 | 
             
                  </Flex>
         | 
| 51 | 
             
                  <Flex gap={8} vertical className={styles.generateParameters}>
         | 
| 52 | 
             
                    {query.map((x, idx) => {
         | 
    	
        web/src/pages/flow/canvas/node/dropdown.tsx
    CHANGED
    
    | @@ -3,6 +3,7 @@ import { CopyOutlined } from '@ant-design/icons'; | |
| 3 | 
             
            import { Flex, MenuProps } from 'antd';
         | 
| 4 | 
             
            import { useCallback } from 'react';
         | 
| 5 | 
             
            import { useTranslation } from 'react-i18next';
         | 
|  | |
| 6 | 
             
            import { useDuplicateNode } from '../../hooks';
         | 
| 7 | 
             
            import useGraphStore from '../../store';
         | 
| 8 |  | 
| @@ -15,10 +16,17 @@ interface IProps { | |
| 15 | 
             
            const NodeDropdown = ({ id, iconFontColor, label }: IProps) => {
         | 
| 16 | 
             
              const { t } = useTranslation();
         | 
| 17 | 
             
              const deleteNodeById = useGraphStore((store) => store.deleteNodeById);
         | 
|  | |
|  | |
|  | |
| 18 |  | 
| 19 | 
             
              const deleteNode = useCallback(() => {
         | 
| 20 | 
            -
                 | 
| 21 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
| 22 |  | 
| 23 | 
             
              const duplicateNode = useDuplicateNode();
         | 
| 24 |  | 
|  | |
| 3 | 
             
            import { Flex, MenuProps } from 'antd';
         | 
| 4 | 
             
            import { useCallback } from 'react';
         | 
| 5 | 
             
            import { useTranslation } from 'react-i18next';
         | 
| 6 | 
            +
            import { Operator } from '../../constant';
         | 
| 7 | 
             
            import { useDuplicateNode } from '../../hooks';
         | 
| 8 | 
             
            import useGraphStore from '../../store';
         | 
| 9 |  | 
|  | |
| 16 | 
             
            const NodeDropdown = ({ id, iconFontColor, label }: IProps) => {
         | 
| 17 | 
             
              const { t } = useTranslation();
         | 
| 18 | 
             
              const deleteNodeById = useGraphStore((store) => store.deleteNodeById);
         | 
| 19 | 
            +
              const deleteIterationNodeById = useGraphStore(
         | 
| 20 | 
            +
                (store) => store.deleteIterationNodeById,
         | 
| 21 | 
            +
              );
         | 
| 22 |  | 
| 23 | 
             
              const deleteNode = useCallback(() => {
         | 
| 24 | 
            +
                if (label === Operator.Iteration) {
         | 
| 25 | 
            +
                  deleteIterationNodeById(id);
         | 
| 26 | 
            +
                } else {
         | 
| 27 | 
            +
                  deleteNodeById(id);
         | 
| 28 | 
            +
                }
         | 
| 29 | 
            +
              }, [label, deleteIterationNodeById, id, deleteNodeById]);
         | 
| 30 |  | 
| 31 | 
             
              const duplicateNode = useDuplicateNode();
         | 
| 32 |  | 
    	
        web/src/pages/flow/canvas/node/generate-node.tsx
    CHANGED
    
    | @@ -4,7 +4,7 @@ import { Flex } from 'antd'; | |
| 4 | 
             
            import classNames from 'classnames';
         | 
| 5 | 
             
            import { get } from 'lodash';
         | 
| 6 | 
             
            import { Handle, NodeProps, Position } from 'reactflow';
         | 
| 7 | 
            -
            import { useGetComponentLabelByValue } from '../../hooks';
         | 
| 8 | 
             
            import { IGenerateParameter, NodeData } from '../../interface';
         | 
| 9 | 
             
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         | 
| 10 | 
             
            import styles from './index.less';
         | 
|  | |
| 4 | 
             
            import classNames from 'classnames';
         | 
| 5 | 
             
            import { get } from 'lodash';
         | 
| 6 | 
             
            import { Handle, NodeProps, Position } from 'reactflow';
         | 
| 7 | 
            +
            import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
         | 
| 8 | 
             
            import { IGenerateParameter, NodeData } from '../../interface';
         | 
| 9 | 
             
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         | 
| 10 | 
             
            import styles from './index.less';
         | 
    	
        web/src/pages/flow/canvas/node/index.less
    CHANGED
    
    | @@ -1,15 +1,3 @@ | |
| 1 | 
            -
            .commonNode() {
         | 
| 2 | 
            -
              box-shadow:
         | 
| 3 | 
            -
                -6px 0 12px 0 rgba(179, 177, 177, 0.08),
         | 
| 4 | 
            -
                -3px 0 6px -4px rgba(0, 0, 0, 0.12),
         | 
| 5 | 
            -
                -6px 0 16px 6px rgba(0, 0, 0, 0.05);
         | 
| 6 | 
            -
             | 
| 7 | 
            -
              padding: 10px;
         | 
| 8 | 
            -
              border-radius: 10px;
         | 
| 9 | 
            -
              background: white;
         | 
| 10 | 
            -
              width: 200px;
         | 
| 11 | 
            -
            }
         | 
| 12 | 
            -
             | 
| 13 | 
             
            .dark {
         | 
| 14 | 
             
              background: rgb(63, 63, 63) !important;
         | 
| 15 | 
             
            }
         | 
| @@ -43,6 +31,22 @@ | |
| 43 | 
             
              border: 1.5px solid rgb(59, 118, 244);
         | 
| 44 | 
             
            }
         | 
| 45 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 46 | 
             
            .handle {
         | 
| 47 | 
             
              display: inline-flex;
         | 
| 48 | 
             
              align-items: center;
         | 
| @@ -133,6 +137,12 @@ | |
| 133 | 
             
              }
         | 
| 134 | 
             
            }
         | 
| 135 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 136 | 
             
            .nodeText {
         | 
| 137 | 
             
              padding-inline: 0.4em;
         | 
| 138 | 
             
              padding-block: 0.2em 0.1em;
         | 
| @@ -142,12 +152,6 @@ | |
| 142 | 
             
              .textEllipsis();
         | 
| 143 | 
             
            }
         | 
| 144 |  | 
| 145 | 
            -
            .nodeTitle {
         | 
| 146 | 
            -
              font-weight: 600;
         | 
| 147 | 
            -
              text-align: center;
         | 
| 148 | 
            -
              .textEllipsis();
         | 
| 149 | 
            -
            }
         | 
| 150 | 
            -
             | 
| 151 | 
             
            .nodeHeader {
         | 
| 152 | 
             
              padding-bottom: 12px;
         | 
| 153 | 
             
            }
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 1 | 
             
            .dark {
         | 
| 2 | 
             
              background: rgb(63, 63, 63) !important;
         | 
| 3 | 
             
            }
         | 
|  | |
| 31 | 
             
              border: 1.5px solid rgb(59, 118, 244);
         | 
| 32 | 
             
            }
         | 
| 33 |  | 
| 34 | 
            +
            .selectedIterationNode {
         | 
| 35 | 
            +
              border-bottom: 1.5px solid rgb(59, 118, 244);
         | 
| 36 | 
            +
              border-left: 1.5px solid rgb(59, 118, 244);
         | 
| 37 | 
            +
              border-right: 1.5px solid rgb(59, 118, 244);
         | 
| 38 | 
            +
            }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            .iterationHeader {
         | 
| 41 | 
            +
              .commonNodeShadow();
         | 
| 42 | 
            +
            }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            .selectedHeader {
         | 
| 45 | 
            +
              border-top: 1.9px solid rgb(59, 118, 244);
         | 
| 46 | 
            +
              border-left: 1.9px solid rgb(59, 118, 244);
         | 
| 47 | 
            +
              border-right: 1.9px solid rgb(59, 118, 244);
         | 
| 48 | 
            +
            }
         | 
| 49 | 
            +
             | 
| 50 | 
             
            .handle {
         | 
| 51 | 
             
              display: inline-flex;
         | 
| 52 | 
             
              align-items: center;
         | 
|  | |
| 137 | 
             
              }
         | 
| 138 | 
             
            }
         | 
| 139 |  | 
| 140 | 
            +
            .iterationNode {
         | 
| 141 | 
            +
              .commonNodeShadow();
         | 
| 142 | 
            +
              border-bottom-left-radius: 10px;
         | 
| 143 | 
            +
              border-bottom-right-radius: 10px;
         | 
| 144 | 
            +
            }
         | 
| 145 | 
            +
             | 
| 146 | 
             
            .nodeText {
         | 
| 147 | 
             
              padding-inline: 0.4em;
         | 
| 148 | 
             
              padding-block: 0.2em 0.1em;
         | 
|  | |
| 152 | 
             
              .textEllipsis();
         | 
| 153 | 
             
            }
         | 
| 154 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 155 | 
             
            .nodeHeader {
         | 
| 156 | 
             
              padding-bottom: 12px;
         | 
| 157 | 
             
            }
         | 
    	
        web/src/pages/flow/canvas/node/iteration-node.tsx
    ADDED
    
    | @@ -0,0 +1,118 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import { useTheme } from '@/components/theme-provider';
         | 
| 2 | 
            +
            import { cn } from '@/lib/utils';
         | 
| 3 | 
            +
            import { ListRestart } from 'lucide-react';
         | 
| 4 | 
            +
            import { Handle, NodeProps, NodeResizeControl, Position } from 'reactflow';
         | 
| 5 | 
            +
            import { NodeData } from '../../interface';
         | 
| 6 | 
            +
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         | 
| 7 | 
            +
            import styles from './index.less';
         | 
| 8 | 
            +
            import NodeHeader from './node-header';
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            function ResizeIcon() {
         | 
| 11 | 
            +
              return (
         | 
| 12 | 
            +
                <svg
         | 
| 13 | 
            +
                  xmlns="http://www.w3.org/2000/svg"
         | 
| 14 | 
            +
                  width="20"
         | 
| 15 | 
            +
                  height="20"
         | 
| 16 | 
            +
                  viewBox="0 0 24 24"
         | 
| 17 | 
            +
                  strokeWidth="2"
         | 
| 18 | 
            +
                  stroke="#5025f9"
         | 
| 19 | 
            +
                  fill="none"
         | 
| 20 | 
            +
                  strokeLinecap="round"
         | 
| 21 | 
            +
                  strokeLinejoin="round"
         | 
| 22 | 
            +
                  style={{ position: 'absolute', right: 5, bottom: 5 }}
         | 
| 23 | 
            +
                >
         | 
| 24 | 
            +
                  <path stroke="none" d="M0 0h24v24H0z" fill="none" />
         | 
| 25 | 
            +
                  <polyline points="16 20 20 20 20 16" />
         | 
| 26 | 
            +
                  <line x1="14" y1="14" x2="20" y2="20" />
         | 
| 27 | 
            +
                  <polyline points="8 4 4 4 4 8" />
         | 
| 28 | 
            +
                  <line x1="4" y1="4" x2="10" y2="10" />
         | 
| 29 | 
            +
                </svg>
         | 
| 30 | 
            +
              );
         | 
| 31 | 
            +
            }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            const controlStyle = {
         | 
| 34 | 
            +
              background: 'transparent',
         | 
| 35 | 
            +
              border: 'none',
         | 
| 36 | 
            +
            };
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            export function IterationNode({
         | 
| 39 | 
            +
              id,
         | 
| 40 | 
            +
              data,
         | 
| 41 | 
            +
              isConnectable = true,
         | 
| 42 | 
            +
              selected,
         | 
| 43 | 
            +
            }: NodeProps<NodeData>) {
         | 
| 44 | 
            +
              const { theme } = useTheme();
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              return (
         | 
| 47 | 
            +
                <section
         | 
| 48 | 
            +
                  className={cn(
         | 
| 49 | 
            +
                    'w-full h-full bg-zinc-200 opacity-70',
         | 
| 50 | 
            +
                    styles.iterationNode,
         | 
| 51 | 
            +
                    {
         | 
| 52 | 
            +
                      ['bg-gray-800']: theme === 'dark',
         | 
| 53 | 
            +
                      [styles.selectedIterationNode]: selected,
         | 
| 54 | 
            +
                    },
         | 
| 55 | 
            +
                  )}
         | 
| 56 | 
            +
                >
         | 
| 57 | 
            +
                  <NodeResizeControl style={controlStyle} minWidth={100} minHeight={50}>
         | 
| 58 | 
            +
                    <ResizeIcon />
         | 
| 59 | 
            +
                  </NodeResizeControl>
         | 
| 60 | 
            +
                  <Handle
         | 
| 61 | 
            +
                    id="c"
         | 
| 62 | 
            +
                    type="source"
         | 
| 63 | 
            +
                    position={Position.Left}
         | 
| 64 | 
            +
                    isConnectable={isConnectable}
         | 
| 65 | 
            +
                    className={styles.handle}
         | 
| 66 | 
            +
                    style={LeftHandleStyle}
         | 
| 67 | 
            +
                  ></Handle>
         | 
| 68 | 
            +
                  <Handle
         | 
| 69 | 
            +
                    type="source"
         | 
| 70 | 
            +
                    position={Position.Right}
         | 
| 71 | 
            +
                    isConnectable={isConnectable}
         | 
| 72 | 
            +
                    className={styles.handle}
         | 
| 73 | 
            +
                    id="b"
         | 
| 74 | 
            +
                    style={RightHandleStyle}
         | 
| 75 | 
            +
                  ></Handle>
         | 
| 76 | 
            +
                  <NodeHeader
         | 
| 77 | 
            +
                    id={id}
         | 
| 78 | 
            +
                    name={data.name}
         | 
| 79 | 
            +
                    label={data.label}
         | 
| 80 | 
            +
                    wrapperClassName={cn(
         | 
| 81 | 
            +
                      'p-2 bg-white rounded-t-[10px] absolute w-full top-[-60px] left-[-0.3px]',
         | 
| 82 | 
            +
                      styles.iterationHeader,
         | 
| 83 | 
            +
                      {
         | 
| 84 | 
            +
                        [`${styles.dark} text-white`]: theme === 'dark',
         | 
| 85 | 
            +
                        [styles.selectedHeader]: selected,
         | 
| 86 | 
            +
                      },
         | 
| 87 | 
            +
                    )}
         | 
| 88 | 
            +
                  ></NodeHeader>
         | 
| 89 | 
            +
                </section>
         | 
| 90 | 
            +
              );
         | 
| 91 | 
            +
            }
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            export function IterationStartNode({
         | 
| 94 | 
            +
              isConnectable = true,
         | 
| 95 | 
            +
              selected,
         | 
| 96 | 
            +
            }: NodeProps<NodeData>) {
         | 
| 97 | 
            +
              const { theme } = useTheme();
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              return (
         | 
| 100 | 
            +
                <section
         | 
| 101 | 
            +
                  className={cn('bg-white p-2 rounded-xl', {
         | 
| 102 | 
            +
                    [styles.dark]: theme === 'dark',
         | 
| 103 | 
            +
                    [styles.selectedNode]: selected,
         | 
| 104 | 
            +
                  })}
         | 
| 105 | 
            +
                >
         | 
| 106 | 
            +
                  <Handle
         | 
| 107 | 
            +
                    type="source"
         | 
| 108 | 
            +
                    position={Position.Right}
         | 
| 109 | 
            +
                    isConnectable={isConnectable}
         | 
| 110 | 
            +
                    className={styles.handle}
         | 
| 111 | 
            +
                    style={RightHandleStyle}
         | 
| 112 | 
            +
                  ></Handle>
         | 
| 113 | 
            +
                  <div>
         | 
| 114 | 
            +
                    <ListRestart className="size-7" />
         | 
| 115 | 
            +
                  </div>
         | 
| 116 | 
            +
                </section>
         | 
| 117 | 
            +
              );
         | 
| 118 | 
            +
            }
         | 
    	
        web/src/pages/flow/canvas/node/node-header.tsx
    CHANGED
    
    | @@ -8,15 +8,17 @@ import NodeDropdown from './dropdown'; | |
| 8 | 
             
            import { NextNodePopover } from './popover';
         | 
| 9 |  | 
| 10 | 
             
            import { RunTooltip } from '../../flow-tooltip';
         | 
| 11 | 
            -
            import styles from './index.less';
         | 
| 12 | 
             
            interface IProps {
         | 
| 13 | 
             
              id: string;
         | 
| 14 | 
             
              label: string;
         | 
| 15 | 
             
              name: string;
         | 
| 16 | 
             
              gap?: number;
         | 
| 17 | 
             
              className?: string;
         | 
|  | |
| 18 | 
             
            }
         | 
| 19 |  | 
|  | |
|  | |
| 20 | 
             
            export function RunStatus({ id, name, label }: IProps) {
         | 
| 21 | 
             
              const { t } = useTranslate('flow');
         | 
| 22 | 
             
              return (
         | 
| @@ -35,10 +37,17 @@ export function RunStatus({ id, name, label }: IProps) { | |
| 35 | 
             
              );
         | 
| 36 | 
             
            }
         | 
| 37 |  | 
| 38 | 
            -
            const NodeHeader = ({ | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 39 | 
             
              return (
         | 
| 40 | 
            -
                <section>
         | 
| 41 | 
            -
                  {label  | 
| 42 | 
             
                    <RunStatus id={id} name={name} label={label}></RunStatus>
         | 
| 43 | 
             
                  )}
         | 
| 44 | 
             
                  <Flex
         | 
| @@ -52,7 +61,9 @@ const NodeHeader = ({ label, id, name, gap = 4, className }: IProps) => { | |
| 52 | 
             
                      name={label as Operator}
         | 
| 53 | 
             
                      color={operatorMap[label as Operator].color}
         | 
| 54 | 
             
                    ></OperatorIcon>
         | 
| 55 | 
            -
                    <span className= | 
|  | |
|  | |
| 56 | 
             
                    <NodeDropdown id={id} label={label}></NodeDropdown>
         | 
| 57 | 
             
                  </Flex>
         | 
| 58 | 
             
                </section>
         | 
|  | |
| 8 | 
             
            import { NextNodePopover } from './popover';
         | 
| 9 |  | 
| 10 | 
             
            import { RunTooltip } from '../../flow-tooltip';
         | 
|  | |
| 11 | 
             
            interface IProps {
         | 
| 12 | 
             
              id: string;
         | 
| 13 | 
             
              label: string;
         | 
| 14 | 
             
              name: string;
         | 
| 15 | 
             
              gap?: number;
         | 
| 16 | 
             
              className?: string;
         | 
| 17 | 
            +
              wrapperClassName?: string;
         | 
| 18 | 
             
            }
         | 
| 19 |  | 
| 20 | 
            +
            const ExcludedRunStateOperators = [Operator.Answer];
         | 
| 21 | 
            +
             | 
| 22 | 
             
            export function RunStatus({ id, name, label }: IProps) {
         | 
| 23 | 
             
              const { t } = useTranslate('flow');
         | 
| 24 | 
             
              return (
         | 
|  | |
| 37 | 
             
              );
         | 
| 38 | 
             
            }
         | 
| 39 |  | 
| 40 | 
            +
            const NodeHeader = ({
         | 
| 41 | 
            +
              label,
         | 
| 42 | 
            +
              id,
         | 
| 43 | 
            +
              name,
         | 
| 44 | 
            +
              gap = 4,
         | 
| 45 | 
            +
              className,
         | 
| 46 | 
            +
              wrapperClassName,
         | 
| 47 | 
            +
            }: IProps) => {
         | 
| 48 | 
             
              return (
         | 
| 49 | 
            +
                <section className={wrapperClassName}>
         | 
| 50 | 
            +
                  {!ExcludedRunStateOperators.includes(label as Operator) && (
         | 
| 51 | 
             
                    <RunStatus id={id} name={name} label={label}></RunStatus>
         | 
| 52 | 
             
                  )}
         | 
| 53 | 
             
                  <Flex
         | 
|  | |
| 61 | 
             
                      name={label as Operator}
         | 
| 62 | 
             
                      color={operatorMap[label as Operator].color}
         | 
| 63 | 
             
                    ></OperatorIcon>
         | 
| 64 | 
            +
                    <span className="truncate text-center font-semibold text-sm">
         | 
| 65 | 
            +
                      {name}
         | 
| 66 | 
            +
                    </span>
         | 
| 67 | 
             
                    <NodeDropdown id={id} label={label}></NodeDropdown>
         | 
| 68 | 
             
                  </Flex>
         | 
| 69 | 
             
                </section>
         | 
    	
        web/src/pages/flow/canvas/node/popover.tsx
    CHANGED
    
    | @@ -3,7 +3,7 @@ import get from 'lodash/get'; | |
| 3 | 
             
            import React, { MouseEventHandler, useCallback, useMemo } from 'react';
         | 
| 4 | 
             
            import JsonView from 'react18-json-view';
         | 
| 5 | 
             
            import 'react18-json-view/src/style.css';
         | 
| 6 | 
            -
            import {  | 
| 7 |  | 
| 8 | 
             
            import { useTheme } from '@/components/theme-provider';
         | 
| 9 | 
             
            import {
         | 
| @@ -20,6 +20,7 @@ import { | |
| 20 | 
             
              TableRow,
         | 
| 21 | 
             
            } from '@/components/ui/table';
         | 
| 22 | 
             
            import { useTranslate } from '@/hooks/common-hooks';
         | 
|  | |
| 23 |  | 
| 24 | 
             
            interface IProps extends React.PropsWithChildren {
         | 
| 25 | 
             
              nodeId: string;
         | 
|  | |
| 3 | 
             
            import React, { MouseEventHandler, useCallback, useMemo } from 'react';
         | 
| 4 | 
             
            import JsonView from 'react18-json-view';
         | 
| 5 | 
             
            import 'react18-json-view/src/style.css';
         | 
| 6 | 
            +
            import { useReplaceIdWithText } from '../../hooks';
         | 
| 7 |  | 
| 8 | 
             
            import { useTheme } from '@/components/theme-provider';
         | 
| 9 | 
             
            import {
         | 
|  | |
| 20 | 
             
              TableRow,
         | 
| 21 | 
             
            } from '@/components/ui/table';
         | 
| 22 | 
             
            import { useTranslate } from '@/hooks/common-hooks';
         | 
| 23 | 
            +
            import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
         | 
| 24 |  | 
| 25 | 
             
            interface IProps extends React.PropsWithChildren {
         | 
| 26 | 
             
              nodeId: string;
         | 
    	
        web/src/pages/flow/canvas/node/switch-node.tsx
    CHANGED
    
    | @@ -2,7 +2,7 @@ import { useTheme } from '@/components/theme-provider'; | |
| 2 | 
             
            import { Divider, Flex } from 'antd';
         | 
| 3 | 
             
            import classNames from 'classnames';
         | 
| 4 | 
             
            import { Handle, NodeProps, Position } from 'reactflow';
         | 
| 5 | 
            -
            import { useGetComponentLabelByValue } from '../../hooks';
         | 
| 6 | 
             
            import { ISwitchCondition, NodeData } from '../../interface';
         | 
| 7 | 
             
            import { RightHandleStyle } from './handle-icon';
         | 
| 8 | 
             
            import { useBuildSwitchHandlePositions } from './hooks';
         | 
|  | |
| 2 | 
             
            import { Divider, Flex } from 'antd';
         | 
| 3 | 
             
            import classNames from 'classnames';
         | 
| 4 | 
             
            import { Handle, NodeProps, Position } from 'reactflow';
         | 
| 5 | 
            +
            import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
         | 
| 6 | 
             
            import { ISwitchCondition, NodeData } from '../../interface';
         | 
| 7 | 
             
            import { RightHandleStyle } from './handle-icon';
         | 
| 8 | 
             
            import { useBuildSwitchHandlePositions } from './hooks';
         | 
    	
        web/src/pages/flow/canvas/node/template-node.tsx
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
|  | |
| 1 | 
             
            import { Flex } from 'antd';
         | 
| 2 | 
             
            import classNames from 'classnames';
         | 
| 3 | 
             
            import { get } from 'lodash';
         | 
| 4 | 
             
            import { Handle, NodeProps, Position } from 'reactflow';
         | 
| 5 | 
            -
            import { useGetComponentLabelByValue } from '../../hooks';
         | 
| 6 | 
             
            import { IGenerateParameter, NodeData } from '../../interface';
         | 
| 7 | 
             
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         | 
| 8 | 
             
            import NodeHeader from './node-header';
         | 
| 9 |  | 
| 10 | 
            -
            import { useTheme } from '@/components/theme-provider';
         | 
| 11 | 
             
            import styles from './index.less';
         | 
| 12 |  | 
| 13 | 
             
            export function TemplateNode({
         | 
|  | |
| 1 | 
            +
            import { useTheme } from '@/components/theme-provider';
         | 
| 2 | 
             
            import { Flex } from 'antd';
         | 
| 3 | 
             
            import classNames from 'classnames';
         | 
| 4 | 
             
            import { get } from 'lodash';
         | 
| 5 | 
             
            import { Handle, NodeProps, Position } from 'reactflow';
         | 
| 6 | 
            +
            import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
         | 
| 7 | 
             
            import { IGenerateParameter, NodeData } from '../../interface';
         | 
| 8 | 
             
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         | 
| 9 | 
             
            import NodeHeader from './node-header';
         | 
| 10 |  | 
|  | |
| 11 | 
             
            import styles from './index.less';
         | 
| 12 |  | 
| 13 | 
             
            export function TemplateNode({
         | 
    	
        web/src/pages/flow/constant.tsx
    CHANGED
    
    | @@ -50,7 +50,9 @@ import { | |
| 50 | 
             
            } from '@ant-design/icons';
         | 
| 51 | 
             
            import upperFirst from 'lodash/upperFirst';
         | 
| 52 | 
             
            import {
         | 
|  | |
| 53 | 
             
              CloudUpload,
         | 
|  | |
| 54 | 
             
              ListOrdered,
         | 
| 55 | 
             
              OptionIcon,
         | 
| 56 | 
             
              TextCursorInput,
         | 
| @@ -58,6 +60,8 @@ import { | |
| 58 | 
             
              WrapText,
         | 
| 59 | 
             
            } from 'lucide-react';
         | 
| 60 |  | 
|  | |
|  | |
| 61 | 
             
            export enum Operator {
         | 
| 62 | 
             
              Begin = 'Begin',
         | 
| 63 | 
             
              Retrieval = 'Retrieval',
         | 
| @@ -93,6 +97,8 @@ export enum Operator { | |
| 93 | 
             
              Invoke = 'Invoke',
         | 
| 94 | 
             
              Template = 'Template',
         | 
| 95 | 
             
              Email = 'Email',
         | 
|  | |
|  | |
| 96 | 
             
            }
         | 
| 97 |  | 
| 98 | 
             
            export const CommonOperatorList = Object.values(Operator).filter(
         | 
| @@ -134,6 +140,8 @@ export const operatorIconMap = { | |
| 134 | 
             
              [Operator.Invoke]: InvokeIcon,
         | 
| 135 | 
             
              [Operator.Template]: TemplateIcon,
         | 
| 136 | 
             
              [Operator.Email]: EmailIcon,
         | 
|  | |
|  | |
| 137 | 
             
            };
         | 
| 138 |  | 
| 139 | 
             
            export const operatorMap: Record<
         | 
| @@ -270,6 +278,8 @@ export const operatorMap: Record< | |
| 270 | 
             
                backgroundColor: '#dee0e2',
         | 
| 271 | 
             
              },
         | 
| 272 | 
             
              [Operator.Email]: { backgroundColor: '#e6f7ff' },
         | 
|  | |
|  | |
| 273 | 
             
            };
         | 
| 274 |  | 
| 275 | 
             
            export const componentMenuList = [
         | 
| @@ -306,6 +316,9 @@ export const componentMenuList = [ | |
| 306 | 
             
              {
         | 
| 307 | 
             
                name: Operator.Template,
         | 
| 308 | 
             
              },
         | 
|  | |
|  | |
|  | |
| 309 | 
             
              {
         | 
| 310 | 
             
                name: Operator.Note,
         | 
| 311 | 
             
              },
         | 
| @@ -606,6 +619,11 @@ export const initialEmailValues = { | |
| 606 | 
             
              content: '',
         | 
| 607 | 
             
            };
         | 
| 608 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 609 | 
             
            export const CategorizeAnchorPointPositions = [
         | 
| 610 | 
             
              { top: 1, right: 34 },
         | 
| 611 | 
             
              { top: 8, right: 18 },
         | 
| @@ -687,6 +705,8 @@ export const RestrictedUpstreamMap = { | |
| 687 | 
             
              [Operator.Invoke]: [Operator.Begin],
         | 
| 688 | 
             
              [Operator.Template]: [Operator.Begin, Operator.Relevant],
         | 
| 689 | 
             
              [Operator.Email]: [Operator.Begin],
         | 
|  | |
|  | |
| 690 | 
             
            };
         | 
| 691 |  | 
| 692 | 
             
            export const NodeMap = {
         | 
| @@ -724,6 +744,8 @@ export const NodeMap = { | |
| 724 | 
             
              [Operator.Invoke]: 'invokeNode',
         | 
| 725 | 
             
              [Operator.Template]: 'templateNode',
         | 
| 726 | 
             
              [Operator.Email]: 'emailNode',
         | 
|  | |
|  | |
| 727 | 
             
            };
         | 
| 728 |  | 
| 729 | 
             
            export const LanguageOptions = [
         | 
| @@ -2940,4 +2962,5 @@ export const NoDebugOperatorsList = [ | |
| 2940 | 
             
              Operator.Message,
         | 
| 2941 | 
             
              Operator.RewriteQuestion,
         | 
| 2942 | 
             
              Operator.Switch,
         | 
|  | |
| 2943 | 
             
            ];
         | 
|  | |
| 50 | 
             
            } from '@ant-design/icons';
         | 
| 51 | 
             
            import upperFirst from 'lodash/upperFirst';
         | 
| 52 | 
             
            import {
         | 
| 53 | 
            +
              CirclePower,
         | 
| 54 | 
             
              CloudUpload,
         | 
| 55 | 
            +
              IterationCcw,
         | 
| 56 | 
             
              ListOrdered,
         | 
| 57 | 
             
              OptionIcon,
         | 
| 58 | 
             
              TextCursorInput,
         | 
|  | |
| 60 | 
             
              WrapText,
         | 
| 61 | 
             
            } from 'lucide-react';
         | 
| 62 |  | 
| 63 | 
            +
            export const BeginId = 'begin';
         | 
| 64 | 
            +
             | 
| 65 | 
             
            export enum Operator {
         | 
| 66 | 
             
              Begin = 'Begin',
         | 
| 67 | 
             
              Retrieval = 'Retrieval',
         | 
|  | |
| 97 | 
             
              Invoke = 'Invoke',
         | 
| 98 | 
             
              Template = 'Template',
         | 
| 99 | 
             
              Email = 'Email',
         | 
| 100 | 
            +
              Iteration = 'Iteration',
         | 
| 101 | 
            +
              IterationStart = 'IterationItem',
         | 
| 102 | 
             
            }
         | 
| 103 |  | 
| 104 | 
             
            export const CommonOperatorList = Object.values(Operator).filter(
         | 
|  | |
| 140 | 
             
              [Operator.Invoke]: InvokeIcon,
         | 
| 141 | 
             
              [Operator.Template]: TemplateIcon,
         | 
| 142 | 
             
              [Operator.Email]: EmailIcon,
         | 
| 143 | 
            +
              [Operator.Iteration]: IterationCcw,
         | 
| 144 | 
            +
              [Operator.IterationStart]: CirclePower,
         | 
| 145 | 
             
            };
         | 
| 146 |  | 
| 147 | 
             
            export const operatorMap: Record<
         | 
|  | |
| 278 | 
             
                backgroundColor: '#dee0e2',
         | 
| 279 | 
             
              },
         | 
| 280 | 
             
              [Operator.Email]: { backgroundColor: '#e6f7ff' },
         | 
| 281 | 
            +
              [Operator.Iteration]: { backgroundColor: '#e6f7ff' },
         | 
| 282 | 
            +
              [Operator.IterationStart]: { backgroundColor: '#e6f7ff' },
         | 
| 283 | 
             
            };
         | 
| 284 |  | 
| 285 | 
             
            export const componentMenuList = [
         | 
|  | |
| 316 | 
             
              {
         | 
| 317 | 
             
                name: Operator.Template,
         | 
| 318 | 
             
              },
         | 
| 319 | 
            +
              {
         | 
| 320 | 
            +
                name: Operator.Iteration,
         | 
| 321 | 
            +
              },
         | 
| 322 | 
             
              {
         | 
| 323 | 
             
                name: Operator.Note,
         | 
| 324 | 
             
              },
         | 
|  | |
| 619 | 
             
              content: '',
         | 
| 620 | 
             
            };
         | 
| 621 |  | 
| 622 | 
            +
            export const initialIterationValues = {
         | 
| 623 | 
            +
              delimiter: ',',
         | 
| 624 | 
            +
            };
         | 
| 625 | 
            +
            export const initialIterationStartValues = {};
         | 
| 626 | 
            +
             | 
| 627 | 
             
            export const CategorizeAnchorPointPositions = [
         | 
| 628 | 
             
              { top: 1, right: 34 },
         | 
| 629 | 
             
              { top: 8, right: 18 },
         | 
|  | |
| 705 | 
             
              [Operator.Invoke]: [Operator.Begin],
         | 
| 706 | 
             
              [Operator.Template]: [Operator.Begin, Operator.Relevant],
         | 
| 707 | 
             
              [Operator.Email]: [Operator.Begin],
         | 
| 708 | 
            +
              [Operator.Iteration]: [Operator.Begin],
         | 
| 709 | 
            +
              [Operator.IterationStart]: [Operator.Begin],
         | 
| 710 | 
             
            };
         | 
| 711 |  | 
| 712 | 
             
            export const NodeMap = {
         | 
|  | |
| 744 | 
             
              [Operator.Invoke]: 'invokeNode',
         | 
| 745 | 
             
              [Operator.Template]: 'templateNode',
         | 
| 746 | 
             
              [Operator.Email]: 'emailNode',
         | 
| 747 | 
            +
              [Operator.Iteration]: 'group',
         | 
| 748 | 
            +
              [Operator.IterationStart]: 'iterationStartNode',
         | 
| 749 | 
             
            };
         | 
| 750 |  | 
| 751 | 
             
            export const LanguageOptions = [
         | 
|  | |
| 2962 | 
             
              Operator.Message,
         | 
| 2963 | 
             
              Operator.RewriteQuestion,
         | 
| 2964 | 
             
              Operator.Switch,
         | 
| 2965 | 
            +
              Operator.Iteration,
         | 
| 2966 | 
             
            ];
         | 
    	
        web/src/pages/flow/flow-drawer/index.tsx
    CHANGED
    
    | @@ -6,7 +6,7 @@ import { lowerFirst } from 'lodash'; | |
| 6 | 
             
            import { Play } from 'lucide-react';
         | 
| 7 | 
             
            import { useEffect, useRef } from 'react';
         | 
| 8 | 
             
            import { Node } from 'reactflow';
         | 
| 9 | 
            -
            import { Operator, operatorMap } from '../constant';
         | 
| 10 | 
             
            import AkShareForm from '../form/akshare-form';
         | 
| 11 | 
             
            import AnswerForm from '../form/answer-form';
         | 
| 12 | 
             
            import ArXivForm from '../form/arxiv-form';
         | 
| @@ -45,6 +45,7 @@ import { getDrawerWidth, needsSingleStepDebugging } from '../utils'; | |
| 45 | 
             
            import SingleDebugDrawer from './single-debug-drawer';
         | 
| 46 |  | 
| 47 | 
             
            import { RunTooltip } from '../flow-tooltip';
         | 
|  | |
| 48 | 
             
            import styles from './index.less';
         | 
| 49 |  | 
| 50 | 
             
            interface IProps {
         | 
| @@ -89,6 +90,8 @@ const FormMap = { | |
| 89 | 
             
              [Operator.Note]: () => <></>,
         | 
| 90 | 
             
              [Operator.Template]: TemplateForm,
         | 
| 91 | 
             
              [Operator.Email]: EmailForm,
         | 
|  | |
|  | |
| 92 | 
             
            };
         | 
| 93 |  | 
| 94 | 
             
            const EmptyContent = () => <div></div>;
         | 
| @@ -137,11 +140,15 @@ const FormDrawer = ({ | |
| 137 | 
             
                          <label htmlFor="" className={styles.title}>
         | 
| 138 | 
             
                            {t('title')}
         | 
| 139 | 
             
                          </label>
         | 
| 140 | 
            -
                           | 
| 141 | 
            -
                             | 
| 142 | 
            -
             | 
| 143 | 
            -
                             | 
| 144 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
| 145 | 
             
                        </Flex>
         | 
| 146 | 
             
                        {needsSingleStepDebugging(operatorName) && (
         | 
| 147 | 
             
                          <RunTooltip>
         | 
|  | |
| 6 | 
             
            import { Play } from 'lucide-react';
         | 
| 7 | 
             
            import { useEffect, useRef } from 'react';
         | 
| 8 | 
             
            import { Node } from 'reactflow';
         | 
| 9 | 
            +
            import { BeginId, Operator, operatorMap } from '../constant';
         | 
| 10 | 
             
            import AkShareForm from '../form/akshare-form';
         | 
| 11 | 
             
            import AnswerForm from '../form/answer-form';
         | 
| 12 | 
             
            import ArXivForm from '../form/arxiv-form';
         | 
|  | |
| 45 | 
             
            import SingleDebugDrawer from './single-debug-drawer';
         | 
| 46 |  | 
| 47 | 
             
            import { RunTooltip } from '../flow-tooltip';
         | 
| 48 | 
            +
            import IterationForm from '../form/iteration-from';
         | 
| 49 | 
             
            import styles from './index.less';
         | 
| 50 |  | 
| 51 | 
             
            interface IProps {
         | 
|  | |
| 90 | 
             
              [Operator.Note]: () => <></>,
         | 
| 91 | 
             
              [Operator.Template]: TemplateForm,
         | 
| 92 | 
             
              [Operator.Email]: EmailForm,
         | 
| 93 | 
            +
              [Operator.Iteration]: IterationForm,
         | 
| 94 | 
            +
              [Operator.IterationStart]: () => <></>,
         | 
| 95 | 
             
            };
         | 
| 96 |  | 
| 97 | 
             
            const EmptyContent = () => <div></div>;
         | 
|  | |
| 140 | 
             
                          <label htmlFor="" className={styles.title}>
         | 
| 141 | 
             
                            {t('title')}
         | 
| 142 | 
             
                          </label>
         | 
| 143 | 
            +
                          {node?.id === BeginId ? (
         | 
| 144 | 
            +
                            <span>{t(BeginId)}</span>
         | 
| 145 | 
            +
                          ) : (
         | 
| 146 | 
            +
                            <Input
         | 
| 147 | 
            +
                              value={name}
         | 
| 148 | 
            +
                              onBlur={handleNameBlur}
         | 
| 149 | 
            +
                              onChange={handleNameChange}
         | 
| 150 | 
            +
                            ></Input>
         | 
| 151 | 
            +
                          )}
         | 
| 152 | 
             
                        </Flex>
         | 
| 153 | 
             
                        {needsSingleStepDebugging(operatorName) && (
         | 
| 154 | 
             
                          <RunTooltip>
         | 
    	
        web/src/pages/flow/form/akshare-form/index.tsx
    CHANGED
    
    | @@ -12,7 +12,7 @@ const AkShareForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 12 | 
             
                  onValuesChange={onValuesChange}
         | 
| 13 | 
             
                  layout={'vertical'}
         | 
| 14 | 
             
                >
         | 
| 15 | 
            -
                  <DynamicInputVariable  | 
| 16 | 
             
                  <TopNItem initialValue={10} max={99}></TopNItem>
         | 
| 17 | 
             
                </Form>
         | 
| 18 | 
             
              );
         | 
|  | |
| 12 | 
             
                  onValuesChange={onValuesChange}
         | 
| 13 | 
             
                  layout={'vertical'}
         | 
| 14 | 
             
                >
         | 
| 15 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 16 | 
             
                  <TopNItem initialValue={10} max={99}></TopNItem>
         | 
| 17 | 
             
                </Form>
         | 
| 18 | 
             
              );
         | 
    	
        web/src/pages/flow/form/arxiv-form/index.tsx
    CHANGED
    
    | @@ -23,7 +23,7 @@ const ArXivForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 23 | 
             
                  onValuesChange={onValuesChange}
         | 
| 24 | 
             
                  layout={'vertical'}
         | 
| 25 | 
             
                >
         | 
| 26 | 
            -
                  <DynamicInputVariable  | 
| 27 |  | 
| 28 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 29 | 
             
                  <Form.Item label={t('sortBy')} name={'sort_by'}>
         | 
|  | |
| 23 | 
             
                  onValuesChange={onValuesChange}
         | 
| 24 | 
             
                  layout={'vertical'}
         | 
| 25 | 
             
                >
         | 
| 26 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 27 |  | 
| 28 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 29 | 
             
                  <Form.Item label={t('sortBy')} name={'sort_by'}>
         | 
    	
        web/src/pages/flow/form/baidu-fanyi-form/index.tsx
    CHANGED
    
    | @@ -39,7 +39,7 @@ const BaiduFanyiForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 39 | 
             
                  onValuesChange={onValuesChange}
         | 
| 40 | 
             
                  layout={'vertical'}
         | 
| 41 | 
             
                >
         | 
| 42 | 
            -
                  <DynamicInputVariable  | 
| 43 | 
             
                  <Form.Item label={t('appid')} name={'appid'}>
         | 
| 44 | 
             
                    <Input></Input>
         | 
| 45 | 
             
                  </Form.Item>
         | 
|  | |
| 39 | 
             
                  onValuesChange={onValuesChange}
         | 
| 40 | 
             
                  layout={'vertical'}
         | 
| 41 | 
             
                >
         | 
| 42 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 43 | 
             
                  <Form.Item label={t('appid')} name={'appid'}>
         | 
| 44 | 
             
                    <Input></Input>
         | 
| 45 | 
             
                  </Form.Item>
         | 
    	
        web/src/pages/flow/form/baidu-form/index.tsx
    CHANGED
    
    | @@ -12,7 +12,7 @@ const BaiduForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 12 | 
             
                  onValuesChange={onValuesChange}
         | 
| 13 | 
             
                  layout={'vertical'}
         | 
| 14 | 
             
                >
         | 
| 15 | 
            -
                  <DynamicInputVariable  | 
| 16 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 17 | 
             
                </Form>
         | 
| 18 | 
             
              );
         | 
|  | |
| 12 | 
             
                  onValuesChange={onValuesChange}
         | 
| 13 | 
             
                  layout={'vertical'}
         | 
| 14 | 
             
                >
         | 
| 15 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 16 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 17 | 
             
                </Form>
         | 
| 18 | 
             
              );
         | 
    	
        web/src/pages/flow/form/bing-form/index.tsx
    CHANGED
    
    | @@ -21,7 +21,7 @@ const BingForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 21 | 
             
                  onValuesChange={onValuesChange}
         | 
| 22 | 
             
                  layout={'vertical'}
         | 
| 23 | 
             
                >
         | 
| 24 | 
            -
                  <DynamicInputVariable  | 
| 25 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 26 | 
             
                  <Form.Item label={t('channel')} name={'channel'}>
         | 
| 27 | 
             
                    <Select options={options}></Select>
         | 
|  | |
| 21 | 
             
                  onValuesChange={onValuesChange}
         | 
| 22 | 
             
                  layout={'vertical'}
         | 
| 23 | 
             
                >
         | 
| 24 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 25 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 26 | 
             
                  <Form.Item label={t('channel')} name={'channel'}>
         | 
| 27 | 
             
                    <Select options={options}></Select>
         | 
    	
        web/src/pages/flow/form/categorize-form/index.tsx
    CHANGED
    
    | @@ -24,7 +24,7 @@ const CategorizeForm = ({ form, onValuesChange, node }: IOperatorForm) => { | |
| 24 | 
             
                  initialValues={{ items: [{}] }}
         | 
| 25 | 
             
                  layout={'vertical'}
         | 
| 26 | 
             
                >
         | 
| 27 | 
            -
                  <DynamicInputVariable  | 
| 28 | 
             
                  <Form.Item
         | 
| 29 | 
             
                    name={'llm_id'}
         | 
| 30 | 
             
                    label={t('model', { keyPrefix: 'chat' })}
         | 
|  | |
| 24 | 
             
                  initialValues={{ items: [{}] }}
         | 
| 25 | 
             
                  layout={'vertical'}
         | 
| 26 | 
             
                >
         | 
| 27 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 28 | 
             
                  <Form.Item
         | 
| 29 | 
             
                    name={'llm_id'}
         | 
| 30 | 
             
                    label={t('model', { keyPrefix: 'chat' })}
         | 
    	
        web/src/pages/flow/form/components/dynamic-input-variable.tsx
    CHANGED
    
    | @@ -1,13 +1,15 @@ | |
| 1 | 
             
            import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
         | 
| 2 | 
             
            import { Button, Collapse, Flex, Form, Input, Select } from 'antd';
         | 
| 3 | 
            -
             | 
| 4 | 
             
            import { PropsWithChildren, useCallback } from 'react';
         | 
| 5 | 
             
            import { useTranslation } from 'react-i18next';
         | 
| 6 | 
            -
            import {  | 
|  | |
|  | |
|  | |
| 7 | 
             
            import styles from './index.less';
         | 
| 8 |  | 
| 9 | 
             
            interface IProps {
         | 
| 10 | 
            -
               | 
| 11 | 
             
            }
         | 
| 12 |  | 
| 13 | 
             
            enum VariableType {
         | 
| @@ -18,9 +20,12 @@ enum VariableType { | |
| 18 | 
             
            const getVariableName = (type: string) =>
         | 
| 19 | 
             
              type === VariableType.Reference ? 'component_id' : 'value';
         | 
| 20 |  | 
| 21 | 
            -
            const DynamicVariableForm = ({  | 
| 22 | 
             
              const { t } = useTranslation();
         | 
| 23 | 
            -
              const valueOptions = useBuildComponentIdSelectOptions( | 
|  | |
|  | |
|  | |
| 24 | 
             
              const form = Form.useFormInstance();
         | 
| 25 |  | 
| 26 | 
             
              const options = [
         | 
| @@ -114,11 +119,11 @@ export function FormCollapse({ | |
| 114 | 
             
              );
         | 
| 115 | 
             
            }
         | 
| 116 |  | 
| 117 | 
            -
            const DynamicInputVariable = ({  | 
| 118 | 
             
              const { t } = useTranslation();
         | 
| 119 | 
             
              return (
         | 
| 120 | 
             
                <FormCollapse title={t('flow.input')}>
         | 
| 121 | 
            -
                  <DynamicVariableForm  | 
| 122 | 
             
                </FormCollapse>
         | 
| 123 | 
             
              );
         | 
| 124 | 
             
            };
         | 
|  | |
| 1 | 
             
            import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
         | 
| 2 | 
             
            import { Button, Collapse, Flex, Form, Input, Select } from 'antd';
         | 
|  | |
| 3 | 
             
            import { PropsWithChildren, useCallback } from 'react';
         | 
| 4 | 
             
            import { useTranslation } from 'react-i18next';
         | 
| 5 | 
            +
            import { Node } from 'reactflow';
         | 
| 6 | 
            +
            import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
         | 
| 7 | 
            +
            import { NodeData } from '../../interface';
         | 
| 8 | 
            +
             | 
| 9 | 
             
            import styles from './index.less';
         | 
| 10 |  | 
| 11 | 
             
            interface IProps {
         | 
| 12 | 
            +
              node?: Node<NodeData>;
         | 
| 13 | 
             
            }
         | 
| 14 |  | 
| 15 | 
             
            enum VariableType {
         | 
|  | |
| 20 | 
             
            const getVariableName = (type: string) =>
         | 
| 21 | 
             
              type === VariableType.Reference ? 'component_id' : 'value';
         | 
| 22 |  | 
| 23 | 
            +
            const DynamicVariableForm = ({ node }: IProps) => {
         | 
| 24 | 
             
              const { t } = useTranslation();
         | 
| 25 | 
            +
              const valueOptions = useBuildComponentIdSelectOptions(
         | 
| 26 | 
            +
                node?.id,
         | 
| 27 | 
            +
                node?.parentId,
         | 
| 28 | 
            +
              );
         | 
| 29 | 
             
              const form = Form.useFormInstance();
         | 
| 30 |  | 
| 31 | 
             
              const options = [
         | 
|  | |
| 119 | 
             
              );
         | 
| 120 | 
             
            }
         | 
| 121 |  | 
| 122 | 
            +
            const DynamicInputVariable = ({ node }: IProps) => {
         | 
| 123 | 
             
              const { t } = useTranslation();
         | 
| 124 | 
             
              return (
         | 
| 125 | 
             
                <FormCollapse title={t('flow.input')}>
         | 
| 126 | 
            +
                  <DynamicVariableForm node={node}></DynamicVariableForm>
         | 
| 127 | 
             
                </FormCollapse>
         | 
| 128 | 
             
              );
         | 
| 129 | 
             
            };
         | 
    	
        web/src/pages/flow/form/crawler-form/index.tsx
    CHANGED
    
    | @@ -20,7 +20,7 @@ const CrawlerForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 20 | 
             
                  onValuesChange={onValuesChange}
         | 
| 21 | 
             
                  layout={'vertical'}
         | 
| 22 | 
             
                >
         | 
| 23 | 
            -
                  <DynamicInputVariable  | 
| 24 | 
             
                  <Form.Item label={t('proxy')} name={'proxy'}>
         | 
| 25 | 
             
                    <Input placeholder="like: http://127.0.0.1:8888"></Input>
         | 
| 26 | 
             
                  </Form.Item>
         | 
|  | |
| 20 | 
             
                  onValuesChange={onValuesChange}
         | 
| 21 | 
             
                  layout={'vertical'}
         | 
| 22 | 
             
                >
         | 
| 23 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 24 | 
             
                  <Form.Item label={t('proxy')} name={'proxy'}>
         | 
| 25 | 
             
                    <Input placeholder="like: http://127.0.0.1:8888"></Input>
         | 
| 26 | 
             
                  </Form.Item>
         | 
    	
        web/src/pages/flow/form/deepl-form/index.tsx
    CHANGED
    
    | @@ -18,7 +18,7 @@ const DeepLForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 18 | 
             
                  onValuesChange={onValuesChange}
         | 
| 19 | 
             
                  layout={'vertical'}
         | 
| 20 | 
             
                >
         | 
| 21 | 
            -
                  <DynamicInputVariable  | 
| 22 | 
             
                  <TopNItem initialValue={5}></TopNItem>
         | 
| 23 | 
             
                  <Form.Item label={t('authKey')} name={'auth_key'}>
         | 
| 24 | 
             
                    <Select options={options}></Select>
         | 
|  | |
| 18 | 
             
                  onValuesChange={onValuesChange}
         | 
| 19 | 
             
                  layout={'vertical'}
         | 
| 20 | 
             
                >
         | 
| 21 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 22 | 
             
                  <TopNItem initialValue={5}></TopNItem>
         | 
| 23 | 
             
                  <Form.Item label={t('authKey')} name={'auth_key'}>
         | 
| 24 | 
             
                    <Select options={options}></Select>
         | 
    	
        web/src/pages/flow/form/duckduckgo-form/index.tsx
    CHANGED
    
    | @@ -21,7 +21,7 @@ const DuckDuckGoForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 21 | 
             
                  onValuesChange={onValuesChange}
         | 
| 22 | 
             
                  layout={'vertical'}
         | 
| 23 | 
             
                >
         | 
| 24 | 
            -
                  <DynamicInputVariable  | 
| 25 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 26 | 
             
                  <Form.Item
         | 
| 27 | 
             
                    label={t('channel')}
         | 
|  | |
| 21 | 
             
                  onValuesChange={onValuesChange}
         | 
| 22 | 
             
                  layout={'vertical'}
         | 
| 23 | 
             
                >
         | 
| 24 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 25 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 26 | 
             
                  <Form.Item
         | 
| 27 | 
             
                    label={t('channel')}
         | 
    	
        web/src/pages/flow/form/email-form/index.tsx
    CHANGED
    
    | @@ -14,7 +14,7 @@ const EmailForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 14 | 
             
                  onValuesChange={onValuesChange}
         | 
| 15 | 
             
                  layout={'vertical'}
         | 
| 16 | 
             
                >
         | 
| 17 | 
            -
                  <DynamicInputVariable  | 
| 18 |  | 
| 19 | 
             
                  {/* SMTP服务器配置 */}
         | 
| 20 | 
             
                  <Form.Item label={t('smtpServer')} name={'smtp_server'}>
         | 
|  | |
| 14 | 
             
                  onValuesChange={onValuesChange}
         | 
| 15 | 
             
                  layout={'vertical'}
         | 
| 16 | 
             
                >
         | 
| 17 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 18 |  | 
| 19 | 
             
                  {/* SMTP服务器配置 */}
         | 
| 20 | 
             
                  <Form.Item label={t('smtpServer')} name={'smtp_server'}>
         | 
    	
        web/src/pages/flow/form/exesql-form/index.tsx
    CHANGED
    
    | @@ -24,7 +24,7 @@ const ExeSQLForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 24 | 
             
                  onValuesChange={onValuesChange}
         | 
| 25 | 
             
                  layout={'vertical'}
         | 
| 26 | 
             
                >
         | 
| 27 | 
            -
                  <DynamicInputVariable  | 
| 28 | 
             
                  <Form.Item
         | 
| 29 | 
             
                    label={t('dbType')}
         | 
| 30 | 
             
                    name={'db_type'}
         | 
|  | |
| 24 | 
             
                  onValuesChange={onValuesChange}
         | 
| 25 | 
             
                  layout={'vertical'}
         | 
| 26 | 
             
                >
         | 
| 27 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 28 | 
             
                  <Form.Item
         | 
| 29 | 
             
                    label={t('dbType')}
         | 
| 30 | 
             
                    name={'db_type'}
         | 
    	
        web/src/pages/flow/form/generate-form/dynamic-parameters.tsx
    CHANGED
    
    | @@ -2,14 +2,14 @@ import { EditableCell, EditableRow } from '@/components/editable-cell'; | |
| 2 | 
             
            import { useTranslate } from '@/hooks/common-hooks';
         | 
| 3 | 
             
            import { DeleteOutlined } from '@ant-design/icons';
         | 
| 4 | 
             
            import { Button, Flex, Select, Table, TableProps } from 'antd';
         | 
| 5 | 
            -
            import {  | 
| 6 | 
            -
             | 
| 7 | 
            -
            import {  | 
| 8 | 
             
            import { useHandleOperateParameters } from './hooks';
         | 
| 9 | 
            -
            import styles from './index.less';
         | 
| 10 |  | 
|  | |
| 11 | 
             
            interface IProps {
         | 
| 12 | 
            -
               | 
| 13 | 
             
            }
         | 
| 14 |  | 
| 15 | 
             
            const components = {
         | 
| @@ -19,10 +19,11 @@ const components = { | |
| 19 | 
             
              },
         | 
| 20 | 
             
            };
         | 
| 21 |  | 
| 22 | 
            -
            const DynamicParameters = ({  | 
|  | |
| 23 | 
             
              const { t } = useTranslate('flow');
         | 
| 24 |  | 
| 25 | 
            -
              const options = useBuildComponentIdSelectOptions(nodeId);
         | 
| 26 | 
             
              const {
         | 
| 27 | 
             
                dataSource,
         | 
| 28 | 
             
                handleAdd,
         | 
|  | |
| 2 | 
             
            import { useTranslate } from '@/hooks/common-hooks';
         | 
| 3 | 
             
            import { DeleteOutlined } from '@ant-design/icons';
         | 
| 4 | 
             
            import { Button, Flex, Select, Table, TableProps } from 'antd';
         | 
| 5 | 
            +
            import { Node } from 'reactflow';
         | 
| 6 | 
            +
            import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
         | 
| 7 | 
            +
            import { IGenerateParameter, NodeData } from '../../interface';
         | 
| 8 | 
             
            import { useHandleOperateParameters } from './hooks';
         | 
|  | |
| 9 |  | 
| 10 | 
            +
            import styles from './index.less';
         | 
| 11 | 
             
            interface IProps {
         | 
| 12 | 
            +
              node?: Node<NodeData>;
         | 
| 13 | 
             
            }
         | 
| 14 |  | 
| 15 | 
             
            const components = {
         | 
|  | |
| 19 | 
             
              },
         | 
| 20 | 
             
            };
         | 
| 21 |  | 
| 22 | 
            +
            const DynamicParameters = ({ node }: IProps) => {
         | 
| 23 | 
            +
              const nodeId = node?.id;
         | 
| 24 | 
             
              const { t } = useTranslate('flow');
         | 
| 25 |  | 
| 26 | 
            +
              const options = useBuildComponentIdSelectOptions(nodeId, node?.parentId);
         | 
| 27 | 
             
              const {
         | 
| 28 | 
             
                dataSource,
         | 
| 29 | 
             
                handleAdd,
         | 
    	
        web/src/pages/flow/form/generate-form/index.tsx
    CHANGED
    
    | @@ -49,7 +49,7 @@ const GenerateForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 49 | 
             
                  <MessageHistoryWindowSizeItem
         | 
| 50 | 
             
                    initialValue={12}
         | 
| 51 | 
             
                  ></MessageHistoryWindowSizeItem>
         | 
| 52 | 
            -
                  <DynamicParameters  | 
| 53 | 
             
                </Form>
         | 
| 54 | 
             
              );
         | 
| 55 | 
             
            };
         | 
|  | |
| 49 | 
             
                  <MessageHistoryWindowSizeItem
         | 
| 50 | 
             
                    initialValue={12}
         | 
| 51 | 
             
                  ></MessageHistoryWindowSizeItem>
         | 
| 52 | 
            +
                  <DynamicParameters node={node}></DynamicParameters>
         | 
| 53 | 
             
                </Form>
         | 
| 54 | 
             
              );
         | 
| 55 | 
             
            };
         | 
    	
        web/src/pages/flow/form/github-form/index.tsx
    CHANGED
    
    | @@ -12,7 +12,7 @@ const GithubForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 12 | 
             
                  onValuesChange={onValuesChange}
         | 
| 13 | 
             
                  layout={'vertical'}
         | 
| 14 | 
             
                >
         | 
| 15 | 
            -
                  <DynamicInputVariable  | 
| 16 | 
             
                  <TopNItem initialValue={5}></TopNItem>
         | 
| 17 | 
             
                </Form>
         | 
| 18 | 
             
              );
         | 
|  | |
| 12 | 
             
                  onValuesChange={onValuesChange}
         | 
| 13 | 
             
                  layout={'vertical'}
         | 
| 14 | 
             
                >
         | 
| 15 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 16 | 
             
                  <TopNItem initialValue={5}></TopNItem>
         | 
| 17 | 
             
                </Form>
         | 
| 18 | 
             
              );
         | 
    	
        web/src/pages/flow/form/google-form/index.tsx
    CHANGED
    
    | @@ -16,7 +16,7 @@ const GoogleForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 16 | 
             
                  onValuesChange={onValuesChange}
         | 
| 17 | 
             
                  layout={'vertical'}
         | 
| 18 | 
             
                >
         | 
| 19 | 
            -
                  <DynamicInputVariable  | 
| 20 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 21 | 
             
                  <Form.Item label={t('apiKey')} name={'api_key'}>
         | 
| 22 | 
             
                    <Input></Input>
         | 
|  | |
| 16 | 
             
                  onValuesChange={onValuesChange}
         | 
| 17 | 
             
                  layout={'vertical'}
         | 
| 18 | 
             
                >
         | 
| 19 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 20 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 21 | 
             
                  <Form.Item label={t('apiKey')} name={'api_key'}>
         | 
| 22 | 
             
                    <Input></Input>
         | 
    	
        web/src/pages/flow/form/google-scholar-form/index.tsx
    CHANGED
    
    | @@ -45,7 +45,7 @@ const GoogleScholarForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 45 | 
             
                  onValuesChange={onValuesChange}
         | 
| 46 | 
             
                  layout={'vertical'}
         | 
| 47 | 
             
                >
         | 
| 48 | 
            -
                  <DynamicInputVariable  | 
| 49 | 
             
                  <TopNItem initialValue={5}></TopNItem>
         | 
| 50 | 
             
                  <Form.Item
         | 
| 51 | 
             
                    label={t('sortBy')}
         | 
|  | |
| 45 | 
             
                  onValuesChange={onValuesChange}
         | 
| 46 | 
             
                  layout={'vertical'}
         | 
| 47 | 
             
                >
         | 
| 48 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 49 | 
             
                  <TopNItem initialValue={5}></TopNItem>
         | 
| 50 | 
             
                  <Form.Item
         | 
| 51 | 
             
                    label={t('sortBy')}
         | 
    	
        web/src/pages/flow/form/invoke-form/dynamic-variables.tsx
    CHANGED
    
    | @@ -2,15 +2,16 @@ import { EditableCell, EditableRow } from '@/components/editable-cell'; | |
| 2 | 
             
            import { useTranslate } from '@/hooks/common-hooks';
         | 
| 3 | 
             
            import { DeleteOutlined } from '@ant-design/icons';
         | 
| 4 | 
             
            import { Button, Collapse, Flex, Input, Select, Table, TableProps } from 'antd';
         | 
| 5 | 
            -
            import {  | 
| 6 | 
            -
            import {  | 
|  | |
| 7 | 
             
            import { useHandleOperateParameters } from './hooks';
         | 
| 8 |  | 
| 9 | 
            -
            import {  | 
| 10 | 
             
            import styles from './index.less';
         | 
| 11 |  | 
| 12 | 
             
            interface IProps {
         | 
| 13 | 
            -
               | 
| 14 | 
             
            }
         | 
| 15 |  | 
| 16 | 
             
            const components = {
         | 
| @@ -20,10 +21,11 @@ const components = { | |
| 20 | 
             
              },
         | 
| 21 | 
             
            };
         | 
| 22 |  | 
| 23 | 
            -
            const DynamicVariablesForm = ({  | 
|  | |
| 24 | 
             
              const { t } = useTranslate('flow');
         | 
| 25 |  | 
| 26 | 
            -
              const options = useBuildComponentIdSelectOptions(nodeId);
         | 
| 27 | 
             
              const {
         | 
| 28 | 
             
                dataSource,
         | 
| 29 | 
             
                handleAdd,
         | 
|  | |
| 2 | 
             
            import { useTranslate } from '@/hooks/common-hooks';
         | 
| 3 | 
             
            import { DeleteOutlined } from '@ant-design/icons';
         | 
| 4 | 
             
            import { Button, Collapse, Flex, Input, Select, Table, TableProps } from 'antd';
         | 
| 5 | 
            +
            import { trim } from 'lodash';
         | 
| 6 | 
            +
            import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
         | 
| 7 | 
            +
            import { IInvokeVariable, NodeData } from '../../interface';
         | 
| 8 | 
             
            import { useHandleOperateParameters } from './hooks';
         | 
| 9 |  | 
| 10 | 
            +
            import { Node } from 'reactflow';
         | 
| 11 | 
             
            import styles from './index.less';
         | 
| 12 |  | 
| 13 | 
             
            interface IProps {
         | 
| 14 | 
            +
              node?: Node<NodeData>;
         | 
| 15 | 
             
            }
         | 
| 16 |  | 
| 17 | 
             
            const components = {
         | 
|  | |
| 21 | 
             
              },
         | 
| 22 | 
             
            };
         | 
| 23 |  | 
| 24 | 
            +
            const DynamicVariablesForm = ({ node }: IProps) => {
         | 
| 25 | 
            +
              const nodeId = node?.id;
         | 
| 26 | 
             
              const { t } = useTranslate('flow');
         | 
| 27 |  | 
| 28 | 
            +
              const options = useBuildComponentIdSelectOptions(nodeId, node?.parentId);
         | 
| 29 | 
             
              const {
         | 
| 30 | 
             
                dataSource,
         | 
| 31 | 
             
                handleAdd,
         | 
    	
        web/src/pages/flow/form/invoke-form/index.tsx
    CHANGED
    
    | @@ -69,7 +69,7 @@ const InvokeForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 69 | 
             
                    >
         | 
| 70 | 
             
                      <Switch />
         | 
| 71 | 
             
                    </Form.Item>
         | 
| 72 | 
            -
                    <DynamicVariablesForm  | 
| 73 | 
             
                  </Form>
         | 
| 74 | 
             
                </>
         | 
| 75 | 
             
              );
         | 
|  | |
| 69 | 
             
                    >
         | 
| 70 | 
             
                      <Switch />
         | 
| 71 | 
             
                    </Form.Item>
         | 
| 72 | 
            +
                    <DynamicVariablesForm node={node}></DynamicVariablesForm>
         | 
| 73 | 
             
                  </Form>
         | 
| 74 | 
             
                </>
         | 
| 75 | 
             
              );
         | 
    	
        web/src/pages/flow/form/iteration-from/index.tsx
    ADDED
    
    | @@ -0,0 +1,94 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            import { CommaIcon, SemicolonIcon } from '@/assets/icon/Icon';
         | 
| 2 | 
            +
            import { Form, Select } from 'antd';
         | 
| 3 | 
            +
            import {
         | 
| 4 | 
            +
              CornerDownLeft,
         | 
| 5 | 
            +
              IndentIncrease,
         | 
| 6 | 
            +
              Minus,
         | 
| 7 | 
            +
              Slash,
         | 
| 8 | 
            +
              Underline,
         | 
| 9 | 
            +
            } from 'lucide-react';
         | 
| 10 | 
            +
            import { useMemo } from 'react';
         | 
| 11 | 
            +
            import { useTranslation } from 'react-i18next';
         | 
| 12 | 
            +
            import { IOperatorForm } from '../../interface';
         | 
| 13 | 
            +
            import DynamicInputVariable from '../components/dynamic-input-variable';
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            const optionList = [
         | 
| 16 | 
            +
              {
         | 
| 17 | 
            +
                value: ',',
         | 
| 18 | 
            +
                icon: CommaIcon,
         | 
| 19 | 
            +
                text: 'comma',
         | 
| 20 | 
            +
              },
         | 
| 21 | 
            +
              {
         | 
| 22 | 
            +
                value: '\n',
         | 
| 23 | 
            +
                icon: CornerDownLeft,
         | 
| 24 | 
            +
                text: 'lineBreak',
         | 
| 25 | 
            +
              },
         | 
| 26 | 
            +
              {
         | 
| 27 | 
            +
                value: 'tab',
         | 
| 28 | 
            +
                icon: IndentIncrease,
         | 
| 29 | 
            +
                text: 'tab',
         | 
| 30 | 
            +
              },
         | 
| 31 | 
            +
              {
         | 
| 32 | 
            +
                value: '_',
         | 
| 33 | 
            +
                icon: Underline,
         | 
| 34 | 
            +
                text: 'underline',
         | 
| 35 | 
            +
              },
         | 
| 36 | 
            +
              {
         | 
| 37 | 
            +
                value: '/',
         | 
| 38 | 
            +
                icon: Slash,
         | 
| 39 | 
            +
                text: 'diagonal',
         | 
| 40 | 
            +
              },
         | 
| 41 | 
            +
              {
         | 
| 42 | 
            +
                value: '-',
         | 
| 43 | 
            +
                icon: Minus,
         | 
| 44 | 
            +
                text: 'minus',
         | 
| 45 | 
            +
              },
         | 
| 46 | 
            +
              {
         | 
| 47 | 
            +
                value: ';',
         | 
| 48 | 
            +
                icon: SemicolonIcon,
         | 
| 49 | 
            +
                text: 'semicolon',
         | 
| 50 | 
            +
              },
         | 
| 51 | 
            +
            ];
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            const IterationForm = ({ onValuesChange, form, node }: IOperatorForm) => {
         | 
| 54 | 
            +
              const { t } = useTranslation();
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              const options = useMemo(() => {
         | 
| 57 | 
            +
                return optionList.map((x) => {
         | 
| 58 | 
            +
                  let Icon = x.icon;
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  return {
         | 
| 61 | 
            +
                    value: x.value,
         | 
| 62 | 
            +
                    label: (
         | 
| 63 | 
            +
                      <div className="flex items-center gap-2">
         | 
| 64 | 
            +
                        <Icon className={'size-4'}></Icon>
         | 
| 65 | 
            +
                        {t(`flow.delimiterOptions.${x.text}`)}
         | 
| 66 | 
            +
                      </div>
         | 
| 67 | 
            +
                    ),
         | 
| 68 | 
            +
                  };
         | 
| 69 | 
            +
                });
         | 
| 70 | 
            +
              }, [t]);
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              return (
         | 
| 73 | 
            +
                <Form
         | 
| 74 | 
            +
                  name="basic"
         | 
| 75 | 
            +
                  autoComplete="off"
         | 
| 76 | 
            +
                  form={form}
         | 
| 77 | 
            +
                  onValuesChange={onValuesChange}
         | 
| 78 | 
            +
                  layout={'vertical'}
         | 
| 79 | 
            +
                >
         | 
| 80 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 81 | 
            +
                  <Form.Item
         | 
| 82 | 
            +
                    name={['delimiter']}
         | 
| 83 | 
            +
                    label={t('knowledgeDetails.delimiter')}
         | 
| 84 | 
            +
                    initialValue={`\\n!?;。;!?`}
         | 
| 85 | 
            +
                    rules={[{ required: true }]}
         | 
| 86 | 
            +
                    tooltip={t('flow.delimiterTip')}
         | 
| 87 | 
            +
                  >
         | 
| 88 | 
            +
                    <Select options={options}></Select>
         | 
| 89 | 
            +
                  </Form.Item>
         | 
| 90 | 
            +
                </Form>
         | 
| 91 | 
            +
              );
         | 
| 92 | 
            +
            };
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            export default IterationForm;
         | 
    	
        web/src/pages/flow/form/jin10-form/index.tsx
    CHANGED
    
    | @@ -65,7 +65,7 @@ const Jin10Form = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 65 | 
             
                  onValuesChange={onValuesChange}
         | 
| 66 | 
             
                  layout={'vertical'}
         | 
| 67 | 
             
                >
         | 
| 68 | 
            -
                  <DynamicInputVariable  | 
| 69 | 
             
                  <Form.Item label={t('type')} name={'type'} initialValue={'flash'}>
         | 
| 70 | 
             
                    <Select options={jin10TypeOptions}></Select>
         | 
| 71 | 
             
                  </Form.Item>
         | 
|  | |
| 65 | 
             
                  onValuesChange={onValuesChange}
         | 
| 66 | 
             
                  layout={'vertical'}
         | 
| 67 | 
             
                >
         | 
| 68 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 69 | 
             
                  <Form.Item label={t('type')} name={'type'} initialValue={'flash'}>
         | 
| 70 | 
             
                    <Select options={jin10TypeOptions}></Select>
         | 
| 71 | 
             
                  </Form.Item>
         | 
    	
        web/src/pages/flow/form/keyword-extract-form/index.tsx
    CHANGED
    
    | @@ -16,7 +16,7 @@ const KeywordExtractForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 16 | 
             
                  onValuesChange={onValuesChange}
         | 
| 17 | 
             
                  layout={'vertical'}
         | 
| 18 | 
             
                >
         | 
| 19 | 
            -
                  <DynamicInputVariable  | 
| 20 | 
             
                  <Form.Item
         | 
| 21 | 
             
                    name={'llm_id'}
         | 
| 22 | 
             
                    label={t('model', { keyPrefix: 'chat' })}
         | 
|  | |
| 16 | 
             
                  onValuesChange={onValuesChange}
         | 
| 17 | 
             
                  layout={'vertical'}
         | 
| 18 | 
             
                >
         | 
| 19 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 20 | 
             
                  <Form.Item
         | 
| 21 | 
             
                    name={'llm_id'}
         | 
| 22 | 
             
                    label={t('model', { keyPrefix: 'chat' })}
         | 
    	
        web/src/pages/flow/form/pubmed-form/index.tsx
    CHANGED
    
    | @@ -15,7 +15,7 @@ const PubMedForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 15 | 
             
                  onValuesChange={onValuesChange}
         | 
| 16 | 
             
                  layout={'vertical'}
         | 
| 17 | 
             
                >
         | 
| 18 | 
            -
                  <DynamicInputVariable  | 
| 19 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 20 | 
             
                  <Form.Item
         | 
| 21 | 
             
                    label={t('email')}
         | 
|  | |
| 15 | 
             
                  onValuesChange={onValuesChange}
         | 
| 16 | 
             
                  layout={'vertical'}
         | 
| 17 | 
             
                >
         | 
| 18 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 19 | 
             
                  <TopNItem initialValue={10}></TopNItem>
         | 
| 20 | 
             
                  <Form.Item
         | 
| 21 | 
             
                    label={t('email')}
         | 
    	
        web/src/pages/flow/form/qweather-form/index.tsx
    CHANGED
    
    | @@ -55,7 +55,7 @@ const QWeatherForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 55 | 
             
                  onValuesChange={onValuesChange}
         | 
| 56 | 
             
                  layout={'vertical'}
         | 
| 57 | 
             
                >
         | 
| 58 | 
            -
                  <DynamicInputVariable  | 
| 59 | 
             
                  <Form.Item label={t('webApiKey')} name={'web_apikey'}>
         | 
| 60 | 
             
                    <Input></Input>
         | 
| 61 | 
             
                  </Form.Item>
         | 
|  | |
| 55 | 
             
                  onValuesChange={onValuesChange}
         | 
| 56 | 
             
                  layout={'vertical'}
         | 
| 57 | 
             
                >
         | 
| 58 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 59 | 
             
                  <Form.Item label={t('webApiKey')} name={'web_apikey'}>
         | 
| 60 | 
             
                    <Input></Input>
         | 
| 61 | 
             
                  </Form.Item>
         | 
    	
        web/src/pages/flow/form/retrieval-form/index.tsx
    CHANGED
    
    | @@ -32,7 +32,7 @@ const RetrievalForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 32 | 
             
                  form={form}
         | 
| 33 | 
             
                  layout={'vertical'}
         | 
| 34 | 
             
                >
         | 
| 35 | 
            -
                  <DynamicInputVariable  | 
| 36 | 
             
                  <SimilaritySlider
         | 
| 37 | 
             
                    isTooltipShown
         | 
| 38 | 
             
                    vectorSimilarityWeightName="keywords_similarity_weight"
         | 
|  | |
| 32 | 
             
                  form={form}
         | 
| 33 | 
             
                  layout={'vertical'}
         | 
| 34 | 
             
                >
         | 
| 35 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 36 | 
             
                  <SimilaritySlider
         | 
| 37 | 
             
                    isTooltipShown
         | 
| 38 | 
             
                    vectorSimilarityWeightName="keywords_similarity_weight"
         | 
    	
        web/src/pages/flow/form/switch-form/index.tsx
    CHANGED
    
    | @@ -9,7 +9,7 @@ import { | |
| 9 | 
             
              SwitchOperatorOptions,
         | 
| 10 | 
             
            } from '../../constant';
         | 
| 11 | 
             
            import { useBuildFormSelectOptions } from '../../form-hooks';
         | 
| 12 | 
            -
            import { useBuildComponentIdSelectOptions } from '../../hooks';
         | 
| 13 | 
             
            import { IOperatorForm, ISwitchForm } from '../../interface';
         | 
| 14 | 
             
            import { getOtherFieldValues } from '../../utils';
         | 
| 15 |  | 
| @@ -43,7 +43,10 @@ const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => { | |
| 43 | 
             
                }));
         | 
| 44 | 
             
              }, [t]);
         | 
| 45 |  | 
| 46 | 
            -
              const componentIdOptions = useBuildComponentIdSelectOptions( | 
|  | |
|  | |
|  | |
| 47 |  | 
| 48 | 
             
              return (
         | 
| 49 | 
             
                <Form
         | 
|  | |
| 9 | 
             
              SwitchOperatorOptions,
         | 
| 10 | 
             
            } from '../../constant';
         | 
| 11 | 
             
            import { useBuildFormSelectOptions } from '../../form-hooks';
         | 
| 12 | 
            +
            import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
         | 
| 13 | 
             
            import { IOperatorForm, ISwitchForm } from '../../interface';
         | 
| 14 | 
             
            import { getOtherFieldValues } from '../../utils';
         | 
| 15 |  | 
|  | |
| 43 | 
             
                }));
         | 
| 44 | 
             
              }, [t]);
         | 
| 45 |  | 
| 46 | 
            +
              const componentIdOptions = useBuildComponentIdSelectOptions(
         | 
| 47 | 
            +
                node?.id,
         | 
| 48 | 
            +
                node?.parentId,
         | 
| 49 | 
            +
              );
         | 
| 50 |  | 
| 51 | 
             
              return (
         | 
| 52 | 
             
                <Form
         | 
    	
        web/src/pages/flow/form/template-form/index.tsx
    CHANGED
    
    | @@ -18,7 +18,7 @@ const TemplateForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 18 | 
             
                    <Input.TextArea rows={8} placeholder={t('flow.blank')} />
         | 
| 19 | 
             
                  </Form.Item>
         | 
| 20 |  | 
| 21 | 
            -
                  <DynamicParameters  | 
| 22 | 
             
                </Form>
         | 
| 23 | 
             
              );
         | 
| 24 | 
             
            };
         | 
|  | |
| 18 | 
             
                    <Input.TextArea rows={8} placeholder={t('flow.blank')} />
         | 
| 19 | 
             
                  </Form.Item>
         | 
| 20 |  | 
| 21 | 
            +
                  <DynamicParameters node={node}></DynamicParameters>
         | 
| 22 | 
             
                </Form>
         | 
| 23 | 
             
              );
         | 
| 24 | 
             
            };
         | 
    	
        web/src/pages/flow/form/tushare-form/index.tsx
    CHANGED
    
    | @@ -56,7 +56,7 @@ const TuShareForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 56 | 
             
                  onValuesChange={onValuesChange}
         | 
| 57 | 
             
                  layout={'vertical'}
         | 
| 58 | 
             
                >
         | 
| 59 | 
            -
                  <DynamicInputVariable  | 
| 60 | 
             
                  <Form.Item
         | 
| 61 | 
             
                    label={t('token')}
         | 
| 62 | 
             
                    name={'token'}
         | 
|  | |
| 56 | 
             
                  onValuesChange={onValuesChange}
         | 
| 57 | 
             
                  layout={'vertical'}
         | 
| 58 | 
             
                >
         | 
| 59 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 60 | 
             
                  <Form.Item
         | 
| 61 | 
             
                    label={t('token')}
         | 
| 62 | 
             
                    name={'token'}
         | 
    	
        web/src/pages/flow/form/wencai-form/index.tsx
    CHANGED
    
    | @@ -24,7 +24,7 @@ const WenCaiForm = ({ onValuesChange, form, node }: IOperatorForm) => { | |
| 24 | 
             
                  onValuesChange={onValuesChange}
         | 
| 25 | 
             
                  layout={'vertical'}
         | 
| 26 | 
             
                >
         | 
| 27 | 
            -
                  <DynamicInputVariable  | 
| 28 | 
             
                  <TopNItem initialValue={20} max={99}></TopNItem>
         | 
| 29 | 
             
                  <Form.Item label={t('queryType')} name={'query_type'}>
         | 
| 30 | 
             
                    <Select options={wenCaiQueryTypeOptions}></Select>
         | 
|  | |
| 24 | 
             
                  onValuesChange={onValuesChange}
         | 
| 25 | 
             
                  layout={'vertical'}
         | 
| 26 | 
             
                >
         | 
| 27 | 
            +
                  <DynamicInputVariable node={node}></DynamicInputVariable>
         | 
| 28 | 
             
                  <TopNItem initialValue={20} max={99}></TopNItem>
         | 
| 29 | 
             
                  <Form.Item label={t('queryType')} name={'query_type'}>
         | 
| 30 | 
             
                    <Select options={wenCaiQueryTypeOptions}></Select>
         |