diff --git a/docSite/content/zh-cn/docs/development/upgrading/486.md b/docSite/content/zh-cn/docs/development/upgrading/486.md index 0695de57d52..cdb942db341 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/486.md +++ b/docSite/content/zh-cn/docs/development/upgrading/486.md @@ -13,9 +13,9 @@ weight: 818 ### 2. 修改镜像 -- fastgpt 镜像 tag 修改成 v4.8.6-alpha -- fastgpt-sandbox 镜像 tag 修改成 v4.8.6-alpha -- 商业版镜像 tag 修改成 v4.8.6-alpha +- fastgpt 镜像 tag 修改成 v4.8.6-alpha2 +- fastgpt-sandbox 镜像 tag 修改成 v4.8.6-alpha2 +- 商业版镜像 tag 修改成 v4.8.6-alpha2 ### 3. 执行初始化 @@ -39,6 +39,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv486' \ 4. 新增 - 移动文本加工和自定义反馈到基础节点中 5. 优化 - Read file 默认选中从节点,实现 MongoDB 读写分离,减轻主节点压力 6. 优化 - 知识库导入接口,返回值对齐 -7. 修复 - 工作流中团队插件加载异常 -8. 修复 - 知识库集合目录导航失效 -9. 修复 - 通过 API 调用 chat 接口,传递 System 异常 \ No newline at end of file +7. 优化 - Mongo model 重复加载 +8. 修复 - 工作流中团队插件加载异常 +9. 修复 - 知识库集合目录导航失效 +10. 修复 - 通过 API 调用 chat 接口,传递 System 异常 \ No newline at end of file diff --git a/packages/global/core/workflow/template/output.ts b/packages/global/core/workflow/template/output.ts index ee791bf2d86..826938fb8b4 100644 --- a/packages/global/core/workflow/template/output.ts +++ b/packages/global/core/workflow/template/output.ts @@ -8,5 +8,10 @@ export const Output_Template_AddOutput: FlowNodeOutputItemType = { key: NodeOutputKeyEnum.addOutputParam, type: FlowNodeOutputTypeEnum.dynamic, valueType: WorkflowIOValueTypeEnum.dynamic, - label: '' + label: '', + customFieldConfig: { + selectValueTypeList: Object.values(WorkflowIOValueTypeEnum), + showDescription: false, + showDefaultValue: false + } }; diff --git a/packages/global/core/workflow/template/system/http468.ts b/packages/global/core/workflow/template/system/http468.ts index 3200762c972..5a980fd8a1b 100644 --- a/packages/global/core/workflow/template/system/http468.ts +++ b/packages/global/core/workflow/template/system/http468.ts @@ -82,12 +82,7 @@ export const HttpNode468: FlowNodeTemplateType = { ], outputs: [ { - ...Output_Template_AddOutput, - customFieldConfig: { - selectValueTypeList: Object.values(WorkflowIOValueTypeEnum), - showDescription: false, - showDefaultValue: true - } + ...Output_Template_AddOutput }, { id: NodeOutputKeyEnum.error, diff --git a/packages/global/core/workflow/template/system/sandbox/index.ts b/packages/global/core/workflow/template/system/sandbox/index.ts index 9dca7a72bbc..36e2f2867ea 100644 --- a/packages/global/core/workflow/template/system/sandbox/index.ts +++ b/packages/global/core/workflow/template/system/sandbox/index.ts @@ -36,6 +36,32 @@ export const CodeNode: FlowNodeTemplateType = { showDefaultValue: true } }, + { + renderTypeList: [FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.string, + canEdit: true, + key: 'data1', + label: 'data1', + customInputConfig: { + selectValueTypeList: Object.values(WorkflowIOValueTypeEnum), + showDescription: false, + showDefaultValue: true + }, + required: true + }, + { + renderTypeList: [FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.string, + canEdit: true, + key: 'data2', + label: 'data2', + customInputConfig: { + selectValueTypeList: Object.values(WorkflowIOValueTypeEnum), + showDescription: false, + showDefaultValue: true + }, + required: true + }, { key: NodeInputKeyEnum.codeType, renderTypeList: [FlowNodeInputTypeEnum.hidden], @@ -52,7 +78,7 @@ export const CodeNode: FlowNodeTemplateType = { outputs: [ { ...Output_Template_AddOutput, - description: '将代码中 return 的对象作为输出,传递给后续的节点' + description: '将代码中 return 的对象作为输出,传递给后续的节点。变量名需要对应 return 的 key' }, { id: NodeOutputKeyEnum.rawResponse, diff --git a/packages/service/common/mongo/index.ts b/packages/service/common/mongo/index.ts index a31239106c5..4c7d60e84ff 100644 --- a/packages/service/common/mongo/index.ts +++ b/packages/service/common/mongo/index.ts @@ -1,6 +1,9 @@ import { addLog } from '../../common/system/log'; import mongoose, { Model } from 'mongoose'; +export default mongoose; +export * from 'mongoose'; + export const connectionMongo = (() => { if (!global.mongodb) { global.mongodb = mongoose; @@ -9,9 +12,6 @@ export const connectionMongo = (() => { return global.mongodb; })(); -export default mongoose; -export * from 'mongoose'; - const addCommonMiddleware = (schema: mongoose.Schema) => { const operations = [ /^find/, diff --git a/packages/service/common/system/log.ts b/packages/service/common/system/log.ts index 49bf208bfc2..cd5d97788d2 100644 --- a/packages/service/common/system/log.ts +++ b/packages/service/common/system/log.ts @@ -1,8 +1,8 @@ import dayjs from 'dayjs'; import chalk from 'chalk'; import { LogLevelEnum } from './log/constant'; -// import { MongoLog } from './log/schema'; -import connectionMongo from '../mongo/index'; +import { connectionMongo } from '../mongo/index'; +import { getMongoLog } from './log/schema'; const logMap = { [LogLevelEnum.debug]: { @@ -52,14 +52,14 @@ export const addLog = { level === LogLevelEnum.error && console.error(obj); // store - // if (level >= STORE_LOG_LEVEL && connectionMongo.connection.readyState === 1) { - // // store log - // MongoLog.create({ - // text: msg, - // level, - // metadata: obj - // }); - // } + if (level >= STORE_LOG_LEVEL && connectionMongo.connection.readyState === 1) { + // store log + getMongoLog().create({ + text: msg, + level, + metadata: obj + }); + } }, debug(msg: string, obj?: Record) { this.log(LogLevelEnum.debug, msg, obj); diff --git a/packages/service/common/system/log/schema.ts b/packages/service/common/system/log/schema.ts index caca4d63314..c14fabba170 100644 --- a/packages/service/common/system/log/schema.ts +++ b/packages/service/common/system/log/schema.ts @@ -4,24 +4,26 @@ import { LogLevelEnum } from './constant'; export const LogCollectionName = 'system_logs'; -const SystemLogSchema = new Schema({ - text: { - type: String, - required: true - }, - level: { - type: String, - required: true, - enum: Object.values(LogLevelEnum) - }, - time: { - type: Date, - default: () => new Date() - }, - metadata: Object -}); +export const getMongoLog = () => { + const SystemLogSchema = new Schema({ + text: { + type: String, + required: true + }, + level: { + type: String, + required: true, + enum: Object.values(LogLevelEnum) + }, + time: { + type: Date, + default: () => new Date() + }, + metadata: Object + }); -SystemLogSchema.index({ time: 1 }, { expires: '15d' }); -SystemLogSchema.index({ level: 1 }); + SystemLogSchema.index({ time: 1 }, { expires: '15d' }); + SystemLogSchema.index({ level: 1 }); -export const MongoLog = getMongoModel(LogCollectionName, SystemLogSchema); + return getMongoModel(LogCollectionName, SystemLogSchema); +}; diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json index d81bf1e90c0..3b0278f96f3 100644 --- a/packages/web/i18n/en/app.json +++ b/packages/web/i18n/en/app.json @@ -57,7 +57,7 @@ }, "module": { "Combine Modules": "Combine Modules", - "Confirm Sync": "Using the latest template will overwrite the existing one and may result in the loss of some previous configuration information. Please confirm.", + "Confirm Sync": "The template will be updated to the latest template configuration. Fields that do not exist in the template will be deleted (including all custom fields). You are advised to make a copy of the node and then update the original node version.", "Custom Title Tip": "This title will be displayed during the conversation", "My Modules": "My Modules", "No Modules": "No plugins yet~", diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 4ebc216de13..e7e55a6c059 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -1068,7 +1068,7 @@ "Debug": "Debug", "Debug Node": "Debug mode", "Failed": "Execution failed", - "Not intro": "This node has no introduction~\\", + "Not intro": "This node has no introduction~", "Run from here": "Run from here", "Run result": "Run result", "Running": "Running", diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index 3230af044e3..b50df83fe85 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -16,7 +16,7 @@ "Tool input": "Tool", "code": { "Reset template": "Reset template", - "Reset template confirm": "Are you sure to restore the code template? Be careful to save the current code." + "Reset template confirm": "Are you sure to restore the code template? All input and output to template values will be reset, please be careful to save the current code." }, "ifelse": { "Input value": "Input", diff --git a/packages/web/i18n/zh/app.json b/packages/web/i18n/zh/app.json index 8a288e2bbcb..23b097b069d 100644 --- a/packages/web/i18n/zh/app.json +++ b/packages/web/i18n/zh/app.json @@ -56,7 +56,7 @@ }, "module": { "Combine Modules": "组合模块", - "Confirm Sync": "将会使用最新模板进行覆盖,可能会丢失一些旧的配置信息,请确认", + "Confirm Sync": "将会更新至最新的模板配置,不存在模板中的字段将会被删除(包括所有自定义字段),建议您先复制一份节点,再更新原来节点的版本。", "Custom Title Tip": "该标题名字会展示在对话过程中", "My Modules": "", "No Modules": "没找到插件", diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index a618b2cc71c..08fbf7bc833 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -1077,7 +1077,7 @@ "Debug": "调试", "Debug Node": "Debug 模式", "Failed": "运行失败", - "Not intro": "这个节点没有介绍~\\", + "Not intro": "这个节点没有介绍~", "Run from here": "从这里开始运行", "Run result": "", "Running": "运行中", diff --git a/packages/web/i18n/zh/workflow.json b/packages/web/i18n/zh/workflow.json index cf7461d4627..97e682229a2 100644 --- a/packages/web/i18n/zh/workflow.json +++ b/packages/web/i18n/zh/workflow.json @@ -16,7 +16,7 @@ "Tool input": "工具参数", "code": { "Reset template": "还原模板", - "Reset template confirm": "确认还原代码模板?请注意保存当前代码。" + "Reset template confirm": "确认还原代码模板?将会重置所有输入和输出至模板值,请注意保存当前代码。" }, "ifelse": { "Input value": "输入值", diff --git a/projects/app/src/components/common/folder/SelectOneResource.tsx b/projects/app/src/components/common/folder/SelectOneResource.tsx index 2e1a6a61dde..2e9e4307f8b 100644 --- a/projects/app/src/components/common/folder/SelectOneResource.tsx +++ b/projects/app/src/components/common/folder/SelectOneResource.tsx @@ -155,7 +155,7 @@ const SelectOneResource = ({ return loading ? ( ) : ( - + ); diff --git a/projects/app/src/pages/app/detail/components/InfoModal.tsx b/projects/app/src/pages/app/detail/components/InfoModal.tsx index 8ee2705af66..68b0cf51497 100644 --- a/projects/app/src/pages/app/detail/components/InfoModal.tsx +++ b/projects/app/src/pages/app/detail/components/InfoModal.tsx @@ -63,8 +63,8 @@ const InfoModal = ({ onClose }: { onClose: () => void }) => { const avatar = getValues('avatar'); // submit config - const { mutate: saveSubmitSuccess, isLoading: btnLoading } = useRequest({ - mutationFn: async (data: AppSchema) => { + const { runAsync: saveSubmitSuccess, loading: btnLoading } = useRequest2( + async (data: AppSchema) => { await updateAppDetail({ name: data.name, avatar: data.avatar, @@ -72,16 +72,17 @@ const InfoModal = ({ onClose }: { onClose: () => void }) => { defaultPermission: data.defaultPermission }); }, - onSuccess() { - onClose(); - toast({ - title: t('common.Update Success'), - status: 'success' - }); - reloadApp(); - }, - errorToast: t('common.Update Failed') - }); + { + onSuccess() { + toast({ + title: t('common.Update Success'), + status: 'success' + }); + reloadApp(); + }, + errorToast: t('common.Update Failed') + } + ); const saveSubmitError = useCallback(() => { // deep search message @@ -101,8 +102,8 @@ const InfoModal = ({ onClose }: { onClose: () => void }) => { }, [errors, t, toast]); const saveUpdateModel = useCallback( - () => handleSubmit((data) => saveSubmitSuccess(data), saveSubmitError)(), - [handleSubmit, saveSubmitError, saveSubmitSuccess] + () => handleSubmit((data) => saveSubmitSuccess(data).then(onClose), saveSubmitError)(), + [handleSubmit, onClose, saveSubmitError, saveSubmitSuccess] ); const onSelectFile = useCallback( @@ -210,7 +211,7 @@ const InfoModal = ({ onClose }: { onClose: () => void }) => { isInheritPermission={appDetail.inheritPermission} onChange={(v) => { setValue('defaultPermission', v); - handleSubmit((data) => saveSubmitSuccess(data), saveSubmitError)(); + return handleSubmit((data) => saveSubmitSuccess(data), saveSubmitError)(); }} hasParent={!!appDetail.parentId} /> diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx index 1afbc18d287..c10a7bd462b 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/NodeTemplatesModal.tsx @@ -396,7 +396,9 @@ const RenderList = React.memo(function RenderList({ {t(template.name)} - {t(template.intro || 'core.workflow.Not intro')} + + {t(template.intro) || t('core.workflow.Not intro')} + } > diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeCode.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeCode.tsx index 60e0d4f3348..d263dc611c5 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeCode.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodeCode.tsx @@ -16,7 +16,8 @@ import CodeEditor from '@fastgpt/web/components/common/Textarea/CodeEditor'; import { Box, Flex } from '@chakra-ui/react'; import { useI18n } from '@/web/context/I18n'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; -import { JS_TEMPLATE } from '@fastgpt/global/core/workflow/template/system/sandbox/constants'; +import { getLatestNodeTemplate } from '@/web/core/workflow/utils'; +import { CodeNode } from '@fastgpt/global/core/workflow/template/system/sandbox'; const NodeCode = ({ data, selected }: NodeProps) => { const { t } = useTranslation(); @@ -24,6 +25,8 @@ const NodeCode = ({ data, selected }: NodeProps) => { const { nodeId, inputs, outputs } = data; const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs); const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); + const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode); + const { isTool, commonInputs } = splitToolInputs(inputs, nodeId); const { ConfirmModal, openConfirm } = useConfirm({ content: workflowT('code.Reset template confirm') @@ -41,14 +44,9 @@ const NodeCode = ({ data, selected }: NodeProps) => { color={'primary.500'} fontSize={'xs'} onClick={openConfirm(() => { - onChangeNode({ - nodeId, - type: 'updateInput', - key: item.key, - value: { - ...item, - value: JS_TEMPLATE - } + onResetNode({ + id: nodeId, + node: getLatestNodeTemplate(data, CodeNode) }); })} > diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/InputEditModal.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/InputEditModal.tsx index 201e190b35b..da707c86c98 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/InputEditModal.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/NodePluginIO/InputEditModal.tsx @@ -37,6 +37,7 @@ export const defaultInput: FlowNodeInputItemType = { renderTypeList: [FlowNodeInputTypeEnum.reference], // Can only choose one here selectedTypeIndex: 0, valueType: WorkflowIOValueTypeEnum.string, + canEdit: true, key: '', label: '' }; diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx index e73f386f4aa..94b6ee3108f 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx @@ -16,7 +16,7 @@ import { useDebug } from '../../hooks/useDebug'; import { ResponseBox } from '@/components/ChatBox/components/WholeResponseModal'; import EmptyTip from '@fastgpt/web/components/common/EmptyTip'; import { getPreviewPluginNode } from '@/web/core/app/api/plugin'; -import { storeNode2FlowNode, updateFlowNodeVersion } from '@/web/core/workflow/utils'; +import { storeNode2FlowNode, getLatestNodeTemplate } from '@/web/core/workflow/utils'; import { getNanoid } from '@fastgpt/global/common/string/tools'; import { useContextSelector } from 'use-context-selector'; import { WorkflowContext } from '../../../context'; @@ -24,8 +24,6 @@ import { useI18n } from '@/web/context/I18n'; import { moduleTemplatesFlat } from '@fastgpt/global/core/workflow/template/constants'; import { QuestionOutlineIcon } from '@chakra-ui/icons'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; -import { useSystemStore } from '@/web/common/system/useSystemStore'; -import { useMount } from 'ahooks'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useWorkflowUtils } from '../../hooks/useUtils'; @@ -56,13 +54,11 @@ const NodeCard = (props: Props) => { minW = '300px', maxW = '600px', nodeId, - flowNodeType, selected, menuForbid, isTool = false, isError = false, - debugResult, - pluginId + debugResult } = props; const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList); @@ -106,11 +102,11 @@ const NodeCard = (props: Props) => { ); const hasNewVersion = newNodeVersion && newNodeVersion !== node?.version; - const template = moduleTemplatesFlat.find((item) => item.flowNodeType === node?.flowNodeType); - - const onClickSyncVersion = useCallback(async () => { - try { + const { runAsync: onClickSyncVersion } = useRequest2( + async () => { + const template = moduleTemplatesFlat.find((item) => item.flowNodeType === node?.flowNodeType); if (!node || !template) return; + if (node?.flowNodeType === FlowNodeTypeEnum.pluginModule) { if (!node.pluginId) return; onResetNode({ @@ -120,14 +116,15 @@ const NodeCard = (props: Props) => { } else { onResetNode({ id: nodeId, - node: updateFlowNodeVersion(node, template) + node: getLatestNodeTemplate(node, template) }); } await getNodeVersion(); - } catch (error) { - console.error('Error fetching plugin module:', error); + }, + { + refreshDeps: [node, nodeId, onResetNode, getNodeVersion] } - }, [getNodeVersion, node, nodeId, onResetNode, template]); + ); /* Node header */ const Header = useMemo(() => { @@ -197,12 +194,7 @@ const NodeCard = (props: Props) => { )} - + @@ -219,8 +211,6 @@ const NodeCard = (props: Props) => { appT, onOpenConfirmSync, onClickSyncVersion, - pluginId, - flowNodeType, intro, ConfirmSyncModal, onOpenCustomTitleModal, @@ -274,13 +264,9 @@ export default React.memo(NodeCard); const MenuRender = React.memo(function MenuRender({ nodeId, - pluginId, - flowNodeType, menuForbid }: { nodeId: string; - pluginId?: string; - flowNodeType: Props['flowNodeType']; menuForbid?: Props['menuForbid']; }) { const { t } = useTranslation(); diff --git a/projects/app/src/pages/chat/components/ChatHistorySlider.tsx b/projects/app/src/pages/chat/components/ChatHistorySlider.tsx index 1b5274119e5..3e4352bd33a 100644 --- a/projects/app/src/pages/chat/components/ChatHistorySlider.tsx +++ b/projects/app/src/pages/chat/components/ChatHistorySlider.tsx @@ -164,8 +164,12 @@ const ChatHistorySlider = ({ px: 1 }} list={[ - { label: t('core.chat.Recent use'), value: TabEnum.recently }, - ...(!isTeamChat ? [{ label: t('App'), value: TabEnum.app }] : []), + ...(isTeamChat + ? [{ label: t('App'), value: TabEnum.recently }] + : [ + { label: t('core.chat.Recent use'), value: TabEnum.recently }, + { label: t('App'), value: TabEnum.app } + ]), { label: t('core.chat.History'), value: TabEnum.history } ]} value={currentTab} @@ -185,8 +189,8 @@ const ChatHistorySlider = ({ > {t('core.chat.New Chat')} - - {(isPc || !showApps) && ( + {/* Clear */} + {isPc && ( template.flowNodeType === storeNode.flowNodeType) || EmptyNode; + const templateInputs = template.inputs.filter((input) => !input.canEdit); + const templateOutputs = template.outputs.filter( + (output) => output.type !== FlowNodeOutputTypeEnum.dynamic + ); + const dynamicInput = template.inputs.find( + (input) => input.renderTypeList[0] === FlowNodeInputTypeEnum.addInputParam + ); + // replace item data const nodeItem: FlowNodeItemType = { ...template, ...storeNode, version: storeNode.version ?? template.version ?? defaultNodeVersion, - inputs: template.inputs + /* + Inputs and outputs, New fields are added, not reduced + */ + inputs: templateInputs .map((templateInput) => { const storeInput = storeNode.inputs.find((item) => item.key === templateInput.key) || templateInput; @@ -91,27 +104,35 @@ export const storeNode2FlowNode = ({ }; }) .concat( - /* - 1. Plugin input - 2. Old version adapt: Dynamic input will be added to the node inputs. - */ - storeNode.inputs.filter((item) => !template.inputs.find((input) => input.key === item.key)) + /* Concat dynamic inputs */ + storeNode.inputs + .filter((item) => !templateInputs.find((input) => input.key === item.key)) + .map((item) => { + if (!dynamicInput) return item; + + return { + ...item, + ...getInputComponentProps(dynamicInput) + }; + }) ), - outputs: template.outputs + outputs: templateOutputs .map((templateOutput) => { const storeOutput = template.outputs.find((item) => item.key === templateOutput.key) || templateOutput; + return { ...storeOutput, ...templateOutput, id: storeOutput.id ?? templateOutput.id, + label: storeOutput.label ?? templateOutput.label, value: storeOutput.value ?? templateOutput.value }; }) .concat( storeNode.outputs.filter( - (item) => !template.outputs.find((output) => output.key === item.key) + (item) => !templateOutputs.find((output) => output.key === item.key) ) ) }; @@ -365,37 +386,42 @@ export const getWorkflowGlobalVariables = ({ export type CombinedItemType = Partial & Partial; -export const updateFlowNodeVersion = ( +/* Reset node to latest version */ +export const getLatestNodeTemplate = ( node: FlowNodeItemType, template: FlowNodeTemplateType ): FlowNodeItemType => { - function updateArrayBasedOnTemplate( - nodeArray: T[], - templateArray: T[] - ): T[] { - return templateArray.map((templateItem) => { - const nodeItem = nodeArray.find((item) => item.key === templateItem.key); - if (nodeItem) { - return { ...templateItem, ...nodeItem } as T; - } - return { ...templateItem }; - }); - } - const updatedNode: FlowNodeItemType = { ...node, ...template, + inputs: template.inputs.map((templateItem) => { + const nodeItem = node.inputs.find((item) => item.key === templateItem.key); + if (nodeItem) { + return { + ...templateItem, + value: nodeItem.value, + selectedTypeIndex: nodeItem.selectedTypeIndex, + valueType: nodeItem.valueType + }; + } + return { ...templateItem }; + }), + outputs: template.outputs.map((templateItem) => { + const nodeItem = node.outputs.find((item) => item.key === templateItem.key); + if (nodeItem) { + return { + ...templateItem, + id: nodeItem.id, + value: nodeItem.value, + valueType: nodeItem.valueType + }; + } + return { ...templateItem }; + }), name: node.name, intro: node.intro }; - if (node.inputs && template.inputs) { - updatedNode.inputs = updateArrayBasedOnTemplate(node.inputs, template.inputs); - } - if (node.outputs && template.outputs) { - updatedNode.outputs = updateArrayBasedOnTemplate(node.outputs, template.outputs); - } - return updatedNode; };