4.8.13 perf (#3112)
* fix: share page load title error * update file input doc * perf: auto add file urls * perf: auto ser loop node offset height
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 151 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB |
BIN
docSite/assets/imgs/image-5.png
Normal file
BIN
docSite/assets/imgs/image-5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 372 KiB |
BIN
docSite/assets/imgs/image-6.png
Normal file
BIN
docSite/assets/imgs/image-6.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 471 KiB |
BIN
docSite/assets/imgs/image-7.png
Normal file
BIN
docSite/assets/imgs/image-7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 416 KiB |
@@ -20,10 +20,12 @@ weight: 110
|
|||||||
|
|
||||||
随后,你的调试对话框中,就会出现一个文件选择的 icon,可以点击文件选择 icon,选择你需要上传的文件。
|
随后,你的调试对话框中,就会出现一个文件选择的 icon,可以点击文件选择 icon,选择你需要上传的文件。
|
||||||
|
|
||||||
由于采用的是工具调用模式,所以在提问时候,可能需要加上适当的引导,让模型知道,你需要读取`文档`。
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
**工作模式**
|
||||||
|
|
||||||
|
从 4.8.13 版本起,简易模式的文件读取将会强制解析文件并放入 system 提示词中,避免连续对话时,模型有时候不会主动调用读取文件的工具。
|
||||||
|
|
||||||
## 工作流中使用
|
## 工作流中使用
|
||||||
|
|
||||||
工作流中,可以在系统配置中,找到`文件输入`配置项,点击其右侧的`开启`/`关闭`按键,即可打开配置弹窗。
|
工作流中,可以在系统配置中,找到`文件输入`配置项,点击其右侧的`开启`/`关闭`按键,即可打开配置弹窗。
|
||||||
@@ -32,14 +34,13 @@ weight: 110
|
|||||||
|
|
||||||
在工作流中,使用文件的方式很多,最简单的就是类似下图中,直接通过工具调用接入文档解析,实现和简易模式一样的效果。
|
在工作流中,使用文件的方式很多,最简单的就是类似下图中,直接通过工具调用接入文档解析,实现和简易模式一样的效果。
|
||||||
|
|
||||||

|
| | |
|
||||||
|
| --------------------- | --------------------- |
|
||||||
|
|  |  |
|
||||||
|
|
||||||
也可以更简单点,强制每轮对话都携带上文档内容进行回答,这样就不需要调用两次 AI 才能读取文档内容了。
|
当然,你也可以在工作流中,对文档进行内容提取、内容分析等,然后将分析的结果传递给 HTTP 或者其他模块,从而实现文件处理的 SOP。
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
当然,你也可以在工作流中,对文档进行内容提取、内容分析等,然后将分析的结果传递给 HTTP 或者其他模块,从而实现文件处理的 SOP。不过目前版本,`插件`中并未支持文件处理,所以在构建 SOP 的话可能还是有一些麻烦。
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## 文档解析工作原理
|
## 文档解析工作原理
|
||||||
|
|
||||||
@@ -73,23 +74,8 @@ type UserChatItemValueItemType = {
|
|||||||
|
|
||||||
文档解析依赖文档解析节点,这个节点会接收一个`array<string>`类型的输入,对应的是文件输入的 URL;输出的是一个`string`,对应的是文档解析后的内容。
|
文档解析依赖文档解析节点,这个节点会接收一个`array<string>`类型的输入,对应的是文件输入的 URL;输出的是一个`string`,对应的是文档解析后的内容。
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* 在文档解析节点中,只会解析`文档`类型的 URL,它是通过文件 URL 解析出来的`文名件后缀`去判断的。如果你同时选择了文档和图片,图片会被忽略。
|
* 在文档解析节点中,只会解析`文档`类型的 URL,它是通过文件 URL 解析出来的`文名件后缀`去判断的。如果你同时选择了文档和图片,图片会被忽略。
|
||||||
* 文档解析节点,除了解析本轮工作流接收的文件外,还会把历史记录中的文档 URL 进行解析。最终会解析至多 n 个文档,n 取决于你配置文件上传时,允许的最大文件数量。
|
* **文档解析节点,只会解析本轮工作流接收的文件,不会解析历史记录的文件。**
|
||||||
|
|
||||||
{{% alert icon="🤖" context="success" %}}
|
|
||||||
举例:
|
|
||||||
|
|
||||||
配置了最多允许 5 个文件上传
|
|
||||||
|
|
||||||
1. 第一轮对话,上传 3 个文档和 1 个图片:文档解析节点,返回 3 个文档内容。
|
|
||||||
2. 第二轮对话,不上传任何文件:文档解析节点,返回 3 个文档内容。
|
|
||||||
3. 第三轮对话,上传 2 个文档:文档解析节点,返回 5 个文档内容。
|
|
||||||
4. 第四轮对话,上传 1 个文档:文档解析节点,返回 5 个文档内容,第一轮对话中的第三个文档会被过滤掉。
|
|
||||||
|
|
||||||
{{% /alert %}}
|
|
||||||
|
|
||||||
* 多个文档内容如何拼接的
|
* 多个文档内容如何拼接的
|
||||||
|
|
||||||
按下列的模板,对多个文件进行拼接,即文件名+文件内容的形式组成一个字符串,不同文档之间通过分隔符:`\n******\n` 进行分割。
|
按下列的模板,对多个文件进行拼接,即文件名+文件内容的形式组成一个字符串,不同文档之间通过分隔符:`\n******\n` 进行分割。
|
||||||
@@ -101,32 +87,27 @@ ${content}
|
|||||||
</Content>
|
</Content>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 工具调用如何使用文档解析
|
### AI节点中如何使用文档解析
|
||||||
|
|
||||||
在工具调用中,文档解析节点的调用提示词为:`解析对话中所有上传的文档,并返回对应文档内容`。
|
在 AI 节点(AI对话/工具调用)中,新增了一个文档链接的输入,可以直接引用文档的地址,从而实现文档内容的引用。
|
||||||
|
|
||||||
作为工具被执行后,文档解析节点会返回解析后的文档内容作为工具响应。
|
它接收一个`Array<string>`类型的输入,最终这些 url 会被解析,并进行提示词拼接,放置在 role=system 的消息中。提示词模板如下:
|
||||||
|
|
||||||
### AI对话中如何使用文档解析
|
|
||||||
|
|
||||||
在 AI 对话节点中,新增了一个文档引用的输入,可以直接引用文档解析节点的输出,从而实现文档内容的引用。
|
|
||||||
|
|
||||||
它接收一个`string`类型的输入,除了可以引用文档解析结果外,还可以实现自定义内容引用,最终会进行提示词拼接,放置在 role=system 的消息中。提示词模板如下:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
将 <Quote></Quote> 中的内容作为本次对话的参考:
|
将 <FilesContent></FilesContent> 中的内容作为本次对话的参考:
|
||||||
<Quote>
|
<FilesContent>
|
||||||
{{quote}}
|
{{quote}}
|
||||||
</Quote>
|
</FilesContent>
|
||||||
```
|
```
|
||||||
|
|
||||||
quote 为引用的内容。
|
# 4.8.13版本起,关于文件上传的更新
|
||||||
|
|
||||||

|
由于与 4.8.9 版本有些差异,尽管我们做了向下兼容,避免工作流立即不可用。但是请尽快的按新版本规则进行调整工作流,后续将会去除兼容性代码。
|
||||||
|
|
||||||
## 文件输入后续更新
|
1. 简易模式中,将会强制进行文件解析,不再由模型决策是否解析,保证每次都能参考文档。
|
||||||
|
2. 文档解析:不再解析历史记录中的文件。
|
||||||
* 插件支持配置文件输入。
|
3. 工具调用:支持直接选择文档引用,不需要再挂载文档解析工具。会自动解析历史记录中的文件。
|
||||||
* 子应用和插件调用,支持传递文件输入。
|
4. AI 对话:支持直接选择文档引用,不需要进过文档解析节点。会自动解析历史记录中的文件。
|
||||||
* 文档解析,结构化解析结果。
|
5. 插件单独运行:不再支持全局文件;插件输入支持配置文件类型,可以取代全局文件上传。
|
||||||
* 更多的文件类型输入以及解析器。
|
6. **工作流调用插件:不再自动传递工作流上传的文件到插件,需要手动给插件输入指定变量。**
|
||||||
|
7. **工作流调用工作流:不再自动传递工作流上传的文件到子工作流,可以手动选择需要传递的文件链接。**
|
||||||
@@ -199,6 +199,7 @@ export enum NodeInputKeyEnum {
|
|||||||
childrenNodeIdList = 'childrenNodeIdList',
|
childrenNodeIdList = 'childrenNodeIdList',
|
||||||
nodeWidth = 'nodeWidth',
|
nodeWidth = 'nodeWidth',
|
||||||
nodeHeight = 'nodeHeight',
|
nodeHeight = 'nodeHeight',
|
||||||
|
loopNodeInputHeight = 'loopNodeInputHeight',
|
||||||
// loop start
|
// loop start
|
||||||
loopStartInput = 'loopStartInput',
|
loopStartInput = 'loopStartInput',
|
||||||
loopStartIndex = 'loopStartIndex',
|
loopStartIndex = 'loopStartIndex',
|
||||||
|
|||||||
@@ -113,6 +113,13 @@ export const Input_Template_Node_Height: FlowNodeInputItemType = {
|
|||||||
label: '',
|
label: '',
|
||||||
value: 600
|
value: 600
|
||||||
};
|
};
|
||||||
|
export const Input_Template_LOOP_NODE_OFFSET: FlowNodeInputItemType = {
|
||||||
|
key: NodeInputKeyEnum.loopNodeInputHeight,
|
||||||
|
renderTypeList: [FlowNodeInputTypeEnum.hidden],
|
||||||
|
valueType: WorkflowIOValueTypeEnum.number,
|
||||||
|
label: '',
|
||||||
|
value: 320
|
||||||
|
};
|
||||||
|
|
||||||
export const Input_Template_Stream_MODE: FlowNodeInputItemType = {
|
export const Input_Template_Stream_MODE: FlowNodeInputItemType = {
|
||||||
key: NodeInputKeyEnum.forbidStream,
|
key: NodeInputKeyEnum.forbidStream,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { getHandleConfig } from '../../utils';
|
|||||||
import { i18nT } from '../../../../../../web/i18n/utils';
|
import { i18nT } from '../../../../../../web/i18n/utils';
|
||||||
import {
|
import {
|
||||||
Input_Template_Children_Node_List,
|
Input_Template_Children_Node_List,
|
||||||
|
Input_Template_LOOP_NODE_OFFSET,
|
||||||
Input_Template_Node_Height,
|
Input_Template_Node_Height,
|
||||||
Input_Template_Node_Width
|
Input_Template_Node_Width
|
||||||
} from '../../input';
|
} from '../../input';
|
||||||
@@ -40,7 +41,8 @@ export const LoopNode: FlowNodeTemplateType = {
|
|||||||
},
|
},
|
||||||
Input_Template_Children_Node_List,
|
Input_Template_Children_Node_List,
|
||||||
Input_Template_Node_Width,
|
Input_Template_Node_Width,
|
||||||
Input_Template_Node_Height
|
Input_Template_Node_Height,
|
||||||
|
Input_Template_LOOP_NODE_OFFSET
|
||||||
],
|
],
|
||||||
outputs: [
|
outputs: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { useKeyboard } from './useKeyboard';
|
|||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '../../context';
|
import { WorkflowContext } from '../../context';
|
||||||
import { THelperLine } from '@fastgpt/global/core/workflow/type';
|
import { THelperLine } from '@fastgpt/global/core/workflow/type';
|
||||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||||
import { useDebounceEffect, useMemoizedFn } from 'ahooks';
|
import { useDebounceEffect, useMemoizedFn } from 'ahooks';
|
||||||
import {
|
import {
|
||||||
Input_Template_Node_Height,
|
Input_Template_Node_Height,
|
||||||
@@ -304,7 +304,7 @@ export const useWorkflow = () => {
|
|||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{ childNodes: [] as Node[], loopNode: undefined as Node | undefined }
|
{ childNodes: [] as Node[], loopNode: undefined as Node<FlowNodeItemType> | undefined }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!loopNode) return;
|
if (!loopNode) return;
|
||||||
@@ -314,6 +314,10 @@ export const useWorkflow = () => {
|
|||||||
const width = Math.max(rect.width + 80, 840);
|
const width = Math.max(rect.width + 80, 840);
|
||||||
const height = Math.max(rect.height + 80, 600);
|
const height = Math.max(rect.height + 80, 600);
|
||||||
|
|
||||||
|
const offsetHeight =
|
||||||
|
loopNode.data.inputs.find((input) => input.key === NodeInputKeyEnum.loopNodeInputHeight)
|
||||||
|
?.value ?? 83;
|
||||||
|
|
||||||
// Update parentNode size and position
|
// Update parentNode size and position
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
nodeId: parentId,
|
nodeId: parentId,
|
||||||
@@ -340,7 +344,7 @@ export const useWorkflow = () => {
|
|||||||
type: 'position',
|
type: 'position',
|
||||||
position: {
|
position: {
|
||||||
x: rect.x - 70,
|
x: rect.x - 70,
|
||||||
y: rect.y - 320
|
y: rect.y - offsetHeight - 240
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -608,8 +612,36 @@ export const useWorkflow = () => {
|
|||||||
state
|
state
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Add default input
|
||||||
|
const node = nodeList.find((n) => n.nodeId === connect.target);
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
// 1. Add file input
|
||||||
|
if (
|
||||||
|
node.flowNodeType === FlowNodeTypeEnum.chatNode ||
|
||||||
|
node.flowNodeType === FlowNodeTypeEnum.tools ||
|
||||||
|
node.flowNodeType === FlowNodeTypeEnum.appModule
|
||||||
|
) {
|
||||||
|
const input = node.inputs.find((i) => i.key === NodeInputKeyEnum.fileUrlList);
|
||||||
|
if (input && (!input?.value || input.value.length === 0)) {
|
||||||
|
const workflowStartNode = nodeList.find(
|
||||||
|
(n) => n.flowNodeType === FlowNodeTypeEnum.workflowStart
|
||||||
|
);
|
||||||
|
if (!workflowStartNode) return;
|
||||||
|
onChangeNode({
|
||||||
|
nodeId: node.nodeId,
|
||||||
|
type: 'updateInput',
|
||||||
|
key: NodeInputKeyEnum.fileUrlList,
|
||||||
|
value: {
|
||||||
|
...input,
|
||||||
|
value: [[workflowStartNode.nodeId, NodeOutputKeyEnum.userFiles]]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[setEdges]
|
[nodeList, onChangeNode, setEdges]
|
||||||
);
|
);
|
||||||
const customOnConnect = useCallback(
|
const customOnConnect = useCallback(
|
||||||
(connect: Connection) => {
|
(connect: Connection) => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||||
import React, { useEffect, useMemo, useRef } from 'react';
|
import React, { useEffect, useMemo, useRef } from 'react';
|
||||||
import { Background, NodePositionChange, NodeProps } from 'reactflow';
|
import { Background, NodeProps } from 'reactflow';
|
||||||
import NodeCard from '../render/NodeCard';
|
import NodeCard from '../render/NodeCard';
|
||||||
import Container from '../../components/Container';
|
import Container from '../../components/Container';
|
||||||
import IOTitle from '../../components/IOTitle';
|
import IOTitle from '../../components/IOTitle';
|
||||||
@@ -21,7 +21,10 @@ import {
|
|||||||
VARIABLE_NODE_ID,
|
VARIABLE_NODE_ID,
|
||||||
WorkflowIOValueTypeEnum
|
WorkflowIOValueTypeEnum
|
||||||
} from '@fastgpt/global/core/workflow/constants';
|
} from '@fastgpt/global/core/workflow/constants';
|
||||||
import { Input_Template_Children_Node_List } from '@fastgpt/global/core/workflow/template/input';
|
import {
|
||||||
|
Input_Template_Children_Node_List,
|
||||||
|
Input_Template_LOOP_NODE_OFFSET
|
||||||
|
} from '@fastgpt/global/core/workflow/template/input';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '../../../context';
|
import { WorkflowContext } from '../../../context';
|
||||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||||
@@ -29,25 +32,30 @@ import { AppContext } from '../../../../context';
|
|||||||
import { isValidArrayReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
import { isValidArrayReferenceValue } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { ReferenceArrayValueType } from '@fastgpt/global/core/workflow/type/io';
|
import { ReferenceArrayValueType } from '@fastgpt/global/core/workflow/type/io';
|
||||||
import { useWorkflow } from '../../hooks/useWorkflow';
|
import { useWorkflow } from '../../hooks/useWorkflow';
|
||||||
import { WorkflowNodeEdgeContext } from '../../../context/workflowInitContext';
|
|
||||||
import { useSize } from 'ahooks';
|
import { useSize } from 'ahooks';
|
||||||
|
|
||||||
const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { nodeId, inputs, outputs, isFolded } = data;
|
const { nodeId, inputs, outputs, isFolded } = data;
|
||||||
const getNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.getNodes);
|
|
||||||
const onNodesChange = useContextSelector(WorkflowNodeEdgeContext, (v) => v.onNodesChange);
|
|
||||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||||
|
|
||||||
const { resetParentNodeSizeAndPosition } = useWorkflow();
|
const { resetParentNodeSizeAndPosition } = useWorkflow();
|
||||||
|
|
||||||
const { nodeWidth, nodeHeight, loopInputArray } = useMemo(() => {
|
const {
|
||||||
|
nodeWidth,
|
||||||
|
nodeHeight,
|
||||||
|
loopInputArray,
|
||||||
|
loopNodeInputHeight = Input_Template_LOOP_NODE_OFFSET
|
||||||
|
} = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
nodeWidth: inputs.find((input) => input.key === NodeInputKeyEnum.nodeWidth)?.value,
|
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)
|
loopInputArray: inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray),
|
||||||
|
loopNodeInputHeight: inputs.find(
|
||||||
|
(input) => input.key === NodeInputKeyEnum.loopNodeInputHeight
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}, [inputs]);
|
}, [inputs]);
|
||||||
|
|
||||||
@@ -83,7 +91,6 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
})(value[0]);
|
})(value[0]);
|
||||||
return ArrayTypeMap[valueType as keyof typeof ArrayTypeMap] ?? WorkflowIOValueTypeEnum.arrayAny;
|
return ArrayTypeMap[valueType as keyof typeof ArrayTypeMap] ?? WorkflowIOValueTypeEnum.arrayAny;
|
||||||
}, [appDetail.chatConfig, loopInputArray, nodeList]);
|
}, [appDetail.chatConfig, loopInputArray, nodeList]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loopInputArray) return;
|
if (!loopInputArray) return;
|
||||||
onChangeNode({
|
onChangeNode({
|
||||||
@@ -103,7 +110,6 @@ 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,
|
||||||
@@ -117,35 +123,25 @@ const NodeLoop = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
resetParentNodeSizeAndPosition(nodeId);
|
resetParentNodeSizeAndPosition(nodeId);
|
||||||
}, [childrenNodeIdList]);
|
}, [childrenNodeIdList]);
|
||||||
|
|
||||||
// Update child node position
|
// Update loop node offset value
|
||||||
const inputBoxRef = useRef<HTMLDivElement>(null);
|
const inputBoxRef = useRef<HTMLDivElement>(null);
|
||||||
const size = useSize(inputBoxRef);
|
const size = useSize(inputBoxRef);
|
||||||
const prevHeightRef = useRef<number>(); // 添加 ref 来存储前一个高度值
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!size?.height) return;
|
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;
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
// Get the height of the input box
|
type: 'replaceInput',
|
||||||
// Computed input
|
key: NodeInputKeyEnum.loopNodeInputHeight,
|
||||||
const nodes = getNodes();
|
value: {
|
||||||
const childNodes = nodes.filter((n) => n.data.parentNodeId === nodeId);
|
...loopNodeInputHeight,
|
||||||
|
value: size.height
|
||||||
const childNodesChange: NodePositionChange[] = childNodes.map((node) => {
|
}
|
||||||
return {
|
|
||||||
type: 'position',
|
|
||||||
id: node.id,
|
|
||||||
position: {
|
|
||||||
x: node.position.x,
|
|
||||||
y: node.position.y + diffHeight
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onNodesChange(childNodesChange);
|
setTimeout(() => {
|
||||||
|
resetParentNodeSizeAndPosition(nodeId);
|
||||||
|
}, 50);
|
||||||
}, [size?.height]);
|
}, [size?.height]);
|
||||||
|
|
||||||
const Render = useMemo(() => {
|
const Render = useMemo(() => {
|
||||||
|
|||||||
@@ -430,9 +430,13 @@ const WorkflowContextProvider = ({
|
|||||||
item.key === props.key ? props.value : item
|
item.key === props.key ? props.value : item
|
||||||
);
|
);
|
||||||
} else if (type === 'replaceInput') {
|
} else if (type === 'replaceInput') {
|
||||||
updateObj.inputs = updateObj.inputs.map((item) =>
|
if (!updateObj.inputs.find((item) => item.key === props.key)) {
|
||||||
item.key === props.key ? props.value : item
|
updateObj.inputs.push(props.value);
|
||||||
);
|
} else {
|
||||||
|
updateObj.inputs = updateObj.inputs.map((item) =>
|
||||||
|
item.key === props.key ? props.value : item
|
||||||
|
);
|
||||||
|
}
|
||||||
} else if (type === 'addInput') {
|
} else if (type === 'addInput') {
|
||||||
const input = node.data.inputs.find((input) => input.key === props.value.key);
|
const input = node.data.inputs.find((input) => input.key === props.value.key);
|
||||||
if (input) {
|
if (input) {
|
||||||
|
|||||||
Reference in New Issue
Block a user