Skip to content

Commit

Permalink
feat: add context menu & comment node (#2834)
Browse files Browse the repository at this point in the history
* feat: add comment node

* useMemo
  • Loading branch information
newfish-cmyk authored Sep 29, 2024
1 parent 7bdff9c commit 7c829fe
Show file tree
Hide file tree
Showing 14 changed files with 440 additions and 113 deletions.
6 changes: 5 additions & 1 deletion packages/global/core/workflow/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ export enum NodeInputKeyEnum {
loopEndInput = 'loopEndInput',

// form input
userInputForms = 'userInputForms'
userInputForms = 'userInputForms',

// comment
commentText = 'commentText',
commentSize = 'commentSize'
}

export enum NodeOutputKeyEnum {
Expand Down
3 changes: 2 additions & 1 deletion packages/global/core/workflow/node/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ export enum FlowNodeTypeEnum {
loop = 'loop',
loopStart = 'loopStart',
loopEnd = 'loopEnd',
formInput = 'formInput'
formInput = 'formInput',
comment = 'comment'
}

// node IO value type
Expand Down
40 changes: 40 additions & 0 deletions packages/global/core/workflow/template/system/comment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node.d';
import {
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum,
WorkflowIOValueTypeEnum
} from '../../constants';
import { getHandleConfig } from '../utils';

export const CommentNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.comment,
templateType: FlowNodeTemplateTypeEnum.systemInput,
flowNodeType: FlowNodeTypeEnum.comment,
sourceHandle: getHandleConfig(false, false, false, false),
targetHandle: getHandleConfig(false, false, false, false),
avatar: '',
name: '',
intro: '',
version: '4811',
inputs: [
{
key: NodeInputKeyEnum.commentText,
renderTypeList: [],
valueType: WorkflowIOValueTypeEnum.string,
label: '',
value: ''
},
{
key: NodeInputKeyEnum.commentSize,
renderTypeList: [],
valueType: WorkflowIOValueTypeEnum.object,
label: '',
value: {
width: 240,
height: 140
}
}
],
outputs: []
};
1 change: 1 addition & 0 deletions packages/service/core/workflow/dispatch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
[FlowNodeTypeEnum.pluginConfig]: () => Promise.resolve(),
[FlowNodeTypeEnum.emptyNode]: () => Promise.resolve(),
[FlowNodeTypeEnum.globalVariable]: () => Promise.resolve(),
[FlowNodeTypeEnum.comment]: () => Promise.resolve(),

[FlowNodeTypeEnum.runApp]: dispatchAppRequest // abandoned
};
Expand Down
1 change: 1 addition & 0 deletions packages/web/components/common/Icon/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const iconPaths = {
closeSolid: () => import('./icons/closeSolid.svg'),
collectionLight: () => import('./icons/collectionLight.svg'),
collectionSolid: () => import('./icons/collectionSolid.svg'),
comment: () => import('./icons/comment.svg'),
'common/add2': () => import('./icons/common/add2.svg'),
'common/addCircleLight': () => import('./icons/common/addCircleLight.svg'),
'common/addLight': () => import('./icons/common/addLight.svg'),
Expand Down
3 changes: 3 additions & 0 deletions packages/web/components/common/Icon/icons/comment.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/web/i18n/en/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"contains": "Contains",
"content_to_retrieve": "Content to Retrieve",
"content_to_search": "Content to Search",
"context_menu.add_comment": "Add comment",
"create_link_error": "Error creating link",
"custom_feedback": "Custom Feedback",
"custom_input": "Custom Input",
Expand All @@ -38,6 +39,7 @@
"edit_input": "Edit Input",
"edit_output": "Edit output",
"end_with": "Ends With",
"enter_comment": "Enter comment",
"error_info_returns_empty_on_success": "Error information of code execution, returns empty on success",
"execute_a_simple_script_code_usually_for_complex_data_processing": "Execute a simple script code, usually for complex data processing.",
"execute_different_branches_based_on_conditions": "Execute different branches based on conditions.",
Expand Down
3 changes: 3 additions & 0 deletions packages/web/i18n/zh/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"contains": "包含",
"content_to_retrieve": "需要检索的内容",
"content_to_search": "需要检索的内容",
"contextMenu.addComment": "添加注释",
"context_menu.add_comment": "添加注释",
"create_link_error": "创建链接异常",
"custom_feedback": "自定义反馈",
"custom_input": "自定义输入",
Expand All @@ -38,6 +40,7 @@
"edit_input": "编辑输入",
"edit_output": "编辑输出",
"end_with": "结束为",
"enter_comment": "输入注释",
"error_info_returns_empty_on_success": "代码运行错误信息,成功时返回空",
"execute_a_simple_script_code_usually_for_complex_data_processing": "执行一段简单的脚本代码,通常用于进行复杂的数据处理。",
"execute_different_branches_based_on_conditions": "根据一定的条件,执行不同的分支。",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Box, Flex } from '@chakra-ui/react';
import React from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'react-i18next';
import { nodeTemplate2FlowNode } from '@/web/core/workflow/utils';
import { CommentNode } from '@fastgpt/global/core/workflow/template/system/comment';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../context';
import { useReactFlow } from 'reactflow';

type ContextMenuProps = {
top: number;
left: number;
};

