mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-22 12:20:34 +00:00
feat: support workflow node fold (#2797)
* feat: support workflow node fold * fix * fix
This commit is contained in:
1
packages/global/core/workflow/type/node.d.ts
vendored
1
packages/global/core/workflow/type/node.d.ts
vendored
@@ -104,6 +104,7 @@ export type FlowNodeItemType = FlowNodeTemplateType & {
|
||||
response?: ChatHistoryItemResType;
|
||||
isExpired?: boolean;
|
||||
};
|
||||
isFolded?: boolean;
|
||||
};
|
||||
|
||||
// store node type
|
||||
|
@@ -123,6 +123,7 @@ export const iconPaths = {
|
||||
'core/chat/chatLight': () => import('./icons/core/chat/chatLight.svg'),
|
||||
'core/chat/chatModelTag': () => import('./icons/core/chat/chatModelTag.svg'),
|
||||
'core/chat/chevronDown': () => import('./icons/core/chat/chevronDown.svg'),
|
||||
'core/chat/chevronRight': () => import('./icons/core/chat/chevronRight.svg'),
|
||||
'core/chat/chevronSelector': () => import('./icons/core/chat/chevronSelector.svg'),
|
||||
'core/chat/chevronUp': () => import('./icons/core/chat/chevronUp.svg'),
|
||||
'core/chat/export/pdf': () => import('./icons/core/chat/export/pdf.svg'),
|
||||
|
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.19277 5.29289C8.80224 5.68342 8.80224 6.31658 9.19277 6.70711L14.4857 12L9.19277 17.2929C8.80224 17.6834 8.80224 18.3166 9.19277 18.7071C9.58329 19.0976 10.2165 19.0976 10.607 18.7071L16.607 12.7071C16.9975 12.3166 16.9975 11.6834 16.607 11.2929L10.607 5.29289C10.2165 4.90237 9.58329 4.90237 9.19277 5.29289Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 448 B |
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
@@ -27,6 +27,16 @@ const ButtonEdge = (props: EdgeProps) => {
|
||||
targetHandleId,
|
||||
style
|
||||
} = props;
|
||||
|
||||
const parentNode = useMemo(() => {
|
||||
for (const node of nodeList) {
|
||||
if ((node.nodeId === source || node.nodeId === target) && node.parentNodeId) {
|
||||
return nodeList.find((parent) => parent.nodeId === node.parentNodeId);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}, [nodeList, source, target]);
|
||||
|
||||
const defaultZIndex = useMemo(
|
||||
() => (nodeList.find((node) => node.nodeId === source && node.parentNodeId) ? 1001 : 0),
|
||||
[nodeList, source]
|
||||
@@ -127,55 +137,59 @@ const ButtonEdge = (props: EdgeProps) => {
|
||||
})();
|
||||
return (
|
||||
<EdgeLabelRenderer>
|
||||
<Flex
|
||||
display={isHover || highlightEdge ? 'flex' : 'none'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
position={'absolute'}
|
||||
transform={`translate(-55%, -50%) translate(${labelX}px,${labelY}px)`}
|
||||
pointerEvents={'all'}
|
||||
w={'17px'}
|
||||
h={'17px'}
|
||||
bg={'white'}
|
||||
borderRadius={'17px'}
|
||||
cursor={'pointer'}
|
||||
zIndex={9999}
|
||||
onClick={() => onDelConnect(id)}
|
||||
>
|
||||
<MyIcon name={'core/workflow/closeEdge'} w={'100%'}></MyIcon>
|
||||
</Flex>
|
||||
{!isToolEdge && (
|
||||
<Box hidden={parentNode?.isFolded}>
|
||||
<Flex
|
||||
display={isHover || highlightEdge ? 'flex' : 'none'}
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
position={'absolute'}
|
||||
transform={arrowTransform}
|
||||
transform={`translate(-55%, -50%) translate(${labelX}px,${labelY}px)`}
|
||||
pointerEvents={'all'}
|
||||
w={highlightEdge ? '14px' : '10px'}
|
||||
h={highlightEdge ? '14px' : '10px'}
|
||||
// bg={'white'}
|
||||
zIndex={highlightEdge ? 1000 : defaultZIndex}
|
||||
w={'17px'}
|
||||
h={'17px'}
|
||||
bg={'white'}
|
||||
borderRadius={'17px'}
|
||||
cursor={'pointer'}
|
||||
zIndex={9999}
|
||||
onClick={() => onDelConnect(id)}
|
||||
>
|
||||
<MyIcon
|
||||
name={'core/workflow/edgeArrow'}
|
||||
w={'100%'}
|
||||
color={edgeColor}
|
||||
{...(highlightEdge
|
||||
? {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
: {})}
|
||||
></MyIcon>
|
||||
<MyIcon name={'core/workflow/closeEdge'} w={'100%'}></MyIcon>
|
||||
</Flex>
|
||||
)}
|
||||
{!isToolEdge && (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
justifyContent={'center'}
|
||||
position={'absolute'}
|
||||
transform={arrowTransform}
|
||||
pointerEvents={'all'}
|
||||
w={highlightEdge ? '14px' : '10px'}
|
||||
h={highlightEdge ? '14px' : '10px'}
|
||||
// bg={'white'}
|
||||
zIndex={highlightEdge ? 1000 : defaultZIndex}
|
||||
>
|
||||
<MyIcon
|
||||
name={'core/workflow/edgeArrow'}
|
||||
w={'100%'}
|
||||
color={edgeColor}
|
||||
{...(highlightEdge
|
||||
? {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
: {})}
|
||||
></MyIcon>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
</EdgeLabelRenderer>
|
||||
);
|
||||
}, [
|
||||
parentNode?.isFolded,
|
||||
isHover,
|
||||
highlightEdge,
|
||||
labelX,
|
||||
labelY,
|
||||
isToolEdge,
|
||||
defaultZIndex,
|
||||
edgeColor,
|
||||
targetPosition,
|
||||
newTargetX,
|
||||
@@ -214,7 +228,8 @@ const ButtonEdge = (props: EdgeProps) => {
|
||||
targetY={newTargetY}
|
||||
style={{
|
||||
...edgeStyle,
|
||||
stroke: edgeColor
|
||||
stroke: edgeColor,
|
||||
display: parentNode?.isFolded ? 'none' : 'block'
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -227,7 +242,8 @@ const ButtonEdge = (props: EdgeProps) => {
|
||||
source,
|
||||
target,
|
||||
style,
|
||||
highlightEdge
|
||||
highlightEdge,
|
||||
parentNode?.isFolded
|
||||
]);
|
||||
|
||||
return (
|
||||
|
@@ -1,5 +1,13 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Background, ControlButton, MiniMap, Panel, useReactFlow, useViewport } from 'reactflow';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Background,
|
||||
ControlButton,
|
||||
MiniMap,
|
||||
MiniMapNodeProps,
|
||||
Panel,
|
||||
useReactFlow,
|
||||
useViewport
|
||||
} from 'reactflow';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
@@ -26,7 +34,8 @@ const FlowController = React.memo(function FlowController() {
|
||||
canUndo,
|
||||
workflowControlMode,
|
||||
setWorkflowControlMode,
|
||||
mouseInCanvas
|
||||
mouseInCanvas,
|
||||
nodeList
|
||||
} = useContextSelector(WorkflowContext, (v) => v);
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -52,6 +61,20 @@ const FlowController = React.memo(function FlowController() {
|
||||
zoomOut();
|
||||
});
|
||||
|
||||
const MiniMapNode = useCallback(
|
||||
({ x, y, width, height, color, id }: MiniMapNodeProps) => {
|
||||
const node = nodeList.find((node) => node.nodeId === id);
|
||||
const parentNode = nodeList.find((n) => n.nodeId === node?.parentNodeId);
|
||||
|
||||
if (parentNode?.isFolded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <rect x={x} y={y} width={width} height={height} fill={color} />;
|
||||
},
|
||||
[nodeList]
|
||||
);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
@@ -64,6 +87,7 @@ const FlowController = React.memo(function FlowController() {
|
||||
boxShadow: '0px 0px 1px rgba(19, 51, 107, 0.10), 0px 4px 10px rgba(19, 51, 107, 0.10)'
|
||||
}}
|
||||
pannable
|
||||
nodeComponent={MiniMapNode}
|
||||
/>
|
||||
<Panel
|
||||
position={'bottom-right'}
|
||||
@@ -180,9 +204,10 @@ const FlowController = React.memo(function FlowController() {
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
MiniMapNode,
|
||||
workflowControlMode,
|
||||
isMac,
|
||||
t,
|
||||
isMac,
|
||||
undo,
|
||||
canUndo,
|
||||
redo,
|
||||
|
@@ -13,7 +13,8 @@ import {
|
||||
getNodesBounds,
|
||||
Rect,
|
||||
NodeRemoveChange,
|
||||
NodeSelectionChange
|
||||
NodeSelectionChange,
|
||||
Position
|
||||
} from 'reactflow';
|
||||
import { EDGE_TYPE, FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import 'reactflow/dist/style.css';
|
||||
@@ -30,6 +31,8 @@ import {
|
||||
Input_Template_Node_Width
|
||||
} from '@fastgpt/global/core/workflow/template/input';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { IfElseResultEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||
|
||||
/*
|
||||
Compute helper lines for snapping nodes to each other
|
||||
@@ -367,8 +370,8 @@ export const useWorkflow = () => {
|
||||
const checkNodeOverLoopNode = useMemoizedFn((node: Node) => {
|
||||
if (!node) return;
|
||||
|
||||
// 获取所有与当前节点相交的节点
|
||||
const intersections = getIntersectingNodes(node);
|
||||
// 获取所有与当前节点相交的节点,不包含折叠的节点
|
||||
const intersections = getIntersectingNodes(node).filter((node) => !node.data.isFolded);
|
||||
// 获取所有与当前节点相交的节点中,类型为 loop 的节点
|
||||
const parentNode = intersections.find((item) => item.type === FlowNodeTypeEnum.loop);
|
||||
|
||||
@@ -544,9 +547,19 @@ export const useWorkflow = () => {
|
||||
/* connect */
|
||||
const onConnectStart = useCallback(
|
||||
(event: any, params: OnConnectStartParams) => {
|
||||
if (!params.nodeId) return;
|
||||
const sourceNode = nodes.find((node) => node.id === params.nodeId);
|
||||
if (sourceNode?.data.isFolded) {
|
||||
return onChangeNode({
|
||||
nodeId: params.nodeId,
|
||||
type: 'attr',
|
||||
key: 'isFolded',
|
||||
value: false
|
||||
});
|
||||
}
|
||||
setConnectingEdge(params);
|
||||
},
|
||||
[setConnectingEdge]
|
||||
[nodes, setConnectingEdge, onChangeNode]
|
||||
);
|
||||
const onConnectEnd = useCallback(() => {
|
||||
setConnectingEdge(undefined);
|
||||
@@ -581,7 +594,7 @@ export const useWorkflow = () => {
|
||||
connect
|
||||
});
|
||||
},
|
||||
[onConnect, t, toast]
|
||||
[onConnect, t, toast, nodes]
|
||||
);
|
||||
|
||||
/* edge */
|
||||
|
@@ -22,7 +22,7 @@ import { WorkflowContext } from '../../../context';
|
||||
|
||||
const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const { nodeId, inputs, outputs, isFolded } = data;
|
||||
const { onChangeNode, nodeList } = useContextSelector(WorkflowContext, (v) => v);
|
||||
|
||||
const { nodeWidth, nodeHeight } = useMemo(() => {
|
||||
@@ -53,14 +53,14 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
return (
|
||||
<NodeCard
|
||||
selected={selected}
|
||||
maxW={'full'}
|
||||
minW={900}
|
||||
minH={900}
|
||||
w={nodeWidth}
|
||||
h={nodeHeight}
|
||||
menuForbid={{
|
||||
copy: true
|
||||
}}
|
||||
maxW="full"
|
||||
{...(!isFolded && {
|
||||
minW: '900px',
|
||||
minH: '900px',
|
||||
w: nodeWidth,
|
||||
h: nodeHeight
|
||||
})}
|
||||
menuForbid={{ copy: true }}
|
||||
{...data}
|
||||
>
|
||||
<Container position={'relative'} flex={1}>
|
||||
|
@@ -94,17 +94,15 @@ const NodeLoopStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
<NodeCard
|
||||
selected={selected}
|
||||
{...data}
|
||||
w={'420px'}
|
||||
h={'176px'}
|
||||
menuForbid={{
|
||||
copy: true,
|
||||
delete: true,
|
||||
debug: true
|
||||
}}
|
||||
>
|
||||
<Box px={4}>
|
||||
<Box px={4} w={'420px'} h={'116px'}>
|
||||
{!loopItemInputType ? (
|
||||
<EmptyTip text={t('workflow:loop_start_tip')} py={0} mt={0} iconSize={'32px'} />
|
||||
<EmptyTip text={t('workflow:loop_start_tip')} py={0} mt={4} iconSize={'32px'} />
|
||||
) : (
|
||||
<Box bg={'white'} borderRadius={'md'} overflow={'hidden'} border={'base'}>
|
||||
<TableContainer>
|
||||
|
@@ -56,11 +56,6 @@ const NodeUserSelect = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
value: options.filter((input) => input.key !== item.key)
|
||||
}
|
||||
});
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'delOutput',
|
||||
key: item.key
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</MyTooltip>
|
||||
|
@@ -6,7 +6,13 @@ import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../../context';
|
||||
|
||||
export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
||||
export const ConnectionSourceHandle = ({
|
||||
nodeId,
|
||||
isFoldNode
|
||||
}: {
|
||||
nodeId: string;
|
||||
isFoldNode?: boolean;
|
||||
}) => {
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
@@ -26,8 +32,7 @@ export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
||||
const rightTargetConnected = edges.some(
|
||||
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Right)
|
||||
);
|
||||
|
||||
if (!node || !node?.sourceHandle?.right || rightTargetConnected) return null;
|
||||
if (!isFoldNode && (!node || !node?.sourceHandle?.right || rightTargetConnected)) return null;
|
||||
|
||||
return (
|
||||
<SourceHandle
|
||||
@@ -102,7 +107,7 @@ export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
||||
TopHandlee,
|
||||
BottomHandlee
|
||||
};
|
||||
}, [connectingEdge, edges, nodeId, nodeList]);
|
||||
}, [connectingEdge, edges, nodeId, nodeList, isFoldNode]);
|
||||
|
||||
return showSourceHandle ? (
|
||||
<>
|
||||
|
@@ -32,8 +32,8 @@ const MySourceHandle = React.memo(function MySourceHandle({
|
||||
|
||||
const node = useMemo(() => nodes.find((node) => node.data.nodeId === nodeId), [nodes, nodeId]);
|
||||
const connected = edges.some((edge) => edge.sourceHandle === handleId);
|
||||
const nodeFolded = node?.data.isFolded && edges.some((edge) => edge.source === nodeId);
|
||||
const nodeIsHover = hoverNodeId === nodeId;
|
||||
|
||||
const active = useMemo(
|
||||
() => nodeIsHover || node?.selected || connectingEdge?.handleId === handleId,
|
||||
[nodeIsHover, node?.selected, connectingEdge, handleId]
|
||||
@@ -73,7 +73,7 @@ const MySourceHandle = React.memo(function MySourceHandle({
|
||||
};
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
if (connected || nodeFolded) {
|
||||
return {
|
||||
styles: {
|
||||
...connectedStyle,
|
||||
@@ -89,7 +89,7 @@ const MySourceHandle = React.memo(function MySourceHandle({
|
||||
styles: undefined,
|
||||
showAddIcon: false
|
||||
};
|
||||
}, [active, connected, highlightStyle, translateStr, transform, connectedStyle]);
|
||||
}, [active, connected, nodeFolded, highlightStyle, translateStr, transform, connectedStyle]);
|
||||
|
||||
const RenderHandle = useMemo(() => {
|
||||
return (
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Box, Button, Card, Flex, Image } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||
@@ -61,7 +61,8 @@ const NodeCard = (props: Props) => {
|
||||
menuForbid,
|
||||
isTool = false,
|
||||
isError = false,
|
||||
debugResult
|
||||
debugResult,
|
||||
isFolded
|
||||
} = props;
|
||||
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
@@ -81,7 +82,12 @@ const NodeCard = (props: Props) => {
|
||||
[isTool, nodeList]
|
||||
);
|
||||
|
||||
const node = nodeList.find((node) => node.nodeId === nodeId);
|
||||
const { node, parentNode } = useMemo(() => {
|
||||
const node = nodeList.find((node) => node.nodeId === nodeId);
|
||||
const parentNode = nodeList.find((n) => n.nodeId === node?.parentNodeId);
|
||||
return { node, parentNode };
|
||||
}, [nodeList, nodeId]);
|
||||
|
||||
const { openConfirm: onOpenConfirmSync, ConfirmModal: ConfirmSyncModal } = useConfirm({
|
||||
content: t('app:module.Confirm Sync')
|
||||
});
|
||||
@@ -155,6 +161,31 @@ const NodeCard = (props: Props) => {
|
||||
|
||||
{/* avatar and name */}
|
||||
<Flex alignItems={'center'}>
|
||||
<Box
|
||||
mr={2}
|
||||
cursor={'pointer'}
|
||||
rounded={'sm'}
|
||||
_hover={{ bg: 'myGray.200' }}
|
||||
onClick={() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'attr',
|
||||
key: 'isFolded',
|
||||
value: !isFolded
|
||||
});
|
||||
}}
|
||||
>
|
||||
{!isFolded ? (
|
||||
<MyIcon name={'core/chat/chevronDown'} w={'24px'} h={'24px'} color={'myGray.500'} />
|
||||
) : (
|
||||
<MyIcon
|
||||
name={'core/chat/chevronRight'}
|
||||
w={'24px'}
|
||||
h={'24px'}
|
||||
color={'myGray.500'}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Avatar src={avatar} borderRadius={'sm'} objectFit={'contain'} w={'30px'} h={'30px'} />
|
||||
<Box ml={3} fontSize={'md'} fontWeight={'medium'}>
|
||||
{t(name as any)}
|
||||
@@ -250,19 +281,21 @@ const NodeCard = (props: Props) => {
|
||||
ConfirmSyncModal,
|
||||
onOpenCustomTitleModal,
|
||||
onChangeNode,
|
||||
toast
|
||||
toast,
|
||||
isFolded
|
||||
]);
|
||||
const RenderHandle = useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
<ConnectionSourceHandle nodeId={nodeId} />
|
||||
<ConnectionSourceHandle nodeId={nodeId} isFoldNode={isFolded} />
|
||||
<ConnectionTargetHandle nodeId={nodeId} />
|
||||
</>
|
||||
);
|
||||
}, [nodeId]);
|
||||
}, [nodeId, isFolded]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
hidden={parentNode?.isFolded}
|
||||
flexDirection={'column'}
|
||||
minW={minW}
|
||||
maxW={maxW}
|
||||
@@ -298,7 +331,7 @@ const NodeCard = (props: Props) => {
|
||||
>
|
||||
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
|
||||
{Header}
|
||||
{children}
|
||||
{!isFolded && children}
|
||||
{RenderHandle}
|
||||
|
||||
<EditTitleModal maxLength={20} />
|
||||
|
@@ -561,9 +561,9 @@ const WorkflowContextProvider = ({
|
||||
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
||||
|
||||
if (!checkResults) {
|
||||
const storeNodes = uiWorkflow2StoreWorkflow({ nodes, edges });
|
||||
const storeWorkflow = uiWorkflow2StoreWorkflow({ nodes, edges });
|
||||
|
||||
return storeNodes;
|
||||
return storeWorkflow;
|
||||
} else if (!hideTip) {
|
||||
checkResults.forEach((nodeId) => onUpdateNodeError(nodeId, true));
|
||||
toast({
|
||||
|
@@ -25,7 +25,8 @@ export const uiWorkflow2StoreWorkflow = ({
|
||||
version: item.data.version,
|
||||
inputs: item.data.inputs,
|
||||
outputs: item.data.outputs,
|
||||
pluginId: item.data.pluginId
|
||||
pluginId: item.data.pluginId,
|
||||
isFolded: item.data.isFolded
|
||||
}));
|
||||
|
||||
// get all handle
|
||||
@@ -49,6 +50,8 @@ export const uiWorkflow2StoreWorkflow = ({
|
||||
(item) => {
|
||||
// Not in react flow page
|
||||
if (!reactFlowViewport) return true;
|
||||
const currentSourceNode = nodes.find((node) => node.data.nodeId === item.source);
|
||||
if (currentSourceNode?.data.isFolded) return true;
|
||||
return handleIdList.includes(item.sourceHandle) && handleIdList.includes(item.targetHandle);
|
||||
}
|
||||
);
|
||||
|
@@ -532,7 +532,8 @@ export const compareSnapshot = (
|
||||
name: node.data.name,
|
||||
intro: node.data.intro,
|
||||
avatar: node.data.avatar,
|
||||
version: node.data.version
|
||||
version: node.data.version,
|
||||
isFolded: node.data.isFolded
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
Reference in New Issue
Block a user