4.8.13 test (#3098)
* perf: loop node refresh * rename context * comment * fix: ts * perf: push chat log
This commit is contained in:
@@ -50,5 +50,5 @@ WORKFLOW_MAX_LOOP_TIMES=50
|
||||
|
||||
# 对话日志推送服务
|
||||
# URL/INTERVAL 为空时不推送
|
||||
CHAT_LOG_URL=http://localhost:8080
|
||||
CHAT_LOG_INTERVAL=10000
|
||||
# CHAT_LOG_URL=http://localhost:8080
|
||||
# CHAT_LOG_INTERVAL=10000
|
||||
|
||||
@@ -30,7 +30,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import SaveButton from '../Workflow/components/SaveButton';
|
||||
import PublishHistories from '../PublishHistoriesSlider';
|
||||
import {
|
||||
WorkflowActionContext,
|
||||
WorkflowNodeEdgeContext,
|
||||
WorkflowInitContext
|
||||
} from '../WorkflowComponents/context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../WorkflowComponents/context/workflowEventContext';
|
||||
@@ -50,7 +50,7 @@ const Header = () => {
|
||||
} = useDisclosure();
|
||||
|
||||
const nodes = useContextSelector(WorkflowInitContext, (v) => v.nodes);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const {
|
||||
flowData2StoreData,
|
||||
flowData2StoreDataAndCheck,
|
||||
|
||||
@@ -30,7 +30,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import SaveButton from './components/SaveButton';
|
||||
import PublishHistories from '../PublishHistoriesSlider';
|
||||
import {
|
||||
WorkflowActionContext,
|
||||
WorkflowNodeEdgeContext,
|
||||
WorkflowInitContext
|
||||
} from '../WorkflowComponents/context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../WorkflowComponents/context/workflowEventContext';
|
||||
@@ -54,7 +54,7 @@ const Header = () => {
|
||||
} = useDisclosure();
|
||||
|
||||
const nodes = useContextSelector(WorkflowInitContext, (v) => v.nodes);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const {
|
||||
flowData2StoreData,
|
||||
flowData2StoreDataAndCheck,
|
||||
|
||||
@@ -50,7 +50,7 @@ import { useUserStore } from '@/web/support/user/useUserStore';
|
||||
import { LoopStartNode } from '@fastgpt/global/core/workflow/template/system/loop/loopStart';
|
||||
import { LoopEndNode } from '@fastgpt/global/core/workflow/template/system/loop/loopEnd';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { WorkflowActionContext } from '../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../context/workflowInitContext';
|
||||
|
||||
type ModuleTemplateListProps = {
|
||||
isOpen: boolean;
|
||||
@@ -389,7 +389,7 @@ const RenderList = React.memo(function RenderList({
|
||||
const { computedNewNodeName } = useWorkflowUtils();
|
||||
const { toast } = useToast();
|
||||
|
||||
const setNodes = useContextSelector(WorkflowActionContext, (v) => v.setNodes);
|
||||
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setNodes);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const formatTemplates = useMemo<NodeTemplateListType>(() => {
|
||||
|
||||
@@ -6,12 +6,12 @@ import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/w
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
import { useThrottleEffect } from 'ahooks';
|
||||
import { WorkflowActionContext, WorkflowInitContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext, WorkflowInitContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../../context/workflowEventContext';
|
||||
|
||||
const ButtonEdge = (props: EdgeProps) => {
|
||||
const nodes = useContextSelector(WorkflowInitContext, (v) => v.nodes);
|
||||
const onEdgesChange = useContextSelector(WorkflowActionContext, (v) => v.onEdgesChange);
|
||||
const onEdgesChange = useContextSelector(WorkflowNodeEdgeContext, (v) => v.onEdgesChange);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||
const hoverEdgeId = useContextSelector(WorkflowEventContext, (v) => v.hoverEdgeId);
|
||||
|
||||
@@ -7,12 +7,12 @@ import { CommentNode } from '@fastgpt/global/core/workflow/template/system/comme
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
import { useReactFlow } from 'reactflow';
|
||||
import { WorkflowActionContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../../context/workflowEventContext';
|
||||
|
||||
const ContextMenu = () => {
|
||||
const { t } = useTranslation();
|
||||
const setNodes = useContextSelector(WorkflowActionContext, (v) => v.setNodes);
|
||||
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setNodes);
|
||||
const menu = useContextSelector(WorkflowEventContext, (v) => v.menu);
|
||||
const setMenu = useContextSelector(WorkflowEventContext, (ctx) => ctx.setMenu);
|
||||
|
||||
|
||||
@@ -51,13 +51,12 @@ const FlowController = React.memo(function FlowController() {
|
||||
e.stopPropagation();
|
||||
if (!mouseInCanvas) return;
|
||||
|
||||
const isUndo = e.key.toLowerCase() === 'z' && !e.shiftKey;
|
||||
const isRedo = (e.key.toLowerCase() === 'z' && e.shiftKey) || e.key.toLowerCase() === 'y';
|
||||
|
||||
if (isUndo) {
|
||||
undo();
|
||||
} else if (isRedo) {
|
||||
if (isRedo) {
|
||||
redo();
|
||||
} else {
|
||||
undo();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import { AppContext } from '../../../context';
|
||||
import { VariableInputItem } from '@/components/core/chat/ChatContainer/ChatBox/components/VariableInput';
|
||||
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
|
||||
import MyTextarea from '@/components/common/Textarea/MyTextarea';
|
||||
import { WorkflowActionContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../context/workflowInitContext';
|
||||
|
||||
const MyRightDrawer = dynamic(
|
||||
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
|
||||
@@ -50,9 +50,9 @@ export const useDebug = () => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
|
||||
const setNodes = useContextSelector(WorkflowActionContext, (v) => v.setNodes);
|
||||
const getNodes = useContextSelector(WorkflowActionContext, (v) => v.getNodes);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setNodes);
|
||||
const getNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.getNodes);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||
const onStartNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStartNodeDebug);
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ import { useContextSelector } from 'use-context-selector';
|
||||
import { useWorkflowUtils } from './useUtils';
|
||||
import { useKeyPress as useKeyPressEffect } from 'ahooks';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { WorkflowActionContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../../context/workflowEventContext';
|
||||
|
||||
export const useKeyboard = () => {
|
||||
const { t } = useTranslation();
|
||||
const getNodes = useContextSelector(WorkflowActionContext, (v) => v.getNodes);
|
||||
const setNodes = useContextSelector(WorkflowActionContext, (v) => v.setNodes);
|
||||
const getNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.getNodes);
|
||||
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setNodes);
|
||||
const mouseInCanvas = useContextSelector(WorkflowEventContext, (v) => v.mouseInCanvas);
|
||||
|
||||
const { copyData } = useCopyData();
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
Input_Template_Node_Width
|
||||
} from '@fastgpt/global/core/workflow/template/input';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import { WorkflowActionContext, WorkflowInitContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext, WorkflowInitContext } from '../../context/workflowInitContext';
|
||||
import { formatTime2YMDHMS } from '@fastgpt/global/common/string/time';
|
||||
import { AppContext } from '../../../context';
|
||||
import { WorkflowEventContext } from '../../context/workflowEventContext';
|
||||
@@ -278,10 +278,10 @@ export const useWorkflow = () => {
|
||||
const appDetail = useContextSelector(AppContext, (e) => e.appDetail);
|
||||
|
||||
const nodes = useContextSelector(WorkflowInitContext, (state) => state.nodes);
|
||||
const onNodesChange = useContextSelector(WorkflowActionContext, (state) => state.onNodesChange);
|
||||
const edges = useContextSelector(WorkflowActionContext, (state) => state.edges);
|
||||
const setEdges = useContextSelector(WorkflowActionContext, (v) => v.setEdges);
|
||||
const onEdgesChange = useContextSelector(WorkflowActionContext, (v) => v.onEdgesChange);
|
||||
const onNodesChange = useContextSelector(WorkflowNodeEdgeContext, (state) => state.onNodesChange);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (state) => state.edges);
|
||||
const setEdges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setEdges);
|
||||
const onEdgesChange = useContextSelector(WorkflowNodeEdgeContext, (v) => v.onEdgesChange);
|
||||
const { setConnectingEdge, nodeList, onChangeNode, pushPastSnapshot } = useContextSelector(
|
||||
WorkflowContext,
|
||||
(v) => v
|
||||
@@ -294,20 +294,9 @@ export const useWorkflow = () => {
|
||||
|
||||
// Loop node size and position
|
||||
const resetParentNodeSizeAndPosition = useMemoizedFn((parentId: string) => {
|
||||
const { childNodes, loopNode } = nodes.reduce(
|
||||
(acc, node) => {
|
||||
if (node.data.parentNodeId === parentId) {
|
||||
acc.childNodes.push(node);
|
||||
}
|
||||
if (node.id === parentId) {
|
||||
acc.loopNode = node;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ childNodes: [] as Node[], loopNode: undefined as Node | undefined }
|
||||
);
|
||||
const rect = getNodesBounds(childNodes);
|
||||
const childNodes = nodes.filter((node) => node.data.parentNodeId === parentId);
|
||||
|
||||
const rect = getNodesBounds(childNodes);
|
||||
// Calculate parent node size with minimum width/height constraints
|
||||
const width = Math.max(rect.width + 80, 840);
|
||||
const height = Math.max(rect.height + 80, 600);
|
||||
@@ -332,9 +321,6 @@ export const useWorkflow = () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate position offset
|
||||
const offsetHeight = loopNode?.height ? loopNode.height - height - 380 : 0;
|
||||
|
||||
// Update parentNode position
|
||||
onNodesChange([
|
||||
{
|
||||
@@ -342,7 +328,7 @@ export const useWorkflow = () => {
|
||||
type: 'position',
|
||||
position: {
|
||||
x: rect.x - 70,
|
||||
y: rect.y - (320 + offsetHeight)
|
||||
y: rect.y - 320
|
||||
}
|
||||
}
|
||||
]);
|
||||
@@ -392,15 +378,6 @@ export const useWorkflow = () => {
|
||||
|
||||
// Check if a node is placed on top of a loop node
|
||||
const checkNodeOverLoopNode = useMemoizedFn((node: Node) => {
|
||||
if (!node) return;
|
||||
|
||||
// 获取所有与当前节点相交的节点
|
||||
const intersections = getIntersectingNodes(node);
|
||||
// 获取所有与当前节点相交的节点中,类型为 loop 的节点且它不能是折叠状态
|
||||
const parentNode = intersections.find(
|
||||
(item) => !item.data.isFolded && item.type === FlowNodeTypeEnum.loop
|
||||
);
|
||||
|
||||
const unSupportedTypes = [
|
||||
FlowNodeTypeEnum.workflowStart,
|
||||
FlowNodeTypeEnum.loop,
|
||||
@@ -409,7 +386,16 @@ export const useWorkflow = () => {
|
||||
FlowNodeTypeEnum.systemConfig
|
||||
];
|
||||
|
||||
if (parentNode && !node.data.parentNodeId) {
|
||||
if (!node || node.data.parentNodeId) return;
|
||||
|
||||
// 获取所有与当前节点相交的节点
|
||||
const intersections = getIntersectingNodes(node);
|
||||
// 获取所有与当前节点相交的节点中,类型为 loop 的节点且它不能是折叠状态
|
||||
const parentNode = intersections.find(
|
||||
(item) => !item.data.isFolded && item.type === FlowNodeTypeEnum.loop
|
||||
);
|
||||
|
||||
if (parentNode) {
|
||||
if (unSupportedTypes.includes(node.type as FlowNodeTypeEnum)) {
|
||||
return toast({
|
||||
status: 'warning',
|
||||
@@ -427,8 +413,6 @@ export const useWorkflow = () => {
|
||||
setEdges((state) =>
|
||||
state.filter((edge) => edge.source !== node.id && edge.target !== node.id)
|
||||
);
|
||||
|
||||
resetParentNodeSizeAndPosition(parentNode.id);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useWorkflow } from './hooks/useWorkflow';
|
||||
import HelperLines from './components/HelperLines';
|
||||
import FlowController from './components/FlowController';
|
||||
import ContextMenu from './components/ContextMenu';
|
||||
import { WorkflowActionContext, WorkflowInitContext } from '../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext, WorkflowInitContext } from '../context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../context/workflowEventContext';
|
||||
|
||||
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
|
||||
@@ -66,7 +66,7 @@ const edgeTypes = {
|
||||
|
||||
const Workflow = () => {
|
||||
const nodes = useContextSelector(WorkflowInitContext, (v) => v.nodes);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const reactFlowWrapper = useContextSelector(WorkflowEventContext, (v) => v.reactFlowWrapper);
|
||||
const workflowControlMode = useContextSelector(
|
||||
WorkflowEventContext,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||
import React, { useEffect, useMemo, useRef, useCallback } from 'react';
|
||||
import { Background, NodeProps } from 'reactflow';
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { Background, NodePositionChange, NodeProps } from 'reactflow';
|
||||
import NodeCard from '../render/NodeCard';
|
||||
import Container from '../../components/Container';
|
||||
import IOTitle from '../../components/IOTitle';
|
||||
@@ -26,18 +26,27 @@ import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../context';
|
||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
import { AppContext } from '../../../../context';
|
||||
import { isReferenceValue, isReferenceValueArray } from '@fastgpt/global/core/workflow/utils';
|
||||
import { ReferenceItemValueType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import { isValidArrayReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
||||
import { ReferenceArrayValueType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import { useWorkflow } from '../../hooks/useWorkflow';
|
||||
import { WorkflowNodeEdgeContext } from '../../../context/workflowInitContext';
|
||||
import { useSize } from 'ahooks';
|
||||
|
||||
const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs, outputs, isFolded } = data;
|
||||
const { onChangeNode, nodeList } = useContextSelector(WorkflowContext, (v) => v);
|
||||
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
||||
const getNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.getNodes);
|
||||
const onNodesChange = useContextSelector(WorkflowNodeEdgeContext, (v) => v.onNodesChange);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||
|
||||
const { resetParentNodeSizeAndPosition } = useWorkflow();
|
||||
|
||||
const loopInputArray = inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray);
|
||||
const loopInputArray = useMemo(
|
||||
() => inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray),
|
||||
[inputs]
|
||||
);
|
||||
|
||||
const { nodeWidth, nodeHeight } = useMemo(() => {
|
||||
return {
|
||||
@@ -46,23 +55,28 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
};
|
||||
}, [inputs]);
|
||||
|
||||
const childrenNodeIdList = useMemo(() => {
|
||||
return JSON.stringify(
|
||||
nodeList.filter((node) => node.parentNodeId === nodeId).map((node) => node.nodeId)
|
||||
);
|
||||
}, [nodeId, nodeList]);
|
||||
|
||||
// Detect and update array input type
|
||||
// Update array input type
|
||||
// Computed the reference value type
|
||||
const newValueType = useMemo(() => {
|
||||
if (!loopInputArray) return WorkflowIOValueTypeEnum.arrayAny;
|
||||
const value = loopInputArray.value as ReferenceArrayValueType;
|
||||
|
||||
if (
|
||||
!value ||
|
||||
value.length === 0 ||
|
||||
!isValidArrayReferenceValue(
|
||||
value,
|
||||
nodeList.map((node) => node.nodeId)
|
||||
)
|
||||
)
|
||||
return WorkflowIOValueTypeEnum.arrayAny;
|
||||
|
||||
const nodeIds = nodeList.map((node) => node.nodeId);
|
||||
const globalVariables = getWorkflowGlobalVariables({
|
||||
nodes: nodeList,
|
||||
chatConfig: appDetail.chatConfig
|
||||
});
|
||||
|
||||
const getValueType = (value: ReferenceItemValueType) => {
|
||||
const valueType = ((value) => {
|
||||
if (value?.[0] === VARIABLE_NODE_ID) {
|
||||
return globalVariables.find((item) => item.key === value[1])?.valueType;
|
||||
} else {
|
||||
@@ -70,21 +84,8 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const output = node?.outputs.find((output) => output.id === value?.[1]);
|
||||
return output?.valueType;
|
||||
}
|
||||
};
|
||||
|
||||
const valueType = (() => {
|
||||
if (isReferenceValue(loopInputArray?.value, nodeIds)) {
|
||||
return getValueType(loopInputArray?.value);
|
||||
} else if (isReferenceValueArray(loopInputArray?.value, nodeIds)) {
|
||||
return getValueType(loopInputArray?.value?.[0]);
|
||||
} else {
|
||||
return WorkflowIOValueTypeEnum.arrayAny;
|
||||
}
|
||||
})();
|
||||
|
||||
const type = ArrayTypeMap[valueType as keyof typeof ArrayTypeMap];
|
||||
|
||||
return type ?? WorkflowIOValueTypeEnum.arrayAny;
|
||||
})(value[0]);
|
||||
return ArrayTypeMap[valueType as keyof typeof ArrayTypeMap] ?? WorkflowIOValueTypeEnum.arrayAny;
|
||||
}, [appDetail.chatConfig, loopInputArray, nodeList]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -101,6 +102,11 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
}, [newValueType]);
|
||||
|
||||
// Update childrenNodeIdList
|
||||
const childrenNodeIdList = useMemo(() => {
|
||||
return JSON.stringify(
|
||||
nodeList.filter((node) => node.parentNodeId === nodeId).map((node) => node.nodeId)
|
||||
);
|
||||
}, [nodeId, nodeList]);
|
||||
useEffect(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
@@ -111,20 +117,47 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
value: JSON.parse(childrenNodeIdList)
|
||||
}
|
||||
});
|
||||
}, [childrenNodeIdList, nodeId, onChangeNode]);
|
||||
resetParentNodeSizeAndPosition(nodeId);
|
||||
}, [childrenNodeIdList]);
|
||||
|
||||
// Update child node position
|
||||
const inputBoxRef = useRef<HTMLDivElement>(null);
|
||||
const size = useSize(inputBoxRef);
|
||||
const prevHeightRef = useRef<number>(); // 添加 ref 来存储前一个高度值
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
resetParentNodeSizeAndPosition(nodeId);
|
||||
}, 0);
|
||||
}, [loopInputArray, nodeId, resetParentNodeSizeAndPosition]);
|
||||
if (!size?.height) return;
|
||||
if (prevHeightRef.current === size.height) return;
|
||||
const diffHeight = prevHeightRef.current ? size.height - prevHeightRef.current : 0;
|
||||
prevHeightRef.current = size.height;
|
||||
|
||||
if (diffHeight === 0) return;
|
||||
|
||||
// Get the height of the input box
|
||||
// Computed input
|
||||
const nodes = getNodes();
|
||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === nodeId);
|
||||
|
||||
const childNodesChange: NodePositionChange[] = childNodes.map((node) => {
|
||||
return {
|
||||
type: 'position',
|
||||
id: node.id,
|
||||
position: {
|
||||
x: node.position.x,
|
||||
y: node.position.y + diffHeight
|
||||
}
|
||||
};
|
||||
});
|
||||
console.log(childNodesChange);
|
||||
|
||||
onNodesChange(childNodesChange);
|
||||
}, [size?.height]);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
<NodeCard selected={selected} maxW="full" menuForbid={{ copy: true }} {...data}>
|
||||
<Container position={'relative'} flex={1}>
|
||||
<IOTitle text={t('common:common.Input')} />
|
||||
<Box mb={6} maxW={'500px'}>
|
||||
<Box mb={6} maxW={'500px'} ref={inputBoxRef}>
|
||||
<RenderInput nodeId={nodeId} flowInputList={inputs} />
|
||||
</Box>
|
||||
<FormLabel required fontWeight={'medium'} mb={3} color={'myGray.600'}>
|
||||
|
||||
@@ -147,7 +147,7 @@ const VariableSelector = ({
|
||||
});
|
||||
|
||||
const onSelect = useCallback(
|
||||
(e: ReferenceItemValueType) => {
|
||||
(e?: ReferenceItemValueType) => {
|
||||
if (!e) return;
|
||||
|
||||
onChangeNode({
|
||||
|
||||
@@ -49,7 +49,7 @@ import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { getEditorVariables } from '../../../utils';
|
||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import { WorkflowActionContext } from '../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../context/workflowInitContext';
|
||||
const CurlImportModal = dynamic(() => import('./CurlImportModal'));
|
||||
|
||||
const defaultFormBody = {
|
||||
@@ -82,7 +82,7 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
||||
@@ -259,7 +259,7 @@ export function RenderHttpProps({
|
||||
const { t } = useTranslation();
|
||||
const [selectedTab, setSelectedTab] = useState(TabEnum.params);
|
||||
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const { appDetail } = useContextSelector(AppContext, (v) => v);
|
||||
|
||||
@@ -309,7 +309,7 @@ const VariableSelector = ({
|
||||
}: {
|
||||
nodeId: string;
|
||||
variable?: ReferenceItemValueType;
|
||||
onSelect: (e: ReferenceItemValueType) => void;
|
||||
onSelect: (e?: ReferenceItemValueType) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -110,7 +110,8 @@ function Reference({
|
||||
const [editField, setEditField] = useState<FlowNodeInputItemType>();
|
||||
|
||||
const onSelect = useCallback(
|
||||
(e: ReferenceValueType) => {
|
||||
(e?: ReferenceValueType) => {
|
||||
if (!e) return;
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
|
||||
@@ -34,7 +34,7 @@ import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import { useCreation, useMemoizedFn } from 'ahooks';
|
||||
import { getEditorVariables } from '../../utils';
|
||||
import { isArray } from 'lodash';
|
||||
import { WorkflowActionContext } from '../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../context/workflowInitContext';
|
||||
|
||||
const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { inputs = [], nodeId } = data;
|
||||
@@ -43,7 +43,7 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
|
||||
const menuList = useRef([
|
||||
{
|
||||
@@ -104,14 +104,14 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
||||
(item) => item.renderType === updateItem.renderType
|
||||
);
|
||||
|
||||
const handleUpdate = (newValue: ReferenceValueType | string) => {
|
||||
const handleUpdate = (newValue?: ReferenceValueType | string) => {
|
||||
if (typeof newValue === 'string') {
|
||||
onUpdateList(
|
||||
updateList.map((update, i) =>
|
||||
i === index ? { ...update, value: ['', newValue] } : update
|
||||
)
|
||||
);
|
||||
} else {
|
||||
} else if (newValue) {
|
||||
onUpdateList(
|
||||
updateList.map((update, i) =>
|
||||
i === index ? { ...update, value: newValue as ReferenceItemValueType } : update
|
||||
@@ -181,7 +181,7 @@ const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) =>
|
||||
if (i === index) {
|
||||
return {
|
||||
...update,
|
||||
value: ['', ''],
|
||||
value: undefined,
|
||||
renderType:
|
||||
updateItem.renderType === FlowNodeInputTypeEnum.input
|
||||
? FlowNodeInputTypeEnum.reference
|
||||
@@ -318,7 +318,7 @@ const VariableSelector = ({
|
||||
nodeId: string;
|
||||
variable?: ReferenceValueType;
|
||||
valueType?: WorkflowIOValueTypeEnum;
|
||||
onSelect: (e: ReferenceValueType) => void;
|
||||
onSelect: (e?: ReferenceValueType) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../../context';
|
||||
import { WorkflowActionContext } from '../../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../../context/workflowInitContext';
|
||||
|
||||
export const ConnectionSourceHandle = ({
|
||||
nodeId,
|
||||
@@ -14,7 +14,7 @@ export const ConnectionSourceHandle = ({
|
||||
nodeId: string;
|
||||
isFoldNode?: boolean;
|
||||
}) => {
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const { connectingEdge, nodeList } = useContextSelector(WorkflowContext, (ctx) => ctx);
|
||||
|
||||
const { showSourceHandle, RightHandle, LeftHandlee, TopHandlee, BottomHandlee } = useMemo(() => {
|
||||
@@ -137,7 +137,7 @@ export const ConnectionTargetHandle = React.memo(function ConnectionTargetHandle
|
||||
}: {
|
||||
nodeId: string;
|
||||
}) {
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const { connectingEdge, nodeList } = useContextSelector(WorkflowContext, (ctx) => ctx);
|
||||
|
||||
const { LeftHandle, rightHandle, topHandle, bottomHandle } = useMemo(() => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Connection, Handle, Position } from 'reactflow';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
|
||||
import { WorkflowActionContext } from '../../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../../context/workflowInitContext';
|
||||
|
||||
const handleSize = '16px';
|
||||
|
||||
@@ -17,7 +17,7 @@ type ToolHandleProps = BoxProps & {
|
||||
export const ToolTargetHandle = ({ show, nodeId }: ToolHandleProps) => {
|
||||
const { t } = useTranslation();
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
|
||||
const handleId = NodeOutputKeyEnum.selectedTools;
|
||||
|
||||
@@ -65,7 +65,7 @@ export const ToolTargetHandle = ({ show, nodeId }: ToolHandleProps) => {
|
||||
|
||||
export const ToolSourceHandle = () => {
|
||||
const { t } = useTranslation();
|
||||
const setEdges = useContextSelector(WorkflowActionContext, (v) => v.setEdges);
|
||||
const setEdges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setEdges);
|
||||
|
||||
/* onConnect edge, delete tool input and switch */
|
||||
const onConnect = useCallback(
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../../context';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import {
|
||||
WorkflowActionContext,
|
||||
WorkflowNodeEdgeContext,
|
||||
WorkflowInitContext
|
||||
} from '../../../../context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../../../../context/workflowEventContext';
|
||||
@@ -29,7 +29,7 @@ const MySourceHandle = React.memo(function MySourceHandle({
|
||||
highlightStyle: Record<string, any>;
|
||||
connectedStyle: Record<string, any>;
|
||||
}) {
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const nodes = useContextSelector(WorkflowInitContext, (v) => v.nodes);
|
||||
const hoverNodeId = useContextSelector(WorkflowEventContext, (v) => v.hoverNodeId);
|
||||
@@ -154,7 +154,7 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
||||
highlightStyle: Record<string, any>;
|
||||
connectedStyle: Record<string, any>;
|
||||
}) {
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
|
||||
const connected = edges.some((edge) => edge.targetHandle === handleId);
|
||||
|
||||
@@ -26,7 +26,7 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useWorkflowUtils } from '../../hooks/useUtils';
|
||||
import { WholeResponseContent } from '@/components/core/chat/components/WholeResponseModal';
|
||||
import { getDocPath } from '@/web/common/system/doc';
|
||||
import { WorkflowActionContext } from '../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../context/workflowInitContext';
|
||||
import { WorkflowEventContext } from '../../../context/workflowEventContext';
|
||||
import MyImage from '@fastgpt/web/components/common/Image/MyImage';
|
||||
|
||||
@@ -394,8 +394,8 @@ const MenuRender = React.memo(function MenuRender({
|
||||
const { t } = useTranslation();
|
||||
const { openDebugNode, DebugInputModal } = useDebug();
|
||||
|
||||
const setNodes = useContextSelector(WorkflowActionContext, (v) => v.setNodes);
|
||||
const setEdges = useContextSelector(WorkflowActionContext, (v) => v.setEdges);
|
||||
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setNodes);
|
||||
const setEdges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.setEdges);
|
||||
const { computedNewNodeName } = useWorkflowUtils();
|
||||
|
||||
const onCopyNode = useCallback(
|
||||
|
||||
@@ -123,7 +123,8 @@ function Reference({
|
||||
const [editField, setEditField] = useState<FlowNodeInputItemType>();
|
||||
|
||||
const onSelect = useCallback(
|
||||
(e: ReferenceValueType) => {
|
||||
(e?: ReferenceValueType) => {
|
||||
if (!e) return;
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'replaceInput',
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponents/context';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { AppContext } from '@/pages/app/detail/components/context';
|
||||
import { WorkflowActionContext } from '../../../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../../../context/workflowInitContext';
|
||||
|
||||
const MultipleRowSelect = dynamic(() =>
|
||||
import('@fastgpt/web/components/common/MySelect/MultipleRowSelect').then(
|
||||
@@ -64,7 +64,7 @@ export const useReference = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
// 获取可选的变量列表
|
||||
@@ -119,7 +119,7 @@ const Reference = ({ item, nodeId }: RenderInputProps) => {
|
||||
const isArray = item.valueType?.includes('array') ?? false;
|
||||
|
||||
const onSelect = useCallback(
|
||||
(e: ReferenceValueType) => {
|
||||
(e?: ReferenceValueType) => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
|
||||
@@ -7,12 +7,12 @@ import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponent
|
||||
import { useCreation } from 'ahooks';
|
||||
import { AppContext } from '@/pages/app/detail/components/context';
|
||||
import { getEditorVariables } from '../../../../../utils';
|
||||
import { WorkflowActionContext } from '../../../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../../../context/workflowInitContext';
|
||||
|
||||
const TextInputRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@ import { WorkflowContext } from '@/pages/app/detail/components/WorkflowComponent
|
||||
import { useCreation } from 'ahooks';
|
||||
import { AppContext } from '@/pages/app/detail/components/context';
|
||||
import { getEditorVariables } from '../../../../../utils';
|
||||
import { WorkflowActionContext } from '../../../../../context/workflowInitContext';
|
||||
import { WorkflowNodeEdgeContext } from '../../../../../context/workflowInitContext';
|
||||
|
||||
const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const edges = useContextSelector(WorkflowActionContext, (v) => v.edges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
|
||||
@@ -39,9 +39,16 @@ import { useTranslation } from 'next-i18next';
|
||||
import { formatTime2YMDHMS, formatTime2YMDHMW } from '@fastgpt/global/common/string/time';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||
import WorkflowInitContextProvider, { WorkflowActionContext } from './workflowInitContext';
|
||||
import WorkflowInitContextProvider, { WorkflowNodeEdgeContext } from './workflowInitContext';
|
||||
import WorkflowEventContextProvider from './workflowEventContext';
|
||||
|
||||
/*
|
||||
Context
|
||||
1. WorkflowInitContext: 带 nodes
|
||||
2. WorkflowNodeEdgeContext: 除了 nodes 外的,nodes 操作。以及 edges 和其操作
|
||||
3. WorkflowContextProvider: 旧的 context,未拆分
|
||||
4. WorkflowEventContextProvider:一些边缘的 event
|
||||
*/
|
||||
export const ReactFlowCustomProvider = ({
|
||||
templates,
|
||||
children
|
||||
@@ -322,8 +329,8 @@ const WorkflowContextProvider = ({
|
||||
const appId = appDetail._id;
|
||||
|
||||
/* edge */
|
||||
const edges = useContextSelector(WorkflowActionContext, (state) => state.edges);
|
||||
const setEdges = useContextSelector(WorkflowActionContext, (state) => state.setEdges);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (state) => state.edges);
|
||||
const setEdges = useContextSelector(WorkflowNodeEdgeContext, (state) => state.setEdges);
|
||||
const onDelEdge = useCallback(
|
||||
({
|
||||
nodeId,
|
||||
@@ -351,9 +358,12 @@ const WorkflowContextProvider = ({
|
||||
const [connectingEdge, setConnectingEdge] = useState<OnConnectStartParams>();
|
||||
|
||||
/* node */
|
||||
const setNodes = useContextSelector(WorkflowActionContext, (state) => state.setNodes);
|
||||
const getNodes = useContextSelector(WorkflowActionContext, (state) => state.getNodes);
|
||||
const nodeListString = useContextSelector(WorkflowActionContext, (state) => state.nodeListString);
|
||||
const setNodes = useContextSelector(WorkflowNodeEdgeContext, (state) => state.setNodes);
|
||||
const getNodes = useContextSelector(WorkflowNodeEdgeContext, (state) => state.getNodes);
|
||||
const nodeListString = useContextSelector(
|
||||
WorkflowNodeEdgeContext,
|
||||
(state) => state.nodeListString
|
||||
);
|
||||
|
||||
const nodeList = useMemo(
|
||||
() => JSON.parse(nodeListString) as FlowNodeItemType[],
|
||||
|
||||
@@ -56,7 +56,7 @@ type WorkflowActionContextType = {
|
||||
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
||||
onEdgesChange: OnChange<EdgeChange>;
|
||||
};
|
||||
export const WorkflowActionContext = createContext<WorkflowActionContextType>({
|
||||
export const WorkflowNodeEdgeContext = createContext<WorkflowActionContextType>({
|
||||
setNodes: function (
|
||||
value: React.SetStateAction<Node<FlowNodeItemType, string | undefined>[]>
|
||||
): void {
|
||||
@@ -128,9 +128,9 @@ const WorkflowInitContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
nodes
|
||||
}}
|
||||
>
|
||||
<WorkflowActionContext.Provider value={actionContextValue}>
|
||||
<WorkflowNodeEdgeContext.Provider value={actionContextValue}>
|
||||
{children}
|
||||
</WorkflowActionContext.Provider>
|
||||
</WorkflowNodeEdgeContext.Provider>
|
||||
</WorkflowInitContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -16,15 +16,15 @@ import { EmptyNode } from '@fastgpt/global/core/workflow/template/system/emptyNo
|
||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { getGlobalVariableNode } from './adapt';
|
||||
import { VARIABLE_NODE_ID, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { EditorVariablePickerType } from '@fastgpt/web/components/common/Textarea/PromptEditor/type';
|
||||
import {
|
||||
formatEditorVariablePickerIcon,
|
||||
getAppChatConfig,
|
||||
getGuideModule,
|
||||
isReferenceValue,
|
||||
isReferenceValueFormat
|
||||
isValidArrayReferenceValue,
|
||||
isValidReferenceValue
|
||||
} from '@fastgpt/global/core/workflow/utils';
|
||||
import { TFunction } from 'next-i18next';
|
||||
import {
|
||||
@@ -263,17 +263,72 @@ export const getRefData = ({
|
||||
};
|
||||
};
|
||||
|
||||
// 根据数据类型,过滤无效的节点输出
|
||||
export const filterWorkflowNodeOutputsByType = (
|
||||
outputs: FlowNodeOutputItemType[],
|
||||
valueType: WorkflowIOValueTypeEnum
|
||||
): FlowNodeOutputItemType[] => {
|
||||
const validTypeMap: Record<WorkflowIOValueTypeEnum, WorkflowIOValueTypeEnum[]> = {
|
||||
[WorkflowIOValueTypeEnum.string]: [WorkflowIOValueTypeEnum.string],
|
||||
[WorkflowIOValueTypeEnum.number]: [WorkflowIOValueTypeEnum.number],
|
||||
[WorkflowIOValueTypeEnum.boolean]: [WorkflowIOValueTypeEnum.boolean],
|
||||
[WorkflowIOValueTypeEnum.object]: [WorkflowIOValueTypeEnum.object],
|
||||
[WorkflowIOValueTypeEnum.arrayString]: [
|
||||
WorkflowIOValueTypeEnum.string,
|
||||
WorkflowIOValueTypeEnum.arrayString,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.arrayNumber]: [
|
||||
WorkflowIOValueTypeEnum.number,
|
||||
WorkflowIOValueTypeEnum.arrayNumber,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.arrayBoolean]: [
|
||||
WorkflowIOValueTypeEnum.boolean,
|
||||
WorkflowIOValueTypeEnum.arrayBoolean,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.arrayObject]: [
|
||||
WorkflowIOValueTypeEnum.object,
|
||||
WorkflowIOValueTypeEnum.arrayObject,
|
||||
WorkflowIOValueTypeEnum.arrayAny,
|
||||
WorkflowIOValueTypeEnum.chatHistory,
|
||||
WorkflowIOValueTypeEnum.datasetQuote,
|
||||
WorkflowIOValueTypeEnum.dynamic,
|
||||
WorkflowIOValueTypeEnum.selectDataset,
|
||||
WorkflowIOValueTypeEnum.selectApp
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.chatHistory]: [
|
||||
WorkflowIOValueTypeEnum.chatHistory,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.datasetQuote]: [
|
||||
WorkflowIOValueTypeEnum.datasetQuote,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.dynamic]: [
|
||||
WorkflowIOValueTypeEnum.dynamic,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.selectDataset]: [
|
||||
WorkflowIOValueTypeEnum.selectDataset,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.selectApp]: [
|
||||
WorkflowIOValueTypeEnum.selectApp,
|
||||
WorkflowIOValueTypeEnum.arrayAny
|
||||
],
|
||||
[WorkflowIOValueTypeEnum.arrayAny]: [WorkflowIOValueTypeEnum.arrayAny],
|
||||
[WorkflowIOValueTypeEnum.any]: [WorkflowIOValueTypeEnum.arrayAny]
|
||||
};
|
||||
|
||||
return outputs.filter(
|
||||
(output) =>
|
||||
valueType === WorkflowIOValueTypeEnum.any ||
|
||||
valueType === WorkflowIOValueTypeEnum.arrayAny ||
|
||||
!output.valueType ||
|
||||
output.valueType === WorkflowIOValueTypeEnum.any ||
|
||||
output.valueType === valueType ||
|
||||
valueType?.replace('array', '').toLowerCase() === output.valueType
|
||||
validTypeMap[valueType].includes(output.valueType)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -341,46 +396,25 @@ export const checkWorkflowNodeAndConnection = ({
|
||||
if (input.value === undefined) return true;
|
||||
}
|
||||
|
||||
if (
|
||||
node.data.flowNodeType === FlowNodeTypeEnum.pluginOutput &&
|
||||
(input.value?.length === 0 ||
|
||||
(isReferenceValue(input.value, nodeIds) && !input.value?.[1]))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// Check plugin output
|
||||
// if (
|
||||
// node.data.flowNodeType === FlowNodeTypeEnum.pluginOutput &&
|
||||
// (input.value?.length === 0 ||
|
||||
// (isValidReferenceValue(input.value, nodeIds) && !input.value?.[1]))
|
||||
// ) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// check reference invalid
|
||||
const renderType = input.renderTypeList[input.selectedTypeIndex || 0];
|
||||
if (renderType === FlowNodeInputTypeEnum.reference) {
|
||||
const checkReference = (value: [string, string]) => {
|
||||
if (value[0] === VARIABLE_NODE_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const sourceNode = nodes.find((item) => item.data.nodeId === value[0]);
|
||||
if (!sourceNode) {
|
||||
if (input.valueType?.startsWith('array')) {
|
||||
if (input.required && (!input.value || input.value.length === 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const sourceOutput = filterWorkflowNodeOutputsByType(
|
||||
sourceNode.data.outputs,
|
||||
input.valueType as WorkflowIOValueTypeEnum
|
||||
).find((item) => item.id === value[1]);
|
||||
return !sourceOutput;
|
||||
};
|
||||
|
||||
// Old format
|
||||
if (isReferenceValueFormat(input.value)) {
|
||||
return input.required && checkReference(input.value);
|
||||
return isValidArrayReferenceValue(input.value, nodeIds);
|
||||
}
|
||||
|
||||
// New format
|
||||
return input.value.some((inputItem: ReferenceItemValueType) => {
|
||||
if (!Array.isArray(inputItem) || inputItem.length !== 2) {
|
||||
return true;
|
||||
}
|
||||
return checkReference(inputItem as [string, string]);
|
||||
});
|
||||
return input.required && !isValidReferenceValue(input.value, nodeIds);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user