feat: loop start add index (#3101)

* feat: loop start add index

* update doc
This commit is contained in:
Archer
2024-11-08 17:21:19 +08:00
committed by archer
parent 6c6c964b8a
commit 49aaf9b77e
7 changed files with 66 additions and 45 deletions

View File

@@ -256,9 +256,9 @@ export enum NodeOutputKeyEnum {
// loop
loopArray = 'loopArray',
// loop start
loopStartInput = 'loopStartInput',
loopArrayIndex = 'loopArrayIndex',
// form input
formInputResult = 'formInputResult'

View File

@@ -1,8 +1,13 @@
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type/node.d';
import {
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
WorkflowIOValueTypeEnum
} from '../../../constants';
import { getHandleConfig } from '../../utils';
@@ -30,5 +35,13 @@ export const LoopStartNode: FlowNodeTemplateType = {
value: ''
}
],
outputs: []
outputs: [
{
id: NodeOutputKeyEnum.loopArrayIndex,
key: NodeOutputKeyEnum.loopArrayIndex,
label: i18nT('workflow:Array_element_index'),
type: FlowNodeOutputTypeEnum.static,
valueType: WorkflowIOValueTypeEnum.number
}
]
};

View File

@@ -43,6 +43,7 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
let totalPoints = 0;
let newVariables: Record<string, any> = props.variables;
let index = 0;
for await (const item of loopInputArray.filter(Boolean)) {
runtimeNodes.forEach((node) => {
if (
@@ -50,14 +51,21 @@ export const dispatchLoop = async (props: Props): Promise<Response> => {
node.flowNodeType === FlowNodeTypeEnum.loopStart
) {
node.isEntry = true;
node.inputs = node.inputs.map((input) =>
input.key === NodeInputKeyEnum.loopStartInput
? {
...input,
value: item
}
: input
);
node.inputs = node.inputs.map((input) => {
if (input.key === NodeInputKeyEnum.loopStartInput) {
return {
...input,
value: item
};
} else if (input.key === NodeInputKeyEnum.loopStartInput) {
return {
...input,
value: index++
};
} else {
return input;
}
});
}
});
const response = await dispatchWorkFlow({

View File

@@ -1,5 +1,6 @@
{
"Array_element": "Array element",
"Array_element_index": "Index",
"Code": "Code",
"Confirm_sync_node": "It will be updated to the latest node configuration and fields that do not exist in the template will be deleted (including all custom fields).\n\nIf the fields are complex, it is recommended that you copy a node first and then update the original node to facilitate parameter copying.",
"Node.Open_Node_Course": "Open node course",

View File

@@ -1,5 +1,6 @@
{
"Array_element": "数组元素",
"Array_element_index": "下标",
"Code": "代码",
"Confirm_sync_node": "将会更新至最新的节点配置,不存在模板中的字段将会被删除(包括所有自定义字段)。\n如果字段较为复杂建议您先复制一份节点再更新原来的节点便于参数复制。",
"Node.Open_Node_Course": "查看节点教程",

View File

@@ -43,15 +43,11 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { resetParentNodeSizeAndPosition } = useWorkflow();
const loopInputArray = useMemo(
() => inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray),
[inputs]
);
const { nodeWidth, nodeHeight } = useMemo(() => {
const { nodeWidth, nodeHeight, loopInputArray } = useMemo(() => {
return {
nodeWidth: inputs.find((input) => input.key === NodeInputKeyEnum.nodeWidth)?.value,
nodeHeight: inputs.find((input) => input.key === NodeInputKeyEnum.nodeHeight)?.value
nodeHeight: inputs.find((input) => input.key === NodeInputKeyEnum.nodeHeight)?.value,
loopInputArray: inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray)
};
}, [inputs]);

View File

@@ -8,11 +8,15 @@ import { WorkflowContext } from '../../../context';
import {
NodeInputKeyEnum,
NodeOutputKeyEnum,
toolValueTypeList,
WorkflowIOValueTypeEnum
} from '@fastgpt/global/core/workflow/constants';
import { Box, Flex, Table, TableContainer, Tbody, Td, Th, Thead, Tr } from '@chakra-ui/react';
import React, { useEffect, useMemo } from 'react';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import {
FlowNodeOutputTypeEnum,
FlowValueTypeMap
} from '@fastgpt/global/core/workflow/node/constant';
import MyIcon from '@fastgpt/web/components/common/Icon';
const typeMap = {
@@ -24,7 +28,7 @@ const typeMap = {
const NodeLoopStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation();
const { nodeId } = data;
const { nodeId, outputs } = data;
const { nodeList, onChangeNode } = useContextSelector(WorkflowContext, (v) => v);
const loopStartNode = useMemo(
@@ -94,23 +98,21 @@ const NodeLoopStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
debug: true
}}
>
<Box px={4} pt={2} w={'420px'} h={'116px'}>
{!loopItemInputType ? (
<EmptyTip text={t('workflow:loop_start_tip')} py={0} mt={4} iconSize={'32px'} />
) : (
<Box bg={'white'} borderRadius={'md'} overflow={'hidden'} border={'base'}>
<TableContainer>
<Table bg={'white'}>
<Thead>
<Tr>
<Th borderBottomLeftRadius={'none !important'}>
{t('workflow:Variable_name')}
</Th>
<Th>{t('common:core.workflow.Value type')}</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Box px={4} pt={2} w={'420px'}>
<Box bg={'white'} borderRadius={'md'} overflow={'hidden'} border={'base'}>
<TableContainer>
<Table bg={'white'}>
<Thead>
<Tr>
<Th borderBottomLeftRadius={'none !important'}>
{t('workflow:Variable_name')}
</Th>
<Th>{t('common:core.workflow.Value type')}</Th>
</Tr>
</Thead>
<Tbody>
{outputs.map((output) => (
<Tr key={output.id}>
<Td>
<Flex alignItems={'center'}>
<MyIcon
@@ -119,20 +121,20 @@ const NodeLoopStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
mr={1}
color={'primary.600'}
/>
{t('workflow:Array_element')}
{t(output.label)}
</Flex>
</Td>
<Td>{loopItemInputType}</Td>
{output.valueType && <Td>{FlowValueTypeMap[output.valueType]?.label}</Td>}
</Tr>
</Tbody>
</Table>
</TableContainer>
</Box>
)}
))}
</Tbody>
</Table>
</TableContainer>
</Box>
</Box>
</NodeCard>
);
}, [data, loopItemInputType, selected, t]);
}, [data, outputs, selected, t]);
return Render;
};