const ContextMenu = ({ top, left }: ContextMenuProps) => {
const { t } = useTranslation();
const setNodes = useContextSelector(WorkflowContext, (ctx) => ctx.setNodes);
const setMenu = useContextSelector(WorkflowContext, (ctx) => ctx.setMenu);

const { screenToFlowPosition } = useReactFlow();
const newNode = nodeTemplate2FlowNode({
template: CommentNode,
position: screenToFlowPosition({ x: left, y: top }),
t
});

return (
<Box position="relative">
<Box
position="absolute"
top={`${top - 6}px`}
left={`${left + 10}px`}
width={0}
height={0}
borderLeft="6px solid transparent"
borderRight="6px solid transparent"
borderBottom="6px solid white"
zIndex={2}
filter="drop-shadow(0px -1px 2px rgba(0, 0, 0, 0.1))"
/>
<Flex
position={'absolute'}
top={top}
left={left}
bg={'white'}
w={'120px'}
height={9}
p={1}
rounded={'md'}
boxShadow={'0px 2px 4px 0px #A1A7B340'}
className="context-menu"
alignItems={'center'}
color={'myGray.600'}
cursor={'pointer'}
_hover={{
color: 'primary.500'
}}
onClick={() => {
setMenu(null);
setNodes((state) => {
const newState = state
.map((node) => ({
...node,
selected: false
}))
// @ts-ignore
.concat(newNode);
return newState;
});
}}
zIndex={1}
>
<MyIcon name="comment" w={'16px'} h={'16px'} ml={1} />
<Box fontSize={'12px'} fontWeight={'500'} ml={1.5}>
{t('workflow:context_menu.add_comment')}
</Box>
</Flex>
</Box>
);
};

export default React.memo(ContextMenu);
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ export const useWorkflow = () => {
setEdges,
onChangeNode,
onEdgesChange,
setHoverEdgeId
setHoverEdgeId,
setMenu
} = useContextSelector(WorkflowContext, (v) => v);

const { getIntersectingNodes } = useReactFlow();
Expand Down Expand Up @@ -599,7 +600,7 @@ export const useWorkflow = () => {
connect
});
},
[onConnect, t, toast, nodes]
[onConnect, t, toast]
);

/* edge */
Expand All @@ -613,6 +614,24 @@ export const useWorkflow = () => {
setHoverEdgeId(undefined);
}, [setHoverEdgeId]);

// context menu
const onPaneContextMenu = useCallback(
(e: any) => {
// Prevent native context menu from showing
e.preventDefault();

setMenu({
top: e.clientY - 64,
left: e.clientX - 12
});
},
[setMenu]
);

const onPaneClick = useCallback(() => {
setMenu(null);
}, [setMenu]);

return {
handleNodesChange,
handleEdgeChange,
Expand All @@ -624,7 +643,9 @@ export const useWorkflow = () => {
onEdgeMouseLeave,
helperLineHorizontal,
helperLineVertical,
onNodeDragStop
onNodeDragStop,
onPaneContextMenu,
onPaneClick
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { WorkflowContext } from '../context';
import { useWorkflow } from './hooks/useWorkflow';
import HelperLines from './components/HelperLines';
import FlowController from './components/FlowController';
import ContextMenu from './components/ContextMenu';

export const minZoom = 0.1;
export const maxZoom = 1.5;
Expand Down Expand Up @@ -57,14 +58,15 @@ const nodeTypes: Record<FlowNodeTypeEnum, any> = {
[FlowNodeTypeEnum.loop]: dynamic(() => import('./nodes/Loop/NodeLoop')),
[FlowNodeTypeEnum.loopStart]: dynamic(() => import('./nodes/Loop/NodeLoopStart')),
[FlowNodeTypeEnum.loopEnd]: dynamic(() => import('./nodes/Loop/NodeLoopEnd')),
[FlowNodeTypeEnum.formInput]: dynamic(() => import('./nodes/NodeFormInput'))
[FlowNodeTypeEnum.formInput]: dynamic(() => import('./nodes/NodeFormInput')),
[FlowNodeTypeEnum.comment]: dynamic(() => import('./nodes/NodeComment'))
};
const edgeTypes = {
[EDGE_TYPE]: ButtonEdge
};

const Workflow = () => {
const { nodes, edges, reactFlowWrapper, workflowControlMode } = useContextSelector(
const { nodes, edges, menu, reactFlowWrapper, workflowControlMode } = useContextSelector(
WorkflowContext,
(v) => v
);
Expand All @@ -79,7 +81,9 @@ const Workflow = () => {
onEdgeMouseLeave,
helperLineHorizontal,
helperLineVertical,
onNodeDragStop
onNodeDragStop,
onPaneContextMenu,
onPaneClick
} = useWorkflow();

const {
Expand Down Expand Up @@ -121,6 +125,7 @@ const Workflow = () => {
<NodeTemplatesModal isOpen={isOpenTemplate} onClose={onCloseTemplate} />
</>

{menu && <ContextMenu {...menu} />}
<ReactFlow
ref={reactFlowWrapper}
fitView
Expand All @@ -142,6 +147,8 @@ const Workflow = () => {
onEdgeMouseEnter={onEdgeMouseEnter}
onEdgeMouseLeave={onEdgeMouseLeave}
panOnScrollSpeed={2}
onPaneContextMenu={onPaneContextMenu}
onPaneClick={onPaneClick}
{...(workflowControlMode === 'select'
? {
selectionMode: SelectionMode.Full,
Expand Down
Loading

0 comments on commit 7c829fe

Please sign in to comment.