balibabu
		
	commited on
		
		
					Commit 
							
							·
						
						4138aee
	
1
								Parent(s):
							
							845e389
								
feat: Add hint for operators, round to square, input variable, readable operator ID. #3056 (#3057)
Browse files### What problem does this PR solve?
feat: Add hint for operators, round to square, input variable, readable
operator ID. #3056
### Type of change
- [ ] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)
- [ ] Documentation Update
- [ ] Refactoring
- [ ] Performance Improvement
- [ ] Other (please describe):
This view is limited to 50 files because it contains too many changes.  
							See raw diff
- web/src/assets/svg/begin.svg +9 -0
 - web/src/assets/svg/concentrator.svg +2 -2
 - web/src/assets/svg/keyword.svg +2 -2
 - web/src/assets/svg/llm/baai.svg +12 -0
 - web/src/assets/svg/llm/nomic-ai.svg +7 -0
 - web/src/assets/svg/llm/sentence-transformers.svg +29 -0
 - web/src/assets/svg/llm/youdao.svg +13 -0
 - web/src/assets/svg/plus-circle-fill.svg +2 -0
 - web/src/assets/svg/plus.svg +5 -0
 - web/src/assets/svg/resize.svg +6 -0
 - web/src/assets/svg/switch.svg +1 -1
 - web/src/components/knowledge-base-item.tsx +8 -2
 - web/src/components/llm-select/index.less +3 -0
 - web/src/components/llm-select/index.tsx +3 -1
 - web/src/components/llm-select/llm-label.tsx +31 -0
 - web/src/components/svg-icon.tsx +24 -1
 - web/src/constants/setting.ts +50 -0
 - web/src/hooks/{llm-hooks.ts → llm-hooks.tsx} +21 -2
 - web/src/locales/en.ts +4 -2
 - web/src/locales/zh-traditional.ts +5 -2
 - web/src/locales/zh.ts +7 -4
 - web/src/pages/flow/canvas/index.tsx +12 -0
 - web/src/pages/flow/canvas/node/begin-node.tsx +16 -13
 - web/src/pages/flow/canvas/node/categorize-node.tsx +32 -53
 - web/src/pages/flow/canvas/node/dropdown.tsx +1 -1
 - web/src/pages/flow/canvas/node/generate-node.tsx +74 -0
 - web/src/pages/flow/canvas/node/handle-icon.tsx +20 -0
 - web/src/pages/flow/canvas/node/hooks.ts +73 -73
 - web/src/pages/flow/canvas/node/index.less +118 -56
 - web/src/pages/flow/canvas/node/index.tsx +5 -35
 - web/src/pages/flow/canvas/node/keyword-node.tsx +54 -0
 - web/src/pages/flow/canvas/node/logic-node.tsx +5 -52
 - web/src/pages/flow/canvas/node/message-node.tsx +63 -0
 - web/src/pages/flow/canvas/node/node-header.tsx +35 -0
 - web/src/pages/flow/canvas/node/note-node.tsx +61 -22
 - web/src/pages/flow/canvas/node/relevant-node.tsx +28 -38
 - web/src/pages/flow/canvas/node/retrieval-node.tsx +85 -0
 - web/src/pages/flow/canvas/node/rewrite-node.tsx +54 -0
 - web/src/pages/flow/canvas/node/switch-node.tsx +112 -0
 - web/src/pages/flow/constant.tsx +15 -14
 - web/src/pages/flow/flow-drawer/index.less +6 -0
 - web/src/pages/flow/flow-drawer/index.tsx +29 -15
 - web/src/pages/flow/flow-sider/index.tsx +5 -2
 - web/src/pages/flow/form-hooks.ts +4 -15
 - web/src/pages/flow/form/categorize-form/dynamic-categorize.tsx +20 -6
 - web/src/pages/flow/form/categorize-form/index.less +11 -0
 - web/src/pages/flow/form/generate-form/dynamic-parameters.tsx +1 -0
 - web/src/pages/flow/form/switch-form/index.less +21 -0
 - web/src/pages/flow/form/switch-form/index.tsx +121 -97
 - web/src/pages/flow/hooks.ts +23 -3
 
    	
        web/src/assets/svg/begin.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/concentrator.svg
    CHANGED
    
    | 
												 | 
										
| 
												 | 
									
								
    	
        web/src/assets/svg/keyword.svg
    CHANGED
    
    | 
												 | 
										
| 
												 | 
									
								
    	
        web/src/assets/svg/llm/baai.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/llm/nomic-ai.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/llm/sentence-transformers.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/llm/youdao.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/plus-circle-fill.svg
    CHANGED
    
    | 
												 | 
										
| 
												 | 
									
								
    	
        web/src/assets/svg/plus.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/resize.svg
    ADDED
    
    | 
											 | 
									
								
    	
        web/src/assets/svg/switch.svg
    CHANGED
    
    | 
												 | 
										
| 
												 | 
									
								
    	
        web/src/components/knowledge-base-item.tsx
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 1 | 
         
             
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
             
            import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks';
         
     | 
