mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
perf:change plugin version update position (#1493)
* perf:change plugin version update position * use nodeversion
This commit is contained in:
2
packages/global/core/plugin/type.d.ts
vendored
2
packages/global/core/plugin/type.d.ts
vendored
@@ -23,6 +23,7 @@ export type PluginItemSchema = {
|
||||
customHeaders?: string;
|
||||
};
|
||||
version?: 'v1' | 'v2';
|
||||
nodeVersion?: string;
|
||||
};
|
||||
|
||||
/* plugin template */
|
||||
@@ -32,6 +33,7 @@ export type PluginTemplateType = PluginRuntimeType & {
|
||||
source: `${PluginSourceEnum}`;
|
||||
templateType: FlowNodeTemplateType['templateType'];
|
||||
intro: string;
|
||||
nodeVersion: string;
|
||||
};
|
||||
|
||||
export type PluginRuntimeType = {
|
||||
|
@@ -64,6 +64,7 @@ export type FlowNodeTemplateType = FlowNodeCommonType & {
|
||||
// action
|
||||
forbidDelete?: boolean; // forbid delete
|
||||
unique?: boolean;
|
||||
nodeVersion?: string;
|
||||
};
|
||||
export type FlowNodeItemType = FlowNodeTemplateType & {
|
||||
nodeId: string;
|
||||
|
@@ -52,7 +52,8 @@ const getPluginTemplateById = async (id: string): Promise<PluginTemplateType> =>
|
||||
nodes: item.modules,
|
||||
edges: item.edges,
|
||||
templateType: FlowNodeTemplateTypeEnum.personalPlugin,
|
||||
isTool: true
|
||||
isTool: true,
|
||||
nodeVersion: item?.nodeVersion || ''
|
||||
};
|
||||
}
|
||||
return Promise.reject('plugin not found');
|
||||
@@ -72,6 +73,7 @@ export async function getPluginPreviewNode({ id }: { id: string }): Promise<Flow
|
||||
intro: plugin.intro,
|
||||
showStatus: plugin.showStatus,
|
||||
isTool: plugin.isTool,
|
||||
nodeVersion: plugin.nodeVersion,
|
||||
version: '481',
|
||||
sourceHandle: getHandleConfig(true, true, true, true),
|
||||
targetHandle: getHandleConfig(true, true, true, true),
|
||||
|
@@ -64,6 +64,10 @@ const PluginSchema = new Schema({
|
||||
version: {
|
||||
type: String,
|
||||
enum: ['v1', 'v2']
|
||||
},
|
||||
nodeVersion: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -62,7 +62,7 @@ export const valueTypeFormat = (value: any, type?: WorkflowIOValueTypeEnum) => {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
if (type === 'number') return Number(value);
|
||||
if (type === 'boolean') return Boolean(value);
|
||||
if (type === 'boolean') return value === 'true' ? true : false;
|
||||
try {
|
||||
if (type === WorkflowIOValueTypeEnum.datasetQuote && !Array.isArray(value)) {
|
||||
return JSON.parse(value);
|
||||
|
@@ -39,6 +39,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.",
|
||||
"Custom Title Tip": "This title will be displayed during the conversation",
|
||||
"My Modules": "My Modules",
|
||||
"No Modules": "No modules yet~",
|
||||
|
@@ -38,6 +38,7 @@
|
||||
},
|
||||
"module": {
|
||||
"Combine Modules": "组合模块",
|
||||
"Confirm Sync": "将会使用最新模板进行覆盖,可能会丢失一些旧的配置信息,请确认",
|
||||
"Custom Title Tip": "该标题名字会展示在对话过程中",
|
||||
"My Modules": "",
|
||||
"No Modules": "还没有模块~",
|
||||
|
@@ -1,13 +1,15 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Box, Button, Card, Flex } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type {
|
||||
FlowNodeItemType,
|
||||
FlowNodeTemplateType
|
||||
} from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { LOGO_ICON } from '@fastgpt/global/common/system/constants';
|
||||
import { ToolTargetHandle } from './Handle/ToolHandle';
|
||||
@@ -17,7 +19,6 @@ import { useDebug } from '../../hooks/useDebug';
|
||||
import { ResponseBox } from '@/components/ChatBox/WholeResponseModal';
|
||||
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||
import { getPreviewPluginModule } from '@/web/core/plugin/api';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { storeNode2FlowNode, updateFlowNodeVersion } from '@/web/core/workflow/utils';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
@@ -26,6 +27,8 @@ import { useI18n } from '@/web/context/I18n';
|
||||
import { moduleTemplatesFlat } from '@fastgpt/global/core/workflow/template/constants';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { isEqual } from 'lodash';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
type Props = FlowNodeItemType & {
|
||||
children?: React.ReactNode | React.ReactNode[] | string;
|
||||
@@ -69,6 +72,9 @@ const NodeCard = (props: Props) => {
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
|
||||
|
||||
const [hasNewVersion, setHasNewVersion] = useState(false);
|
||||
const { setLoading } = useSystemStore();
|
||||
|
||||
// custom title edit
|
||||
const { onOpenModal: onOpenCustomTitleModal, EditModal: EditTitleModal } = useEditTitle({
|
||||
title: t('common.Custom Title'),
|
||||
@@ -81,13 +87,50 @@ const NodeCard = (props: Props) => {
|
||||
);
|
||||
|
||||
const node = nodeList.find((node) => node.nodeId === nodeId);
|
||||
const { openConfirm: onOpenConfirmSync, ConfirmModal: ConfirmSyncModal } = useConfirm({
|
||||
content: appT('module.Confirm Sync')
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchPluginModule = async () => {
|
||||
if (node?.flowNodeType === FlowNodeTypeEnum.pluginModule) {
|
||||
if (!node?.pluginId) return;
|
||||
const template = await getPreviewPluginModule(node.pluginId);
|
||||
setHasNewVersion(!!template.nodeVersion && node.nodeVersion !== template.nodeVersion);
|
||||
} else {
|
||||
const template = moduleTemplatesFlat.find(
|
||||
(item) => item.flowNodeType === node?.flowNodeType
|
||||
);
|
||||
setHasNewVersion(node?.version !== template?.version);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPluginModule();
|
||||
}, [node]);
|
||||
|
||||
const template = moduleTemplatesFlat.find((item) => item.flowNodeType === node?.flowNodeType);
|
||||
const hasNewVersion = useMemo(() => {
|
||||
return (
|
||||
template?.flowNodeType !== FlowNodeTypeEnum.pluginModule &&
|
||||
node?.version !== template?.version
|
||||
);
|
||||
}, [node?.version, template?.flowNodeType, template?.version]);
|
||||
|
||||
const onClickSyncVersion = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
if (!node || !template) return;
|
||||
if (node?.flowNodeType === 'pluginModule') {
|
||||
if (!node.pluginId) return;
|
||||
onResetNode({
|
||||
id: nodeId,
|
||||
node: await getPreviewPluginModule(node.pluginId)
|
||||
});
|
||||
} else {
|
||||
onResetNode({
|
||||
id: nodeId,
|
||||
node: updateFlowNodeVersion(node, template)
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching plugin module:', error);
|
||||
}
|
||||
setLoading(false);
|
||||
}, [node, nodeId, onResetNode, setLoading, template]);
|
||||
|
||||
/* Node header */
|
||||
const Header = useMemo(() => {
|
||||
@@ -149,13 +192,7 @@ const NodeCard = (props: Props) => {
|
||||
fontWeight={'medium'}
|
||||
cursor={'pointer'}
|
||||
_hover={{ bg: 'yellow.100' }}
|
||||
onClick={() => {
|
||||
if (!node || !template) return;
|
||||
onResetNode({
|
||||
id: nodeId,
|
||||
node: updateFlowNodeVersion(node, template)
|
||||
});
|
||||
}}
|
||||
onClick={onOpenConfirmSync(onClickSyncVersion)}
|
||||
>
|
||||
<Box>{appT('app.modules.has new version')}</Box>
|
||||
<QuestionOutlineIcon ml={1} />
|
||||
@@ -171,6 +208,7 @@ const NodeCard = (props: Props) => {
|
||||
/>
|
||||
<NodeIntro nodeId={nodeId} intro={intro} />
|
||||
</Box>
|
||||
<ConfirmSyncModal />
|
||||
</Box>
|
||||
);
|
||||
}, [
|
||||
@@ -181,16 +219,16 @@ const NodeCard = (props: Props) => {
|
||||
name,
|
||||
menuForbid,
|
||||
hasNewVersion,
|
||||
appT,
|
||||
onOpenConfirmSync,
|
||||
onClickSyncVersion,
|
||||
pluginId,
|
||||
flowNodeType,
|
||||
intro,
|
||||
ConfirmSyncModal,
|
||||
onOpenCustomTitleModal,
|
||||
onChangeNode,
|
||||
toast,
|
||||
appT,
|
||||
node,
|
||||
template,
|
||||
onResetNode
|
||||
toast
|
||||
]);
|
||||
|
||||
return (
|
||||
@@ -249,21 +287,14 @@ const MenuRender = React.memo(function MenuRender({
|
||||
menuForbid?: Props['menuForbid'];
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { setLoading } = useSystemStore();
|
||||
const { openDebugNode, DebugInputModal } = useDebug();
|
||||
|
||||
const { openConfirm: onOpenConfirmSync, ConfirmModal: ConfirmSyncModal } = useConfirm({
|
||||
content: t('module.Confirm Sync Plugin')
|
||||
});
|
||||
|
||||
const { openConfirm: onOpenConfirmDeleteNode, ConfirmModal: ConfirmDeleteModal } = useConfirm({
|
||||
content: t('core.module.Confirm Delete Node'),
|
||||
type: 'delete'
|
||||
});
|
||||
|
||||
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
|
||||
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||
|
||||
const onCopyNode = useCallback(
|
||||
@@ -310,22 +341,6 @@ const MenuRender = React.memo(function MenuRender({
|
||||
},
|
||||
[setEdges, setNodes]
|
||||
);
|
||||
const onClickSyncVersion = useCallback(async () => {
|
||||
if (!pluginId) return;
|
||||
try {
|
||||
setLoading(true);
|
||||
onResetNode({
|
||||
id: nodeId,
|
||||
node: await getPreviewPluginModule(pluginId)
|
||||
});
|
||||
} catch (e) {
|
||||
return toast({
|
||||
status: 'error',
|
||||
title: getErrText(e, t('plugin.Get Plugin Module Detail Failed'))
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
}, [nodeId, onResetNode, pluginId, setLoading, t, toast]);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
const menuList = [
|
||||
@@ -349,17 +364,6 @@ const MenuRender = React.memo(function MenuRender({
|
||||
onClick: () => onCopyNode(nodeId)
|
||||
}
|
||||
]),
|
||||
...(flowNodeType === FlowNodeTypeEnum.pluginModule
|
||||
? [
|
||||
{
|
||||
icon: 'common/refreshLight',
|
||||
label: t('plugin.Synchronous version'),
|
||||
variant: 'whiteBase',
|
||||
onClick: onOpenConfirmSync(onClickSyncVersion)
|
||||
}
|
||||
]
|
||||
: []),
|
||||
|
||||
...(menuForbid?.delete
|
||||
? []
|
||||
: [
|
||||
@@ -401,7 +405,6 @@ const MenuRender = React.memo(function MenuRender({
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
<ConfirmSyncModal />
|
||||
<ConfirmDeleteModal />
|
||||
<DebugInputModal />
|
||||
</>
|
||||
@@ -411,11 +414,7 @@ const MenuRender = React.memo(function MenuRender({
|
||||
menuForbid?.copy,
|
||||
menuForbid?.delete,
|
||||
t,
|
||||
flowNodeType,
|
||||
onOpenConfirmSync,
|
||||
onClickSyncVersion,
|
||||
onOpenConfirmDeleteNode,
|
||||
ConfirmSyncModal,
|
||||
ConfirmDeleteModal,
|
||||
DebugInputModal,
|
||||
openDebugNode,
|
||||
|
@@ -22,7 +22,8 @@ export const flowNode2StoreNodes = ({
|
||||
version: item.data.version,
|
||||
inputs: item.data.inputs,
|
||||
outputs: item.data.outputs,
|
||||
pluginId: item.data.pluginId
|
||||
pluginId: item.data.pluginId,
|
||||
nodeVersion: item.data.nodeVersion
|
||||
}));
|
||||
|
||||
// get all handle
|
||||
|
@@ -7,6 +7,8 @@ import { MongoPlugin } from '@fastgpt/service/core/plugin/schema';
|
||||
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
|
||||
import { ClientSession } from '@fastgpt/service/common/mongo';
|
||||
import { httpApiSchema2Plugins } from '@fastgpt/global/core/plugin/httpPlugin/utils';
|
||||
import { isEqual } from 'lodash';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||
try {
|
||||
@@ -22,7 +24,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
per: 'owner'
|
||||
});
|
||||
|
||||
const updateData = {
|
||||
const originPlugin = await MongoPlugin.findById(id);
|
||||
|
||||
let updateData = {
|
||||
name: props.name,
|
||||
intro: props.intro,
|
||||
avatar: props.avatar,
|
||||
@@ -32,9 +36,26 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
||||
modules: modules
|
||||
}),
|
||||
...(edges?.length && { edges }),
|
||||
metadata: props.metadata
|
||||
metadata: props.metadata,
|
||||
nodeVersion: originPlugin?.nodeVersion
|
||||
};
|
||||
|
||||
const isNodeVersionEqual =
|
||||
isEqual(
|
||||
originPlugin?.modules.map((module) => {
|
||||
return { ...module, position: undefined };
|
||||
}),
|
||||
updateData.modules?.map((module) => {
|
||||
return { ...module, position: undefined };
|
||||
})
|
||||
) && isEqual(originPlugin?.edges, updateData.edges);
|
||||
|
||||
if (!isNodeVersionEqual) {
|
||||
updateData = {
|
||||
...updateData,
|
||||
nodeVersion: nanoid(6)
|
||||
};
|
||||
}
|
||||
if (props.metadata?.apiSchemaStr) {
|
||||
await mongoSessionRun(async (session) => {
|
||||
// update children
|
||||
|
Reference in New Issue
Block a user