perf:change plugin version update position (#1493)

* perf:change plugin version update position

* use nodeversion
This commit is contained in:
heheer
2024-05-15 17:06:49 +08:00
committed by GitHub
parent 8386f707cd
commit d5073f98ab
10 changed files with 98 additions and 66 deletions

View File

@@ -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 = {

View File

@@ -64,6 +64,7 @@ export type FlowNodeTemplateType = FlowNodeCommonType & {
// action
forbidDelete?: boolean; // forbid delete
unique?: boolean;
nodeVersion?: string;
};
export type FlowNodeItemType = FlowNodeTemplateType & {
nodeId: string;

View File

@@ -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),

View File

@@ -64,6 +64,10 @@ const PluginSchema = new Schema({
version: {
type: String,
enum: ['v1', 'v2']
},
nodeVersion: {
type: String,
default: ''
}
});

View File

@@ -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);

View File

@@ -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~",

View File

@@ -38,6 +38,7 @@
},
"module": {
"Combine Modules": "组合模块",
"Confirm Sync": "将会使用最新模板进行覆盖,可能会丢失一些旧的配置信息,请确认",
"Custom Title Tip": "该标题名字会展示在对话过程中",
"My Modules": "",
"No Modules": "还没有模块~",

View File

@@ -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 template = moduleTemplatesFlat.find((item) => item.flowNodeType === node?.flowNodeType);
const hasNewVersion = useMemo(() => {
return (
template?.flowNodeType !== FlowNodeTypeEnum.pluginModule &&
node?.version !== template?.version
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
);
}, [node?.version, template?.flowNodeType, template?.version]);
setHasNewVersion(node?.version !== template?.version);
}
};
fetchPluginModule();
}, [node]);
const template = moduleTemplatesFlat.find((item) => item.flowNodeType === node?.flowNodeType);
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,

View File

@@ -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

View File

@@ -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