| 3 | 
         
            -
            import {  
     | 
| 
         | 
|
| 4 | 
         | 
| 5 | 
         
             
            const KnowledgeBaseItem = () => {
         
     | 
| 6 | 
         
             
              const { t } = useTranslate('chat');
         
     | 
| 
         @@ -8,7 +9,12 @@ const KnowledgeBaseItem = () => { 
     | 
|
| 8 | 
         
             
              const { list: knowledgeList } = useNextFetchKnowledgeList(true);
         
     | 
| 9 | 
         | 
| 10 | 
         
             
              const knowledgeOptions = knowledgeList.map((x) => ({
         
     | 
| 11 | 
         
            -
                label:  
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 12 | 
         
             
                value: x.id,
         
     | 
| 13 | 
         
             
              }));
         
     | 
| 14 | 
         | 
| 
         | 
|
| 1 | 
         
             
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
             
            import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks';
         
     | 
| 3 | 
         
            +
            import { UserOutlined } from '@ant-design/icons';
         
     | 
| 4 | 
         
            +
            import { Avatar, Form, Select, Space } from 'antd';
         
     | 
| 5 | 
         | 
| 6 | 
         
             
            const KnowledgeBaseItem = () => {
         
     | 
| 7 | 
         
             
              const { t } = useTranslate('chat');
         
     | 
| 
         | 
|
| 9 | 
         
             
              const { list: knowledgeList } = useNextFetchKnowledgeList(true);
         
     | 
| 10 | 
         | 
| 11 | 
         
             
              const knowledgeOptions = knowledgeList.map((x) => ({
         
     | 
| 12 | 
         
            +
                label: (
         
     | 
| 13 | 
         
            +
                  <Space>
         
     | 
| 14 | 
         
            +
                    <Avatar size={20} icon={<UserOutlined />} src={x.avatar} />
         
     | 
| 15 | 
         
            +
                    {x.name}
         
     | 
| 16 | 
         
            +
                  </Space>
         
     | 
| 17 | 
         
            +
                ),
         
     | 
| 18 | 
         
             
                value: x.id,
         
     | 
| 19 | 
         
             
              }));
         
     | 
| 20 | 
         | 
    	
        web/src/components/llm-select/index.less
    ADDED
    
    | 
         @@ -0,0 +1,3 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            .llmLabel {
         
     | 
| 2 | 
         
            +
              font-size: 14px;
         
     | 
| 3 | 
         
            +
            }
         
     | 
    	
        web/src/components/llm-select/index.tsx
    CHANGED
    
    | 
         @@ -7,9 +7,10 @@ interface IProps { 
     | 
|
| 7 | 
         
             
              id?: string;
         
     | 
| 8 | 
         
             
              value?: string;
         
     | 
| 9 | 
         
             
              onChange?: (value: string) => void;
         
     | 
| 
         | 
|
| 10 | 
         
             
            }
         
     | 
| 11 | 
         | 
| 12 | 
         
            -
            const LLMSelect = ({ id, value, onChange }: IProps) => {
         
     | 
| 13 | 
         
             
              const modelOptions = useComposeLlmOptionsByModelTypes([
         
     | 
| 14 | 
         
             
                LlmModelType.Chat,
         
     | 
| 15 | 
         
             
                LlmModelType.Image2text,
         
     | 
| 
         @@ -38,6 +39,7 @@ const LLMSelect = ({ id, value, onChange }: IProps) => { 
     | 
|
| 38 | 
         
             
                    id={id}
         
     | 
| 39 | 
         
             
                    value={value}
         
     | 
| 40 | 
         
             
                    onChange={onChange}
         
     | 
| 
         | 
|
| 41 | 
         
             
                  />
         
     | 
| 42 | 
         
             
                </Popover>
         
     | 
| 43 | 
         
             
              );
         
     | 
| 
         | 
|
| 7 | 
         
             
              id?: string;
         
     | 
| 8 | 
         
             
              value?: string;
         
     | 
| 9 | 
         
             
              onChange?: (value: string) => void;
         
     | 
| 10 | 
         
            +
              disabled?: boolean;
         
     | 
| 11 | 
         
             
            }
         
     | 
| 12 | 
         | 
| 13 | 
         
            +
            const LLMSelect = ({ id, value, onChange, disabled }: IProps) => {
         
     | 
| 14 | 
         
             
              const modelOptions = useComposeLlmOptionsByModelTypes([
         
     | 
| 15 | 
         
             
                LlmModelType.Chat,
         
     | 
| 16 | 
         
             
                LlmModelType.Image2text,
         
     | 
| 
         | 
|
| 39 | 
         
             
                    id={id}
         
     | 
| 40 | 
         
             
                    value={value}
         
     | 
| 41 | 
         
             
                    onChange={onChange}
         
     | 
| 42 | 
         
            +
                    disabled={disabled}
         
     | 
| 43 | 
         
             
                  />
         
     | 
| 44 | 
         
             
                </Popover>
         
     | 
| 45 | 
         
             
              );
         
     | 
    	
        web/src/components/llm-select/llm-label.tsx
    ADDED
    
    | 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { LlmModelType } from '@/constants/knowledge';
         
     | 
| 2 | 
         
            +
            import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks';
         
     | 
| 3 | 
         
            +
            import { useMemo } from 'react';
         
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
            interface IProps {
         
     | 
| 6 | 
         
            +
              id?: string;
         
     | 
| 7 | 
         
            +
              value?: string;
         
     | 
| 8 | 
         
            +
              onChange?: (value: string) => void;
         
     | 
| 9 | 
         
            +
              disabled?: boolean;
         
     | 
| 10 | 
         
            +
            }
         
     | 
| 11 | 
         
            +
             
     | 
| 12 | 
         
            +
            const LLMLabel = ({ value }: IProps) => {
         
     | 
| 13 | 
         
            +
              const modelOptions = useComposeLlmOptionsByModelTypes([
         
     | 
| 14 | 
         
            +
                LlmModelType.Chat,
         
     | 
| 15 | 
         
            +
                LlmModelType.Image2text,
         
     | 
| 16 | 
         
            +
              ]);
         
     | 
| 17 | 
         
            +
             
     | 
| 18 | 
         
            +
              const label = useMemo(() => {
         
     | 
| 19 | 
         
            +
                for (const item of modelOptions) {
         
     | 
| 20 | 
         
            +
                  for (const option of item.options) {
         
     | 
| 21 | 
         
            +
                    if (option.value === value) {
         
     | 
| 22 | 
         
            +
                      return option.label;
         
     | 
| 23 | 
         
            +
                    }
         
     | 
| 24 | 
         
            +
                  }
         
     | 
| 25 | 
         
            +
                }
         
     | 
| 26 | 
         
            +
              }, [modelOptions, value]);
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
              return <div>{label}</div>;
         
     | 
| 29 | 
         
            +
            };
         
     | 
| 30 | 
         
            +
             
     | 
| 31 | 
         
            +
            export default LLMLabel;
         
     | 
    	
        web/src/components/svg-icon.tsx
    CHANGED
    
    | 
         @@ -1,5 +1,8 @@ 
     | 
|
| 1 | 
         
            -
            import  
     | 
| 
         | 
|
| 2 | 
         
             
            import { IconComponentProps } from '@ant-design/icons/lib/components/Icon';
         
     | 
| 
         | 
|
| 
         | 
|
| 3 | 
         | 
| 4 | 
         
             
            const importAll = (requireContext: __WebpackModuleApi.RequireContext) => {
         
     | 
| 5 | 
         
             
              const list = requireContext.keys().map((key) => {
         
     | 
| 
         @@ -36,4 +39,24 @@ const SvgIcon = ({ name, width, height, ...restProps }: IProps) => { 
     | 
|
| 36 | 
         
             
              );
         
     | 
| 37 | 
         
             
            };
         
     | 
| 38 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 39 | 
         
             
            export default SvgIcon;
         
     | 
| 
         | 
|
| 1 | 
         
            +
            import { IconMap } from '@/constants/setting';
         
     | 
| 2 | 
         
            +
            import Icon, { UserOutlined } from '@ant-design/icons';
         
     | 
| 3 | 
         
             
            import { IconComponentProps } from '@ant-design/icons/lib/components/Icon';
         
     | 
| 4 | 
         
            +
            import { Avatar } from 'antd';
         
     | 
| 5 | 
         
            +
            import { AvatarSize } from 'antd/es/avatar/AvatarContext';
         
     | 
| 6 | 
         | 
| 7 | 
         
             
            const importAll = (requireContext: __WebpackModuleApi.RequireContext) => {
         
     | 
| 8 | 
         
             
              const list = requireContext.keys().map((key) => {
         
     | 
| 
         | 
|
| 39 | 
         
             
              );
         
     | 
| 40 | 
         
             
            };
         
     | 
| 41 | 
         | 
| 42 | 
         
            +
            export const LlmIcon = ({
         
     | 
| 43 | 
         
            +
              name,
         
     | 
| 44 | 
         
            +
              height = 48,
         
     | 
| 45 | 
         
            +
              width = 48,
         
     | 
| 46 | 
         
            +
              size = 'large',
         
     | 
| 47 | 
         
            +
            }: {
         
     | 
| 48 | 
         
            +
              name: string;
         
     | 
| 49 | 
         
            +
              height?: number;
         
     | 
| 50 | 
         
            +
              width?: number;
         
     | 
| 51 | 
         
            +
              size?: AvatarSize;
         
     | 
| 52 | 
         
            +
            }) => {
         
     | 
| 53 | 
         
            +
              const icon = IconMap[name as keyof typeof IconMap];
         
     | 
| 54 | 
         
            +
             
     | 
| 55 | 
         
            +
              return icon ? (
         
     | 
| 56 | 
         
            +
                <SvgIcon name={`llm/${icon}`} width={width} height={height}></SvgIcon>
         
     | 
| 57 | 
         
            +
              ) : (
         
     | 
| 58 | 
         
            +
                <Avatar shape="square" size={size} icon={<UserOutlined />} />
         
     | 
| 59 | 
         
            +
              );
         
     | 
| 60 | 
         
            +
            };
         
     | 
| 61 | 
         
            +
             
     | 
| 62 | 
         
             
            export default SvgIcon;
         
     | 
    	
        web/src/constants/setting.ts
    CHANGED
    
    | 
         @@ -19,6 +19,56 @@ export const UserSettingRouteMap = { 
     | 
|
| 19 | 
         
             
              [UserSettingRouteKey.Logout]: 'Log out',
         
     | 
| 20 | 
         
             
            };
         
     | 
| 21 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 22 | 
         
             
            export const TimezoneList = [
         
     | 
| 23 | 
         
             
              'UTC-11\tPacific/Midway',
         
     | 
| 24 | 
         
             
              'UTC-11\tPacific/Niue',
         
     | 
| 
         | 
|
| 19 | 
         
             
              [UserSettingRouteKey.Logout]: 'Log out',
         
     | 
| 20 | 
         
             
            };
         
     | 
| 21 | 
         | 
| 22 | 
         
            +
            // Please lowercase the file name
         
     | 
| 23 | 
         
            +
            export const IconMap = {
         
     | 
| 24 | 
         
            +
              'Tongyi-Qianwen': 'tongyi',
         
     | 
| 25 | 
         
            +
              Moonshot: 'moonshot',
         
     | 
| 26 | 
         
            +
              OpenAI: 'openai',
         
     | 
| 27 | 
         
            +
              'ZHIPU-AI': 'zhipu',
         
     | 
| 28 | 
         
            +
              文心一言: 'wenxin',
         
     | 
| 29 | 
         
            +
              Ollama: 'ollama',
         
     | 
| 30 | 
         
            +
              Xinference: 'xinference',
         
     | 
| 31 | 
         
            +
              DeepSeek: 'deepseek',
         
     | 
| 32 | 
         
            +
              VolcEngine: 'volc_engine',
         
     | 
| 33 | 
         
            +
              BaiChuan: 'baichuan',
         
     | 
| 34 | 
         
            +
              Jina: 'jina',
         
     | 
| 35 | 
         
            +
              MiniMax: 'chat-minimax',
         
     | 
| 36 | 
         
            +
              Mistral: 'mistral',
         
     | 
| 37 | 
         
            +
              'Azure-OpenAI': 'azure',
         
     | 
| 38 | 
         
            +
              Bedrock: 'bedrock',
         
     | 
| 39 | 
         
            +
              Gemini: 'gemini',
         
     | 
| 40 | 
         
            +
              Groq: 'groq-next',
         
     | 
| 41 | 
         
            +
              OpenRouter: 'open-router',
         
     | 
| 42 | 
         
            +
              LocalAI: 'local-ai',
         
     | 
| 43 | 
         
            +
              StepFun: 'stepfun',
         
     | 
| 44 | 
         
            +
              NVIDIA: 'nvidia',
         
     | 
| 45 | 
         
            +
              'LM-Studio': 'lm-studio',
         
     | 
| 46 | 
         
            +
              'OpenAI-API-Compatible': 'openai-api',
         
     | 
| 47 | 
         
            +
              cohere: 'cohere',
         
     | 
| 48 | 
         
            +
              LeptonAI: 'lepton-ai',
         
     | 
| 49 | 
         
            +
              TogetherAI: 'together-ai',
         
     | 
| 50 | 
         
            +
              PerfXCloud: 'perfx-cloud',
         
     | 
| 51 | 
         
            +
              Upstage: 'upstage',
         
     | 
| 52 | 
         
            +
              'novita.ai': 'novita-ai',
         
     | 
| 53 | 
         
            +
              SILICONFLOW: 'siliconflow',
         
     | 
| 54 | 
         
            +
              '01.AI': 'yi',
         
     | 
| 55 | 
         
            +
              Replicate: 'replicate',
         
     | 
| 56 | 
         
            +
              'Tencent Hunyuan': 'hunyuan',
         
     | 
| 57 | 
         
            +
              'XunFei Spark': 'spark',
         
     | 
| 58 | 
         
            +
              BaiduYiyan: 'yiyan',
         
     | 
| 59 | 
         
            +
              'Fish Audio': 'fish-audio',
         
     | 
| 60 | 
         
            +
              'Tencent Cloud': 'tencent-cloud',
         
     | 
| 61 | 
         
            +
              Anthropic: 'anthropic',
         
     | 
| 62 | 
         
            +
              'Voyage AI': 'voyage',
         
     | 
| 63 | 
         
            +
              'Google Cloud': 'google-cloud',
         
     | 
| 64 | 
         
            +
              HuggingFace: 'huggingface',
         
     | 
| 65 | 
         
            +
              Youdao: 'youdao',
         
     | 
| 66 | 
         
            +
              BAAI: 'baai',
         
     | 
| 67 | 
         
            +
              'nomic-ai': 'nomic-ai',
         
     | 
| 68 | 
         
            +
              jinaai: 'jina',
         
     | 
| 69 | 
         
            +
              'sentence-transformers': 'sentence-transformers',
         
     | 
| 70 | 
         
            +
            };
         
     | 
| 71 | 
         
            +
             
     | 
| 72 | 
         
             
            export const TimezoneList = [
         
     | 
| 73 | 
         
             
              'UTC-11\tPacific/Midway',
         
     | 
| 74 | 
         
             
              'UTC-11\tPacific/Niue',
         
     | 
    	
        web/src/hooks/{llm-hooks.ts → llm-hooks.tsx}
    RENAMED
    
    | 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
         | 
|
| 1 | 
         
             
            import { LlmModelType } from '@/constants/knowledge';
         
     | 
| 2 | 
         
             
            import { ResponseGetType } from '@/interfaces/database/base';
         
     | 
| 3 | 
         
             
            import {
         
     | 
| 
         @@ -13,7 +14,7 @@ import { 
     | 
|
| 13 | 
         
             
            import userService from '@/services/user-service';
         
     | 
| 14 | 
         
             
            import { sortLLmFactoryListBySpecifiedOrder } from '@/utils/common-util';
         
     | 
| 15 | 
         
             
            import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
         
     | 
| 16 | 
         
            -
            import { message } from 'antd';
         
     | 
| 17 | 
         
             
            import { DefaultOptionType } from 'antd/es/select';
         
     | 
| 18 | 
         
             
            import { useMemo } from 'react';
         
     | 
| 19 | 
         
             
            import { useTranslation } from 'react-i18next';
         
     | 
| 
         @@ -53,6 +54,14 @@ export const useSelectLlmOptions = () => { 
     | 
|
| 53 | 
         
             
              return embeddingModelOptions;
         
     | 
| 54 | 
         
             
            };
         
     | 
| 55 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 56 | 
         
             
            export const useSelectLlmOptionsByModelType = () => {
         
     | 
| 57 | 
         
             
              const llmInfo: IThirdOAIModelCollection = useFetchLlmList();
         
     | 
| 58 | 
         | 
| 
         @@ -71,7 +80,17 @@ export const useSelectLlmOptionsByModelType = () => { 
     | 
|
| 71 | 
         
             
                            x.available,
         
     | 
| 72 | 
         
             
                        )
         
     | 
| 73 | 
         
             
                        .map((x) => ({
         
     | 
| 74 | 
         
            -
                          label:  
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 75 | 
         
             
                          value: `${x.llm_name}@${x.fid}`,
         
     | 
| 76 | 
         
             
                          disabled: !x.available,
         
     | 
| 77 | 
         
             
                        })),
         
     | 
| 
         | 
|
| 1 | 
         
            +
            import { LlmIcon } from '@/components/svg-icon';
         
     | 
| 2 | 
         
             
            import { LlmModelType } from '@/constants/knowledge';
         
     | 
| 3 | 
         
             
            import { ResponseGetType } from '@/interfaces/database/base';
         
     | 
| 4 | 
         
             
            import {
         
     | 
| 
         | 
|
| 14 | 
         
             
            import userService from '@/services/user-service';
         
     | 
| 15 | 
         
             
            import { sortLLmFactoryListBySpecifiedOrder } from '@/utils/common-util';
         
     | 
| 16 | 
         
             
            import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
         
     | 
| 17 | 
         
            +
            import { Flex, message } from 'antd';
         
     | 
| 18 | 
         
             
            import { DefaultOptionType } from 'antd/es/select';
         
     | 
| 19 | 
         
             
            import { useMemo } from 'react';
         
     | 
| 20 | 
         
             
            import { useTranslation } from 'react-i18next';
         
     | 
| 
         | 
|
| 54 | 
         
             
              return embeddingModelOptions;
         
     | 
| 55 | 
         
             
            };
         
     | 
| 56 | 
         | 
| 57 | 
         
            +
            const getLLMIconName = (fid: string, llm_name: string) => {
         
     | 
| 58 | 
         
            +
              if (fid === 'FastEmbed') {
         
     | 
| 59 | 
         
            +
                return llm_name.split('/').at(0) ?? '';
         
     | 
| 60 | 
         
            +
              }
         
     | 
| 61 | 
         
            +
             
     | 
| 62 | 
         
            +
              return fid;
         
     | 
| 63 | 
         
            +
            };
         
     | 
| 64 | 
         
            +
             
     | 
| 65 | 
         
             
            export const useSelectLlmOptionsByModelType = () => {
         
     | 
| 66 | 
         
             
              const llmInfo: IThirdOAIModelCollection = useFetchLlmList();
         
     | 
| 67 | 
         | 
| 
         | 
|
| 80 | 
         
             
                            x.available,
         
     | 
| 81 | 
         
             
                        )
         
     | 
| 82 | 
         
             
                        .map((x) => ({
         
     | 
| 83 | 
         
            +
                          label: (
         
     | 
| 84 | 
         
            +
                            <Flex align="center" gap={6}>
         
     | 
| 85 | 
         
            +
                              <LlmIcon
         
     | 
| 86 | 
         
            +
                                name={getLLMIconName(x.fid, x.llm_name)}
         
     | 
| 87 | 
         
            +
                                width={26}
         
     | 
| 88 | 
         
            +
                                height={26}
         
     | 
| 89 | 
         
            +
                                size={'small'}
         
     | 
| 90 | 
         
            +
                              />
         
     | 
| 91 | 
         
            +
                              <span>{x.llm_name}</span>
         
     | 
| 92 | 
         
            +
                            </Flex>
         
     | 
| 93 | 
         
            +
                          ),
         
     | 
| 94 | 
         
             
                          value: `${x.llm_name}@${x.fid}`,
         
     | 
| 95 | 
         
             
                          disabled: !x.available,
         
     | 
| 96 | 
         
             
                        })),
         
     | 
    	
        web/src/locales/en.ts
    CHANGED
    
    | 
         @@ -728,18 +728,20 @@ The above is the content you need to summarize.`, 
     | 
|
| 728 | 
         
             
                    'The  window size of conversation history that needed to be seen by LLM. The larger the better. But be careful with the maximum content length of LLM.',
         
     | 
| 729 | 
         
             
                  wikipedia: 'Wikipedia',
         
     | 
| 730 | 
         
             
                  pubMed: 'PubMed',
         
     | 
| 
         | 
|
| 
         | 
|
| 731 | 
         
             
                  email: 'Email',
         
     | 
| 732 | 
         
             
                  emailTip:
         
     | 
| 733 | 
         
             
                    'This component is used to get search result from https://pubmed.ncbi.nlm.nih.gov/. Typically, it performs as a supplement to knowledgebases. Top N specifies the number of search results you need to adapt. E-mail is a required field.',
         
     | 
| 734 | 
         
             
                  arXiv: 'ArXiv',
         
     | 
| 735 | 
         
            -
                   
     | 
| 736 | 
         
             
                    'This component is used to get search result from https://arxiv.org/. Typically, it performs as a supplement to knowledgebases. Top N specifies the number of search results you need to adapt.',
         
     | 
| 737 | 
         
             
                  sortBy: 'Sort by',
         
     | 
| 738 | 
         
             
                  submittedDate: 'Submitted date',
         
     | 
| 739 | 
         
             
                  lastUpdatedDate: 'Last updated date',
         
     | 
| 740 | 
         
             
                  relevance: 'Relevance',
         
     | 
| 741 | 
         
             
                  google: 'Google',
         
     | 
| 742 | 
         
            -
                   
     | 
| 743 | 
         
             
                    'This component is used to get search result fromhttps://www.google.com/ . Typically, it performs as a supplement to knowledgebases. Top N and SerpApi API key specifies the number of search results you need to adapt.',
         
     | 
| 744 | 
         
             
                  bing: 'Bing',
         
     | 
| 745 | 
         
             
                  bingTip:
         
     | 
| 
         | 
|
| 728 | 
         
             
                    'The  window size of conversation history that needed to be seen by LLM. The larger the better. But be careful with the maximum content length of LLM.',
         
     | 
| 729 | 
         
             
                  wikipedia: 'Wikipedia',
         
     | 
| 730 | 
         
             
                  pubMed: 'PubMed',
         
     | 
| 731 | 
         
            +
                  pubMedDescription:
         
     | 
| 732 | 
         
            +
                    'This component is used to get search result from https://pubmed.ncbi.nlm.nih.gov/. Typically, it performs as a supplement to knowledgebases. Top N specifies the number of search results you need to adapt. E-mail is a required field.',
         
     | 
| 733 | 
         
             
                  email: 'Email',
         
     | 
| 734 | 
         
             
                  emailTip:
         
     | 
| 735 | 
         
             
                    'This component is used to get search result from https://pubmed.ncbi.nlm.nih.gov/. Typically, it performs as a supplement to knowledgebases. Top N specifies the number of search results you need to adapt. E-mail is a required field.',
         
     | 
| 736 | 
         
             
                  arXiv: 'ArXiv',
         
     | 
| 737 | 
         
            +
                  arXivDescription:
         
     | 
| 738 | 
         
             
                    'This component is used to get search result from https://arxiv.org/. Typically, it performs as a supplement to knowledgebases. Top N specifies the number of search results you need to adapt.',
         
     | 
| 739 | 
         
             
                  sortBy: 'Sort by',
         
     | 
| 740 | 
         
             
                  submittedDate: 'Submitted date',
         
     | 
| 741 | 
         
             
                  lastUpdatedDate: 'Last updated date',
         
     | 
| 742 | 
         
             
                  relevance: 'Relevance',
         
     | 
| 743 | 
         
             
                  google: 'Google',
         
     | 
| 744 | 
         
            +
                  googleDescription:
         
     | 
| 745 | 
         
             
                    'This component is used to get search result fromhttps://www.google.com/ . Typically, it performs as a supplement to knowledgebases. Top N and SerpApi API key specifies the number of search results you need to adapt.',
         
     | 
| 746 | 
         
             
                  bing: 'Bing',
         
     | 
| 747 | 
         
             
                  bingTip:
         
     | 
    	
        web/src/locales/zh-traditional.ts
    CHANGED
    
    | 
         @@ -680,18 +680,21 @@ export default { 
     | 
|
| 680 | 
         
             
                  messageHistoryWindowSizeTip:
         
     | 
| 681 | 
         
             
                    'LLM需要查看的對話記錄的視窗大小。越大越好。但要注意LLM的最大內容長度。',
         
     | 
| 682 | 
         
             
                  wikipedia: '維基百科',
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 683 | 
         
             
                  email: '信箱',
         
     | 
| 684 | 
         
             
                  emailTip:
         
     | 
| 685 | 
         
             
                    '此元件用於從 https://pubmed.ncbi.nlm.nih.gov/ 取得搜尋結果。通常,它充當知識庫的補充。 Top N 指定您需要適應的搜尋結果的數量。電子郵件是必填欄位。',
         
     | 
| 686 | 
         
             
                  arXiv: 'ArXiv',
         
     | 
| 687 | 
         
            -
                   
     | 
| 688 | 
         
             
                    '此元件用於從 https://arxiv.org/ 取得搜尋結果。通常,它充當知識庫的補充。 Top N 指定您需要適應的搜尋結果的數量。',
         
     | 
| 689 | 
         
             
                  sortBy: '排序方式',
         
     | 
| 690 | 
         
             
                  submittedDate: '提交日期',
         
     | 
| 691 | 
         
             
                  lastUpdatedDate: '最後更新日期',
         
     | 
| 692 | 
         
             
                  relevance: '關聯',
         
     | 
| 693 | 
         
             
                  google: 'Google',
         
     | 
| 694 | 
         
            -
                   
     | 
| 695 | 
         
             
                    '此元件用於從https://www.google.com/取得搜尋結果。通常,它作為知識庫的補充。 Top N 和 SerpApi API 金鑰指定您需要調整的搜尋結果數量。',
         
     | 
| 696 | 
         
             
                  bing: 'Bing',
         
     | 
| 697 | 
         
             
                  bingTip:
         
     | 
| 
         | 
|
| 680 | 
         
             
                  messageHistoryWindowSizeTip:
         
     | 
| 681 | 
         
             
                    'LLM需要查看的對話記錄的視窗大小。越大越好。但要注意LLM的最大內容長度。',
         
     | 
| 682 | 
         
             
                  wikipedia: '維基百科',
         
     | 
| 683 | 
         
            +
                  pubMed: 'PubMed',
         
     | 
| 684 | 
         
            +
                  pubMedDescription:
         
     | 
| 685 | 
         
            +
                    '此元件用於從 https://pubmed.ncbi.nlm.nih.gov/ 取得搜尋結果。通常,它充當知識庫的補充。 Top N 指定您需要適應的搜尋結果的數量。電子郵件是必填欄位。',
         
     | 
| 686 | 
         
             
                  email: '信箱',
         
     | 
| 687 | 
         
             
                  emailTip:
         
     | 
| 688 | 
         
             
                    '此元件用於從 https://pubmed.ncbi.nlm.nih.gov/ 取得搜尋結果。通常,它充當知識庫的補充。 Top N 指定您需要適應的搜尋結果的數量。電子郵件是必填欄位。',
         
     | 
| 689 | 
         
             
                  arXiv: 'ArXiv',
         
     | 
| 690 | 
         
            +
                  arXivDescription:
         
     | 
| 691 | 
         
             
                    '此元件用於從 https://arxiv.org/ 取得搜尋結果。通常,它充當知識庫的補充。 Top N 指定您需要適應的搜尋結果的數量。',
         
     | 
| 692 | 
         
             
                  sortBy: '排序方式',
         
     | 
| 693 | 
         
             
                  submittedDate: '提交日期',
         
     | 
| 694 | 
         
             
                  lastUpdatedDate: '最後更新日期',
         
     | 
| 695 | 
         
             
                  relevance: '關聯',
         
     | 
| 696 | 
         
             
                  google: 'Google',
         
     | 
| 697 | 
         
            +
                  googleDescription:
         
     | 
| 698 | 
         
             
                    '此元件用於從https://www.google.com/取得搜尋結果。通常,它作為知識庫的補充。 Top N 和 SerpApi API 金鑰指定您需要調整的搜尋結果數量。',
         
     | 
| 699 | 
         
             
                  bing: 'Bing',
         
     | 
| 700 | 
         
             
                  bingTip:
         
     | 
    	
        web/src/locales/zh.ts
    CHANGED
    
    | 
         @@ -688,7 +688,7 @@ export default { 
     | 
|
| 688 | 
         
             
                  keywordExtract: '关键词',
         
     | 
| 689 | 
         
             
                  keywordExtractDescription: `该组件用于从用户的问题中提取关键词。Top N指定需要提取的关键词数量。`,
         
     | 
| 690 | 
         
             
                  baidu: '百度',
         
     | 
| 691 | 
         
            -
                  baiduDescription:  
     | 
| 692 | 
         
             
                  duckDuckGo: 'DuckDuckGo',
         
     | 
| 693 | 
         
             
                  duckDuckGoDescription:
         
     | 
| 694 | 
         
             
                    '此元件用於從 www.duckduckgo.com 取得搜尋結果。通常,它作為知識庫的補充。 Top N 指定您需要調整的搜尋結果數。',
         
     | 
| 
         @@ -700,18 +700,21 @@ export default { 
     | 
|
| 700 | 
         
             
                  messageHistoryWindowSizeTip:
         
     | 
| 701 | 
         
             
                    'LLM 需要查看的对话历史窗口大小。越大越好。但要注意 LLM 的最大内容长度。',
         
     | 
| 702 | 
         
             
                  wikipedia: '维基百科',
         
     | 
| 703 | 
         
            -
                  email: '邮箱',
         
     | 
| 704 | 
         
             
                  emailTip:
         
     | 
| 705 | 
         
             
                    '此组件用于从 https://pubmed.ncbi.nlm.nih.gov/ 获取搜索结果。通常,它作为知识库的补充。Top N 指定您需要调整的搜索结果数。电子邮件是必填字段。',
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 706 | 
         
             
                  arXiv: 'ArXiv',
         
     | 
| 707 | 
         
            -
                   
     | 
| 708 | 
         
             
                    '此组件用于从 https://arxiv.org/ 获取搜索结果。通常,它作为知识库的补充。Top N 指定您需要调整的搜索结果数量。',
         
     | 
| 709 | 
         
             
                  sortBy: '排序方式',
         
     | 
| 710 | 
         
             
                  submittedDate: '提交日期',
         
     | 
| 711 | 
         
             
                  lastUpdatedDate: '最后更新日期',
         
     | 
| 712 | 
         
             
                  relevance: '关联',
         
     | 
| 713 | 
         
             
                  google: 'Google',
         
     | 
| 714 | 
         
            -
                   
     | 
| 715 | 
         
             
                    '此组件用于从https://www.google.com/获取搜索结果。通常,它作为知识库的补充。Top N 和 SerpApi API 密钥指定您需要调整的搜索结果数量。',
         
     | 
| 716 | 
         
             
                  bing: 'Bing',
         
     | 
| 717 | 
         
             
                  bingTip:
         
     | 
| 
         | 
|
| 688 | 
         
             
                  keywordExtract: '关键词',
         
     | 
| 689 | 
         
             
                  keywordExtractDescription: `该组件用于从用户的问题中提取关键词。Top N指定需要提取的关键词数量。`,
         
     | 
| 690 | 
         
             
                  baidu: '百度',
         
     | 
| 691 | 
         
            +
                  baiduDescription: `此组件用于从 www.baidu.com 获取搜索结果。通常,它作为知识库的补充。Top N 指定您需要调整的搜索结果数量。`,
         
     | 
| 692 | 
         
             
                  duckDuckGo: 'DuckDuckGo',
         
     | 
| 693 | 
         
             
                  duckDuckGoDescription:
         
     | 
| 694 | 
         
             
                    '此元件用於從 www.duckduckgo.com 取得搜尋結果。通常,它作為知識庫的補充。 Top N 指定您需要調整的搜尋結果數。',
         
     | 
| 
         | 
|
| 700 | 
         
             
                  messageHistoryWindowSizeTip:
         
     | 
| 701 | 
         
             
                    'LLM 需要查看的对话历史窗口大小。越大越好。但要注意 LLM 的最大内容长度。',
         
     | 
| 702 | 
         
             
                  wikipedia: '维基百科',
         
     | 
| 
         | 
|
| 703 | 
         
             
                  emailTip:
         
     | 
| 704 | 
         
             
                    '此组件用于从 https://pubmed.ncbi.nlm.nih.gov/ 获取搜索结果。通常,它作为知识库的补充。Top N 指定您需要调整的搜索结果数。电子邮件是必填字段。',
         
     | 
| 705 | 
         
            +
                  email: '邮箱',
         
     | 
| 706 | 
         
            +
                  pubMed: 'PubMed',
         
     | 
| 707 | 
         
            +
                  pubMedDescription:
         
     | 
| 708 | 
         
            +
                    '此组件用于从 https://pubmed.ncbi.nlm.nih.gov/ 获取搜索结果。通常,它作为知识库的补充。Top N 指定您需要调整的搜索结果数。电子邮件是必填字段。',
         
     | 
| 709 | 
         
             
                  arXiv: 'ArXiv',
         
     | 
| 710 | 
         
            +
                  arXivDescription:
         
     | 
| 711 | 
         
             
                    '此组件用于从 https://arxiv.org/ 获取搜索结果。通常,它作为知识库的补充。Top N 指定您需要调整的搜索结果数量。',
         
     | 
| 712 | 
         
             
                  sortBy: '排序方式',
         
     | 
| 713 | 
         
             
                  submittedDate: '提交日期',
         
     | 
| 714 | 
         
             
                  lastUpdatedDate: '最后更新日期',
         
     | 
| 715 | 
         
             
                  relevance: '关联',
         
     | 
| 716 | 
         
             
                  google: 'Google',
         
     | 
| 717 | 
         
            +
                  googleDescription:
         
     | 
| 718 | 
         
             
                    '此组件用于从https://www.google.com/获取搜索结果。通常,它作为知识库的补充。Top N 和 SerpApi API 密钥指定您需要调整的搜索结果数量。',
         
     | 
| 719 | 
         
             
                  bing: 'Bing',
         
     | 
| 720 | 
         
             
                  bingTip:
         
     | 
    	
        web/src/pages/flow/canvas/index.tsx
    CHANGED
    
    | 
         @@ -22,9 +22,15 @@ import styles from './index.less'; 
     | 
|
| 22 | 
         
             
            import { RagNode } from './node';
         
     | 
| 23 | 
         
             
            import { BeginNode } from './node/begin-node';
         
     | 
| 24 | 
         
             
            import { CategorizeNode } from './node/categorize-node';
         
     | 
| 
         | 
|
| 
         | 
|
| 25 | 
         
             
            import { LogicNode } from './node/logic-node';
         
     | 
| 
         | 
|
| 26 | 
         
             
            import NoteNode from './node/note-node';
         
     | 
| 27 | 
         
             
            import { RelevantNode } from './node/relevant-node';
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 28 | 
         | 
| 29 | 
         
             
            const nodeTypes = {
         
     | 
| 30 | 
         
             
              ragNode: RagNode,
         
     | 
| 
         @@ -33,6 +39,12 @@ const nodeTypes = { 
     | 
|
| 33 | 
         
             
              relevantNode: RelevantNode,
         
     | 
| 34 | 
         
             
              logicNode: LogicNode,
         
     | 
| 35 | 
         
             
              noteNode: NoteNode,
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 36 | 
         
             
            };
         
     | 
| 37 | 
         | 
| 38 | 
         
             
            const edgeTypes = {
         
     | 
| 
         | 
|
| 22 | 
         
             
            import { RagNode } from './node';
         
     | 
| 23 | 
         
             
            import { BeginNode } from './node/begin-node';
         
     | 
| 24 | 
         
             
            import { CategorizeNode } from './node/categorize-node';
         
     | 
| 25 | 
         
            +
            import { GenerateNode } from './node/generate-node';
         
     | 
| 26 | 
         
            +
            import { KeywordNode } from './node/keyword-node';
         
     | 
| 27 | 
         
             
            import { LogicNode } from './node/logic-node';
         
     | 
| 28 | 
         
            +
            import { MessageNode } from './node/message-node';
         
     | 
| 29 | 
         
             
            import NoteNode from './node/note-node';
         
     | 
| 30 | 
         
             
            import { RelevantNode } from './node/relevant-node';
         
     | 
| 31 | 
         
            +
            import { RetrievalNode } from './node/retrieval-node';
         
     | 
| 32 | 
         
            +
            import { RewriteNode } from './node/rewrite-node';
         
     | 
| 33 | 
         
            +
            import { SwitchNode } from './node/switch-node';
         
     | 
| 34 | 
         | 
| 35 | 
         
             
            const nodeTypes = {
         
     | 
| 36 | 
         
             
              ragNode: RagNode,
         
     | 
| 
         | 
|
| 39 | 
         
             
              relevantNode: RelevantNode,
         
     | 
| 40 | 
         
             
              logicNode: LogicNode,
         
     | 
| 41 | 
         
             
              noteNode: NoteNode,
         
     | 
| 42 | 
         
            +
              switchNode: SwitchNode,
         
     | 
| 43 | 
         
            +
              generateNode: GenerateNode,
         
     | 
| 44 | 
         
            +
              retrievalNode: RetrievalNode,
         
     | 
| 45 | 
         
            +
              messageNode: MessageNode,
         
     | 
| 46 | 
         
            +
              rewriteNode: RewriteNode,
         
     | 
| 47 | 
         
            +
              keywordNode: KeywordNode,
         
     | 
| 48 | 
         
             
            };
         
     | 
| 49 | 
         | 
| 50 | 
         
             
            const edgeTypes = {
         
     | 
    	
        web/src/pages/flow/canvas/node/begin-node.tsx
    CHANGED
    
    | 
         @@ -1,25 +1,24 @@ 
     | 
|
| 1 | 
         
            -
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
             
            import { Flex } from 'antd';
         
     | 
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
            -
            import  
     | 
| 5 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 6 | 
         
             
            import { Operator, operatorMap } from '../../constant';
         
     | 
| 7 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 
         | 
|
| 
         | 
|
| 8 | 
         
             
            import styles from './index.less';
         
     | 
| 9 | 
         | 
| 10 | 
         
             
            // TODO: do not allow other nodes to connect to this node
         
     | 
| 11 | 
         
            -
            export function BeginNode({  
     | 
| 12 | 
         
            -
              const { t } =  
     | 
| 
         | 
|
| 13 | 
         
             
              return (
         
     | 
| 14 | 
         
             
                <section
         
     | 
| 15 | 
         
             
                  className={classNames(styles.ragNode, {
         
     | 
| 16 | 
         
             
                    [styles.selectedNode]: selected,
         
     | 
| 17 | 
         
             
                  })}
         
     | 
| 18 | 
         
             
                  style={{
         
     | 
| 19 | 
         
            -
                     
     | 
| 20 | 
         
            -
                    color: 'white',
         
     | 
| 21 | 
         
            -
                    width: 50,
         
     | 
| 22 | 
         
            -
                    height: 50,
         
     | 
| 23 | 
         
             
                  }}
         
     | 
| 24 | 
         
             
                >
         
     | 
| 25 | 
         
             
                  <Handle
         
     | 
| 
         @@ -27,13 +26,17 @@ export function BeginNode({ id, data, selected }: NodeProps<NodeData>) { 
     | 
|
| 27 | 
         
             
                    position={Position.Right}
         
     | 
| 28 | 
         
             
                    isConnectable
         
     | 
| 29 | 
         
             
                    className={styles.handle}
         
     | 
| 
         | 
|
| 30 | 
         
             
                  ></Handle>
         
     | 
| 31 | 
         
            -
             
     | 
| 32 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 33 | 
         
             
                  </Flex>
         
     | 
| 34 | 
         
            -
                  <section className={styles.bottomBox}>
         
     | 
| 35 | 
         
            -
                    <div className={styles.nodeName}>{data.name}</div>
         
     | 
| 36 | 
         
            -
                  </section>
         
     | 
| 37 | 
         
             
                </section>
         
     | 
| 38 | 
         
             
              );
         
     | 
| 39 | 
         
             
            }
         
     | 
| 
         | 
|
| 
         | 
|
| 1 | 
         
             
            import { Flex } from 'antd';
         
     | 
| 2 | 
         
             
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            +
            import { useTranslation } from 'react-i18next';
         
     | 
| 4 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 5 | 
         
             
            import { Operator, operatorMap } from '../../constant';
         
     | 
| 6 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 7 | 
         
            +
            import OperatorIcon from '../../operator-icon';
         
     | 
| 8 | 
         
            +
            import { RightHandleStyle } from './handle-icon';
         
     | 
| 9 | 
         
             
            import styles from './index.less';
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            // TODO: do not allow other nodes to connect to this node
         
     | 
| 12 | 
         
            +
            export function BeginNode({ selected, data }: NodeProps<NodeData>) {
         
     | 
| 13 | 
         
            +
              const { t } = useTranslation();
         
     | 
| 14 | 
         
            +
             
     | 
| 15 | 
         
             
              return (
         
     | 
| 16 | 
         
             
                <section
         
     | 
| 17 | 
         
             
                  className={classNames(styles.ragNode, {
         
     | 
| 18 | 
         
             
                    [styles.selectedNode]: selected,
         
     | 
| 19 | 
         
             
                  })}
         
     | 
| 20 | 
         
             
                  style={{
         
     | 
| 21 | 
         
            +
                    width: 100,
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 22 | 
         
             
                  }}
         
     | 
| 23 | 
         
             
                >
         
     | 
| 24 | 
         
             
                  <Handle
         
     | 
| 
         | 
|
| 26 | 
         
             
                    position={Position.Right}
         
     | 
| 27 | 
         
             
                    isConnectable
         
     | 
| 28 | 
         
             
                    className={styles.handle}
         
     | 
| 29 | 
         
            +
                    style={RightHandleStyle}
         
     | 
| 30 | 
         
             
                  ></Handle>
         
     | 
| 31 | 
         
            +
             
     | 
| 32 | 
         
            +
                  <Flex align="center" justify={'space-around'}>
         
     | 
| 33 | 
         
            +
                    <OperatorIcon
         
     | 
| 34 | 
         
            +
                      name={data.label as Operator}
         
     | 
| 35 | 
         
            +
                      fontSize={24}
         
     | 
| 36 | 
         
            +
                      color={operatorMap[data.label as Operator].color}
         
     | 
| 37 | 
         
            +
                    ></OperatorIcon>
         
     | 
| 38 | 
         
            +
                    <div className={styles.nodeTitle}>{t(`flow.begin`)}</div>
         
     | 
| 39 | 
         
             
                  </Flex>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 40 | 
         
             
                </section>
         
     | 
| 41 | 
         
             
              );
         
     | 
| 42 | 
         
             
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/categorize-node.tsx
    CHANGED
    
    | 
         @@ -1,22 +1,17 @@ 
     | 
|
| 1 | 
         
            -
            import  
     | 
| 2 | 
         
             
            import { Flex } from 'antd';
         
     | 
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
            -
            import  
     | 
| 5 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 6 | 
         
            -
            import { Operator, SwitchElseTo, operatorMap } from '../../constant';
         
     | 
| 7 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 8 | 
         
            -
            import  
     | 
| 9 | 
         
            -
            import CategorizeHandle from './categorize-handle';
         
     | 
| 10 | 
         
            -
            import NodeDropdown from './dropdown';
         
     | 
| 11 | 
         
             
            import { useBuildCategorizeHandlePositions } from './hooks';
         
     | 
| 12 | 
         
             
            import styles from './index.less';
         
     | 
| 
         | 
|
| 13 | 
         
             
            import NodePopover from './popover';
         
     | 
| 14 | 
         | 
| 15 | 
         
             
            export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
         
     | 
| 16 | 
         
            -
              const style = operatorMap[data.label as Operator];
         
     | 
| 17 | 
         
            -
              const { t } = useTranslate('flow');
         
     | 
| 18 | 
         
             
              const { positions } = useBuildCategorizeHandlePositions({ data, id });
         
     | 
| 19 | 
         
            -
              const operatorName = data.label;
         
     | 
| 20 | 
         | 
| 21 | 
         
             
              return (
         
     | 
| 22 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 
         @@ -24,10 +19,6 @@ export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) { 
     | 
|
| 24 | 
         
             
                    className={classNames(styles.logicNode, {
         
     | 
| 25 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 26 | 
         
             
                    })}
         
     | 
| 27 | 
         
            -
                    style={{
         
     | 
| 28 | 
         
            -
                      backgroundColor: style.backgroundColor,
         
     | 
| 29 | 
         
            -
                      color: style.color,
         
     | 
| 30 | 
         
            -
                    }}
         
     | 
| 31 | 
         
             
                  >
         
     | 
| 32 | 
         
             
                    <Handle
         
     | 
| 33 | 
         
             
                      type="target"
         
     | 
| 
         @@ -36,47 +27,35 @@ export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) { 
     | 
|
| 36 | 
         
             
                      className={styles.handle}
         
     | 
| 37 | 
         
             
                      id={'a'}
         
     | 
| 38 | 
         
             
                    ></Handle>
         
     | 
| 39 | 
         
            -
             
     | 
| 40 | 
         
            -
             
     | 
| 41 | 
         
            -
                       
     | 
| 42 | 
         
            -
                       
     | 
| 43 | 
         
            -
                       
     | 
| 44 | 
         
            -
                       
     | 
| 45 | 
         
            -
                    ></ 
     | 
| 46 | 
         
            -
             
     | 
| 47 | 
         
            -
             
     | 
| 48 | 
         
            -
                       
     | 
| 49 | 
         
            -
             
     | 
| 50 | 
         
            -
                       
     | 
| 51 | 
         
            -
                       
     | 
| 52 | 
         
            -
             
     | 
| 53 | 
         
            -
             
     | 
| 54 | 
         
            -
             
     | 
| 55 | 
         
            -
             
     | 
| 56 | 
         
            -
             
     | 
| 57 | 
         
            -
             
     | 
| 58 | 
         
            -
             
     | 
| 59 | 
         
            -
             
     | 
| 60 | 
         
            -
             
     | 
| 61 | 
         
            -
             
     | 
| 62 | 
         
            -
             
     | 
| 63 | 
         
            -
             
     | 
| 64 | 
         
            -
                           
     | 
| 65 | 
         
            -
             
     | 
| 66 | 
         
            -
             
     | 
| 67 | 
         
            -
                      );
         
     | 
| 68 | 
         
            -
                    })}
         
     | 
| 69 | 
         
            -
                    <Flex vertical align="center" justify="center" gap={6}>
         
     | 
| 70 | 
         
            -
                      <OperatorIcon
         
     | 
| 71 | 
         
            -
                        name={data.label as Operator}
         
     | 
| 72 | 
         
            -
                        fontSize={24}
         
     | 
| 73 | 
         
            -
                      ></OperatorIcon>
         
     | 
| 74 | 
         
            -
                      <span className={styles.type}>{t(lowerFirst(data.label))}</span>
         
     | 
| 75 | 
         
            -
                      <NodeDropdown id={id}></NodeDropdown>
         
     | 
| 76 | 
         
             
                    </Flex>
         
     | 
| 77 | 
         
            -
                    <section className={styles.bottomBox}>
         
     | 
| 78 | 
         
            -
                      <div className={styles.nodeName}>{data.name}</div>
         
     | 
| 79 | 
         
            -
                    </section>
         
     | 
| 80 | 
         
             
                  </section>
         
     | 
| 81 | 
         
             
                </NodePopover>
         
     | 
| 82 | 
         
             
              );
         
     | 
| 
         | 
|
| 1 | 
         
            +
            import LLMLabel from '@/components/llm-select/llm-label';
         
     | 
| 2 | 
         
             
            import { Flex } from 'antd';
         
     | 
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
            +
            import { get } from 'lodash';
         
     | 
| 5 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 
         | 
|
| 6 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 7 | 
         
            +
            import { RightHandleStyle } from './handle-icon';
         
     | 
| 
         | 
|
| 
         | 
|
| 8 | 
         
             
            import { useBuildCategorizeHandlePositions } from './hooks';
         
     | 
| 9 | 
         
             
            import styles from './index.less';
         
     | 
| 10 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 11 | 
         
             
            import NodePopover from './popover';
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
         
     | 
| 
         | 
|
| 
         | 
|
| 14 | 
         
             
              const { positions } = useBuildCategorizeHandlePositions({ data, id });
         
     | 
| 
         | 
|
| 15 | 
         | 
| 16 | 
         
             
              return (
         
     | 
| 17 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 
         | 
|
| 19 | 
         
             
                    className={classNames(styles.logicNode, {
         
     | 
| 20 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 21 | 
         
             
                    })}
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 22 | 
         
             
                  >
         
     | 
| 23 | 
         
             
                    <Handle
         
     | 
| 24 | 
         
             
                      type="target"
         
     | 
| 
         | 
|
| 27 | 
         
             
                      className={styles.handle}
         
     | 
| 28 | 
         
             
                      id={'a'}
         
     | 
| 29 | 
         
             
                    ></Handle>
         
     | 
| 30 | 
         
            +
             
     | 
| 31 | 
         
            +
                    <NodeHeader
         
     | 
| 32 | 
         
            +
                      id={id}
         
     | 
| 33 | 
         
            +
                      name={data.name}
         
     | 
| 34 | 
         
            +
                      label={data.label}
         
     | 
| 35 | 
         
            +
                      className={styles.nodeHeader}
         
     | 
| 36 | 
         
            +
                    ></NodeHeader>
         
     | 
| 37 | 
         
            +
             
     | 
| 38 | 
         
            +
                    <Flex vertical gap={8}>
         
     | 
| 39 | 
         
            +
                      <div className={styles.nodeText}>
         
     | 
| 40 | 
         
            +
                        <LLMLabel value={get(data, 'form.llm_id')}></LLMLabel>
         
     | 
| 41 | 
         
            +
                      </div>
         
     | 
| 42 | 
         
            +
                      {positions.map((position, idx) => {
         
     | 
| 43 | 
         
            +
                        return (
         
     | 
| 44 | 
         
            +
                          <div key={idx}>
         
     | 
| 45 | 
         
            +
                            <div className={styles.nodeText}>{position.text}</div>
         
     | 
| 46 | 
         
            +
                            <Handle
         
     | 
| 47 | 
         
            +
                              key={position.text}
         
     | 
| 48 | 
         
            +
                              id={position.text}
         
     | 
| 49 | 
         
            +
                              type="source"
         
     | 
| 50 | 
         
            +
                              position={Position.Right}
         
     | 
| 51 | 
         
            +
                              isConnectable
         
     | 
| 52 | 
         
            +
                              className={styles.handle}
         
     | 
| 53 | 
         
            +
                              style={{ ...RightHandleStyle, top: position.top }}
         
     | 
| 54 | 
         
            +
                            ></Handle>
         
     | 
| 55 | 
         
            +
                          </div>
         
     | 
| 56 | 
         
            +
                        );
         
     | 
| 57 | 
         
            +
                      })}
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 58 | 
         
             
                    </Flex>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 59 | 
         
             
                  </section>
         
     | 
| 60 | 
         
             
                </NodePopover>
         
     | 
| 61 | 
         
             
              );
         
     | 
    	
        web/src/pages/flow/canvas/node/dropdown.tsx
    CHANGED
    
    | 
         @@ -38,7 +38,7 @@ const NodeDropdown = ({ id, iconFontColor }: IProps) => { 
     | 
|
| 38 | 
         | 
| 39 | 
         
             
              return (
         
     | 
| 40 | 
         
             
                <OperateDropdown
         
     | 
| 41 | 
         
            -
                  iconFontSize={ 
     | 
| 42 | 
         
             
                  height={14}
         
     | 
| 43 | 
         
             
                  deleteItem={deleteNode}
         
     | 
| 44 | 
         
             
                  items={items}
         
     | 
| 
         | 
|
| 38 | 
         | 
| 39 | 
         
             
              return (
         
     | 
| 40 | 
         
             
                <OperateDropdown
         
     | 
| 41 | 
         
            +
                  iconFontSize={22}
         
     | 
| 42 | 
         
             
                  height={14}
         
     | 
| 43 | 
         
             
                  deleteItem={deleteNode}
         
     | 
| 44 | 
         
             
                  items={items}
         
     | 
    	
        web/src/pages/flow/canvas/node/generate-node.tsx
    ADDED
    
    | 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import LLMLabel from '@/components/llm-select/llm-label';
         
     | 
| 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';
         
     | 
| 7 | 
         
            +
            import { IGenerateParameter, NodeData } from '../../interface';
         
     | 
| 8 | 
         
            +
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         
     | 
| 9 | 
         
            +
            import styles from './index.less';
         
     | 
| 10 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 11 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
            export function GenerateNode({
         
     | 
| 14 | 
         
            +
              id,
         
     | 
| 15 | 
         
            +
              data,
         
     | 
| 16 | 
         
            +
              isConnectable = true,
         
     | 
| 17 | 
         
            +
              selected,
         
     | 
| 18 | 
         
            +
            }: NodeProps<NodeData>) {
         
     | 
| 19 | 
         
            +
              const parameters: IGenerateParameter[] = get(data, 'form.parameters', []);
         
     | 
| 20 | 
         
            +
              const getLabel = useGetComponentLabelByValue(id);
         
     | 
| 21 | 
         
            +
             
     | 
| 22 | 
         
            +
              return (
         
     | 
| 23 | 
         
            +
                <NodePopover nodeId={id}>
         
     | 
| 24 | 
         
            +
                  <section
         
     | 
| 25 | 
         
            +
                    className={classNames(styles.logicNode, {
         
     | 
| 26 | 
         
            +
                      [styles.selectedNode]: selected,
         
     | 
| 27 | 
         
            +
                    })}
         
     | 
| 28 | 
         
            +
                  >
         
     | 
| 29 | 
         
            +
                    <Handle
         
     | 
| 30 | 
         
            +
                      id="c"
         
     | 
| 31 | 
         
            +
                      type="source"
         
     | 
| 32 | 
         
            +
                      position={Position.Left}
         
     | 
| 33 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 34 | 
         
            +
                      className={styles.handle}
         
     | 
| 35 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 36 | 
         
            +
                    ></Handle>
         
     | 
| 37 | 
         
            +
                    <Handle
         
     | 
| 38 | 
         
            +
                      type="source"
         
     | 
| 39 | 
         
            +
                      position={Position.Right}
         
     | 
| 40 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 41 | 
         
            +
                      className={styles.handle}
         
     | 
| 42 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 43 | 
         
            +
                      id="b"
         
     | 
| 44 | 
         
            +
                    ></Handle>
         
     | 
| 45 | 
         
            +
             
     | 
| 46 | 
         
            +
                    <NodeHeader
         
     | 
| 47 | 
         
            +
                      id={id}
         
     | 
| 48 | 
         
            +
                      name={data.name}
         
     | 
| 49 | 
         
            +
                      label={data.label}
         
     | 
| 50 | 
         
            +
                      className={styles.nodeHeader}
         
     | 
| 51 | 
         
            +
                    ></NodeHeader>
         
     | 
| 52 | 
         
            +
             
     | 
| 53 | 
         
            +
                    <div className={styles.nodeText}>
         
     | 
| 54 | 
         
            +
                      <LLMLabel value={get(data, 'form.llm_id')}></LLMLabel>
         
     | 
| 55 | 
         
            +
                    </div>
         
     | 
| 56 | 
         
            +
                    <Flex gap={8} vertical className={styles.generateParameters}>
         
     | 
| 57 | 
         
            +
                      {parameters.map((x) => (
         
     | 
| 58 | 
         
            +
                        <Flex
         
     | 
| 59 | 
         
            +
                          key={x.id}
         
     | 
| 60 | 
         
            +
                          align="center"
         
     | 
| 61 | 
         
            +
                          gap={6}
         
     | 
| 62 | 
         
            +
                          className={styles.conditionBlock}
         
     | 
| 63 | 
         
            +
                        >
         
     | 
| 64 | 
         
            +
                          <label htmlFor="">{x.key}</label>
         
     | 
| 65 | 
         
            +
                          <span className={styles.parameterValue}>
         
     | 
| 66 | 
         
            +
                            {getLabel(x.component_id)}
         
     | 
| 67 | 
         
            +
                          </span>
         
     | 
| 68 | 
         
            +
                        </Flex>
         
     | 
| 69 | 
         
            +
                      ))}
         
     | 
| 70 | 
         
            +
                    </Flex>
         
     | 
| 71 | 
         
            +
                  </section>
         
     | 
| 72 | 
         
            +
                </NodePopover>
         
     | 
| 73 | 
         
            +
              );
         
     | 
| 74 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/handle-icon.tsx
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { PlusOutlined } from '@ant-design/icons';
         
     | 
| 2 | 
         
            +
            import { CSSProperties } from 'react';
         
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
            export const HandleIcon = () => {
         
     | 
| 5 | 
         
            +
              return (
         
     | 
| 6 | 
         
            +
                <PlusOutlined
         
     | 
| 7 | 
         
            +
                  style={{ fontSize: 6, color: 'white', position: 'absolute', zIndex: 10 }}
         
     | 
| 8 | 
         
            +
                />
         
     | 
| 9 | 
         
            +
              );
         
     | 
| 10 | 
         
            +
            };
         
     | 
| 11 | 
         
            +
             
     | 
| 12 | 
         
            +
            export const RightHandleStyle: CSSProperties = {
         
     | 
| 13 | 
         
            +
              right: -5,
         
     | 
| 14 | 
         
            +
            };
         
     | 
| 15 | 
         
            +
             
     | 
| 16 | 
         
            +
            export const LeftHandleStyle: CSSProperties = {
         
     | 
| 17 | 
         
            +
              left: -7,
         
     | 
| 18 | 
         
            +
            };
         
     | 
| 19 | 
         
            +
             
     | 
| 20 | 
         
            +
            export default HandleIcon;
         
     | 
    	
        web/src/pages/flow/canvas/node/hooks.ts
    CHANGED
    
    | 
         @@ -1,14 +1,13 @@ 
     | 
|
| 1 | 
         
             
            import get from 'lodash/get';
         
     | 
| 2 | 
         
            -
            import  
     | 
| 3 | 
         
            -
            import { useEffect, useMemo, useState } from 'react';
         
     | 
| 4 | 
         
             
            import { useUpdateNodeInternals } from 'reactflow';
         
     | 
| 5 | 
         
            -
            import {  
     | 
| 6 | 
         
            -
            import { IPosition, NodeData } from '../../interface';
         
     | 
| 7 | 
         
             
            import {
         
     | 
| 8 | 
         
            -
               
     | 
| 9 | 
         
            -
               
     | 
| 10 | 
         
            -
               
     | 
| 11 | 
         
            -
            } from '../../ 
     | 
| 
         | 
|
| 12 | 
         | 
| 13 | 
         
             
            export const useBuildCategorizeHandlePositions = ({
         
     | 
| 14 | 
         
             
              data,
         
     | 
| 
         @@ -17,85 +16,86 @@ export const useBuildCategorizeHandlePositions = ({ 
     | 
|
| 17 | 
         
             
              id: string;
         
     | 
| 18 | 
         
             
              data: NodeData;
         
     | 
| 19 | 
         
             
            }) => {
         
     | 
| 20 | 
         
            -
              const operatorName = data.label as Operator;
         
     | 
| 21 | 
         
             
              const updateNodeInternals = useUpdateNodeInternals();
         
     | 
| 22 | 
         
            -
              const [positionMap, setPositionMap] = useState<Record<string, IPosition>>({});
         
     | 
| 23 | 
         | 
| 24 | 
         
            -
              const categoryData = useMemo(() => {
         
     | 
| 25 | 
         
            -
                 
     | 
| 26 | 
         
            -
             
     | 
| 27 | 
         
            -
                } else if (operatorName === Operator.Switch) {
         
     | 
| 28 | 
         
            -
                  return get(data, 'form.conditions', []);
         
     | 
| 29 | 
         
            -
                }
         
     | 
| 30 | 
         
            -
                return {};
         
     | 
| 31 | 
         
            -
              }, [data, operatorName]);
         
     | 
| 32 | 
         | 
| 33 | 
         
             
              const positions = useMemo(() => {
         
     | 
| 34 | 
         
            -
                 
     | 
| 35 | 
         
            -
                   
     | 
| 36 | 
         
            -
             
     | 
| 37 | 
         
            -
             
     | 
| 38 | 
         
            -
             
     | 
| 39 | 
         
            -
                      text = generateSwitchHandleText(idx);
         
     | 
| 40 | 
         
            -
                    }
         
     | 
| 41 | 
         
            -
                    return { text, ...position };
         
     | 
| 42 | 
         
            -
                  })
         
     | 
| 43 | 
         
            -
                  .filter((x) => typeof x?.right === 'number');
         
     | 
| 44 | 
         
            -
              }, [categoryData, positionMap, operatorName]);
         
     | 
| 45 | 
         
            -
             
     | 
| 46 | 
         
            -
              useEffect(() => {
         
     | 
| 47 | 
         
            -
                // Cache used coordinates
         
     | 
| 48 | 
         
            -
                setPositionMap((state) => {
         
     | 
| 49 | 
         
            -
                  const categoryDataKeys = Object.keys(categoryData);
         
     | 
| 50 | 
         
            -
                  const stateKeys = Object.keys(state);
         
     | 
| 51 | 
         
            -
                  if (!isKeysEqual(categoryDataKeys, stateKeys)) {
         
     | 
| 52 | 
         
            -
                    const { newPositionMap, intersectionKeys } = buildNewPositionMap(
         
     | 
| 53 | 
         
            -
                      categoryDataKeys,
         
     | 
| 54 | 
         
            -
                      state,
         
     | 
| 55 | 
         
            -
                    );
         
     | 
| 56 | 
         
            -
             
     | 
| 57 | 
         
            -
                    const nextPositionMap = {
         
     | 
| 58 | 
         
            -
                      ...pick(state, intersectionKeys),
         
     | 
| 59 | 
         
            -
                      ...newPositionMap,
         
     | 
| 60 | 
         
            -
                    };
         
     | 
| 61 | 
         | 
| 62 | 
         
            -
             
     | 
| 63 | 
         
            -
                   
     | 
| 64 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 65 | 
         
             
                });
         
     | 
| 
         | 
|
| 
         | 
|
| 66 | 
         
             
              }, [categoryData]);
         
     | 
| 67 | 
         | 
| 68 | 
         
             
              useEffect(() => {
         
     | 
| 69 | 
         
             
                updateNodeInternals(id);
         
     | 
| 70 | 
         
            -
              }, [id, updateNodeInternals,  
     | 
| 71 | 
         | 
| 72 | 
         
             
              return { positions };
         
     | 
| 73 | 
         
             
            };
         
     | 
| 74 | 
         | 
| 75 | 
         
            -
             
     | 
| 76 | 
         
            -
             
     | 
| 77 | 
         
            -
             
     | 
| 78 | 
         
            -
             
     | 
| 79 | 
         
            -
             
     | 
| 80 | 
         
            -
             
     | 
| 81 | 
         
            -
             
     | 
| 82 | 
         
            -
             
     | 
| 83 | 
         
            -
            //   const conditions = useMemo(() => get(data, 'form.conditions', []), [data]);
         
     | 
| 84 | 
         
            -
            //   const updateNodeInternals = useUpdateNodeInternals();
         
     | 
| 85 | 
         | 
| 86 | 
         
            -
             
     | 
| 87 | 
         
            -
             
     | 
| 88 | 
         
            -
             
     | 
| 89 | 
         
            -
            //         const text = `Item ${idx}`;
         
     | 
| 90 | 
         
            -
            //         const position = positionMap[text];
         
     | 
| 91 | 
         
            -
            //         return { text: text, ...position };
         
     | 
| 92 | 
         
            -
            //       })
         
     | 
| 93 | 
         
            -
            //       .filter((x) => typeof x?.right === 'number');
         
     | 
| 94 | 
         
            -
            //   }, [conditions, positionMap]);
         
     | 
| 95 | 
         | 
| 96 | 
         
            -
             
     | 
| 97 | 
         
            -
             
     | 
| 98 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 99 | 
         | 
| 100 | 
         
            -
             
     | 
| 101 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
             
            import get from 'lodash/get';
         
     | 
| 2 | 
         
            +
            import { useEffect, useMemo } from 'react';
         
     | 
| 
         | 
|
| 3 | 
         
             
            import { useUpdateNodeInternals } from 'reactflow';
         
     | 
| 4 | 
         
            +
            import { SwitchElseTo } from '../../constant';
         
     | 
| 
         | 
|
| 5 | 
         
             
            import {
         
     | 
| 6 | 
         
            +
              ICategorizeItemResult,
         
     | 
| 7 | 
         
            +
              ISwitchCondition,
         
     | 
| 8 | 
         
            +
              NodeData,
         
     | 
| 9 | 
         
            +
            } from '../../interface';
         
     | 
| 10 | 
         
            +
            import { generateSwitchHandleText } from '../../utils';
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            export const useBuildCategorizeHandlePositions = ({
         
     | 
| 13 | 
         
             
              data,
         
     | 
| 
         | 
|
| 16 | 
         
             
              id: string;
         
     | 
| 17 | 
         
             
              data: NodeData;
         
     | 
| 18 | 
         
             
            }) => {
         
     | 
| 
         | 
|
| 19 | 
         
             
              const updateNodeInternals = useUpdateNodeInternals();
         
     | 
| 
         | 
|
| 20 | 
         | 
| 21 | 
         
            +
              const categoryData: ICategorizeItemResult = useMemo(() => {
         
     | 
| 22 | 
         
            +
                return get(data, `form.category_description`, {});
         
     | 
| 23 | 
         
            +
              }, [data]);
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 24 | 
         | 
| 25 | 
         
             
              const positions = useMemo(() => {
         
     | 
| 26 | 
         
            +
                const list: Array<{
         
     | 
| 27 | 
         
            +
                  text: string;
         
     | 
| 28 | 
         
            +
                  top: number;
         
     | 
| 29 | 
         
            +
                  idx: number;
         
     | 
| 30 | 
         
            +
                }> = [];
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 31 | 
         | 
| 32 | 
         
            +
                Object.keys(categoryData).forEach((x, idx) => {
         
     | 
| 33 | 
         
            +
                  list.push({
         
     | 
| 34 | 
         
            +
                    text: x,
         
     | 
| 35 | 
         
            +
                    idx,
         
     | 
| 36 | 
         
            +
                    top: idx === 0 ? 98 : list[idx - 1].top + 8 + 26,
         
     | 
| 37 | 
         
            +
                  });
         
     | 
| 38 | 
         
             
                });
         
     | 
| 39 | 
         
            +
             
     | 
| 40 | 
         
            +
                return list;
         
     | 
| 41 | 
         
             
              }, [categoryData]);
         
     | 
| 42 | 
         | 
| 43 | 
         
             
              useEffect(() => {
         
     | 
| 44 | 
         
             
                updateNodeInternals(id);
         
     | 
| 45 | 
         
            +
              }, [id, updateNodeInternals, categoryData]);
         
     | 
| 46 | 
         | 
| 47 | 
         
             
              return { positions };
         
     | 
| 48 | 
         
             
            };
         
     | 
| 49 | 
         | 
| 50 | 
         
            +
            export const useBuildSwitchHandlePositions = ({
         
     | 
| 51 | 
         
            +
              data,
         
     | 
| 52 | 
         
            +
              id,
         
     | 
| 53 | 
         
            +
            }: {
         
     | 
| 54 | 
         
            +
              id: string;
         
     | 
| 55 | 
         
            +
              data: NodeData;
         
     | 
| 56 | 
         
            +
            }) => {
         
     | 
| 57 | 
         
            +
              const updateNodeInternals = useUpdateNodeInternals();
         
     | 
| 
         | 
|
| 
         | 
|
| 58 | 
         | 
| 59 | 
         
            +
              const conditions: ISwitchCondition[] = useMemo(() => {
         
     | 
| 60 | 
         
            +
                return get(data, 'form.conditions', []);
         
     | 
| 61 | 
         
            +
              }, [data]);
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 62 | 
         | 
| 63 | 
         
            +
              const positions = useMemo(() => {
         
     | 
| 64 | 
         
            +
                const list: Array<{
         
     | 
| 65 | 
         
            +
                  text: string;
         
     | 
| 66 | 
         
            +
                  top: number;
         
     | 
| 67 | 
         
            +
                  idx: number;
         
     | 
| 68 | 
         
            +
                  condition?: ISwitchCondition;
         
     | 
| 69 | 
         
            +
                }> = [];
         
     | 
| 70 | 
         
            +
             
     | 
| 71 | 
         
            +
                [...conditions, ''].forEach((x, idx) => {
         
     | 
| 72 | 
         
            +
                  let top = idx === 0 ? 58 : list[idx - 1].top + 32; // case number (Case 1) height + flex gap
         
     | 
| 73 | 
         
            +
                  if (idx - 1 >= 0) {
         
     | 
| 74 | 
         
            +
                    const previousItems = conditions[idx - 1]?.items ?? [];
         
     | 
| 75 | 
         
            +
                    if (previousItems.length > 0) {
         
     | 
| 76 | 
         
            +
                      top += 12; // ConditionBlock padding
         
     | 
| 77 | 
         
            +
                      top += previousItems.length * 22; // condition variable height
         
     | 
| 78 | 
         
            +
                      top += (previousItems.length - 1) * 25; // operator height
         
     | 
| 79 | 
         
            +
                    }
         
     | 
| 80 | 
         
            +
                  }
         
     | 
| 81 | 
         
            +
             
     | 
| 82 | 
         
            +
                  list.push({
         
     | 
| 83 | 
         
            +
                    text:
         
     | 
| 84 | 
         
            +
                      idx < conditions.length
         
     | 
| 85 | 
         
            +
                        ? generateSwitchHandleText(idx)
         
     | 
| 86 | 
         
            +
                        : SwitchElseTo,
         
     | 
| 87 | 
         
            +
                    idx,
         
     | 
| 88 | 
         
            +
                    top,
         
     | 
| 89 | 
         
            +
                    condition: typeof x === 'string' ? undefined : x,
         
     | 
| 90 | 
         
            +
                  });
         
     | 
| 91 | 
         
            +
                });
         
     | 
| 92 | 
         | 
| 93 | 
         
            +
                return list;
         
     | 
| 94 | 
         
            +
              }, [conditions]);
         
     | 
| 95 | 
         
            +
             
     | 
| 96 | 
         
            +
              useEffect(() => {
         
     | 
| 97 | 
         
            +
                updateNodeInternals(id);
         
     | 
| 98 | 
         
            +
              }, [id, updateNodeInternals, conditions]);
         
     | 
| 99 | 
         
            +
             
     | 
| 100 | 
         
            +
              return { positions };
         
     | 
| 101 | 
         
            +
            };
         
     | 
    	
        web/src/pages/flow/canvas/node/index.less
    CHANGED
    
    | 
         @@ -3,22 +3,16 @@ 
     | 
|
| 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 | 
         | 
| 8 | 
         
             
            .ragNode {
         
     | 
| 9 | 
         
            -
              position: relative;
         
     | 
| 10 | 
         
             
              .commonNode();
         
     | 
| 11 | 
         | 
| 12 | 
         
            -
              padding: 5px;
         
     | 
| 13 | 
         
            -
              border-radius: 5px;
         
     | 
| 14 | 
         
            -
              background: white;
         
     | 
| 15 | 
         
            -
              width: 50px;
         
     | 
| 16 | 
         
            -
              height: 50px;
         
     | 
| 17 | 
         
            -
              border-radius: 50%;
         
     | 
| 18 | 
         
            -
              display: flex;
         
     | 
| 19 | 
         
            -
              // align-items: center;
         
     | 
| 20 | 
         
            -
              // justify-self: center;
         
     | 
| 21 | 
         
            -
              justify-content: center;
         
     | 
| 22 | 
         
             
              .nodeName {
         
     | 
| 23 | 
         
             
                font-size: 10px;
         
     | 
| 24 | 
         
             
                color: black;
         
     | 
| 
         @@ -28,23 +22,10 @@ 
     | 
|
| 28 | 
         
             
                color: #777;
         
     | 
| 29 | 
         
             
                font-size: 12px;
         
     | 
| 30 | 
         
             
              }
         
     | 
| 31 | 
         
            -
              .type {
         
     | 
| 32 | 
         
            -
                // font-size: 12px;
         
     | 
| 33 | 
         
            -
              }
         
     | 
| 34 | 
         
             
              .description {
         
     | 
| 35 | 
         
             
                font-size: 10px;
         
     | 
| 36 | 
         
             
              }
         
     | 
| 37 | 
         
            -
             
     | 
| 38 | 
         
            -
                position: absolute;
         
     | 
| 39 | 
         
            -
                bottom: -34px;
         
     | 
| 40 | 
         
            -
                background: white;
         
     | 
| 41 | 
         
            -
                padding: 2px 5px;
         
     | 
| 42 | 
         
            -
                border-radius: 5px;
         
     | 
| 43 | 
         
            -
                box-shadow:
         
     | 
| 44 | 
         
            -
                  -6px 0 12px 0 rgba(179, 177, 177, 0.08),
         
     | 
| 45 | 
         
            -
                  -3px 0 6px -4px rgba(0, 0, 0, 0.12),
         
     | 
| 46 | 
         
            -
                  -6px 0 16px 6px rgba(0, 0, 0, 0.05);
         
     | 
| 47 | 
         
            -
              }
         
     | 
| 48 | 
         
             
              .categorizeAnchorPointText {
         
     | 
| 49 | 
         
             
                position: absolute;
         
     | 
| 50 | 
         
             
                top: -4px;
         
     | 
| 
         @@ -53,14 +34,25 @@ 
     | 
|
| 53 | 
         
             
              }
         
     | 
| 54 | 
         
             
            }
         
     | 
| 55 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 56 | 
         
             
            .selectedNode {
         
     | 
| 57 | 
         
            -
              border:  
     | 
| 58 | 
         
             
            }
         
     | 
| 59 | 
         | 
| 60 | 
         
             
            .handle {
         
     | 
| 61 | 
         
             
              display: inline-flex;
         
     | 
| 62 | 
         
            -
               
     | 
| 63 | 
         
            -
               
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 64 | 
         
             
            }
         
     | 
| 65 | 
         | 
| 66 | 
         
             
            .jsonView {
         
     | 
| 
         @@ -71,19 +63,8 @@ 
     | 
|
| 71 | 
         
             
            }
         
     | 
| 72 | 
         | 
| 73 | 
         
             
            .logicNode {
         
     | 
| 74 | 
         
            -
              position: relative;
         
     | 
| 75 | 
         
             
              .commonNode();
         
     | 
| 76 | 
         | 
| 77 | 
         
            -
              padding: 5px;
         
     | 
| 78 | 
         
            -
              border-radius: 5px;
         
     | 
| 79 | 
         
            -
              background: white;
         
     | 
| 80 | 
         
            -
              width: 100px;
         
     | 
| 81 | 
         
            -
              height: 100px;
         
     | 
| 82 | 
         
            -
              border-radius: 50%;
         
     | 
| 83 | 
         
            -
              display: flex;
         
     | 
| 84 | 
         
            -
              // align-items: center;
         
     | 
| 85 | 
         
            -
              // justify-self: center;
         
     | 
| 86 | 
         
            -
              justify-content: center;
         
     | 
| 87 | 
         
             
              .nodeName {
         
     | 
| 88 | 
         
             
                font-size: 10px;
         
     | 
| 89 | 
         
             
                color: black;
         
     | 
| 
         @@ -93,41 +74,122 @@ 
     | 
|
| 93 | 
         
             
                color: #777;
         
     | 
| 94 | 
         
             
                font-size: 12px;
         
     | 
| 95 | 
         
             
              }
         
     | 
| 96 | 
         
            -
             
     | 
| 97 | 
         
            -
                // font-size: 12px;
         
     | 
| 98 | 
         
            -
              }
         
     | 
| 99 | 
         
             
              .description {
         
     | 
| 100 | 
         
             
                font-size: 10px;
         
     | 
| 101 | 
         
             
              }
         
     | 
| 102 | 
         
            -
             
     | 
| 103 | 
         
            -
                position: absolute;
         
     | 
| 104 | 
         
            -
                bottom: -34px;
         
     | 
| 105 | 
         
            -
                background: white;
         
     | 
| 106 | 
         
            -
                padding: 2px 5px;
         
     | 
| 107 | 
         
            -
                border-radius: 5px;
         
     | 
| 108 | 
         
            -
                box-shadow:
         
     | 
| 109 | 
         
            -
                  -6px 0 12px 0 rgba(179, 177, 177, 0.08),
         
     | 
| 110 | 
         
            -
                  -3px 0 6px -4px rgba(0, 0, 0, 0.12),
         
     | 
| 111 | 
         
            -
                  -6px 0 16px 6px rgba(0, 0, 0, 0.05);
         
     | 
| 112 | 
         
            -
              }
         
     | 
| 113 | 
         
             
              .categorizeAnchorPointText {
         
     | 
| 114 | 
         
             
                position: absolute;
         
     | 
| 115 | 
         
             
                top: -4px;
         
     | 
| 116 | 
         
             
                left: 8px;
         
     | 
| 117 | 
         
             
                white-space: nowrap;
         
     | 
| 118 | 
         
             
              }
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 119 | 
         
             
            }
         
     | 
| 120 | 
         | 
| 121 | 
         
             
            .noteNode {
         
     | 
| 122 | 
         
             
              .commonNode();
         
     | 
| 123 | 
         
            -
              width: 140px;
         
     | 
| 124 | 
         
            -
               
     | 
| 
         | 
|
| 
         | 
|
| 125 | 
         
             
              border-radius: 10px;
         
     | 
| 126 | 
         
            -
               
     | 
| 127 | 
         
             
              .noteTitle {
         
     | 
| 
         | 
|
| 128 | 
         
             
                font-size: 12px;
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 129 | 
         
             
              }
         
     | 
| 130 | 
         
             
              .noteForm {
         
     | 
| 131 | 
         
             
                margin-top: 4px;
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 132 | 
         
             
              }
         
     | 
| 133 | 
         
             
            }
         
     | 
| 
         | 
|
| 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 | 
         
             
            .ragNode {
         
     | 
| 
         | 
|
| 14 | 
         
             
              .commonNode();
         
     | 
| 15 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 16 | 
         
             
              .nodeName {
         
     | 
| 17 | 
         
             
                font-size: 10px;
         
     | 
| 18 | 
         
             
                color: black;
         
     | 
| 
         | 
|
| 22 | 
         
             
                color: #777;
         
     | 
| 23 | 
         
             
                font-size: 12px;
         
     | 
| 24 | 
         
             
              }
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 25 | 
         
             
              .description {
         
     | 
| 26 | 
         
             
                font-size: 10px;
         
     | 
| 27 | 
         
             
              }
         
     | 
| 28 | 
         
            +
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 29 | 
         
             
              .categorizeAnchorPointText {
         
     | 
| 30 | 
         
             
                position: absolute;
         
     | 
| 31 | 
         
             
                top: -4px;
         
     | 
| 
         | 
|
| 34 | 
         
             
              }
         
     | 
| 35 | 
         
             
            }
         
     | 
| 36 | 
         | 
| 37 | 
         
            +
            @lightBackgroundColor: rgba(150, 150, 150, 0.1);
         
     | 
| 38 | 
         
            +
            @darkBackgroundColor: rgba(150, 150, 150, 0.2);
         
     | 
| 39 | 
         
            +
             
     | 
| 40 | 
         
             
            .selectedNode {
         
     | 
| 41 | 
         
            +
              border: 1.5px solid rgb(59, 118, 244);
         
     | 
| 42 | 
         
             
            }
         
     | 
| 43 | 
         | 
| 44 | 
         
             
            .handle {
         
     | 
| 45 | 
         
             
              display: inline-flex;
         
     | 
| 46 | 
         
            +
              align-items: center;
         
     | 
| 47 | 
         
            +
              justify-content: center;
         
     | 
| 48 | 
         
            +
              width: 12px;
         
     | 
| 49 | 
         
            +
              height: 12px;
         
     | 
| 50 | 
         
            +
              background: rgb(59, 88, 253);
         
     | 
| 51 | 
         
            +
              border: 1px solid white;
         
     | 
| 52 | 
         
            +
              z-index: 1;
         
     | 
| 53 | 
         
            +
              background-image: url('@/assets/svg/plus.svg');
         
     | 
| 54 | 
         
            +
              background-size: cover;
         
     | 
| 55 | 
         
            +
              background-position: center;
         
     | 
| 56 | 
         
             
            }
         
     | 
| 57 | 
         | 
| 58 | 
         
             
            .jsonView {
         
     | 
| 
         | 
|
| 63 | 
         
             
            }
         
     | 
| 64 | 
         | 
| 65 | 
         
             
            .logicNode {
         
     | 
| 
         | 
|
| 66 | 
         
             
              .commonNode();
         
     | 
| 67 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 68 | 
         
             
              .nodeName {
         
     | 
| 69 | 
         
             
                font-size: 10px;
         
     | 
| 70 | 
         
             
                color: black;
         
     | 
| 
         | 
|
| 74 | 
         
             
                color: #777;
         
     | 
| 75 | 
         
             
                font-size: 12px;
         
     | 
| 76 | 
         
             
              }
         
     | 
| 77 | 
         
            +
             
     | 
| 
         | 
|
| 
         | 
|
| 78 | 
         
             
              .description {
         
     | 
| 79 | 
         
             
                font-size: 10px;
         
     | 
| 80 | 
         
             
              }
         
     | 
| 81 | 
         
            +
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 82 | 
         
             
              .categorizeAnchorPointText {
         
     | 
| 83 | 
         
             
                position: absolute;
         
     | 
| 84 | 
         
             
                top: -4px;
         
     | 
| 85 | 
         
             
                left: 8px;
         
     | 
| 86 | 
         
             
                white-space: nowrap;
         
     | 
| 87 | 
         
             
              }
         
     | 
| 88 | 
         
            +
              .relevantSourceLabel {
         
     | 
| 89 | 
         
            +
                font-size: 10px;
         
     | 
| 90 | 
         
            +
              }
         
     | 
| 91 | 
         
             
            }
         
     | 
| 92 | 
         | 
| 93 | 
         
             
            .noteNode {
         
     | 
| 94 | 
         
             
              .commonNode();
         
     | 
| 95 | 
         
            +
              min-width: 140px;
         
     | 
| 96 | 
         
            +
              width: auto;
         
     | 
| 97 | 
         
            +
              height: 100%;
         
     | 
| 98 | 
         
            +
              padding: 0;
         
     | 
| 99 | 
         
             
              border-radius: 10px;
         
     | 
| 100 | 
         
            +
              min-height: 128px;
         
     | 
| 101 | 
         
             
              .noteTitle {
         
     | 
| 102 | 
         
            +
                background-color: #edfcff;
         
     | 
| 103 | 
         
             
                font-size: 12px;
         
     | 
| 104 | 
         
            +
                padding: 6px 6px 4px;
         
     | 
| 105 | 
         
            +
                border-top-left-radius: 10px;
         
     | 
| 106 | 
         
            +
                border-top-right-radius: 10px;
         
     | 
| 107 | 
         
             
              }
         
     | 
| 108 | 
         
             
              .noteForm {
         
     | 
| 109 | 
         
             
                margin-top: 4px;
         
     | 
| 110 | 
         
            +
                height: calc(100% - 50px);
         
     | 
| 111 | 
         
            +
              }
         
     | 
| 112 | 
         
            +
              .noteName {
         
     | 
| 113 | 
         
            +
                padding: 0px 4px;
         
     | 
| 114 | 
         
            +
              }
         
     | 
| 115 | 
         
            +
              .noteTextarea {
         
     | 
| 116 | 
         
            +
                resize: none;
         
     | 
| 117 | 
         
            +
                border: 0;
         
     | 
| 118 | 
         
            +
                border-radius: 0;
         
     | 
| 119 | 
         
            +
                height: 100%;
         
     | 
| 120 | 
         
            +
                &:focus {
         
     | 
| 121 | 
         
            +
                  border: none;
         
     | 
| 122 | 
         
            +
                  box-shadow: none;
         
     | 
| 123 | 
         
            +
                }
         
     | 
| 124 | 
         
            +
              }
         
     | 
| 125 | 
         
            +
            }
         
     | 
| 126 | 
         
            +
             
     | 
| 127 | 
         
            +
            .nodeText {
         
     | 
| 128 | 
         
            +
              padding-inline: 0.4em;
         
     | 
| 129 | 
         
            +
              padding-block: 0.2em 0.1em;
         
     | 
| 130 | 
         
            +
              background: @lightBackgroundColor;
         
     | 
| 131 | 
         
            +
              border-radius: 3px;
         
     | 
| 132 | 
         
            +
              min-height: 22px;
         
     | 
| 133 | 
         
            +
              .textEllipsis();
         
     | 
| 134 | 
         
            +
            }
         
     | 
| 135 | 
         
            +
             
     | 
| 136 | 
         
            +
            .nodeTitle {
         
     | 
| 137 | 
         
            +
              font-weight: 600;
         
     | 
| 138 | 
         
            +
              text-align: center;
         
     | 
| 139 | 
         
            +
              .textEllipsis();
         
     | 
| 140 | 
         
            +
            }
         
     | 
| 141 | 
         
            +
             
     | 
| 142 | 
         
            +
            .nodeHeader {
         
     | 
| 143 | 
         
            +
              padding-bottom: 12px;
         
     | 
| 144 | 
         
            +
            }
         
     | 
| 145 | 
         
            +
             
     | 
| 146 | 
         
            +
            .zeroDivider {
         
     | 
| 147 | 
         
            +
              margin: 0 !important;
         
     | 
| 148 | 
         
            +
            }
         
     | 
| 149 | 
         
            +
             
     | 
| 150 | 
         
            +
            .conditionBlock {
         
     | 
| 151 | 
         
            +
              border-radius: 4px;
         
     | 
| 152 | 
         
            +
              padding: 6px;
         
     | 
| 153 | 
         
            +
              background: @lightBackgroundColor;
         
     | 
| 154 | 
         
            +
            }
         
     | 
| 155 | 
         
            +
             
     | 
| 156 | 
         
            +
            .conditionLine {
         
     | 
| 157 | 
         
            +
              border-radius: 4px;
         
     | 
| 158 | 
         
            +
              padding: 0 4px;
         
     | 
| 159 | 
         
            +
              background: @darkBackgroundColor;
         
     | 
| 160 | 
         
            +
              .textEllipsis();
         
     | 
| 161 | 
         
            +
            }
         
     | 
| 162 | 
         
            +
             
     | 
| 163 | 
         
            +
            .conditionKey {
         
     | 
| 164 | 
         
            +
              flex: 1;
         
     | 
| 165 | 
         
            +
            }
         
     | 
| 166 | 
         
            +
             
     | 
| 167 | 
         
            +
            .conditionOperator {
         
     | 
| 168 | 
         
            +
              padding: 0 2px;
         
     | 
| 169 | 
         
            +
              text-align: center;
         
     | 
| 170 | 
         
            +
            }
         
     | 
| 171 | 
         
            +
             
     | 
| 172 | 
         
            +
            .relevantLabel {
         
     | 
| 173 | 
         
            +
              text-align: right;
         
     | 
| 174 | 
         
            +
            }
         
     | 
| 175 | 
         
            +
             
     | 
| 176 | 
         
            +
            .knowledgeNodeName {
         
     | 
| 177 | 
         
            +
              .textEllipsis();
         
     | 
| 178 | 
         
            +
            }
         
     | 
| 179 | 
         
            +
             
     | 
| 180 | 
         
            +
            .messageNodeContainer {
         
     | 
| 181 | 
         
            +
              overflow-y: auto;
         
     | 
| 182 | 
         
            +
              max-height: 300px;
         
     | 
| 183 | 
         
            +
            }
         
     | 
| 184 | 
         
            +
             
     | 
| 185 | 
         
            +
            .generateParameters {
         
     | 
| 186 | 
         
            +
              padding-top: 8px;
         
     | 
| 187 | 
         
            +
              label {
         
     | 
| 188 | 
         
            +
                flex: 2;
         
     | 
| 189 | 
         
            +
                .textEllipsis();
         
     | 
| 190 | 
         
            +
              }
         
     | 
| 191 | 
         
            +
              .parameterValue {
         
     | 
| 192 | 
         
            +
                flex: 3;
         
     | 
| 193 | 
         
            +
                .conditionLine;
         
     | 
| 194 | 
         
             
              }
         
     | 
| 195 | 
         
             
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/index.tsx
    CHANGED
    
    | 
         @@ -1,12 +1,9 @@ 
     | 
|
| 1 | 
         
            -
            import { Flex } from 'antd';
         
     | 
| 2 | 
         
             
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            -
            import pick from 'lodash/pick';
         
     | 
| 4 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 5 | 
         
            -
            import { Operator, operatorMap } from '../../constant';
         
     | 
| 6 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 7 | 
         
            -
            import  
     | 
| 8 | 
         
            -
            import NodeDropdown from './dropdown';
         
     | 
| 9 | 
         
             
            import styles from './index.less';
         
     | 
| 
         | 
|
| 10 | 
         
             
            import NodePopover from './popover';
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            export function RagNode({
         
     | 
| 
         @@ -15,17 +12,12 @@ export function RagNode({ 
     | 
|
| 15 | 
         
             
              isConnectable = true,
         
     | 
| 16 | 
         
             
              selected,
         
     | 
| 17 | 
         
             
            }: NodeProps<NodeData>) {
         
     | 
| 18 | 
         
            -
              const style = operatorMap[data.label as Operator];
         
     | 
| 19 | 
         
            -
             
     | 
| 20 | 
         
             
              return (
         
     | 
| 21 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 22 | 
         
             
                  <section
         
     | 
| 23 | 
         
             
                    className={classNames(styles.ragNode, {
         
     | 
| 24 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 25 | 
         
             
                    })}
         
     | 
| 26 | 
         
            -
                    style={{
         
     | 
| 27 | 
         
            -
                      ...pick(style, ['backgroundColor', 'color']),
         
     | 
| 28 | 
         
            -
                    }}
         
     | 
| 29 | 
         
             
                  >
         
     | 
| 30 | 
         
             
                    <Handle
         
     | 
| 31 | 
         
             
                      id="c"
         
     | 
| 
         @@ -33,39 +25,17 @@ export function RagNode({ 
     | 
|
| 33 | 
         
             
                      position={Position.Left}
         
     | 
| 34 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 35 | 
         
             
                      className={styles.handle}
         
     | 
| 
         | 
|
| 36 | 
         
             
                    ></Handle>
         
     | 
| 37 | 
         
            -
                    <Handle type="source" position={Position.Top} id="d" isConnectable />
         
     | 
| 38 | 
         
             
                    <Handle
         
     | 
| 39 | 
         
             
                      type="source"
         
     | 
| 40 | 
         
             
                      position={Position.Right}
         
     | 
| 41 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 42 | 
         
             
                      className={styles.handle}
         
     | 
| 43 | 
         
             
                      id="b"
         
     | 
| 
         | 
|
| 44 | 
         
             
                    ></Handle>
         
     | 
| 45 | 
         
            -
                    < 
     | 
| 46 | 
         
            -
                    <Flex vertical align="center" justify={'space-around'}>
         
     | 
| 47 | 
         
            -
                      <Flex flex={1} justify="center" align="center">
         
     | 
| 48 | 
         
            -
                        <label htmlFor=""> </label>
         
     | 
| 49 | 
         
            -
                      </Flex>
         
     | 
| 50 | 
         
            -
             
     | 
| 51 | 
         
            -
                      <Flex flex={1}>
         
     | 
| 52 | 
         
            -
                        <OperatorIcon
         
     | 
| 53 | 
         
            -
                          name={data.label as Operator}
         
     | 
| 54 | 
         
            -
                          fontSize={style?.iconFontSize ?? 16}
         
     | 
| 55 | 
         
            -
                          width={style?.iconWidth}
         
     | 
| 56 | 
         
            -
                        ></OperatorIcon>
         
     | 
| 57 | 
         
            -
                      </Flex>
         
     | 
| 58 | 
         
            -
                      <Flex flex={1}>
         
     | 
| 59 | 
         
            -
                        <NodeDropdown
         
     | 
| 60 | 
         
            -
                          id={id}
         
     | 
| 61 | 
         
            -
                          iconFontColor={style?.moreIconColor}
         
     | 
| 62 | 
         
            -
                        ></NodeDropdown>
         
     | 
| 63 | 
         
            -
                      </Flex>
         
     | 
| 64 | 
         
            -
                    </Flex>
         
     | 
| 65 | 
         
            -
             
     | 
| 66 | 
         
            -
                    <section className={styles.bottomBox}>
         
     | 
| 67 | 
         
            -
                      <div className={styles.nodeName}>{data.name}</div>
         
     | 
| 68 | 
         
            -
                    </section>
         
     | 
| 69 | 
         
             
                  </section>
         
     | 
| 70 | 
         
             
                </NodePopover>
         
     | 
| 71 | 
         
             
              );
         
     | 
| 
         | 
|
| 
         | 
|
| 1 | 
         
             
            import classNames from 'classnames';
         
     | 
| 
         | 
|
| 2 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 
         | 
|
| 3 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 4 | 
         
            +
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         
     | 
| 
         | 
|
| 5 | 
         
             
            import styles from './index.less';
         
     | 
| 6 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 7 | 
         
             
            import NodePopover from './popover';
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            export function RagNode({
         
     | 
| 
         | 
|
| 12 | 
         
             
              isConnectable = true,
         
     | 
| 13 | 
         
             
              selected,
         
     | 
| 14 | 
         
             
            }: NodeProps<NodeData>) {
         
     | 
| 
         | 
|
| 
         | 
|
| 15 | 
         
             
              return (
         
     | 
| 16 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 17 | 
         
             
                  <section
         
     | 
| 18 | 
         
             
                    className={classNames(styles.ragNode, {
         
     | 
| 19 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 20 | 
         
             
                    })}
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 21 | 
         
             
                  >
         
     | 
| 22 | 
         
             
                    <Handle
         
     | 
| 23 | 
         
             
                      id="c"
         
     | 
| 
         | 
|
| 25 | 
         
             
                      position={Position.Left}
         
     | 
| 26 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 27 | 
         
             
                      className={styles.handle}
         
     | 
| 28 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 29 | 
         
             
                    ></Handle>
         
     | 
| 
         | 
|
| 30 | 
         
             
                    <Handle
         
     | 
| 31 | 
         
             
                      type="source"
         
     | 
| 32 | 
         
             
                      position={Position.Right}
         
     | 
| 33 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 34 | 
         
             
                      className={styles.handle}
         
     | 
| 35 | 
         
             
                      id="b"
         
     | 
| 36 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 37 | 
         
             
                    ></Handle>
         
     | 
| 38 | 
         
            +
                    <NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 39 | 
         
             
                  </section>
         
     | 
| 40 | 
         
             
                </NodePopover>
         
     | 
| 41 | 
         
             
              );
         
     | 
    	
        web/src/pages/flow/canvas/node/keyword-node.tsx
    ADDED
    
    | 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import LLMLabel from '@/components/llm-select/llm-label';
         
     | 
| 2 | 
         
            +
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            +
            import { get } from 'lodash';
         
     | 
| 4 | 
         
            +
            import { Handle, NodeProps, 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 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 10 | 
         
            +
             
     | 
| 11 | 
         
            +
            export function KeywordNode({
         
     | 
| 12 | 
         
            +
              id,
         
     | 
| 13 | 
         
            +
              data,
         
     | 
| 14 | 
         
            +
              isConnectable = true,
         
     | 
| 15 | 
         
            +
              selected,
         
     | 
| 16 | 
         
            +
            }: NodeProps<NodeData>) {
         
     | 
| 17 | 
         
            +
              return (
         
     | 
| 18 | 
         
            +
                <NodePopover nodeId={id}>
         
     | 
| 19 | 
         
            +
                  <section
         
     | 
| 20 | 
         
            +
                    className={classNames(styles.logicNode, {
         
     | 
| 21 | 
         
            +
                      [styles.selectedNode]: selected,
         
     | 
| 22 | 
         
            +
                    })}
         
     | 
| 23 | 
         
            +
                  >
         
     | 
| 24 | 
         
            +
                    <Handle
         
     | 
| 25 | 
         
            +
                      id="c"
         
     | 
| 26 | 
         
            +
                      type="source"
         
     | 
| 27 | 
         
            +
                      position={Position.Left}
         
     | 
| 28 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 29 | 
         
            +
                      className={styles.handle}
         
     | 
| 30 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 31 | 
         
            +
                    ></Handle>
         
     | 
| 32 | 
         
            +
                    <Handle
         
     | 
| 33 | 
         
            +
                      type="source"
         
     | 
| 34 | 
         
            +
                      position={Position.Right}
         
     | 
| 35 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 36 | 
         
            +
                      className={styles.handle}
         
     | 
| 37 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 38 | 
         
            +
                      id="b"
         
     | 
| 39 | 
         
            +
                    ></Handle>
         
     | 
| 40 | 
         
            +
             
     | 
| 41 | 
         
            +
                    <NodeHeader
         
     | 
| 42 | 
         
            +
                      id={id}
         
     | 
| 43 | 
         
            +
                      name={data.name}
         
     | 
| 44 | 
         
            +
                      label={data.label}
         
     | 
| 45 | 
         
            +
                      className={styles.nodeHeader}
         
     | 
| 46 | 
         
            +
                    ></NodeHeader>
         
     | 
| 47 | 
         
            +
             
     | 
| 48 | 
         
            +
                    <div className={styles.nodeText}>
         
     | 
| 49 | 
         
            +
                      <LLMLabel value={get(data, 'form.llm_id')}></LLMLabel>
         
     | 
| 50 | 
         
            +
                    </div>
         
     | 
| 51 | 
         
            +
                  </section>
         
     | 
| 52 | 
         
            +
                </NodePopover>
         
     | 
| 53 | 
         
            +
              );
         
     | 
| 54 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/logic-node.tsx
    CHANGED
    
    | 
         @@ -1,38 +1,23 @@ 
     | 
|
| 1 | 
         
            -
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
            -
            import { Flex } from 'antd';
         
     | 
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
            -
            import lowerFirst from 'lodash/lowerFirst';
         
     | 
| 5 | 
         
            -
            import pick from 'lodash/pick';
         
     | 
| 6 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 7 | 
         
            -
            import { Operator, operatorMap } from '../../constant';
         
     | 
| 8 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 9 | 
         
            -
            import  
     | 
| 10 | 
         
            -
            import NodeDropdown from './dropdown';
         
     | 
| 11 | 
         
             
            import styles from './index.less';
         
     | 
| 
         | 
|
| 12 | 
         
             
            import NodePopover from './popover';
         
     | 
| 13 | 
         | 
| 14 | 
         
            -
            const ZeroGapOperators = [
         
     | 
| 15 | 
         
            -
              Operator.RewriteQuestion,
         
     | 
| 16 | 
         
            -
              Operator.KeywordExtract,
         
     | 
| 17 | 
         
            -
              Operator.ArXiv,
         
     | 
| 18 | 
         
            -
            ];
         
     | 
| 19 | 
         
            -
             
     | 
| 20 | 
         
             
            export function LogicNode({
         
     | 
| 21 | 
         
             
              id,
         
     | 
| 22 | 
         
             
              data,
         
     | 
| 23 | 
         
             
              isConnectable = true,
         
     | 
| 24 | 
         
             
              selected,
         
     | 
| 25 | 
         
             
            }: NodeProps<NodeData>) {
         
     | 
| 26 | 
         
            -
              const style = operatorMap[data.label as Operator];
         
     | 
| 27 | 
         
            -
              const { t } = useTranslate('flow');
         
     | 
| 28 | 
         
            -
             
     | 
| 29 | 
         
             
              return (
         
     | 
| 30 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 31 | 
         
             
                  <section
         
     | 
| 32 | 
         
             
                    className={classNames(styles.logicNode, {
         
     | 
| 33 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 34 | 
         
             
                    })}
         
     | 
| 35 | 
         
            -
                    style={pick(style, ['backgroundColor', 'width', 'height', 'color'])}
         
     | 
| 36 | 
         
             
                  >
         
     | 
| 37 | 
         
             
                    <Handle
         
     | 
| 38 | 
         
             
                      id="c"
         
     | 
| 
         @@ -40,49 +25,17 @@ export function LogicNode({ 
     | 
|
| 40 | 
         
             
                      position={Position.Left}
         
     | 
| 41 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 42 | 
         
             
                      className={styles.handle}
         
     | 
| 
         | 
|
| 43 | 
         
             
                    ></Handle>
         
     | 
| 44 | 
         
            -
                    <Handle type="source" position={Position.Top} id="d" isConnectable />
         
     | 
| 45 | 
         
             
                    <Handle
         
     | 
| 46 | 
         
             
                      type="source"
         
     | 
| 47 | 
         
             
                      position={Position.Right}
         
     | 
| 48 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 49 | 
         
             
                      className={styles.handle}
         
     | 
| 
         | 
|
| 50 | 
         
             
                      id="b"
         
     | 
| 51 | 
         
             
                    ></Handle>
         
     | 
| 52 | 
         
            -
                    < 
     | 
| 53 | 
         
            -
                    <Flex
         
     | 
| 54 | 
         
            -
                      vertical
         
     | 
| 55 | 
         
            -
                      align="center"
         
     | 
| 56 | 
         
            -
                      justify={'space-around'}
         
     | 
| 57 | 
         
            -
                      gap={ZeroGapOperators.some((x) => x === data.label) ? 0 : 6}
         
     | 
| 58 | 
         
            -
                    >
         
     | 
| 59 | 
         
            -
                      <Flex flex={1} justify="center" align="center">
         
     | 
| 60 | 
         
            -
                        <OperatorIcon
         
     | 
| 61 | 
         
            -
                          name={data.label as Operator}
         
     | 
| 62 | 
         
            -
                          fontSize={style?.iconFontSize ?? 24}
         
     | 
| 63 | 
         
            -
                          width={style?.iconWidth}
         
     | 
| 64 | 
         
            -
                        ></OperatorIcon>
         
     | 
| 65 | 
         
            -
                      </Flex>
         
     | 
| 66 | 
         
            -
             
     | 
| 67 | 
         
            -
                      <Flex flex={1}>
         
     | 
| 68 | 
         
            -
                        <span
         
     | 
| 69 | 
         
            -
                          className={styles.type}
         
     | 
| 70 | 
         
            -
                          style={{ fontSize: style?.fontSize ?? 14 }}
         
     | 
| 71 | 
         
            -
                        >
         
     | 
| 72 | 
         
            -
                          {t(lowerFirst(data.label))}
         
     | 
| 73 | 
         
            -
                        </span>
         
     | 
| 74 | 
         
            -
                      </Flex>
         
     | 
| 75 | 
         
            -
                      <Flex flex={1}>
         
     | 
| 76 | 
         
            -
                        <NodeDropdown
         
     | 
| 77 | 
         
            -
                          id={id}
         
     | 
| 78 | 
         
            -
                          iconFontColor={style?.moreIconColor}
         
     | 
| 79 | 
         
            -
                        ></NodeDropdown>
         
     | 
| 80 | 
         
            -
                      </Flex>
         
     | 
| 81 | 
         
            -
                    </Flex>
         
     | 
| 82 | 
         
            -
             
     | 
| 83 | 
         
            -
                    <section className={styles.bottomBox}>
         
     | 
| 84 | 
         
            -
                      <div className={styles.nodeName}>{data.name}</div>
         
     | 
| 85 | 
         
            -
                    </section>
         
     | 
| 86 | 
         
             
                  </section>
         
     | 
| 87 | 
         
             
                </NodePopover>
         
     | 
| 88 | 
         
             
              );
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 1 | 
         
             
            import classNames from 'classnames';
         
     | 
| 
         | 
|
| 
         | 
|
| 2 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 
         | 
|
| 3 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 4 | 
         
            +
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         
     | 
| 
         | 
|
| 5 | 
         
             
            import styles from './index.less';
         
     | 
| 6 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 7 | 
         
             
            import NodePopover from './popover';
         
     | 
| 8 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 9 | 
         
             
            export function LogicNode({
         
     | 
| 10 | 
         
             
              id,
         
     | 
| 11 | 
         
             
              data,
         
     | 
| 12 | 
         
             
              isConnectable = true,
         
     | 
| 13 | 
         
             
              selected,
         
     | 
| 14 | 
         
             
            }: NodeProps<NodeData>) {
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 15 | 
         
             
              return (
         
     | 
| 16 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 17 | 
         
             
                  <section
         
     | 
| 18 | 
         
             
                    className={classNames(styles.logicNode, {
         
     | 
| 19 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 20 | 
         
             
                    })}
         
     | 
| 
         | 
|
| 21 | 
         
             
                  >
         
     | 
| 22 | 
         
             
                    <Handle
         
     | 
| 23 | 
         
             
                      id="c"
         
     | 
| 
         | 
|
| 25 | 
         
             
                      position={Position.Left}
         
     | 
| 26 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 27 | 
         
             
                      className={styles.handle}
         
     | 
| 28 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 29 | 
         
             
                    ></Handle>
         
     | 
| 
         | 
|
| 30 | 
         
             
                    <Handle
         
     | 
| 31 | 
         
             
                      type="source"
         
     | 
| 32 | 
         
             
                      position={Position.Right}
         
     | 
| 33 | 
         
             
                      isConnectable={isConnectable}
         
     | 
| 34 | 
         
             
                      className={styles.handle}
         
     | 
| 35 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 36 | 
         
             
                      id="b"
         
     | 
| 37 | 
         
             
                    ></Handle>
         
     | 
| 38 | 
         
            +
                    <NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 39 | 
         
             
                  </section>
         
     | 
| 40 | 
         
             
                </NodePopover>
         
     | 
| 41 | 
         
             
              );
         
     | 
    	
        web/src/pages/flow/canvas/node/message-node.tsx
    ADDED
    
    | 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { Flex } from 'antd';
         
     | 
| 2 | 
         
            +
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            +
            import { get } from 'lodash';
         
     | 
| 4 | 
         
            +
            import { Handle, NodeProps, 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 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 10 | 
         
            +
             
     | 
| 11 | 
         
            +
            export function MessageNode({
         
     | 
| 12 | 
         
            +
              id,
         
     | 
| 13 | 
         
            +
              data,
         
     | 
| 14 | 
         
            +
              isConnectable = true,
         
     | 
| 15 | 
         
            +
              selected,
         
     | 
| 16 | 
         
            +
            }: NodeProps<NodeData>) {
         
     | 
| 17 | 
         
            +
              const messages: string[] = get(data, 'form.messages', []);
         
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
              return (
         
     | 
| 20 | 
         
            +
                <NodePopover nodeId={id}>
         
     | 
| 21 | 
         
            +
                  <section
         
     | 
| 22 | 
         
            +
                    className={classNames(styles.logicNode, {
         
     | 
| 23 | 
         
            +
                      [styles.selectedNode]: selected,
         
     | 
| 24 | 
         
            +
                    })}
         
     | 
| 25 | 
         
            +
                  >
         
     | 
| 26 | 
         
            +
                    <Handle
         
     | 
| 27 | 
         
            +
                      id="c"
         
     | 
| 28 | 
         
            +
                      type="source"
         
     | 
| 29 | 
         
            +
                      position={Position.Left}
         
     | 
| 30 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 31 | 
         
            +
                      className={styles.handle}
         
     | 
| 32 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 33 | 
         
            +
                    ></Handle>
         
     | 
| 34 | 
         
            +
                    <Handle
         
     | 
| 35 | 
         
            +
                      type="source"
         
     | 
| 36 | 
         
            +
                      position={Position.Right}
         
     | 
| 37 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 38 | 
         
            +
                      className={styles.handle}
         
     | 
| 39 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 40 | 
         
            +
                      id="b"
         
     | 
| 41 | 
         
            +
                    ></Handle>
         
     | 
| 42 | 
         
            +
                    <NodeHeader
         
     | 
| 43 | 
         
            +
                      id={id}
         
     | 
| 44 | 
         
            +
                      name={data.name}
         
     | 
| 45 | 
         
            +
                      label={data.label}
         
     | 
| 46 | 
         
            +
                      className={classNames({
         
     | 
| 47 | 
         
            +
                        [styles.nodeHeader]: messages.length > 0,
         
     | 
| 48 | 
         
            +
                      })}
         
     | 
| 49 | 
         
            +
                    ></NodeHeader>
         
     | 
| 50 | 
         
            +
             
     | 
| 51 | 
         
            +
                    <Flex vertical gap={8} className={styles.messageNodeContainer}>
         
     | 
| 52 | 
         
            +
                      {messages.map((message, idx) => {
         
     | 
| 53 | 
         
            +
                        return (
         
     | 
| 54 | 
         
            +
                          <div className={styles.nodeText} key={idx}>
         
     | 
| 55 | 
         
            +
                            {message}
         
     | 
| 56 | 
         
            +
                          </div>
         
     | 
| 57 | 
         
            +
                        );
         
     | 
| 58 | 
         
            +
                      })}
         
     | 
| 59 | 
         
            +
                    </Flex>
         
     | 
| 60 | 
         
            +
                  </section>
         
     | 
| 61 | 
         
            +
                </NodePopover>
         
     | 
| 62 | 
         
            +
              );
         
     | 
| 63 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/node-header.tsx
    ADDED
    
    | 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { Flex } from 'antd';
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            import { Operator, operatorMap } from '../../constant';
         
     | 
| 4 | 
         
            +
            import OperatorIcon from '../../operator-icon';
         
     | 
| 5 | 
         
            +
            import NodeDropdown from './dropdown';
         
     | 
| 6 | 
         
            +
            import styles from './index.less';
         
     | 
| 7 | 
         
            +
             
     | 
| 8 | 
         
            +
            interface IProps {
         
     | 
| 9 | 
         
            +
              id: string;
         
     | 
| 10 | 
         
            +
              label: string;
         
     | 
| 11 | 
         
            +
              name: string;
         
     | 
| 12 | 
         
            +
              gap?: number;
         
     | 
| 13 | 
         
            +
              className?: string;
         
     | 
| 14 | 
         
            +
            }
         
     | 
| 15 | 
         
            +
             
     | 
| 16 | 
         
            +
            const NodeHeader = ({ label, id, name, gap = 4, className }: IProps) => {
         
     | 
| 17 | 
         
            +
              return (
         
     | 
| 18 | 
         
            +
                <Flex
         
     | 
| 19 | 
         
            +
                  flex={1}
         
     | 
| 20 | 
         
            +
                  align="center"
         
     | 
| 21 | 
         
            +
                  justify={'space-between'}
         
     | 
| 22 | 
         
            +
                  gap={gap}
         
     | 
| 23 | 
         
            +
                  className={className}
         
     | 
| 24 | 
         
            +
                >
         
     | 
| 25 | 
         
            +
                  <OperatorIcon
         
     | 
| 26 | 
         
            +
                    name={label as Operator}
         
     | 
| 27 | 
         
            +
                    color={operatorMap[label as Operator].color}
         
     | 
| 28 | 
         
            +
                  ></OperatorIcon>
         
     | 
| 29 | 
         
            +
                  <span className={styles.nodeTitle}>{name}</span>
         
     | 
| 30 | 
         
            +
                  <NodeDropdown id={id}></NodeDropdown>
         
     | 
| 31 | 
         
            +
                </Flex>
         
     | 
| 32 | 
         
            +
              );
         
     | 
| 33 | 
         
            +
            };
         
     | 
| 34 | 
         
            +
             
     | 
| 35 | 
         
            +
            export default NodeHeader;
         
     | 
    	
        web/src/pages/flow/canvas/node/note-node.tsx
    CHANGED
    
    | 
         @@ -1,20 +1,33 @@ 
     | 
|
| 1 | 
         
            -
            import { Flex, Form, Input 
     | 
| 2 | 
         
            -
            import  
     | 
| 
         | 
|
| 3 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 4 | 
         
             
            import NodeDropdown from './dropdown';
         
     | 
| 5 | 
         | 
| 6 | 
         
             
            import SvgIcon from '@/components/svg-icon';
         
     | 
| 7 | 
         
            -
            import { useEffect } from 'react';
         
     | 
| 8 | 
         
             
            import { useTranslation } from 'react-i18next';
         
     | 
| 9 | 
         
            -
            import { 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 10 | 
         
             
            import styles from './index.less';
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            const { TextArea } = Input;
         
     | 
| 13 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 14 | 
         
             
            function NoteNode({ data, id }: NodeProps<NodeData>) {
         
     | 
| 15 | 
         
             
              const { t } = useTranslation();
         
     | 
| 16 | 
         
             
              const [form] = Form.useForm();
         
     | 
| 17 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 18 | 
         
             
              const { handleValuesChange } = useHandleFormValuesChange(id);
         
     | 
| 19 | 
         | 
| 20 | 
         
             
              useEffect(() => {
         
     | 
| 
         @@ -22,25 +35,51 @@ function NoteNode({ data, id }: NodeProps<NodeData>) { 
     | 
|
| 22 | 
         
             
              }, [form, data?.form]);
         
     | 
| 23 | 
         | 
| 24 | 
         
             
              return (
         
     | 
| 25 | 
         
            -
                 
     | 
| 26 | 
         
            -
                  < 
     | 
| 27 | 
         
            -
                    < 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 28 | 
         
             
                      <SvgIcon name="note" width={14}></SvgIcon>
         
     | 
| 29 | 
         
            -
                      < 
     | 
| 30 | 
         
            -
             
     | 
| 31 | 
         
            -
             
     | 
| 32 | 
         
            -
             
     | 
| 33 | 
         
            -
             
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
             
     | 
| 36 | 
         
            -
                     
     | 
| 37 | 
         
            -
             
     | 
| 38 | 
         
            -
             
     | 
| 39 | 
         
            -
                       
     | 
| 40 | 
         
            -
             
     | 
| 41 | 
         
            -
             
     | 
| 42 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 43 | 
         
             
              );
         
     | 
| 44 | 
         
             
            }
         
     | 
| 45 | 
         | 
| 46 | 
         
            -
            export default NoteNode;
         
     | 
| 
         | 
|
| 1 | 
         
            +
            import { Flex, Form, Input } from 'antd';
         
     | 
| 2 | 
         
            +
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            +
            import { NodeProps, NodeResizeControl } from 'reactflow';
         
     | 
| 4 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 5 | 
         
             
            import NodeDropdown from './dropdown';
         
     | 
| 6 | 
         | 
| 7 | 
         
             
            import SvgIcon from '@/components/svg-icon';
         
     | 
| 8 | 
         
            +
            import { memo, useEffect } from 'react';
         
     | 
| 9 | 
         
             
            import { useTranslation } from 'react-i18next';
         
     | 
| 10 | 
         
            +
            import {
         
     | 
| 11 | 
         
            +
              useHandleFormValuesChange,
         
     | 
| 12 | 
         
            +
              useHandleNodeNameChange,
         
     | 
| 13 | 
         
            +
            } from '../../hooks';
         
     | 
| 14 | 
         
             
            import styles from './index.less';
         
     | 
| 15 | 
         | 
| 16 | 
         
             
            const { TextArea } = Input;
         
     | 
| 17 | 
         | 
| 18 | 
         
            +
            const controlStyle = {
         
     | 
| 19 | 
         
            +
              background: 'transparent',
         
     | 
| 20 | 
         
            +
              border: 'none',
         
     | 
| 21 | 
         
            +
            };
         
     | 
| 22 | 
         
            +
             
     | 
| 23 | 
         
             
            function NoteNode({ data, id }: NodeProps<NodeData>) {
         
     | 
| 24 | 
         
             
              const { t } = useTranslation();
         
     | 
| 25 | 
         
             
              const [form] = Form.useForm();
         
     | 
| 26 | 
         | 
| 27 | 
         
            +
              const { name, handleNameBlur, handleNameChange } = useHandleNodeNameChange({
         
     | 
| 28 | 
         
            +
                id,
         
     | 
| 29 | 
         
            +
                data,
         
     | 
| 30 | 
         
            +
              });
         
     | 
| 31 | 
         
             
              const { handleValuesChange } = useHandleFormValuesChange(id);
         
     | 
| 32 | 
         | 
| 33 | 
         
             
              useEffect(() => {
         
     | 
| 
         | 
|
| 35 | 
         
             
              }, [form, data?.form]);
         
     | 
| 36 | 
         | 
| 37 | 
         
             
              return (
         
     | 
| 38 | 
         
            +
                <>
         
     | 
| 39 | 
         
            +
                  <NodeResizeControl style={controlStyle} minWidth={190} minHeight={128}>
         
     | 
| 40 | 
         
            +
                    <SvgIcon
         
     | 
| 41 | 
         
            +
                      name="resize"
         
     | 
| 42 | 
         
            +
                      width={12}
         
     | 
| 43 | 
         
            +
                      style={{
         
     | 
| 44 | 
         
            +
                        position: 'absolute',
         
     | 
| 45 | 
         
            +
                        right: 5,
         
     | 
| 46 | 
         
            +
                        bottom: 5,
         
     | 
| 47 | 
         
            +
                        cursor: 'nwse-resize',
         
     | 
| 48 | 
         
            +
                      }}
         
     | 
| 49 | 
         
            +
                    ></SvgIcon>
         
     | 
| 50 | 
         
            +
                  </NodeResizeControl>
         
     | 
| 51 | 
         
            +
                  <section className={styles.noteNode}>
         
     | 
| 52 | 
         
            +
                    <Flex
         
     | 
| 53 | 
         
            +
                      justify={'space-between'}
         
     | 
| 54 | 
         
            +
                      className={classNames(styles.noteTitle, 'note-drag-handle')}
         
     | 
| 55 | 
         
            +
                      align="center"
         
     | 
| 56 | 
         
            +
                      gap={6}
         
     | 
| 57 | 
         
            +
                    >
         
     | 
| 58 | 
         
             
                      <SvgIcon name="note" width={14}></SvgIcon>
         
     | 
| 59 | 
         
            +
                      <Input
         
     | 
| 60 | 
         
            +
                        value={name ?? t('flow.note')}
         
     | 
| 61 | 
         
            +
                        onBlur={handleNameBlur}
         
     | 
| 62 | 
         
            +
                        onChange={handleNameChange}
         
     | 
| 63 | 
         
            +
                        className={styles.noteName}
         
     | 
| 64 | 
         
            +
                      ></Input>
         
     | 
| 65 | 
         
            +
                      <NodeDropdown id={id}></NodeDropdown>
         
     | 
| 66 | 
         
            +
                    </Flex>
         
     | 
| 67 | 
         
            +
                    <Form
         
     | 
| 68 | 
         
            +
                      onValuesChange={handleValuesChange}
         
     | 
| 69 | 
         
            +
                      form={form}
         
     | 
| 70 | 
         
            +
                      className={styles.noteForm}
         
     | 
| 71 | 
         
            +
                    >
         
     | 
| 72 | 
         
            +
                      <Form.Item name="text" noStyle>
         
     | 
| 73 | 
         
            +
                        <TextArea
         
     | 
| 74 | 
         
            +
                          rows={3}
         
     | 
| 75 | 
         
            +
                          placeholder={t('flow.notePlaceholder')}
         
     | 
| 76 | 
         
            +
                          className={styles.noteTextarea}
         
     | 
| 77 | 
         
            +
                        />
         
     | 
| 78 | 
         
            +
                      </Form.Item>
         
     | 
| 79 | 
         
            +
                    </Form>
         
     | 
| 80 | 
         
            +
                  </section>
         
     | 
| 81 | 
         
            +
                </>
         
     | 
| 82 | 
         
             
              );
         
     | 
| 83 | 
         
             
            }
         
     | 
| 84 | 
         | 
| 85 | 
         
            +
            export default memo(NoteNode);
         
     | 
    	
        web/src/pages/flow/canvas/node/relevant-node.tsx
    CHANGED
    
    | 
         @@ -1,28 +1,23 @@ 
     | 
|
| 1 | 
         
            -
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
             
            import { Flex } from 'antd';
         
     | 
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
            -
            import lowerFirst from 'lodash/lowerFirst';
         
     | 
| 5 | 
         
            -
            import pick from 'lodash/pick';
         
     | 
| 6 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 7 | 
         
            -
            import { Operator, operatorMap } from '../../constant';
         
     | 
| 8 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 9 | 
         
            -
            import  
     | 
| 10 | 
         
            -
            import  
     | 
| 11 | 
         | 
| 12 | 
         
            -
            import  
     | 
| 13 | 
         
             
            import styles from './index.less';
         
     | 
| 14 | 
         
            -
            import  
     | 
| 15 | 
         | 
| 16 | 
         
             
            export function RelevantNode({ id, data, selected }: NodeProps<NodeData>) {
         
     | 
| 17 | 
         
            -
              const  
     | 
| 18 | 
         
            -
              const  
     | 
| 19 | 
         
             
              return (
         
     | 
| 20 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 21 | 
         
             
                  <section
         
     | 
| 22 | 
         
             
                    className={classNames(styles.logicNode, {
         
     | 
| 23 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 24 | 
         
             
                    })}
         
     | 
| 25 | 
         
            -
                    style={pick(style, ['backgroundColor', 'width', 'height', 'color'])}
         
     | 
| 26 | 
         
             
                  >
         
     | 
| 27 | 
         
             
                    <Handle
         
     | 
| 28 | 
         
             
                      type="target"
         
     | 
| 
         @@ -32,43 +27,38 @@ export function RelevantNode({ id, data, selected }: NodeProps<NodeData>) { 
     | 
|
| 32 | 
         
             
                      id={'a'}
         
     | 
| 33 | 
         
             
                    ></Handle>
         
     | 
| 34 | 
         
             
                    <Handle
         
     | 
| 35 | 
         
            -
                      type=" 
     | 
| 36 | 
         
            -
                      position={Position. 
     | 
| 37 | 
         
             
                      isConnectable
         
     | 
| 38 | 
         
             
                      className={styles.handle}
         
     | 
| 39 | 
         
            -
                      id={' 
     | 
| 
         | 
|
| 40 | 
         
             
                    ></Handle>
         
     | 
| 41 | 
         
             
                    <Handle
         
     | 
| 42 | 
         
            -
                      type=" 
     | 
| 43 | 
         
            -
                      position={Position. 
     | 
| 44 | 
         
             
                      isConnectable
         
     | 
| 45 | 
         
             
                      className={styles.handle}
         
     | 
| 46 | 
         
            -
                      id={' 
     | 
| 
         | 
|
| 47 | 
         
             
                    ></Handle>
         
     | 
| 48 | 
         
            -
                    < 
     | 
| 49 | 
         
            -
             
     | 
| 50 | 
         
            -
             
     | 
| 51 | 
         
            -
                       
     | 
| 52 | 
         
            -
             
     | 
| 53 | 
         
            -
             
     | 
| 54 | 
         
            -
             
     | 
| 55 | 
         
            -
             
     | 
| 56 | 
         
            -
                       
     | 
| 57 | 
         
            -
             
     | 
| 58 | 
         
            -
                        < 
     | 
| 59 | 
         
            -
                          className={styles.type}
         
     | 
| 60 | 
         
            -
                          style={{ fontSize: style.fontSize ?? 14 }}
         
     | 
| 61 | 
         
            -
                        >
         
     | 
| 62 | 
         
            -
                          {t(lowerFirst(data.label))}
         
     | 
| 63 | 
         
            -
                        </span>
         
     | 
| 64 | 
         
             
                      </Flex>
         
     | 
| 65 | 
         
            -
                      <Flex  
     | 
| 66 | 
         
            -
                        < 
     | 
| 
         | 
|
| 67 | 
         
             
                      </Flex>
         
     | 
| 68 | 
         
             
                    </Flex>
         
     | 
| 69 | 
         
            -
                    <section className={styles.bottomBox}>
         
     | 
| 70 | 
         
            -
                      <div className={styles.nodeName}>{data.name}</div>
         
     | 
| 71 | 
         
            -
                    </section>
         
     | 
| 72 | 
         
             
                  </section>
         
     | 
| 73 | 
         
             
                </NodePopover>
         
     | 
| 74 | 
         
             
              );
         
     | 
| 
         | 
|
| 
         | 
|
| 1 | 
         
             
            import { Flex } from 'antd';
         
     | 
| 2 | 
         
             
            import classNames from 'classnames';
         
     | 
| 
         | 
|
| 
         | 
|
| 3 | 
         
             
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 
         | 
|
| 4 | 
         
             
            import { NodeData } from '../../interface';
         
     | 
| 5 | 
         
            +
            import { RightHandleStyle } from './handle-icon';
         
     | 
| 6 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 7 | 
         | 
| 8 | 
         
            +
            import { get } from 'lodash';
         
     | 
| 9 | 
         
             
            import styles from './index.less';
         
     | 
| 10 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            export function RelevantNode({ id, data, selected }: NodeProps<NodeData>) {
         
     | 
| 13 | 
         
            +
              const yes = get(data, 'form.yes');
         
     | 
| 14 | 
         
            +
              const no = get(data, 'form.no');
         
     | 
| 15 | 
         
             
              return (
         
     | 
| 16 | 
         
             
                <NodePopover nodeId={id}>
         
     | 
| 17 | 
         
             
                  <section
         
     | 
| 18 | 
         
             
                    className={classNames(styles.logicNode, {
         
     | 
| 19 | 
         
             
                      [styles.selectedNode]: selected,
         
     | 
| 20 | 
         
             
                    })}
         
     | 
| 
         | 
|
| 21 | 
         
             
                  >
         
     | 
| 22 | 
         
             
                    <Handle
         
     | 
| 23 | 
         
             
                      type="target"
         
     | 
| 
         | 
|
| 27 | 
         
             
                      id={'a'}
         
     | 
| 28 | 
         
             
                    ></Handle>
         
     | 
| 29 | 
         
             
                    <Handle
         
     | 
| 30 | 
         
            +
                      type="source"
         
     | 
| 31 | 
         
            +
                      position={Position.Right}
         
     | 
| 32 | 
         
             
                      isConnectable
         
     | 
| 33 | 
         
             
                      className={styles.handle}
         
     | 
| 34 | 
         
            +
                      id={'yes'}
         
     | 
| 35 | 
         
            +
                      style={{ ...RightHandleStyle, top: 59 }}
         
     | 
| 36 | 
         
             
                    ></Handle>
         
     | 
| 37 | 
         
             
                    <Handle
         
     | 
| 38 | 
         
            +
                      type="source"
         
     | 
| 39 | 
         
            +
                      position={Position.Right}
         
     | 
| 40 | 
         
             
                      isConnectable
         
     | 
| 41 | 
         
             
                      className={styles.handle}
         
     | 
| 42 | 
         
            +
                      id={'no'}
         
     | 
| 43 | 
         
            +
                      style={{ ...RightHandleStyle, top: 112 }}
         
     | 
| 44 | 
         
             
                    ></Handle>
         
     | 
| 45 | 
         
            +
                    <NodeHeader
         
     | 
| 46 | 
         
            +
                      id={id}
         
     | 
| 47 | 
         
            +
                      name={data.name}
         
     | 
| 48 | 
         
            +
                      label={data.label}
         
     | 
| 49 | 
         
            +
                      className={styles.nodeHeader}
         
     | 
| 50 | 
         
            +
                    ></NodeHeader>
         
     | 
| 51 | 
         
            +
             
     | 
| 52 | 
         
            +
                    <Flex vertical gap={10}>
         
     | 
| 53 | 
         
            +
                      <Flex vertical>
         
     | 
| 54 | 
         
            +
                        <div className={styles.relevantLabel}>Yes</div>
         
     | 
| 55 | 
         
            +
                        <div className={styles.nodeText}>{yes}</div>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 56 | 
         
             
                      </Flex>
         
     | 
| 57 | 
         
            +
                      <Flex vertical>
         
     | 
| 58 | 
         
            +
                        <div className={styles.relevantLabel}>No</div>
         
     | 
| 59 | 
         
            +
                        <div className={styles.nodeText}>{no}</div>
         
     | 
| 60 | 
         
             
                      </Flex>
         
     | 
| 61 | 
         
             
                    </Flex>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 62 | 
         
             
                  </section>
         
     | 
| 63 | 
         
             
                </NodePopover>
         
     | 
| 64 | 
         
             
              );
         
     | 
    	
        web/src/pages/flow/canvas/node/retrieval-node.tsx
    ADDED
    
    | 
         @@ -0,0 +1,85 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks';
         
     | 
| 2 | 
         
            +
            import { UserOutlined } from '@ant-design/icons';
         
     | 
| 3 | 
         
            +
            import { Avatar, Flex } from 'antd';
         
     | 
| 4 | 
         
            +
            import classNames from 'classnames';
         
     | 
| 5 | 
         
            +
            import { get } from 'lodash';
         
     | 
| 6 | 
         
            +
            import { useMemo } from 'react';
         
     | 
| 7 | 
         
            +
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 8 | 
         
            +
            import { NodeData } from '../../interface';
         
     | 
| 9 | 
         
            +
            import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
         
     | 
| 10 | 
         
            +
            import styles from './index.less';
         
     | 
| 11 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 12 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
            export function RetrievalNode({
         
     | 
| 15 | 
         
            +
              id,
         
     | 
| 16 | 
         
            +
              data,
         
     | 
| 17 | 
         
            +
              isConnectable = true,
         
     | 
| 18 | 
         
            +
              selected,
         
     | 
| 19 | 
         
            +
            }: NodeProps<NodeData>) {
         
     | 
| 20 | 
         
            +
              const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []);
         
     | 
| 21 | 
         
            +
              const { list: knowledgeList } = useNextFetchKnowledgeList(true);
         
     | 
| 22 | 
         
            +
              const knowledgeBases = useMemo(() => {
         
     | 
| 23 | 
         
            +
                return knowledgeBaseIds.map((x) => {
         
     | 
| 24 | 
         
            +
                  const item = knowledgeList.find((y) => x === y.id);
         
     | 
| 25 | 
         
            +
                  return {
         
     | 
| 26 | 
         
            +
                    name: item?.name,
         
     | 
| 27 | 
         
            +
                    avatar: item?.avatar,
         
     | 
| 28 | 
         
            +
                    id: x,
         
     | 
| 29 | 
         
            +
                  };
         
     | 
| 30 | 
         
            +
                });
         
     | 
| 31 | 
         
            +
              }, [knowledgeList, knowledgeBaseIds]);
         
     | 
| 32 | 
         
            +
             
     | 
| 33 | 
         
            +
              return (
         
     | 
| 34 | 
         
            +
                <NodePopover nodeId={id}>
         
     | 
| 35 | 
         
            +
                  <section
         
     | 
| 36 | 
         
            +
                    className={classNames(styles.logicNode, {
         
     | 
| 37 | 
         
            +
                      [styles.selectedNode]: selected,
         
     | 
| 38 | 
         
            +
                    })}
         
     | 
| 39 | 
         
            +
                  >
         
     | 
| 40 | 
         
            +
                    <Handle
         
     | 
| 41 | 
         
            +
                      id="c"
         
     | 
| 42 | 
         
            +
                      type="source"
         
     | 
| 43 | 
         
            +
                      position={Position.Left}
         
     | 
| 44 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 45 | 
         
            +
                      className={styles.handle}
         
     | 
| 46 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 47 | 
         
            +
                    ></Handle>
         
     | 
| 48 | 
         
            +
                    <Handle
         
     | 
| 49 | 
         
            +
                      type="source"
         
     | 
| 50 | 
         
            +
                      position={Position.Right}
         
     | 
| 51 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 52 | 
         
            +
                      className={styles.handle}
         
     | 
| 53 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 54 | 
         
            +
                      id="b"
         
     | 
| 55 | 
         
            +
                    ></Handle>
         
     | 
| 56 | 
         
            +
                    <NodeHeader
         
     | 
| 57 | 
         
            +
                      id={id}
         
     | 
| 58 | 
         
            +
                      name={data.name}
         
     | 
| 59 | 
         
            +
                      label={data.label}
         
     | 
| 60 | 
         
            +
                      className={classNames({
         
     | 
| 61 | 
         
            +
                        [styles.nodeHeader]: knowledgeBaseIds.length > 0,
         
     | 
| 62 | 
         
            +
                      })}
         
     | 
| 63 | 
         
            +
                    ></NodeHeader>
         
     | 
| 64 | 
         
            +
                    <Flex vertical gap={8}>
         
     | 
| 65 | 
         
            +
                      {knowledgeBases.map((knowledge) => {
         
     | 
| 66 | 
         
            +
                        return (
         
     | 
| 67 | 
         
            +
                          <div className={styles.nodeText} key={knowledge.id}>
         
     | 
| 68 | 
         
            +
                            <Flex align={'center'} gap={6}>
         
     | 
| 69 | 
         
            +
                              <Avatar
         
     | 
| 70 | 
         
            +
                                size={26}
         
     | 
| 71 | 
         
            +
                                icon={<UserOutlined />}
         
     | 
| 72 | 
         
            +
                                src={knowledge.avatar}
         
     | 
| 73 | 
         
            +
                              />
         
     | 
| 74 | 
         
            +
                              <Flex className={styles.knowledgeNodeName} flex={1}>
         
     | 
| 75 | 
         
            +
                                {knowledge.name}
         
     | 
| 76 | 
         
            +
                              </Flex>
         
     | 
| 77 | 
         
            +
                            </Flex>
         
     | 
| 78 | 
         
            +
                          </div>
         
     | 
| 79 | 
         
            +
                        );
         
     | 
| 80 | 
         
            +
                      })}
         
     | 
| 81 | 
         
            +
                    </Flex>
         
     | 
| 82 | 
         
            +
                  </section>
         
     | 
| 83 | 
         
            +
                </NodePopover>
         
     | 
| 84 | 
         
            +
              );
         
     | 
| 85 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/rewrite-node.tsx
    ADDED
    
    | 
         @@ -0,0 +1,54 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import LLMLabel from '@/components/llm-select/llm-label';
         
     | 
| 2 | 
         
            +
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            +
            import { get } from 'lodash';
         
     | 
| 4 | 
         
            +
            import { Handle, NodeProps, 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 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 10 | 
         
            +
             
     | 
| 11 | 
         
            +
            export function RewriteNode({
         
     | 
| 12 | 
         
            +
              id,
         
     | 
| 13 | 
         
            +
              data,
         
     | 
| 14 | 
         
            +
              isConnectable = true,
         
     | 
| 15 | 
         
            +
              selected,
         
     | 
| 16 | 
         
            +
            }: NodeProps<NodeData>) {
         
     | 
| 17 | 
         
            +
              return (
         
     | 
| 18 | 
         
            +
                <NodePopover nodeId={id}>
         
     | 
| 19 | 
         
            +
                  <section
         
     | 
| 20 | 
         
            +
                    className={classNames(styles.logicNode, {
         
     | 
| 21 | 
         
            +
                      [styles.selectedNode]: selected,
         
     | 
| 22 | 
         
            +
                    })}
         
     | 
| 23 | 
         
            +
                  >
         
     | 
| 24 | 
         
            +
                    <Handle
         
     | 
| 25 | 
         
            +
                      id="c"
         
     | 
| 26 | 
         
            +
                      type="source"
         
     | 
| 27 | 
         
            +
                      position={Position.Left}
         
     | 
| 28 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 29 | 
         
            +
                      className={styles.handle}
         
     | 
| 30 | 
         
            +
                      style={LeftHandleStyle}
         
     | 
| 31 | 
         
            +
                    ></Handle>
         
     | 
| 32 | 
         
            +
                    <Handle
         
     | 
| 33 | 
         
            +
                      type="source"
         
     | 
| 34 | 
         
            +
                      position={Position.Right}
         
     | 
| 35 | 
         
            +
                      isConnectable={isConnectable}
         
     | 
| 36 | 
         
            +
                      className={styles.handle}
         
     | 
| 37 | 
         
            +
                      style={RightHandleStyle}
         
     | 
| 38 | 
         
            +
                      id="b"
         
     | 
| 39 | 
         
            +
                    ></Handle>
         
     | 
| 40 | 
         
            +
             
     | 
| 41 | 
         
            +
                    <NodeHeader
         
     | 
| 42 | 
         
            +
                      id={id}
         
     | 
| 43 | 
         
            +
                      name={data.name}
         
     | 
| 44 | 
         
            +
                      label={data.label}
         
     | 
| 45 | 
         
            +
                      className={styles.nodeHeader}
         
     | 
| 46 | 
         
            +
                    ></NodeHeader>
         
     | 
| 47 | 
         
            +
             
     | 
| 48 | 
         
            +
                    <div className={styles.nodeText}>
         
     | 
| 49 | 
         
            +
                      <LLMLabel value={get(data, 'form.llm_id')}></LLMLabel>
         
     | 
| 50 | 
         
            +
                    </div>
         
     | 
| 51 | 
         
            +
                  </section>
         
     | 
| 52 | 
         
            +
                </NodePopover>
         
     | 
| 53 | 
         
            +
              );
         
     | 
| 54 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/canvas/node/switch-node.tsx
    ADDED
    
    | 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { Divider, Flex } from 'antd';
         
     | 
| 2 | 
         
            +
            import classNames from 'classnames';
         
     | 
| 3 | 
         
            +
            import { Handle, NodeProps, Position } from 'reactflow';
         
     | 
| 4 | 
         
            +
            import { useGetComponentLabelByValue } from '../../hooks';
         
     | 
| 5 | 
         
            +
            import { ISwitchCondition, NodeData } from '../../interface';
         
     | 
| 6 | 
         
            +
            import { RightHandleStyle } from './handle-icon';
         
     | 
| 7 | 
         
            +
            import { useBuildSwitchHandlePositions } from './hooks';
         
     | 
| 8 | 
         
            +
            import styles from './index.less';
         
     | 
| 9 | 
         
            +
            import NodeHeader from './node-header';
         
     | 
| 10 | 
         
            +
            import NodePopover from './popover';
         
     | 
| 11 | 
         
            +
             
     | 
| 12 | 
         
            +
            const getConditionKey = (idx: number, length: number) => {
         
     | 
| 13 | 
         
            +
              if (idx === 0 && length !== 1) {
         
     | 
| 14 | 
         
            +
                return 'If';
         
     | 
| 15 | 
         
            +
              } else if (idx === length - 1) {
         
     | 
| 16 | 
         
            +
                return 'Else';
         
     | 
| 17 | 
         
            +
              }
         
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
              return 'ElseIf';
         
     | 
| 20 | 
         
            +
            };
         
     | 
| 21 | 
         
            +
             
     | 
| 22 | 
         
            +
            const ConditionBlock = ({
         
     | 
| 23 | 
         
            +
              condition,
         
     | 
| 24 | 
         
            +
              nodeId,
         
     | 
| 25 | 
         
            +
            }: {
         
     | 
| 26 | 
         
            +
              condition: ISwitchCondition;
         
     | 
| 27 | 
         
            +
              nodeId: string;
         
     | 
| 28 | 
         
            +
            }) => {
         
     | 
| 29 | 
         
            +
              const items = condition?.items ?? [];
         
     | 
| 30 | 
         
            +
              const getLabel = useGetComponentLabelByValue(nodeId);
         
     | 
| 31 | 
         
            +
              return (
         
     | 
| 32 | 
         
            +
                <Flex vertical className={styles.conditionBlock}>
         
     | 
| 33 | 
         
            +
                  {items.map((x, idx) => (
         
     | 
| 34 | 
         
            +
                    <div key={idx}>
         
     | 
| 35 | 
         
            +
                      <Flex>
         
     | 
| 36 | 
         
            +
                        <div
         
     | 
| 37 | 
         
            +
                          className={classNames(styles.conditionLine, styles.conditionKey)}
         
     | 
| 38 | 
         
            +
                        >
         
     | 
| 39 | 
         
            +
                          {getLabel(x?.cpn_id)}
         
     | 
| 40 | 
         
            +
                        </div>
         
     | 
| 41 | 
         
            +
                        <span className={styles.conditionOperator}>{x?.operator}</span>
         
     | 
| 42 | 
         
            +
                        <Flex flex={1} className={styles.conditionLine}>
         
     | 
| 43 | 
         
            +
                          {x?.value}
         
     | 
| 44 | 
         
            +
                        </Flex>
         
     | 
| 45 | 
         
            +
                      </Flex>
         
     | 
| 46 | 
         
            +
                      {idx + 1 < items.length && (
         
     | 
| 47 | 
         
            +
                        <Divider orientationMargin="0" className={styles.zeroDivider}>
         
     | 
| 48 | 
         
            +
                          {condition?.logical_operator}
         
     | 
| 49 | 
         
            +
                        </Divider>
         
     | 
| 50 | 
         
            +
                      )}
         
     | 
| 51 | 
         
            +
                    </div>
         
     | 
| 52 | 
         
            +
                  ))}
         
     | 
| 53 | 
         
            +
                </Flex>
         
     | 
| 54 | 
         
            +
              );
         
     | 
| 55 | 
         
            +
            };
         
     | 
| 56 | 
         
            +
             
     | 
| 57 | 
         
            +
            export function SwitchNode({ id, data, selected }: NodeProps<NodeData>) {
         
     | 
| 58 | 
         
            +
              const { positions } = useBuildSwitchHandlePositions({ data, id });
         
     | 
| 59 | 
         
            +
             
     | 
| 60 | 
         
            +
              return (
         
     | 
| 61 | 
         
            +
                <NodePopover nodeId={id}>
         
     | 
| 62 | 
         
            +
                  <section
         
     | 
| 63 | 
         
            +
                    className={classNames(styles.logicNode, {
         
     | 
| 64 | 
         
            +
                      [styles.selectedNode]: selected,
         
     | 
| 65 | 
         
            +
                    })}
         
     | 
| 66 | 
         
            +
                  >
         
     | 
| 67 | 
         
            +
                    <Handle
         
     | 
| 68 | 
         
            +
                      type="target"
         
     | 
| 69 | 
         
            +
                      position={Position.Left}
         
     | 
| 70 | 
         
            +
                      isConnectable
         
     | 
| 71 | 
         
            +
                      className={styles.handle}
         
     | 
| 72 | 
         
            +
                      id={'a'}
         
     | 
| 73 | 
         
            +
                    ></Handle>
         
     | 
| 74 | 
         
            +
                    <NodeHeader
         
     | 
| 75 | 
         
            +
                      id={id}
         
     | 
| 76 | 
         
            +
                      name={data.name}
         
     | 
| 77 | 
         
            +
                      label={data.label}
         
     | 
| 78 | 
         
            +
                      className={styles.nodeHeader}
         
     | 
| 79 | 
         
            +
                    ></NodeHeader>
         
     | 
| 80 | 
         
            +
                    <Flex vertical gap={10}>
         
     | 
| 81 | 
         
            +
                      {positions.map((position, idx) => {
         
     | 
| 82 | 
         
            +
                        return (
         
     | 
| 83 | 
         
            +
                          <div key={idx}>
         
     | 
| 84 | 
         
            +
                            <Flex vertical>
         
     | 
| 85 | 
         
            +
                              <Flex justify={'space-between'}>
         
     | 
| 86 | 
         
            +
                                <span>{idx < positions.length - 1 && position.text}</span>
         
     | 
| 87 | 
         
            +
                                <span>{getConditionKey(idx, positions.length)}</span>
         
     | 
| 88 | 
         
            +
                              </Flex>
         
     | 
| 89 | 
         
            +
                              {position.condition && (
         
     | 
| 90 | 
         
            +
                                <ConditionBlock
         
     | 
| 91 | 
         
            +
                                  nodeId={id}
         
     | 
| 92 | 
         
            +
                                  condition={position.condition}
         
     | 
| 93 | 
         
            +
                                ></ConditionBlock>
         
     | 
| 94 | 
         
            +
                              )}
         
     | 
| 95 | 
         
            +
                            </Flex>
         
     | 
| 96 | 
         
            +
                            <Handle
         
     | 
| 97 | 
         
            +
                              key={position.text}
         
     | 
| 98 | 
         
            +
                              id={position.text}
         
     | 
| 99 | 
         
            +
                              type="source"
         
     | 
| 100 | 
         
            +
                              position={Position.Right}
         
     | 
| 101 | 
         
            +
                              isConnectable
         
     | 
| 102 | 
         
            +
                              className={styles.handle}
         
     | 
| 103 | 
         
            +
                              style={{ ...RightHandleStyle, top: position.top }}
         
     | 
| 104 | 
         
            +
                            ></Handle>
         
     | 
| 105 | 
         
            +
                          </div>
         
     | 
| 106 | 
         
            +
                        );
         
     | 
| 107 | 
         
            +
                      })}
         
     | 
| 108 | 
         
            +
                    </Flex>
         
     | 
| 109 | 
         
            +
                  </section>
         
     | 
| 110 | 
         
            +
                </NodePopover>
         
     | 
| 111 | 
         
            +
              );
         
     | 
| 112 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/constant.tsx
    CHANGED
    
    | 
         @@ -2,6 +2,7 @@ import { ReactComponent as AkShareIcon } from '@/assets/svg/akshare.svg'; 
     | 
|
| 2 | 
         
             
            import { ReactComponent as ArXivIcon } from '@/assets/svg/arxiv.svg';
         
     | 
| 3 | 
         
             
            import { ReactComponent as baiduFanyiIcon } from '@/assets/svg/baidu-fanyi.svg';
         
     | 
| 4 | 
         
             
            import { ReactComponent as BaiduIcon } from '@/assets/svg/baidu.svg';
         
     | 
| 
         | 
|
| 5 | 
         
             
            import { ReactComponent as BingIcon } from '@/assets/svg/bing.svg';
         
     | 
| 6 | 
         
             
            import { ReactComponent as ConcentratorIcon } from '@/assets/svg/concentrator.svg';
         
     | 
| 7 | 
         
             
            import { ReactComponent as CrawlerIcon } from '@/assets/svg/crawler.svg';
         
     | 
| 
         @@ -39,7 +40,6 @@ import { 
     | 
|
| 39 | 
         
             
              MessageOutlined,
         
     | 
| 40 | 
         
             
              RocketOutlined,
         
     | 
| 41 | 
         
             
              SendOutlined,
         
     | 
| 42 | 
         
            -
              SlidersOutlined,
         
     | 
| 43 | 
         
             
            } from '@ant-design/icons';
         
     | 
| 44 | 
         
             
            import upperFirst from 'lodash/upperFirst';
         
     | 
| 45 | 
         | 
| 
         @@ -85,7 +85,7 @@ export const operatorIconMap = { 
     | 
|
| 85 | 
         
             
              [Operator.Retrieval]: RocketOutlined,
         
     | 
| 86 | 
         
             
              [Operator.Generate]: MergeCellsOutlined,
         
     | 
| 87 | 
         
             
              [Operator.Answer]: SendOutlined,
         
     | 
| 88 | 
         
            -
              [Operator.Begin]:  
     | 
| 89 | 
         
             
              [Operator.Categorize]: DatabaseOutlined,
         
     | 
| 90 | 
         
             
              [Operator.Message]: MessageOutlined,
         
     | 
| 91 | 
         
             
              [Operator.Relevant]: BranchesOutlined,
         
     | 
| 
         @@ -142,7 +142,7 @@ export const operatorMap: Record< 
     | 
|
| 142 | 
         
             
              },
         
     | 
| 143 | 
         
             
              [Operator.Answer]: {
         
     | 
| 144 | 
         
             
                backgroundColor: '#f4816d',
         
     | 
| 145 | 
         
            -
                color: ' 
     | 
| 146 | 
         
             
              },
         
     | 
| 147 | 
         
             
              [Operator.Begin]: {
         
     | 
| 148 | 
         
             
                backgroundColor: '#4f51d6',
         
     | 
| 
         @@ -157,7 +157,7 @@ export const operatorMap: Record< 
     | 
|
| 157 | 
         
             
              },
         
     | 
| 158 | 
         
             
              [Operator.Relevant]: {
         
     | 
| 159 | 
         
             
                backgroundColor: '#9fd94d',
         
     | 
| 160 | 
         
            -
                color: ' 
     | 
| 161 | 
         
             
                width: 70,
         
     | 
| 162 | 
         
             
                height: 70,
         
     | 
| 163 | 
         
             
                fontSize: 12,
         
     | 
| 
         @@ -165,7 +165,7 @@ export const operatorMap: Record< 
     | 
|
| 165 | 
         
             
              },
         
     | 
| 166 | 
         
             
              [Operator.RewriteQuestion]: {
         
     | 
| 167 | 
         
             
                backgroundColor: '#f8c7f8',
         
     | 
| 168 | 
         
            -
                color: ' 
     | 
| 169 | 
         
             
                width: 70,
         
     | 
| 170 | 
         
             
                height: 70,
         
     | 
| 171 | 
         
             
                fontSize: 12,
         
     | 
| 
         @@ -175,7 +175,7 @@ export const operatorMap: Record< 
     | 
|
| 175 | 
         
             
                width: 70,
         
     | 
| 176 | 
         
             
                height: 70,
         
     | 
| 177 | 
         
             
                backgroundColor: '#0f0e0f',
         
     | 
| 178 | 
         
            -
                color: '# 
     | 
| 179 | 
         
             
                fontSize: 12,
         
     | 
| 180 | 
         
             
                iconWidth: 16,
         
     | 
| 181 | 
         
             
                // iconFontSize: 16,
         
     | 
| 
         @@ -221,14 +221,14 @@ export const operatorMap: Record< 
     | 
|
| 221 | 
         
             
              [Operator.BaiduFanyi]: { backgroundColor: '#e5f2d3' },
         
     | 
| 222 | 
         
             
              [Operator.QWeather]: { backgroundColor: '#a4bbf3' },
         
     | 
| 223 | 
         
             
              [Operator.ExeSQL]: { backgroundColor: '#b9efe8' },
         
     | 
| 224 | 
         
            -
              [Operator.Switch]: { backgroundColor: '#dbaff6' },
         
     | 
| 225 | 
         
             
              [Operator.WenCai]: { backgroundColor: '#faac5b' },
         
     | 
| 226 | 
         
             
              [Operator.AkShare]: { backgroundColor: '#8085f5' },
         
     | 
| 227 | 
         
             
              [Operator.YahooFinance]: { backgroundColor: '#b474ff' },
         
     | 
| 228 | 
         
             
              [Operator.Jin10]: { backgroundColor: '#a0b9f8' },
         
     | 
| 229 | 
         
             
              [Operator.Concentrator]: {
         
     | 
| 230 | 
         
             
                backgroundColor: '#32d2a3',
         
     | 
| 231 | 
         
            -
                color: ' 
     | 
| 232 | 
         
             
                width: 70,
         
     | 
| 233 | 
         
             
                height: 70,
         
     | 
| 234 | 
         
             
                fontSize: 10,
         
     | 
| 
         @@ -586,18 +586,19 @@ export const RestrictedUpstreamMap = { 
     | 
|
| 586 | 
         
             
              [Operator.Concentrator]: [Operator.Begin],
         
     | 
| 587 | 
         
             
              [Operator.TuShare]: [Operator.Begin],
         
     | 
| 588 | 
         
             
              [Operator.Crawler]: [Operator.Begin],
         
     | 
| 
         | 
|
| 589 | 
         
             
            };
         
     | 
| 590 | 
         | 
| 591 | 
         
             
            export const NodeMap = {
         
     | 
| 592 | 
         
             
              [Operator.Begin]: 'beginNode',
         
     | 
| 593 | 
         
             
              [Operator.Categorize]: 'categorizeNode',
         
     | 
| 594 | 
         
            -
              [Operator.Retrieval]: ' 
     | 
| 595 | 
         
            -
              [Operator.Generate]: ' 
     | 
| 596 | 
         
             
              [Operator.Answer]: 'logicNode',
         
     | 
| 597 | 
         
            -
              [Operator.Message]: ' 
     | 
| 598 | 
         
             
              [Operator.Relevant]: 'relevantNode',
         
     | 
| 599 | 
         
            -
              [Operator.RewriteQuestion]: ' 
     | 
| 600 | 
         
            -
              [Operator.KeywordExtract]: ' 
     | 
| 601 | 
         
             
              [Operator.DuckDuckGo]: 'ragNode',
         
     | 
| 602 | 
         
             
              [Operator.Baidu]: 'ragNode',
         
     | 
| 603 | 
         
             
              [Operator.Wikipedia]: 'ragNode',
         
     | 
| 
         @@ -611,7 +612,7 @@ export const NodeMap = { 
     | 
|
| 611 | 
         
             
              [Operator.BaiduFanyi]: 'ragNode',
         
     | 
| 612 | 
         
             
              [Operator.QWeather]: 'ragNode',
         
     | 
| 613 | 
         
             
              [Operator.ExeSQL]: 'ragNode',
         
     | 
| 614 | 
         
            -
              [Operator.Switch]: ' 
     | 
| 615 | 
         
             
              [Operator.Concentrator]: 'logicNode',
         
     | 
| 616 | 
         
             
              [Operator.WenCai]: 'ragNode',
         
     | 
| 617 | 
         
             
              [Operator.AkShare]: 'ragNode',
         
     | 
| 
         | 
|
| 2 | 
         
             
            import { ReactComponent as ArXivIcon } from '@/assets/svg/arxiv.svg';
         
     | 
| 3 | 
         
             
            import { ReactComponent as baiduFanyiIcon } from '@/assets/svg/baidu-fanyi.svg';
         
     | 
| 4 | 
         
             
            import { ReactComponent as BaiduIcon } from '@/assets/svg/baidu.svg';
         
     | 
| 5 | 
         
            +
            import { ReactComponent as BeginIcon } from '@/assets/svg/begin.svg';
         
     | 
| 6 | 
         
             
            import { ReactComponent as BingIcon } from '@/assets/svg/bing.svg';
         
     | 
| 7 | 
         
             
            import { ReactComponent as ConcentratorIcon } from '@/assets/svg/concentrator.svg';
         
     | 
| 8 | 
         
             
            import { ReactComponent as CrawlerIcon } from '@/assets/svg/crawler.svg';
         
     | 
| 
         | 
|
| 40 | 
         
             
              MessageOutlined,
         
     | 
| 41 | 
         
             
              RocketOutlined,
         
     | 
| 42 | 
         
             
              SendOutlined,
         
     | 
| 
         | 
|
| 43 | 
         
             
            } from '@ant-design/icons';
         
     | 
| 44 | 
         
             
            import upperFirst from 'lodash/upperFirst';
         
     | 
| 45 | 
         | 
| 
         | 
|
| 85 | 
         
             
              [Operator.Retrieval]: RocketOutlined,
         
     | 
| 86 | 
         
             
              [Operator.Generate]: MergeCellsOutlined,
         
     | 
| 87 | 
         
             
              [Operator.Answer]: SendOutlined,
         
     | 
| 88 | 
         
            +
              [Operator.Begin]: BeginIcon,
         
     | 
| 89 | 
         
             
              [Operator.Categorize]: DatabaseOutlined,
         
     | 
| 90 | 
         
             
              [Operator.Message]: MessageOutlined,
         
     | 
| 91 | 
         
             
              [Operator.Relevant]: BranchesOutlined,
         
     | 
| 
         | 
|
| 142 | 
         
             
              },
         
     | 
| 143 | 
         
             
              [Operator.Answer]: {
         
     | 
| 144 | 
         
             
                backgroundColor: '#f4816d',
         
     | 
| 145 | 
         
            +
                color: '#f4816d',
         
     | 
| 146 | 
         
             
              },
         
     | 
| 147 | 
         
             
              [Operator.Begin]: {
         
     | 
| 148 | 
         
             
                backgroundColor: '#4f51d6',
         
     | 
| 
         | 
|
| 157 | 
         
             
              },
         
     | 
| 158 | 
         
             
              [Operator.Relevant]: {
         
     | 
| 159 | 
         
             
                backgroundColor: '#9fd94d',
         
     | 
| 160 | 
         
            +
                color: '#8ef005',
         
     | 
| 161 | 
         
             
                width: 70,
         
     | 
| 162 | 
         
             
                height: 70,
         
     | 
| 163 | 
         
             
                fontSize: 12,
         
     | 
| 
         | 
|
| 165 | 
         
             
              },
         
     | 
| 166 | 
         
             
              [Operator.RewriteQuestion]: {
         
     | 
| 167 | 
         
             
                backgroundColor: '#f8c7f8',
         
     | 
| 168 | 
         
            +
                color: '#f32bf3',
         
     | 
| 169 | 
         
             
                width: 70,
         
     | 
| 170 | 
         
             
                height: 70,
         
     | 
| 171 | 
         
             
                fontSize: 12,
         
     | 
| 
         | 
|
| 175 | 
         
             
                width: 70,
         
     | 
| 176 | 
         
             
                height: 70,
         
     | 
| 177 | 
         
             
                backgroundColor: '#0f0e0f',
         
     | 
| 178 | 
         
            +
                color: '#0f0e0f',
         
     | 
| 179 | 
         
             
                fontSize: 12,
         
     | 
| 180 | 
         
             
                iconWidth: 16,
         
     | 
| 181 | 
         
             
                // iconFontSize: 16,
         
     | 
| 
         | 
|
| 221 | 
         
             
              [Operator.BaiduFanyi]: { backgroundColor: '#e5f2d3' },
         
     | 
| 222 | 
         
             
              [Operator.QWeather]: { backgroundColor: '#a4bbf3' },
         
     | 
| 223 | 
         
             
              [Operator.ExeSQL]: { backgroundColor: '#b9efe8' },
         
     | 
| 224 | 
         
            +
              [Operator.Switch]: { backgroundColor: '#dbaff6', color: '#dbaff6' },
         
     | 
| 225 | 
         
             
              [Operator.WenCai]: { backgroundColor: '#faac5b' },
         
     | 
| 226 | 
         
             
              [Operator.AkShare]: { backgroundColor: '#8085f5' },
         
     | 
| 227 | 
         
             
              [Operator.YahooFinance]: { backgroundColor: '#b474ff' },
         
     | 
| 228 | 
         
             
              [Operator.Jin10]: { backgroundColor: '#a0b9f8' },
         
     | 
| 229 | 
         
             
              [Operator.Concentrator]: {
         
     | 
| 230 | 
         
             
                backgroundColor: '#32d2a3',
         
     | 
| 231 | 
         
            +
                color: '#32d2a3',
         
     | 
| 232 | 
         
             
                width: 70,
         
     | 
| 233 | 
         
             
                height: 70,
         
     | 
| 234 | 
         
             
                fontSize: 10,
         
     | 
| 
         | 
|
| 586 | 
         
             
              [Operator.Concentrator]: [Operator.Begin],
         
     | 
| 587 | 
         
             
              [Operator.TuShare]: [Operator.Begin],
         
     | 
| 588 | 
         
             
              [Operator.Crawler]: [Operator.Begin],
         
     | 
| 589 | 
         
            +
              [Operator.Note]: [],
         
     | 
| 590 | 
         
             
            };
         
     | 
| 591 | 
         | 
| 592 | 
         
             
            export const NodeMap = {
         
     | 
| 593 | 
         
             
              [Operator.Begin]: 'beginNode',
         
     | 
| 594 | 
         
             
              [Operator.Categorize]: 'categorizeNode',
         
     | 
| 595 | 
         
            +
              [Operator.Retrieval]: 'retrievalNode',
         
     | 
| 596 | 
         
            +
              [Operator.Generate]: 'generateNode',
         
     | 
| 597 | 
         
             
              [Operator.Answer]: 'logicNode',
         
     | 
| 598 | 
         
            +
              [Operator.Message]: 'messageNode',
         
     | 
| 599 | 
         
             
              [Operator.Relevant]: 'relevantNode',
         
     | 
| 600 | 
         
            +
              [Operator.RewriteQuestion]: 'rewriteNode',
         
     | 
| 601 | 
         
            +
              [Operator.KeywordExtract]: 'keywordNode',
         
     | 
| 602 | 
         
             
              [Operator.DuckDuckGo]: 'ragNode',
         
     | 
| 603 | 
         
             
              [Operator.Baidu]: 'ragNode',
         
     | 
| 604 | 
         
             
              [Operator.Wikipedia]: 'ragNode',
         
     | 
| 
         | 
|
| 612 | 
         
             
              [Operator.BaiduFanyi]: 'ragNode',
         
     | 
| 613 | 
         
             
              [Operator.QWeather]: 'ragNode',
         
     | 
| 614 | 
         
             
              [Operator.ExeSQL]: 'ragNode',
         
     | 
| 615 | 
         
            +
              [Operator.Switch]: 'switchNode',
         
     | 
| 616 | 
         
             
              [Operator.Concentrator]: 'logicNode',
         
     | 
| 617 | 
         
             
              [Operator.WenCai]: 'ragNode',
         
     | 
| 618 | 
         
             
              [Operator.AkShare]: 'ragNode',
         
     | 
    	
        web/src/pages/flow/flow-drawer/index.less
    CHANGED
    
    | 
         @@ -7,3 +7,9 @@ 
     | 
|
| 7 | 
         
             
                font-weight: 600;
         
     | 
| 8 | 
         
             
              }
         
     | 
| 9 | 
         
             
            }
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 7 | 
         
             
                font-weight: 600;
         
     | 
| 8 | 
         
             
              }
         
     | 
| 9 | 
         
             
            }
         
     | 
| 10 | 
         
            +
             
     | 
| 11 | 
         
            +
            .operatorDescription {
         
     | 
| 12 | 
         
            +
              font-size: 14px;
         
     | 
| 13 | 
         
            +
              padding-top: 16px;
         
     | 
| 14 | 
         
            +
              font-weight: normal;
         
     | 
| 15 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/flow-drawer/index.tsx
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ import { IModalProps } from '@/interfaces/common'; 
     | 
|
| 3 | 
         
             
            import { Drawer, Flex, Form, Input } from 'antd';
         
     | 
| 4 | 
         
             
            import { useEffect } from 'react';
         
     | 
| 5 | 
         
             
            import { Node } from 'reactflow';
         
     | 
| 6 | 
         
            -
            import { Operator } from '../constant';
         
     | 
| 7 | 
         
             
            import AkShareForm from '../form/akshare-form';
         
     | 
| 8 | 
         
             
            import AnswerForm from '../form/answer-form';
         
     | 
| 9 | 
         
             
            import ArXivForm from '../form/arxiv-form';
         
     | 
| 
         @@ -36,6 +36,8 @@ import YahooFinanceForm from '../form/yahoo-finance-form'; 
     | 
|
| 36 | 
         
             
            import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks';
         
     | 
| 37 | 
         
             
            import OperatorIcon from '../operator-icon';
         
     | 
| 38 | 
         | 
| 
         | 
|
| 
         | 
|
| 39 | 
         
             
            import styles from './index.less';
         
     | 
| 40 | 
         | 
| 41 | 
         
             
            interface IProps {
         
     | 
| 
         @@ -74,7 +76,7 @@ const FormMap = { 
     | 
|
| 74 | 
         
             
              [Operator.Crawler]: CrawlerForm,
         
     | 
| 75 | 
         
             
            };
         
     | 
| 76 | 
         | 
| 77 | 
         
            -
            const EmptyContent = () => <div 
     | 
| 78 | 
         | 
| 79 | 
         
             
            const FlowDrawer = ({
         
     | 
| 80 | 
         
             
              visible,
         
     | 
| 
         @@ -84,8 +86,10 @@ const FlowDrawer = ({ 
     | 
|
| 84 | 
         
             
              const operatorName: Operator = node?.data.label;
         
     | 
| 85 | 
         
             
              const OperatorForm = FormMap[operatorName] ?? EmptyContent;
         
     | 
| 86 | 
         
             
              const [form] = Form.useForm();
         
     | 
| 87 | 
         
            -
              const { name, handleNameBlur, handleNameChange } =
         
     | 
| 88 | 
         
            -
                 
     | 
| 
         | 
|
| 
         | 
|
| 89 | 
         
             
              const { t } = useTranslate('flow');
         
     | 
| 90 | 
         | 
| 91 | 
         
             
              const { handleValuesChange } = useHandleFormValuesChange(node?.id);
         
     | 
| 
         @@ -99,18 +103,27 @@ const FlowDrawer = ({ 
     | 
|
| 99 | 
         
             
              return (
         
     | 
| 100 | 
         
             
                <Drawer
         
     | 
| 101 | 
         
             
                  title={
         
     | 
| 102 | 
         
            -
                    <Flex  
     | 
| 103 | 
         
            -
                      < 
     | 
| 104 | 
         
            -
             
     | 
| 105 | 
         
            -
             
     | 
| 106 | 
         
            -
                          { 
     | 
| 107 | 
         
            -
                         
     | 
| 108 | 
         
            -
                        < 
     | 
| 109 | 
         
            -
                           
     | 
| 110 | 
         
            -
             
     | 
| 111 | 
         
            -
                           
     | 
| 112 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 113 | 
         
             
                      </Flex>
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 114 | 
         
             
                    </Flex>
         
     | 
| 115 | 
         
             
                  }
         
     | 
| 116 | 
         
             
                  placement="right"
         
     | 
| 
         @@ -119,6 +132,7 @@ const FlowDrawer = ({ 
     | 
|
| 119 | 
         
             
                  getContainer={false}
         
     | 
| 120 | 
         
             
                  mask={false}
         
     | 
| 121 | 
         
             
                  width={470}
         
     | 
| 
         | 
|
| 122 | 
         
             
                >
         
     | 
| 123 | 
         
             
                  <section className={styles.formWrapper}>
         
     | 
| 124 | 
         
             
                    {visible && (
         
     | 
| 
         | 
|
| 3 | 
         
             
            import { Drawer, Flex, Form, Input } from 'antd';
         
     | 
| 4 | 
         
             
            import { useEffect } from 'react';
         
     | 
| 5 | 
         
             
            import { Node } from 'reactflow';
         
     | 
| 6 | 
         
            +
            import { Operator, operatorMap } from '../constant';
         
     | 
| 7 | 
         
             
            import AkShareForm from '../form/akshare-form';
         
     | 
| 8 | 
         
             
            import AnswerForm from '../form/answer-form';
         
     | 
| 9 | 
         
             
            import ArXivForm from '../form/arxiv-form';
         
     | 
| 
         | 
|
| 36 | 
         
             
            import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks';
         
     | 
| 37 | 
         
             
            import OperatorIcon from '../operator-icon';
         
     | 
| 38 | 
         | 
| 39 | 
         
            +
            import { CloseOutlined } from '@ant-design/icons';
         
     | 
| 40 | 
         
            +
            import { lowerFirst } from 'lodash';
         
     | 
| 41 | 
         
             
            import styles from './index.less';
         
     | 
| 42 | 
         | 
| 43 | 
         
             
            interface IProps {
         
     | 
| 
         | 
|
| 76 | 
         
             
              [Operator.Crawler]: CrawlerForm,
         
     | 
| 77 | 
         
             
            };
         
     | 
| 78 | 
         | 
| 79 | 
         
            +
            const EmptyContent = () => <div></div>;
         
     | 
| 80 | 
         | 
| 81 | 
         
             
            const FlowDrawer = ({
         
     | 
| 82 | 
         
             
              visible,
         
     | 
| 
         | 
|
| 86 | 
         
             
              const operatorName: Operator = node?.data.label;
         
     | 
| 87 | 
         
             
              const OperatorForm = FormMap[operatorName] ?? EmptyContent;
         
     | 
| 88 | 
         
             
              const [form] = Form.useForm();
         
     | 
| 89 | 
         
            +
              const { name, handleNameBlur, handleNameChange } = useHandleNodeNameChange({
         
     | 
| 90 | 
         
            +
                id: node?.id,
         
     | 
| 91 | 
         
            +
                data: node?.data,
         
     | 
| 92 | 
         
            +
              });
         
     | 
| 93 | 
         
             
              const { t } = useTranslate('flow');
         
     | 
| 94 | 
         | 
| 95 | 
         
             
              const { handleValuesChange } = useHandleFormValuesChange(node?.id);
         
     | 
| 
         | 
|
| 103 | 
         
             
              return (
         
     | 
| 104 | 
         
             
                <Drawer
         
     | 
| 105 | 
         
             
                  title={
         
     | 
| 106 | 
         
            +
                    <Flex vertical>
         
     | 
| 107 | 
         
            +
                      <Flex gap={'middle'} align="center">
         
     | 
| 108 | 
         
            +
                        <OperatorIcon
         
     | 
| 109 | 
         
            +
                          name={operatorName}
         
     | 
| 110 | 
         
            +
                          color={operatorMap[operatorName]?.color}
         
     | 
| 111 | 
         
            +
                        ></OperatorIcon>
         
     | 
| 112 | 
         
            +
                        <Flex align="center" gap={'small'} flex={1}>
         
     | 
| 113 | 
         
            +
                          <label htmlFor="" className={styles.title}>
         
     | 
| 114 | 
         
            +
                            {t('title')}
         
     | 
| 115 | 
         
            +
                          </label>
         
     | 
| 116 | 
         
            +
                          <Input
         
     | 
| 117 | 
         
            +
                            value={name}
         
     | 
| 118 | 
         
            +
                            onBlur={handleNameBlur}
         
     | 
| 119 | 
         
            +
                            onChange={handleNameChange}
         
     | 
| 120 | 
         
            +
                          ></Input>
         
     | 
| 121 | 
         
            +
                        </Flex>
         
     | 
| 122 | 
         
            +
                        <CloseOutlined onClick={hideModal} />
         
     | 
| 123 | 
         
             
                      </Flex>
         
     | 
| 124 | 
         
            +
                      <span className={styles.operatorDescription}>
         
     | 
| 125 | 
         
            +
                        {t(`${lowerFirst(operatorName)}Description`)}
         
     | 
| 126 | 
         
            +
                      </span>
         
     | 
| 127 | 
         
             
                    </Flex>
         
     | 
| 128 | 
         
             
                  }
         
     | 
| 129 | 
         
             
                  placement="right"
         
     | 
| 
         | 
|
| 132 | 
         
             
                  getContainer={false}
         
     | 
| 133 | 
         
             
                  mask={false}
         
     | 
| 134 | 
         
             
                  width={470}
         
     | 
| 135 | 
         
            +
                  closeIcon={null}
         
     | 
| 136 | 
         
             
                >
         
     | 
| 137 | 
         
             
                  <section className={styles.formWrapper}>
         
     | 
| 138 | 
         
             
                    {visible && (
         
     | 
    	
        web/src/pages/flow/flow-sider/index.tsx
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ import { Card, Divider, Flex, Layout, Tooltip } from 'antd'; 
     | 
|
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
             
            import lowerFirst from 'lodash/lowerFirst';
         
     | 
| 5 | 
         
             
            import React from 'react';
         
     | 
| 6 | 
         
            -
            import { Operator, componentMenuList } from '../constant';
         
     | 
| 7 | 
         
             
            import { useHandleDrag } from '../hooks';
         
     | 
| 8 | 
         
             
            import OperatorIcon from '../operator-icon';
         
     | 
| 9 | 
         
             
            import styles from './index.less';
         
     | 
| 
         @@ -53,7 +53,10 @@ const FlowSide = ({ setCollapsed, collapsed }: IProps) => { 
     | 
|
| 53 | 
         
             
                            onDragStart={handleDragStart(x.name)}
         
     | 
| 54 | 
         
             
                          >
         
     | 
| 55 | 
         
             
                            <Flex align="center" gap={15}>
         
     | 
| 56 | 
         
            -
                              <OperatorIcon 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 57 | 
         
             
                              <section>
         
     | 
| 58 | 
         
             
                                <Tooltip title={t(`${lowerFirst(x.name)}Description`)}>
         
     | 
| 59 | 
         
             
                                  <b>{t(lowerFirst(x.name))}</b>
         
     | 
| 
         | 
|
| 3 | 
         
             
            import classNames from 'classnames';
         
     | 
| 4 | 
         
             
            import lowerFirst from 'lodash/lowerFirst';
         
     | 
| 5 | 
         
             
            import React from 'react';
         
     | 
| 6 | 
         
            +
            import { Operator, componentMenuList, operatorMap } from '../constant';
         
     | 
| 7 | 
         
             
            import { useHandleDrag } from '../hooks';
         
     | 
| 8 | 
         
             
            import OperatorIcon from '../operator-icon';
         
     | 
| 9 | 
         
             
            import styles from './index.less';
         
     | 
| 
         | 
|
| 53 | 
         
             
                            onDragStart={handleDragStart(x.name)}
         
     | 
| 54 | 
         
             
                          >
         
     | 
| 55 | 
         
             
                            <Flex align="center" gap={15}>
         
     | 
| 56 | 
         
            +
                              <OperatorIcon
         
     | 
| 57 | 
         
            +
                                name={x.name}
         
     | 
| 58 | 
         
            +
                                color={operatorMap[x.name].color}
         
     | 
| 59 | 
         
            +
                              ></OperatorIcon>
         
     | 
| 60 | 
         
             
                              <section>
         
     | 
| 61 | 
         
             
                                <Tooltip title={t(`${lowerFirst(x.name)}Description`)}>
         
     | 
| 62 | 
         
             
                                  <b>{t(lowerFirst(x.name))}</b>
         
     | 
    	
        web/src/pages/flow/form-hooks.ts
    CHANGED
    
    | 
         @@ -3,19 +3,6 @@ import { useCallback, useMemo } from 'react'; 
     | 
|
| 3 | 
         
             
            import { Operator, RestrictedUpstreamMap } from './constant';
         
     | 
| 4 | 
         
             
            import useGraphStore from './store';
         
     | 
| 5 | 
         | 
| 6 | 
         
            -
            const ExcludedNodesMap = {
         
     | 
| 7 | 
         
            -
              // exclude some nodes downstream of the classification node
         
     | 
| 8 | 
         
            -
              [Operator.Categorize]: [
         
     | 
| 9 | 
         
            -
                Operator.Categorize,
         
     | 
| 10 | 
         
            -
                Operator.Answer,
         
     | 
| 11 | 
         
            -
                Operator.Begin,
         
     | 
| 12 | 
         
            -
                Operator.Relevant,
         
     | 
| 13 | 
         
            -
              ],
         
     | 
| 14 | 
         
            -
              [Operator.Relevant]: [Operator.Begin, Operator.Answer, Operator.Relevant],
         
     | 
| 15 | 
         
            -
              [Operator.Generate]: [Operator.Begin],
         
     | 
| 16 | 
         
            -
              [Operator.Switch]: [Operator.Begin],
         
     | 
| 17 | 
         
            -
            };
         
     | 
| 18 | 
         
            -
             
     | 
| 19 | 
         
             
            export const useBuildFormSelectOptions = (
         
     | 
| 20 | 
         
             
              operatorName: Operator,
         
     | 
| 21 | 
         
             
              selfId?: string, // exclude the current node
         
     | 
| 
         @@ -24,8 +11,10 @@ export const useBuildFormSelectOptions = ( 
     | 
|
| 24 | 
         | 
| 25 | 
         
             
              const buildCategorizeToOptions = useCallback(
         
     | 
| 26 | 
         
             
                (toList: string[]) => {
         
     | 
| 27 | 
         
            -
                  const excludedNodes: Operator[] =
         
     | 
| 28 | 
         
            -
                     
     | 
| 
         | 
|
| 
         | 
|
| 29 | 
         
             
                  return nodes
         
     | 
| 30 | 
         
             
                    .filter(
         
     | 
| 31 | 
         
             
                      (x) =>
         
     | 
| 
         | 
|
| 3 | 
         
             
            import { Operator, RestrictedUpstreamMap } from './constant';
         
     | 
| 4 | 
         
             
            import useGraphStore from './store';
         
     | 
| 5 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 6 | 
         
             
            export const useBuildFormSelectOptions = (
         
     | 
| 7 | 
         
             
              operatorName: Operator,
         
     | 
| 8 | 
         
             
              selfId?: string, // exclude the current node
         
     | 
| 
         | 
|
| 11 | 
         | 
| 12 | 
         
             
              const buildCategorizeToOptions = useCallback(
         
     | 
| 13 | 
         
             
                (toList: string[]) => {
         
     | 
| 14 | 
         
            +
                  const excludedNodes: Operator[] = [
         
     | 
| 15 | 
         
            +
                    Operator.Note,
         
     | 
| 16 | 
         
            +
                    ...(RestrictedUpstreamMap[operatorName] ?? []),
         
     | 
| 17 | 
         
            +
                  ];
         
     | 
| 18 | 
         
             
                  return nodes
         
     | 
| 19 | 
         
             
                    .filter(
         
     | 
| 20 | 
         
             
                      (x) =>
         
     | 
    	
        web/src/pages/flow/form/categorize-form/dynamic-categorize.tsx
    CHANGED
    
    | 
         @@ -1,6 +1,14 @@ 
     | 
|
| 1 | 
         
             
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
             
            import { CloseOutlined } from '@ant-design/icons';
         
     | 
| 3 | 
         
            -
            import { 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 4 | 
         
             
            import { FormInstance } from 'antd/lib';
         
     | 
| 5 | 
         
             
            import { humanId } from 'human-id';
         
     | 
| 6 | 
         
             
            import trim from 'lodash/trim';
         
     | 
| 
         @@ -15,6 +23,8 @@ import { useUpdateNodeInternals } from 'reactflow'; 
     | 
|
| 15 | 
         
             
            import { Operator } from '../../constant';
         
     | 
| 16 | 
         
             
            import { useBuildFormSelectOptions } from '../../form-hooks';
         
     | 
| 17 | 
         | 
| 
         | 
|
| 
         | 
|
| 18 | 
         
             
            interface IProps {
         
     | 
| 19 | 
         
             
              nodeId?: string;
         
     | 
| 20 | 
         
             
            }
         
     | 
| 
         @@ -105,13 +115,12 @@ const DynamicCategorize = ({ nodeId }: IProps) => { 
     | 
|
| 105 | 
         
             
                        if (nodeId) updateNodeInternals(nodeId);
         
     | 
| 106 | 
         
             
                      };
         
     | 
| 107 | 
         
             
                      return (
         
     | 
| 108 | 
         
            -
                        < 
     | 
| 109 | 
         
            -
                          style={{ display: 'flex', rowGap: 10, flexDirection: 'column' }}
         
     | 
| 110 | 
         
            -
                        >
         
     | 
| 111 | 
         
             
                          {fields.map((field) => (
         
     | 
| 112 | 
         
             
                            <Card
         
     | 
| 113 | 
         
             
                              size="small"
         
     | 
| 114 | 
         
             
                              key={field.key}
         
     | 
| 
         | 
|
| 115 | 
         
             
                              extra={
         
     | 
| 116 | 
         
             
                                <CloseOutlined
         
     | 
| 117 | 
         
             
                                  onClick={() => {
         
     | 
| 
         @@ -172,10 +181,15 @@ const DynamicCategorize = ({ nodeId }: IProps) => { 
     | 
|
| 172 | 
         
             
                            </Card>
         
     | 
| 173 | 
         
             
                          ))}
         
     | 
| 174 | 
         | 
| 175 | 
         
            -
                          <Button 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 176 | 
         
             
                            + {t('addItem')}
         
     | 
| 177 | 
         
             
                          </Button>
         
     | 
| 178 | 
         
            -
                        </ 
     | 
| 179 | 
         
             
                      );
         
     | 
| 180 | 
         
             
                    }}
         
     | 
| 181 | 
         
             
                  </Form.List>
         
     | 
| 
         | 
|
| 1 | 
         
             
            import { useTranslate } from '@/hooks/common-hooks';
         
     | 
| 2 | 
         
             
            import { CloseOutlined } from '@ant-design/icons';
         
     | 
| 3 | 
         
            +
            import {
         
     | 
| 4 | 
         
            +
              Button,
         
     | 
| 5 | 
         
            +
              Card,
         
     | 
| 6 | 
         
            +
              Flex,
         
     | 
| 7 | 
         
            +
              Form,
         
     | 
| 8 | 
         
            +
              FormListFieldData,
         
     | 
| 9 | 
         
            +
              Input,
         
     | 
| 10 | 
         
            +
              Select,
         
     | 
| 11 | 
         
            +
            } from 'antd';
         
     | 
| 12 | 
         
             
            import { FormInstance } from 'antd/lib';
         
     | 
| 13 | 
         
             
            import { humanId } from 'human-id';
         
     | 
| 14 | 
         
             
            import trim from 'lodash/trim';
         
     | 
| 
         | 
|
| 23 | 
         
             
            import { Operator } from '../../constant';
         
     | 
| 24 | 
         
             
            import { useBuildFormSelectOptions } from '../../form-hooks';
         
     | 
| 25 | 
         | 
| 26 | 
         
            +
            import styles from './index.less';
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
             
            interface IProps {
         
     | 
| 29 | 
         
             
              nodeId?: string;
         
     | 
| 30 | 
         
             
            }
         
     | 
| 
         | 
|
| 115 | 
         
             
                        if (nodeId) updateNodeInternals(nodeId);
         
     | 
| 116 | 
         
             
                      };
         
     | 
| 117 | 
         
             
                      return (
         
     | 
| 118 | 
         
            +
                        <Flex gap={18} vertical>
         
     | 
| 
         | 
|
| 
         | 
|
| 119 | 
         
             
                          {fields.map((field) => (
         
     | 
| 120 | 
         
             
                            <Card
         
     | 
| 121 | 
         
             
                              size="small"
         
     | 
| 122 | 
         
             
                              key={field.key}
         
     | 
| 123 | 
         
            +
                              className={styles.caseCard}
         
     | 
| 124 | 
         
             
                              extra={
         
     | 
| 125 | 
         
             
                                <CloseOutlined
         
     | 
| 126 | 
         
             
                                  onClick={() => {
         
     | 
| 
         | 
|
| 181 | 
         
             
                            </Card>
         
     | 
| 182 | 
         
             
                          ))}
         
     | 
| 183 | 
         | 
| 184 | 
         
            +
                          <Button
         
     | 
| 185 | 
         
            +
                            type="dashed"
         
     | 
| 186 | 
         
            +
                            onClick={handleAdd}
         
     | 
| 187 | 
         
            +
                            block
         
     | 
| 188 | 
         
            +
                            className={styles.addButton}
         
     | 
| 189 | 
         
            +
                          >
         
     | 
| 190 | 
         
             
                            + {t('addItem')}
         
     | 
| 191 | 
         
             
                          </Button>
         
     | 
| 192 | 
         
            +
                        </Flex>
         
     | 
| 193 | 
         
             
                      );
         
     | 
| 194 | 
         
             
                    }}
         
     | 
| 195 | 
         
             
                  </Form.List>
         
     | 
    	
        web/src/pages/flow/form/categorize-form/index.less
    ADDED
    
    | 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            @lightBackgroundColor: rgba(150, 150, 150, 0.07);
         
     | 
| 2 | 
         
            +
            @darkBackgroundColor: rgba(150, 150, 150, 0.12);
         
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
            .caseCard {
         
     | 
| 5 | 
         
            +
              background-color: @darkBackgroundColor;
         
     | 
| 6 | 
         
            +
            }
         
     | 
| 7 | 
         
            +
             
     | 
| 8 | 
         
            +
            .addButton {
         
     | 
| 9 | 
         
            +
              color: rgb(22, 119, 255);
         
     | 
| 10 | 
         
            +
              font-weight: 600;
         
     | 
| 11 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/form/generate-form/dynamic-parameters.tsx
    CHANGED
    
    | 
         @@ -90,6 +90,7 @@ const DynamicParameters = ({ nodeId }: IProps) => { 
     | 
|
| 90 | 
         
             
                    components={components}
         
     | 
| 91 | 
         
             
                    rowClassName={() => styles.editableRow}
         
     | 
| 92 | 
         
             
                    scroll={{ x: true }}
         
     | 
| 
         | 
|
| 93 | 
         
             
                  />
         
     | 
| 94 | 
         
             
                </section>
         
     | 
| 95 | 
         
             
              );
         
     | 
| 
         | 
|
| 90 | 
         
             
                    components={components}
         
     | 
| 91 | 
         
             
                    rowClassName={() => styles.editableRow}
         
     | 
| 92 | 
         
             
                    scroll={{ x: true }}
         
     | 
| 93 | 
         
            +
                    bordered
         
     | 
| 94 | 
         
             
                  />
         
     | 
| 95 | 
         
             
                </section>
         
     | 
| 96 | 
         
             
              );
         
     | 
    	
        web/src/pages/flow/form/switch-form/index.less
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            @lightBackgroundColor: rgba(150, 150, 150, 0.07);
         
     | 
| 2 | 
         
            +
            @darkBackgroundColor: rgba(150, 150, 150, 0.12);
         
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
            .caseCard {
         
     | 
| 5 | 
         
            +
              background-color: @lightBackgroundColor;
         
     | 
| 6 | 
         
            +
            }
         
     | 
| 7 | 
         
            +
             
     | 
| 8 | 
         
            +
            .conditionCard {
         
     | 
| 9 | 
         
            +
              background-color: @darkBackgroundColor;
         
     | 
| 10 | 
         
            +
            }
         
     | 
| 11 | 
         
            +
             
     | 
| 12 | 
         
            +
            .elseCase {
         
     | 
| 13 | 
         
            +
              background-color: @lightBackgroundColor;
         
     | 
| 14 | 
         
            +
              padding: 12px;
         
     | 
| 15 | 
         
            +
              border-radius: 8px;
         
     | 
| 16 | 
         
            +
            }
         
     | 
| 17 | 
         
            +
             
     | 
| 18 | 
         
            +
            .addButton {
         
     | 
| 19 | 
         
            +
              color: rgb(22, 119, 255);
         
     | 
| 20 | 
         
            +
              font-weight: 600;
         
     | 
| 21 | 
         
            +
            }
         
     | 
    	
        web/src/pages/flow/form/switch-form/index.tsx
    CHANGED
    
    | 
         @@ -13,6 +13,8 @@ import { useBuildComponentIdSelectOptions } from '../../hooks'; 
     | 
|
| 13 | 
         
             
            import { IOperatorForm, ISwitchForm } from '../../interface';
         
     | 
| 14 | 
         
             
            import { getOtherFieldValues } from '../../utils';
         
     | 
| 15 | 
         | 
| 
         | 
|
| 
         | 
|
| 16 | 
         
             
            const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
         
     | 
| 17 | 
         
             
              const { t } = useTranslation();
         
     | 
| 18 | 
         
             
              const buildCategorizeToOptions = useBuildFormSelectOptions(
         
     | 
| 
         @@ -55,112 +57,134 @@ const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => { 
     | 
|
| 55 | 
         
             
                  <Form.List name="conditions">
         
     | 
| 56 | 
         
             
                    {(fields, { add, remove }) => (
         
     | 
| 57 | 
         
             
                      <div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
         
     | 
| 58 | 
         
            -
                        {fields.map((field) =>  
     | 
| 59 | 
         
            -
                           
     | 
| 60 | 
         
            -
                             
     | 
| 61 | 
         
            -
             
     | 
| 62 | 
         
            -
             
     | 
| 63 | 
         
            -
             
     | 
| 64 | 
         
            -
                               
     | 
| 65 | 
         
            -
             
     | 
| 66 | 
         
            -
             
     | 
| 67 | 
         
            -
             
     | 
| 68 | 
         
            -
             
     | 
| 69 | 
         
            -
             
     | 
| 70 | 
         
            -
             
     | 
| 71 | 
         
            -
                            <Form.Item noStyle dependencies={[field.name, 'items']}>
         
     | 
| 72 | 
         
            -
                              {({ getFieldValue }) =>
         
     | 
| 73 | 
         
            -
                                getFieldValue(['conditions', field.name, 'items'])?.length >
         
     | 
| 74 | 
         
            -
                                  1 && (
         
     | 
| 75 | 
         
            -
                                  <Form.Item
         
     | 
| 76 | 
         
            -
                                    label={t('flow.logicalOperator')}
         
     | 
| 77 | 
         
            -
                                    name={[field.name, 'logical_operator']}
         
     | 
| 78 | 
         
            -
                                  >
         
     | 
| 79 | 
         
            -
                                    <Select options={switchLogicOperatorOptions} />
         
     | 
| 80 | 
         
            -
                                  </Form.Item>
         
     | 
| 81 | 
         
            -
                                )
         
     | 
| 82 | 
         
             
                              }
         
     | 
| 83 | 
         
            -
                             
     | 
| 84 | 
         
            -
             
     | 
| 85 | 
         
            -
             
     | 
| 86 | 
         
            -
             
     | 
| 87 | 
         
            -
             
     | 
| 88 | 
         
            -
             
     | 
| 89 | 
         
            -
             
     | 
| 90 | 
         
            -
             
     | 
| 91 | 
         
            -
             
     | 
| 92 | 
         
            -
             
     | 
| 93 | 
         
            -
             
     | 
| 94 | 
         
            -
             
     | 
| 95 | 
         
            -
                                 
     | 
| 96 | 
         
            -
             
     | 
| 97 | 
         
            -
             
     | 
| 98 | 
         
            -
             
     | 
| 99 | 
         
            -
             
     | 
| 100 | 
         
            -
             
     | 
| 101 | 
         
            -
                                     
     | 
| 102 | 
         
            -
             
     | 
| 103 | 
         
            -
             
     | 
| 104 | 
         
            -
                                       
     | 
| 105 | 
         
            -
             
     | 
| 106 | 
         
            -
             
     | 
| 107 | 
         
            -
             
     | 
| 108 | 
         
            -
             
     | 
| 109 | 
         
            -
             
     | 
| 110 | 
         
            -
             
     | 
| 111 | 
         
            -
             
     | 
| 112 | 
         
            -
             
     | 
| 113 | 
         
            -
             
     | 
| 114 | 
         
            -
             
     | 
| 115 | 
         
            -
                                       
     | 
| 116 | 
         
            -
                                         
     | 
| 117 | 
         
            -
             
     | 
| 118 | 
         
            -
             
     | 
| 119 | 
         
            -
             
     | 
| 120 | 
         
            -
                                          <Select
         
     | 
| 121 | 
         
            -
                                            placeholder={t('flow.componentId')}
         
     | 
| 122 | 
         
            -
                                            options={componentIdOptions}
         
     | 
| 123 | 
         
            -
                                          />
         
     | 
| 124 | 
         
            -
                                        </Form.Item>
         
     | 
| 125 | 
         
            -
                                        <Form.Item
         
     | 
| 126 | 
         
            -
                                          label={t('flow.operator')}
         
     | 
| 127 | 
         
            -
                                          name={[subField.name, 'operator']}
         
     | 
| 128 | 
         
            -
                                        >
         
     | 
| 129 | 
         
            -
                                          <Select
         
     | 
| 130 | 
         
            -
                                            placeholder={t('flow.operator')}
         
     | 
| 131 | 
         
            -
                                            options={switchOperatorOptions}
         
     | 
| 132 | 
         
            -
                                          />
         
     | 
| 133 | 
         
            -
                                        </Form.Item>
         
     | 
| 134 | 
         
            -
                                        <Form.Item
         
     | 
| 135 | 
         
            -
                                          label={t('flow.value')}
         
     | 
| 136 | 
         
            -
                                          name={[subField.name, 'value']}
         
     | 
| 137 | 
         
            -
                                        >
         
     | 
| 138 | 
         
            -
                                          <Input placeholder={t('flow.value')} />
         
     | 
| 139 | 
         
            -
                                        </Form.Item>
         
     | 
| 140 | 
         
            -
                                      </Card>
         
     | 
| 141 | 
         
            -
                                    ))}
         
     | 
| 142 | 
         
            -
                                    <Button
         
     | 
| 143 | 
         
            -
                                      type="dashed"
         
     | 
| 144 | 
         
            -
                                      onClick={() => subOpt.add()}
         
     | 
| 145 | 
         
            -
                                      block
         
     | 
| 146 | 
         
             
                                    >
         
     | 
| 147 | 
         
            -
                                       
     | 
| 148 | 
         
            -
             
     | 
| 149 | 
         
            -
             
     | 
| 150 | 
         
            -
             
     | 
| 151 | 
         
            -
             
     | 
| 152 | 
         
            -
             
     | 
| 153 | 
         
            -
             
     | 
| 154 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 155 | 
         | 
| 156 | 
         
            -
                        <Button  
     | 
| 157 | 
         
             
                          + Add Case
         
     | 
| 158 | 
         
             
                        </Button>
         
     | 
| 159 | 
         
             
                      </div>
         
     | 
| 160 | 
         
             
                    )}
         
     | 
| 161 | 
         
             
                  </Form.List>
         
     | 
| 162 | 
         
             
                  <Divider />
         
     | 
| 163 | 
         
            -
                  <Form.Item 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 164 | 
         
             
                    <Select
         
     | 
| 165 | 
         
             
                      allowClear
         
     | 
| 166 | 
         
             
                      options={buildCategorizeToOptions(getSelectedConditionTos())}
         
     | 
| 
         | 
|
| 13 | 
         
             
            import { IOperatorForm, ISwitchForm } from '../../interface';
         
     | 
| 14 | 
         
             
            import { getOtherFieldValues } from '../../utils';
         
     | 
| 15 | 
         | 
| 16 | 
         
            +
            import styles from './index.less';
         
     | 
| 17 | 
         
            +
             
     | 
| 18 | 
         
             
            const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
         
     | 
| 19 | 
         
             
              const { t } = useTranslation();
         
     | 
| 20 | 
         
             
              const buildCategorizeToOptions = useBuildFormSelectOptions(
         
     | 
| 
         | 
|
| 57 | 
         
             
                  <Form.List name="conditions">
         
     | 
| 58 | 
         
             
                    {(fields, { add, remove }) => (
         
     | 
| 59 | 
         
             
                      <div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
         
     | 
| 60 | 
         
            +
                        {fields.map((field) => {
         
     | 
| 61 | 
         
            +
                          return (
         
     | 
| 62 | 
         
            +
                            <Card
         
     | 
| 63 | 
         
            +
                              size="small"
         
     | 
| 64 | 
         
            +
                              title={`Case ${field.name + 1}`}
         
     | 
| 65 | 
         
            +
                              key={field.key}
         
     | 
| 66 | 
         
            +
                              className={styles.caseCard}
         
     | 
| 67 | 
         
            +
                              extra={
         
     | 
| 68 | 
         
            +
                                <CloseOutlined
         
     | 
| 69 | 
         
            +
                                  onClick={() => {
         
     | 
| 70 | 
         
            +
                                    remove(field.name);
         
     | 
| 71 | 
         
            +
                                  }}
         
     | 
| 72 | 
         
            +
                                />
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 73 | 
         
             
                              }
         
     | 
| 74 | 
         
            +
                            >
         
     | 
| 75 | 
         
            +
                              <Form.Item noStyle dependencies={[field.name, 'items']}>
         
     | 
| 76 | 
         
            +
                                {({ getFieldValue }) =>
         
     | 
| 77 | 
         
            +
                                  getFieldValue(['conditions', field.name, 'items'])
         
     | 
| 78 | 
         
            +
                                    ?.length > 1 && (
         
     | 
| 79 | 
         
            +
                                    <Form.Item
         
     | 
| 80 | 
         
            +
                                      label={t('flow.logicalOperator')}
         
     | 
| 81 | 
         
            +
                                      name={[field.name, 'logical_operator']}
         
     | 
| 82 | 
         
            +
                                    >
         
     | 
| 83 | 
         
            +
                                      <Select options={switchLogicOperatorOptions} />
         
     | 
| 84 | 
         
            +
                                    </Form.Item>
         
     | 
| 85 | 
         
            +
                                  )
         
     | 
| 86 | 
         
            +
                                }
         
     | 
| 87 | 
         
            +
                              </Form.Item>
         
     | 
| 88 | 
         
            +
                              <Form.Item label={t('flow.to')} name={[field.name, 'to']}>
         
     | 
| 89 | 
         
            +
                                <Select
         
     | 
| 90 | 
         
            +
                                  allowClear
         
     | 
| 91 | 
         
            +
                                  options={buildCategorizeToOptions([
         
     | 
| 92 | 
         
            +
                                    form?.getFieldValue(SwitchElseTo),
         
     | 
| 93 | 
         
            +
                                    ...getOtherFieldValues(
         
     | 
| 94 | 
         
            +
                                      form!,
         
     | 
| 95 | 
         
            +
                                      'conditions',
         
     | 
| 96 | 
         
            +
                                      field,
         
     | 
| 97 | 
         
            +
                                      'to',
         
     | 
| 98 | 
         
            +
                                    ),
         
     | 
| 99 | 
         
            +
                                  ])}
         
     | 
| 100 | 
         
            +
                                />
         
     | 
| 101 | 
         
            +
                              </Form.Item>
         
     | 
| 102 | 
         
            +
                              <Form.Item label="Condition">
         
     | 
| 103 | 
         
            +
                                <Form.List name={[field.name, 'items']}>
         
     | 
| 104 | 
         
            +
                                  {(subFields, subOpt) => (
         
     | 
| 105 | 
         
            +
                                    <div
         
     | 
| 106 | 
         
            +
                                      style={{
         
     | 
| 107 | 
         
            +
                                        display: 'flex',
         
     | 
| 108 | 
         
            +
                                        flexDirection: 'column',
         
     | 
| 109 | 
         
            +
                                        rowGap: 16,
         
     | 
| 110 | 
         
            +
                                      }}
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 111 | 
         
             
                                    >
         
     | 
| 112 | 
         
            +
                                      {subFields.map((subField) => (
         
     | 
| 113 | 
         
            +
                                        <Card
         
     | 
| 114 | 
         
            +
                                          key={subField.key}
         
     | 
| 115 | 
         
            +
                                          title={null}
         
     | 
| 116 | 
         
            +
                                          size="small"
         
     | 
| 117 | 
         
            +
                                          className={styles.conditionCard}
         
     | 
| 118 | 
         
            +
                                          bordered
         
     | 
| 119 | 
         
            +
                                          extra={
         
     | 
| 120 | 
         
            +
                                            <CloseOutlined
         
     | 
| 121 | 
         
            +
                                              onClick={() => {
         
     | 
| 122 | 
         
            +
                                                subOpt.remove(subField.name);
         
     | 
| 123 | 
         
            +
                                              }}
         
     | 
| 124 | 
         
            +
                                            />
         
     | 
| 125 | 
         
            +
                                          }
         
     | 
| 126 | 
         
            +
                                        >
         
     | 
| 127 | 
         
            +
                                          <Form.Item
         
     | 
| 128 | 
         
            +
                                            label={t('flow.componentId')}
         
     | 
| 129 | 
         
            +
                                            name={[subField.name, 'cpn_id']}
         
     | 
| 130 | 
         
            +
                                          >
         
     | 
| 131 | 
         
            +
                                            <Select
         
     | 
| 132 | 
         
            +
                                              placeholder={t('flow.componentId')}
         
     | 
| 133 | 
         
            +
                                              options={componentIdOptions}
         
     | 
| 134 | 
         
            +
                                            />
         
     | 
| 135 | 
         
            +
                                          </Form.Item>
         
     | 
| 136 | 
         
            +
                                          <Form.Item
         
     | 
| 137 | 
         
            +
                                            label={t('flow.operator')}
         
     | 
| 138 | 
         
            +
                                            name={[subField.name, 'operator']}
         
     | 
| 139 | 
         
            +
                                          >
         
     | 
| 140 | 
         
            +
                                            <Select
         
     | 
| 141 | 
         
            +
                                              placeholder={t('flow.operator')}
         
     | 
| 142 | 
         
            +
                                              options={switchOperatorOptions}
         
     | 
| 143 | 
         
            +
                                            />
         
     | 
| 144 | 
         
            +
                                          </Form.Item>
         
     | 
| 145 | 
         
            +
                                          <Form.Item
         
     | 
| 146 | 
         
            +
                                            label={t('flow.value')}
         
     | 
| 147 | 
         
            +
                                            name={[subField.name, 'value']}
         
     | 
| 148 | 
         
            +
                                          >
         
     | 
| 149 | 
         
            +
                                            <Input placeholder={t('flow.value')} />
         
     | 
| 150 | 
         
            +
                                          </Form.Item>
         
     | 
| 151 | 
         
            +
                                        </Card>
         
     | 
| 152 | 
         
            +
                                      ))}
         
     | 
| 153 | 
         
            +
                                      <Button
         
     | 
| 154 | 
         
            +
                                        onClick={() => {
         
     | 
| 155 | 
         
            +
                                          form?.setFieldValue(
         
     | 
| 156 | 
         
            +
                                            ['conditions', field.name, 'logical_operator'],
         
     | 
| 157 | 
         
            +
                                            SwitchLogicOperatorOptions[0],
         
     | 
| 158 | 
         
            +
                                          );
         
     | 
| 159 | 
         
            +
                                          subOpt.add({
         
     | 
| 160 | 
         
            +
                                            operator: SwitchOperatorOptions[0].value,
         
     | 
| 161 | 
         
            +
                                          });
         
     | 
| 162 | 
         
            +
                                        }}
         
     | 
| 163 | 
         
            +
                                        block
         
     | 
| 164 | 
         
            +
                                        className={styles.addButton}
         
     | 
| 165 | 
         
            +
                                      >
         
     | 
| 166 | 
         
            +
                                        + Add Condition
         
     | 
| 167 | 
         
            +
                                      </Button>
         
     | 
| 168 | 
         
            +
                                    </div>
         
     | 
| 169 | 
         
            +
                                  )}
         
     | 
| 170 | 
         
            +
                                </Form.List>
         
     | 
| 171 | 
         
            +
                              </Form.Item>
         
     | 
| 172 | 
         
            +
                            </Card>
         
     | 
| 173 | 
         
            +
                          );
         
     | 
| 174 | 
         
            +
                        })}
         
     | 
| 175 | 
         | 
| 176 | 
         
            +
                        <Button onClick={() => add()} block className={styles.addButton}>
         
     | 
| 177 | 
         
             
                          + Add Case
         
     | 
| 178 | 
         
             
                        </Button>
         
     | 
| 179 | 
         
             
                      </div>
         
     | 
| 180 | 
         
             
                    )}
         
     | 
| 181 | 
         
             
                  </Form.List>
         
     | 
| 182 | 
         
             
                  <Divider />
         
     | 
| 183 | 
         
            +
                  <Form.Item
         
     | 
| 184 | 
         
            +
                    label={'ELSE'}
         
     | 
| 185 | 
         
            +
                    name={[SwitchElseTo]}
         
     | 
| 186 | 
         
            +
                    className={styles.elseCase}
         
     | 
| 187 | 
         
            +
                  >
         
     | 
| 188 | 
         
             
                    <Select
         
     | 
| 189 | 
         
             
                      allowClear
         
     | 
| 190 | 
         
             
                      options={buildCategorizeToOptions(getSelectedConditionTos())}
         
     | 
    	
        web/src/pages/flow/hooks.ts
    CHANGED
    
    | 
         @@ -69,6 +69,7 @@ import useGraphStore, { RFState } from './store'; 
     | 
|
| 69 | 
         
             
            import {
         
     | 
| 70 | 
         
             
              buildDslComponentsByGraph,
         
     | 
| 71 | 
         
             
              generateSwitchHandleText,
         
     | 
| 
         | 
|
| 72 | 
         
             
              receiveMessageError,
         
     | 
| 73 | 
         
             
              replaceIdWithText,
         
     | 
| 74 | 
         
             
            } from './utils';
         
     | 
| 
         @@ -250,6 +251,7 @@ export const useHandleDrop = () => { 
     | 
|
| 250 | 
         
             
                    },
         
     | 
| 251 | 
         
             
                    sourcePosition: Position.Right,
         
     | 
| 252 | 
         
             
                    targetPosition: Position.Left,
         
     | 
| 
         | 
|
| 253 | 
         
             
                  };
         
     | 
| 254 | 
         | 
| 255 | 
         
             
                  addNode(newNode);
         
     | 
| 
         @@ -448,11 +450,16 @@ export const useValidateConnection = () => { 
     | 
|
| 448 | 
         
             
              return isValidConnection;
         
     | 
| 449 | 
         
             
            };
         
     | 
| 450 | 
         | 
| 451 | 
         
            -
            export const useHandleNodeNameChange = ( 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 452 | 
         
             
              const [name, setName] = useState<string>('');
         
     | 
| 453 | 
         
             
              const { updateNodeName, nodes } = useGraphStore((state) => state);
         
     | 
| 454 | 
         
            -
              const previousName =  
     | 
| 455 | 
         
            -
              const id = node?.id;
         
     | 
| 456 | 
         | 
| 457 | 
         
             
              const handleNameBlur = useCallback(() => {
         
     | 
| 458 | 
         
             
                const existsSameName = nodes.some((x) => x.data.name === name);
         
     | 
| 
         @@ -639,6 +646,7 @@ const ExcludedNodes = [ 
     | 
|
| 639 | 
         
             
              Operator.Relevant,
         
     | 
| 640 | 
         
             
              Operator.Begin,
         
     | 
| 641 | 
         
             
              Operator.Answer,
         
     | 
| 
         | 
|
| 642 | 
         
             
            ];
         
     | 
| 643 | 
         | 
| 644 | 
         
             
            export const useBuildComponentIdSelectOptions = (nodeId?: string) => {
         
     | 
| 
         @@ -655,3 +663,15 @@ export const useBuildComponentIdSelectOptions = (nodeId?: string) => { 
     | 
|
| 655 | 
         | 
| 656 | 
         
             
              return options;
         
     | 
| 657 | 
         
             
            };
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 69 | 
         
             
            import {
         
     | 
| 70 | 
         
             
              buildDslComponentsByGraph,
         
     | 
| 71 | 
         
             
              generateSwitchHandleText,
         
     | 
| 72 | 
         
            +
              getNodeDragHandle,
         
     | 
| 73 | 
         
             
              receiveMessageError,
         
     | 
| 74 | 
         
             
              replaceIdWithText,
         
     | 
| 75 | 
         
             
            } from './utils';
         
     | 
| 
         | 
|
| 251 | 
         
             
                    },
         
     | 
| 252 | 
         
             
                    sourcePosition: Position.Right,
         
     | 
| 253 | 
         
             
                    targetPosition: Position.Left,
         
     | 
| 254 | 
         
            +
                    dragHandle: getNodeDragHandle(type),
         
     | 
| 255 | 
         
             
                  };
         
     | 
| 256 | 
         | 
| 257 | 
         
             
                  addNode(newNode);
         
     | 
| 
         | 
|
| 450 | 
         
             
              return isValidConnection;
         
     | 
| 451 | 
         
             
            };
         
     | 
| 452 | 
         | 
| 453 | 
         
            +
            export const useHandleNodeNameChange = ({
         
     | 
| 454 | 
         
            +
              id,
         
     | 
| 455 | 
         
            +
              data,
         
     | 
| 456 | 
         
            +
            }: {
         
     | 
| 457 | 
         
            +
              id?: string;
         
     | 
| 458 | 
         
            +
              data: any;
         
     | 
| 459 | 
         
            +
            }) => {
         
     | 
| 460 | 
         
             
              const [name, setName] = useState<string>('');
         
     | 
| 461 | 
         
             
              const { updateNodeName, nodes } = useGraphStore((state) => state);
         
     | 
| 462 | 
         
            +
              const previousName = data?.name;
         
     | 
| 
         | 
|
| 463 | 
         | 
| 464 | 
         
             
              const handleNameBlur = useCallback(() => {
         
     | 
| 465 | 
         
             
                const existsSameName = nodes.some((x) => x.data.name === name);
         
     | 
| 
         | 
|
| 646 | 
         
             
              Operator.Relevant,
         
     | 
| 647 | 
         
             
              Operator.Begin,
         
     | 
| 648 | 
         
             
              Operator.Answer,
         
     | 
| 649 | 
         
            +
              Operator.Note,
         
     | 
| 650 | 
         
             
            ];
         
     | 
| 651 | 
         | 
| 652 | 
         
             
            export const useBuildComponentIdSelectOptions = (nodeId?: string) => {
         
     | 
| 
         | 
|
| 663 | 
         | 
| 664 | 
         
             
              return options;
         
     | 
| 665 | 
         
             
            };
         
     | 
| 666 | 
         
            +
             
     | 
| 667 | 
         
            +
            export const useGetComponentLabelByValue = (nodeId: string) => {
         
     | 
| 668 | 
         
            +
              const options = useBuildComponentIdSelectOptions(nodeId);
         
     | 
| 669 | 
         
            +
             
     | 
| 670 | 
         
            +
              const getLabel = useCallback(
         
     | 
| 671 | 
         
            +
                (val?: string) => {
         
     | 
| 672 | 
         
            +
                  return options.find((x) => x.value === val)?.label;
         
     | 
| 673 | 
         
            +
                },
         
     | 
| 674 | 
         
            +
                [options],
         
     | 
| 675 | 
         
            +
              );
         
     | 
| 676 | 
         
            +
              return getLabel;
         
     | 
| 677 | 
         
            +
            };
         
     |