4.8.13 test (#3102)
* fix: loop index;edge parent check * perf: reference invalid check * fix: ts
This commit is contained in:
@@ -201,6 +201,7 @@ export enum NodeInputKeyEnum {
|
|||||||
nodeHeight = 'nodeHeight',
|
nodeHeight = 'nodeHeight',
|
||||||
// loop start
|
// loop start
|
||||||
loopStartInput = 'loopStartInput',
|
loopStartInput = 'loopStartInput',
|
||||||
|
loopStartIndex = 'loopStartIndex',
|
||||||
// loop end
|
// loop end
|
||||||
loopEndInput = 'loopEndInput',
|
loopEndInput = 'loopEndInput',
|
||||||
|
|
||||||
@@ -258,7 +259,7 @@ export enum NodeOutputKeyEnum {
|
|||||||
loopArray = 'loopArray',
|
loopArray = 'loopArray',
|
||||||
// loop start
|
// loop start
|
||||||
loopStartInput = 'loopStartInput',
|
loopStartInput = 'loopStartInput',
|
||||||
loopArrayIndex = 'loopArrayIndex',
|
loopStartIndex = 'loopStartIndex',
|
||||||
|
|
||||||
// form input
|
// form input
|
||||||
formInputResult = 'formInputResult'
|
formInputResult = 'formInputResult'
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ export const getReferenceVariableValue = ({
|
|||||||
nodes: RuntimeNodeItemType[];
|
nodes: RuntimeNodeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
}) => {
|
}) => {
|
||||||
if (!value) return undefined;
|
if (!value) return value;
|
||||||
|
|
||||||
// handle single reference value
|
// handle single reference value
|
||||||
if (isValidReferenceValueFormat(value)) {
|
if (isValidReferenceValueFormat(value)) {
|
||||||
@@ -253,7 +253,7 @@ export const getReferenceVariableValue = ({
|
|||||||
|
|
||||||
const node = nodes.find((node) => node.nodeId === sourceNodeId);
|
const node = nodes.find((node) => node.nodeId === sourceNodeId);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return undefined;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.outputs.find((output) => output.id === outputId)?.value;
|
return node.outputs.find((output) => output.id === outputId)?.value;
|
||||||
|
|||||||
@@ -33,12 +33,18 @@ export const LoopStartNode: FlowNodeTemplateType = {
|
|||||||
label: '',
|
label: '',
|
||||||
required: true,
|
required: true,
|
||||||
value: ''
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: NodeInputKeyEnum.loopStartIndex,
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
|
valueType: WorkflowIOValueTypeEnum.number,
|
||||||
|
label: i18nT('workflow:Array_element_index')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
outputs: [
|
outputs: [
|
||||||
{
|
{
|
||||||
id: NodeOutputKeyEnum.loopArrayIndex,
|
id: NodeOutputKeyEnum.loopStartIndex,
|
||||||
key: NodeOutputKeyEnum.loopArrayIndex,
|
key: NodeOutputKeyEnum.loopStartIndex,
|
||||||
label: i18nT('workflow:Array_element_index'),
|
label: i18nT('workflow:Array_element_index'),
|
||||||
type: FlowNodeOutputTypeEnum.static,
|
type: FlowNodeOutputTypeEnum.static,
|
||||||
valueType: WorkflowIOValueTypeEnum.number
|
valueType: WorkflowIOValueTypeEnum.number
|
||||||
|
|||||||
@@ -387,6 +387,7 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
node,
|
node,
|
||||||
runtimeEdges
|
runtimeEdges
|
||||||
});
|
});
|
||||||
|
|
||||||
const nodeRunResult = await (() => {
|
const nodeRunResult = await (() => {
|
||||||
if (status === 'run') {
|
if (status === 'run') {
|
||||||
nodeRunBeforeHook(node);
|
nodeRunBeforeHook(node);
|
||||||
@@ -482,8 +483,16 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
: {};
|
: {};
|
||||||
|
|
||||||
node.inputs.forEach((input) => {
|
node.inputs.forEach((input) => {
|
||||||
|
// Special input, not format
|
||||||
if (input.key === dynamicInput?.key) return;
|
if (input.key === dynamicInput?.key) return;
|
||||||
|
|
||||||
|
// Skip some special key
|
||||||
|
if (input.key === NodeInputKeyEnum.childrenNodeIdList) {
|
||||||
|
params[input.key] = input.value;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// replace {{xx}} variables
|
// replace {{xx}} variables
|
||||||
let value = replaceVariable(input.value, variables);
|
let value = replaceVariable(input.value, variables);
|
||||||
|
|
||||||
@@ -506,7 +515,6 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
if (input.canEdit && dynamicInput && params[dynamicInput.key]) {
|
||||||
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
params[dynamicInput.key][input.key] = valueTypeFormat(value, input.valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
params[input.key] = valueTypeFormat(value, input.valueType);
|
params[input.key] = valueTypeFormat(value, input.valueType);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -51,23 +51,16 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
|
|||||||
node.flowNodeType === FlowNodeTypeEnum.loopStart
|
node.flowNodeType === FlowNodeTypeEnum.loopStart
|
||||||
) {
|
) {
|
||||||
node.isEntry = true;
|
node.isEntry = true;
|
||||||
node.inputs = node.inputs.map((input) => {
|
node.inputs.forEach((input) => {
|
||||||
if (input.key === NodeInputKeyEnum.loopStartInput) {
|
if (input.key === NodeInputKeyEnum.loopStartInput) {
|
||||||
return {
|
input.value = item;
|
||||||
...input,
|
} else if (input.key === NodeInputKeyEnum.loopStartIndex) {
|
||||||
value: item
|
input.value = index++;
|
||||||
};
|
|
||||||
} else if (input.key === NodeInputKeyEnum.loopStartInput) {
|
|
||||||
return {
|
|
||||||
...input,
|
|
||||||
value: index++
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return input;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await dispatchWorkFlow({
|
const response = await dispatchWorkFlow({
|
||||||
...props,
|
...props,
|
||||||
runtimeEdges: cloneDeep(runtimeEdges)
|
runtimeEdges: cloneDeep(runtimeEdges)
|
||||||
@@ -77,11 +70,13 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
|
|||||||
(res) => res.moduleType === FlowNodeTypeEnum.loopEnd
|
(res) => res.moduleType === FlowNodeTypeEnum.loopEnd
|
||||||
)?.loopOutputValue;
|
)?.loopOutputValue;
|
||||||
|
|
||||||
|
// Concat runtime response
|
||||||
outputValueArr.push(loopOutputValue);
|
outputValueArr.push(loopOutputValue);
|
||||||
loopDetail.push(...response.flowResponses);
|
loopDetail.push(...response.flowResponses);
|
||||||
assistantResponses.push(...response.assistantResponses);
|
assistantResponses.push(...response.assistantResponses);
|
||||||
|
totalPoints += response.flowUsages.reduce((acc, usage) => acc + usage.totalPoints, 0);
|
||||||
|
|
||||||
totalPoints = response.flowUsages.reduce((acc, usage) => acc + usage.totalPoints, 0);
|
// Concat new variables
|
||||||
newVariables = {
|
newVariables = {
|
||||||
...newVariables,
|
...newVariables,
|
||||||
...response.newVariables
|
...response.newVariables
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import {
|
|||||||
|
|
||||||
type Props = ModuleDispatchProps<{
|
type Props = ModuleDispatchProps<{
|
||||||
[NodeInputKeyEnum.loopStartInput]: any;
|
[NodeInputKeyEnum.loopStartInput]: any;
|
||||||
|
[NodeInputKeyEnum.loopStartIndex]: number;
|
||||||
}>;
|
}>;
|
||||||
type Response = DispatchNodeResultType<{
|
type Response = DispatchNodeResultType<{
|
||||||
[NodeOutputKeyEnum.loopStartInput]: any;
|
[NodeOutputKeyEnum.loopStartInput]: any;
|
||||||
|
[NodeOutputKeyEnum.loopStartIndex]: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
||||||
@@ -18,6 +20,7 @@ export const dispatchLoopStart = async (props: Props): Promise<Response> => {
|
|||||||
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
[DispatchNodeResponseKeyEnum.nodeResponse]: {
|
||||||
loopInputValue: params.loopStartInput
|
loopInputValue: params.loopStartInput
|
||||||
},
|
},
|
||||||
[NodeOutputKeyEnum.loopStartInput]: params.loopStartInput
|
[NodeOutputKeyEnum.loopStartInput]: params.loopStartInput,
|
||||||
|
[NodeOutputKeyEnum.loopStartIndex]: params.loopStartIndex
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export const dispatchPluginInput = (props: PluginInputProps) => {
|
|||||||
* 插件单独运行时,这里会是一个特殊的数组
|
* 插件单独运行时,这里会是一个特殊的数组
|
||||||
* 插件调用的话,这个参数是一个 string[] 不会进行处理
|
* 插件调用的话,这个参数是一个 string[] 不会进行处理
|
||||||
* 硬性要求:API 单独调用插件时,要避免这种特殊类型冲突
|
* 硬性要求:API 单独调用插件时,要避免这种特殊类型冲突
|
||||||
|
|
||||||
|
TODO: 需要 filter max files
|
||||||
*/
|
*/
|
||||||
for (const key in params) {
|
for (const key in params) {
|
||||||
const val = params[key];
|
const val = params[key];
|
||||||
|
|||||||
@@ -130,7 +130,7 @@
|
|||||||
"type.Simple bot": "Simple App",
|
"type.Simple bot": "Simple App",
|
||||||
"type.Workflow bot": "Workflow",
|
"type.Workflow bot": "Workflow",
|
||||||
"upload_file_max_amount": "Maximum File Quantity",
|
"upload_file_max_amount": "Maximum File Quantity",
|
||||||
"upload_file_max_amount_tip": "1. The maximum number of files that can be uploaded at one time.\n2. The maximum number of files remembered by the chat window: each round of dialogue will automatically retrieve files from history, files beyond the range will be forgotten.",
|
"upload_file_max_amount_tip": "Maximum number of files uploaded in a single round of conversation",
|
||||||
"variable.select type_desc": "You can define a global variable that does not need to be filled in by the user.\n\nThe value of this variable can come from the API interface, the Query of the shared link, or assigned through the [Variable Update] module.",
|
"variable.select type_desc": "You can define a global variable that does not need to be filled in by the user.\n\nThe value of this variable can come from the API interface, the Query of the shared link, or assigned through the [Variable Update] module.",
|
||||||
"variable.textarea_type_desc": "Allows users to input up to 4000 characters in the dialogue box.",
|
"variable.textarea_type_desc": "Allows users to input up to 4000 characters in the dialogue box.",
|
||||||
"version.Revert success": "Revert Successful",
|
"version.Revert success": "Revert Successful",
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
"workflow.read_files": "Document Parsing",
|
"workflow.read_files": "Document Parsing",
|
||||||
"workflow.read_files_result": "Document Parsing Result",
|
"workflow.read_files_result": "Document Parsing Result",
|
||||||
"workflow.read_files_result_desc": "Original document text, consisting of file names and document content, separated by hyphens between multiple files.",
|
"workflow.read_files_result_desc": "Original document text, consisting of file names and document content, separated by hyphens between multiple files.",
|
||||||
"workflow.read_files_tip": "Parse all uploaded documents in the dialogue and return the corresponding document content.",
|
"workflow.read_files_tip": "Parse the documents uploaded in this round of dialogue and return the corresponding document content",
|
||||||
"workflow.select_description": "Description Text",
|
"workflow.select_description": "Description Text",
|
||||||
"workflow.select_description_placeholder": "For example: \nAre there tomatoes in the fridge?",
|
"workflow.select_description_placeholder": "For example: \nAre there tomatoes in the fridge?",
|
||||||
"workflow.select_description_tip": "You can add a description text to explain the meaning of each option to the user.",
|
"workflow.select_description_tip": "You can add a description text to explain the meaning of each option to the user.",
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
"type.Simple bot": "简易应用",
|
"type.Simple bot": "简易应用",
|
||||||
"type.Workflow bot": "工作流",
|
"type.Workflow bot": "工作流",
|
||||||
"upload_file_max_amount": "最大文件数量",
|
"upload_file_max_amount": "最大文件数量",
|
||||||
"upload_file_max_amount_tip": "1.单次上传文件的最大数量。\n2.对话窗口记忆的最大文件数量:每轮对话会自动获取历史中的文件,超出范围的文件会被遗忘。",
|
"upload_file_max_amount_tip": "单轮对话中最大上传文件数量",
|
||||||
"variable.select type_desc": "可以为工作流定义全局变量,常用临时缓存。赋值的方式包括:\n1. 从对话页面的 query 参数获取。\n2. 通过 API 的 variables 对象传递。\n3. 通过【变量更新】节点进行赋值。",
|
"variable.select type_desc": "可以为工作流定义全局变量,常用临时缓存。赋值的方式包括:\n1. 从对话页面的 query 参数获取。\n2. 通过 API 的 variables 对象传递。\n3. 通过【变量更新】节点进行赋值。",
|
||||||
"variable.textarea_type_desc": "允许用户最多输入4000字的对话框。",
|
"variable.textarea_type_desc": "允许用户最多输入4000字的对话框。",
|
||||||
"version.Revert success": "回滚成功",
|
"version.Revert success": "回滚成功",
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
"workflow.read_files": "文档解析",
|
"workflow.read_files": "文档解析",
|
||||||
"workflow.read_files_result": "文档解析结果",
|
"workflow.read_files_result": "文档解析结果",
|
||||||
"workflow.read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。",
|
"workflow.read_files_result_desc": "文档原文,由文件名和文档内容组成,多个文件之间通过横线隔开。",
|
||||||
"workflow.read_files_tip": "解析对话中所有上传的文档,并返回对应文档内容",
|
"workflow.read_files_tip": "解析本轮对话上传的文档,并返回对应文档内容",
|
||||||
"workflow.select_description": "说明文字",
|
"workflow.select_description": "说明文字",
|
||||||
"workflow.select_description_placeholder": "例如: \n冰箱里是否有西红柿?",
|
"workflow.select_description_placeholder": "例如: \n冰箱里是否有西红柿?",
|
||||||
"workflow.select_description_tip": "你可以添加一段说明文字,用以向用户说明每个选项代表的含义。",
|
"workflow.select_description_tip": "你可以添加一段说明文字,用以向用户说明每个选项代表的含义。",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { OutLinkChatAuthProps } from '@fastgpt/global/support/permission/chat';
|
|||||||
import { ChatBoxInputFormType } from '../ChatBox/type';
|
import { ChatBoxInputFormType } from '../ChatBox/type';
|
||||||
import { chats2GPTMessages } from '@fastgpt/global/core/chat/adapt';
|
import { chats2GPTMessages } from '@fastgpt/global/core/chat/adapt';
|
||||||
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
|
import { getPluginRunUserQuery } from '@fastgpt/global/core/workflow/utils';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
type PluginRunContextType = OutLinkChatAuthProps &
|
type PluginRunContextType = OutLinkChatAuthProps &
|
||||||
PluginRunBoxProps & {
|
PluginRunBoxProps & {
|
||||||
@@ -226,13 +227,25 @@ const PluginRunContextProvider = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Remove files icon
|
||||||
|
const formatVariables = cloneDeep(variables);
|
||||||
|
for (const key in formatVariables) {
|
||||||
|
if (Array.isArray(formatVariables[key])) {
|
||||||
|
formatVariables[key].forEach((item) => {
|
||||||
|
if (item.url && item.icon) {
|
||||||
|
delete item.icon;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { responseData } = await onStartChat({
|
const { responseData } = await onStartChat({
|
||||||
messages,
|
messages,
|
||||||
controller: chatController.current,
|
controller: chatController.current,
|
||||||
generatingMessage,
|
generatingMessage,
|
||||||
variables: {
|
variables: {
|
||||||
files: files,
|
files,
|
||||||
...variables
|
...formatVariables
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (responseData?.[responseData.length - 1]?.error) {
|
if (responseData?.[responseData.length - 1]?.error) {
|
||||||
|
|||||||
@@ -34,9 +34,12 @@ const ButtonEdge = (props: EdgeProps) => {
|
|||||||
|
|
||||||
// If parentNode is folded, the edge will not be displayed
|
// If parentNode is folded, the edge will not be displayed
|
||||||
const parentNode = useMemo(() => {
|
const parentNode = useMemo(() => {
|
||||||
return nodeList.find(
|
for (const node of nodeList) {
|
||||||
(node) => (node.nodeId === source || node.nodeId === target) && node.parentNodeId
|
if ((node.nodeId === source || node.nodeId === target) && node.parentNodeId) {
|
||||||
);
|
return nodeList.find((parent) => parent.nodeId === node.parentNodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}, [nodeList, source, target]);
|
}, [nodeList, source, target]);
|
||||||
|
|
||||||
const defaultZIndex = useMemo(
|
const defaultZIndex = useMemo(
|
||||||
|
|||||||
@@ -294,7 +294,20 @@ export const useWorkflow = () => {
|
|||||||
|
|
||||||
// Loop node size and position
|
// Loop node size and position
|
||||||
const resetParentNodeSizeAndPosition = useMemoizedFn((parentId: string) => {
|
const resetParentNodeSizeAndPosition = useMemoizedFn((parentId: string) => {
|
||||||
const childNodes = nodes.filter((node) => node.data.parentNodeId === parentId);
|
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 }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!loopNode) return;
|
||||||
|
|
||||||
const rect = getNodesBounds(childNodes);
|
const rect = getNodesBounds(childNodes);
|
||||||
// Calculate parent node size with minimum width/height constraints
|
// Calculate parent node size with minimum width/height constraints
|
||||||
@@ -320,7 +333,6 @@ export const useWorkflow = () => {
|
|||||||
value: height
|
value: height
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update parentNode position
|
// Update parentNode position
|
||||||
onNodesChange([
|
onNodesChange([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
nodeList.filter((node) => node.parentNodeId === nodeId).map((node) => node.nodeId)
|
nodeList.filter((node) => node.parentNodeId === nodeId).map((node) => node.nodeId)
|
||||||
);
|
);
|
||||||
}, [nodeId, nodeList]);
|
}, [nodeId, nodeList]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
nodeId,
|
nodeId,
|
||||||
@@ -143,7 +144,6 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
console.log(childNodesChange);
|
|
||||||
|
|
||||||
onNodesChange(childNodesChange);
|
onNodesChange(childNodesChange);
|
||||||
}, [size?.height]);
|
}, [size?.height]);
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ const NodeLoopStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
mr={1}
|
mr={1}
|
||||||
color={'primary.600'}
|
color={'primary.600'}
|
||||||
/>
|
/>
|
||||||
{t(output.label)}
|
{t(output.label as any)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Td>
|
</Td>
|
||||||
{output.valueType && <Td>{FlowValueTypeMap[output.valueType]?.label}</Td>}
|
{output.valueType && <Td>{FlowValueTypeMap[output.valueType]?.label}</Td>}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import type { RenderInputProps } from '../type';
|
import type { RenderInputProps } from '../type';
|
||||||
import { Flex, Box, ButtonProps, Grid } from '@chakra-ui/react';
|
import { Flex, Box, ButtonProps, Grid } from '@chakra-ui/react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
@@ -240,25 +240,42 @@ const MultipleReferenceSelector = ({
|
|||||||
[list]
|
[list]
|
||||||
);
|
);
|
||||||
|
|
||||||
const ArraySelector = useMemo(() => {
|
// Get valid item and remove invalid item
|
||||||
const selectorVal = value as ReferenceItemValueType[];
|
const formatList = useMemo(() => {
|
||||||
const validSelectValue = selectorVal && selectorVal.length > 0;
|
if (!value) return [];
|
||||||
|
|
||||||
|
return value?.map((item) => {
|
||||||
|
const [nodeName, outputName] = getSelectValue(item);
|
||||||
|
return {
|
||||||
|
rawValue: item,
|
||||||
|
nodeName,
|
||||||
|
outputName
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [getSelectValue, value]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const validList = formatList.filter((item) => item.nodeName && item.outputName);
|
||||||
|
if (validList.length !== value?.length) {
|
||||||
|
onSelect(validList.map((item) => item.rawValue));
|
||||||
|
}
|
||||||
|
}, [formatList, onSelect, value]);
|
||||||
|
|
||||||
|
const ArraySelector = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<MultipleRowArraySelect
|
<MultipleRowArraySelect
|
||||||
label={
|
label={
|
||||||
validSelectValue ? (
|
formatList.length > 0 ? (
|
||||||
<Grid py={3} gridTemplateColumns={'1fr 1fr'} gap={2} fontSize={'sm'}>
|
<Grid py={3} gridTemplateColumns={'1fr 1fr'} gap={2} fontSize={'sm'}>
|
||||||
{selectorVal?.map((item, index) => {
|
{formatList.map(({ nodeName, outputName }, index) => {
|
||||||
const [nodeName, outputName] = getSelectValue(item);
|
if (!nodeName || !outputName) return null;
|
||||||
const isInvalidItem = !nodeName || !outputName;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
key={index}
|
key={index}
|
||||||
bg={isInvalidItem ? 'red.50' : 'primary.50'}
|
bg={'primary.50'}
|
||||||
color={isInvalidItem ? 'red.500' : 'myGray.900'}
|
color={'myGray.900'}
|
||||||
py={1}
|
py={1}
|
||||||
px={1.5}
|
px={1.5}
|
||||||
rounded={'sm'}
|
rounded={'sm'}
|
||||||
@@ -269,27 +286,21 @@ const MultipleReferenceSelector = ({
|
|||||||
maxW={'200px'}
|
maxW={'200px'}
|
||||||
className="textEllipsis"
|
className="textEllipsis"
|
||||||
>
|
>
|
||||||
{isInvalidItem ? (
|
{nodeName}
|
||||||
<>{t('common:invalid_variable')}</>
|
<MyIcon
|
||||||
) : (
|
name={'common/rightArrowLight'}
|
||||||
<>
|
mx={1}
|
||||||
{nodeName}
|
w={'12px'}
|
||||||
<MyIcon
|
color={'myGray.500'}
|
||||||
name={'common/rightArrowLight'}
|
/>
|
||||||
mx={1}
|
{outputName}
|
||||||
w={'12px'}
|
|
||||||
color={'myGray.500'}
|
|
||||||
/>
|
|
||||||
{outputName}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
<MyIcon
|
<MyIcon
|
||||||
name={'common/closeLight'}
|
name={'common/closeLight'}
|
||||||
w={'1rem'}
|
w={'1rem'}
|
||||||
ml={1}
|
ml={1}
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
color={isInvalidItem ? 'red.500' : 'myGray.500'}
|
color={'myGray.500'}
|
||||||
_hover={{
|
_hover={{
|
||||||
color: 'red.600'
|
color: 'red.600'
|
||||||
}}
|
}}
|
||||||
@@ -308,13 +319,13 @@ const MultipleReferenceSelector = ({
|
|||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
value={selectorVal as any}
|
value={value as any}
|
||||||
list={list}
|
list={list}
|
||||||
onSelect={onSelect as any}
|
onSelect={onSelect as any}
|
||||||
popDirection={popDirection}
|
popDirection={popDirection}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [getSelectValue, list, onSelect, placeholder, popDirection, t, value]);
|
}, [formatList, list, onSelect, placeholder, popDirection, value]);
|
||||||
|
|
||||||
return ArraySelector;
|
return ArraySelector;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -364,7 +364,6 @@ const WorkflowContextProvider = ({
|
|||||||
WorkflowNodeEdgeContext,
|
WorkflowNodeEdgeContext,
|
||||||
(state) => state.nodeListString
|
(state) => state.nodeListString
|
||||||
);
|
);
|
||||||
|
|
||||||
const nodeList = useMemo(
|
const nodeList = useMemo(
|
||||||
() => JSON.parse(nodeListString) as FlowNodeItemType[],
|
() => JSON.parse(nodeListString) as FlowNodeItemType[],
|
||||||
[nodeListString]
|
[nodeListString]
|
||||||
|
|||||||
@@ -413,8 +413,10 @@ export const checkWorkflowNodeAndConnection = ({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return input.required && !isValidArrayReferenceValue(input.value, nodeIds);
|
return !isValidArrayReferenceValue(input.value, nodeIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Single reference
|
||||||
return input.required && !isValidReferenceValue(input.value, nodeIds);
|
return input.required && !isValidReferenceValue(input.value, nodeIds);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user