add plugin unexist error tips (#3717)
* add plugin unexist error tips * throw error when run plugin * check workflow * plugin data avoid request twice * auth owner tmbId * fix
This commit is contained in:
parent
4284b78707
commit
896a3f1472
@ -7,6 +7,8 @@ import { StoreNodeItemType } from '../workflow/type/node';
|
|||||||
import { DatasetSearchModeEnum } from '../dataset/constants';
|
import { DatasetSearchModeEnum } from '../dataset/constants';
|
||||||
import { WorkflowTemplateBasicType } from '../workflow/type';
|
import { WorkflowTemplateBasicType } from '../workflow/type';
|
||||||
import { AppTypeEnum } from './constants';
|
import { AppTypeEnum } from './constants';
|
||||||
|
import { AppErrEnum } from '../../common/error/code/app';
|
||||||
|
import { PluginErrEnum } from '../../common/error/code/plugin';
|
||||||
|
|
||||||
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
export const getDefaultAppForm = (): AppSimpleEditFormType => {
|
||||||
return {
|
return {
|
||||||
@ -117,7 +119,8 @@ export const appWorkflow2Form = ({
|
|||||||
version: node.version,
|
version: node.version,
|
||||||
inputs: node.inputs,
|
inputs: node.inputs,
|
||||||
outputs: node.outputs,
|
outputs: node.outputs,
|
||||||
templateType: FlowNodeTemplateTypeEnum.other
|
templateType: FlowNodeTemplateTypeEnum.other,
|
||||||
|
pluginData: node.pluginData
|
||||||
});
|
});
|
||||||
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
|
||||||
defaultAppForm.chatConfig = getAppChatConfig({
|
defaultAppForm.chatConfig = getAppChatConfig({
|
||||||
@ -147,3 +150,18 @@ export const getAppType = (config?: WorkflowTemplateBasicType | AppSimpleEditFor
|
|||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const checkAppUnExistError = (error?: string) => {
|
||||||
|
const unExistError: Array<string> = [
|
||||||
|
AppErrEnum.unAuthApp,
|
||||||
|
AppErrEnum.unExist,
|
||||||
|
PluginErrEnum.unAuth,
|
||||||
|
PluginErrEnum.unExist
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!!error && unExistError.includes(error)) {
|
||||||
|
return error;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
11
packages/global/core/workflow/type/node.d.ts
vendored
11
packages/global/core/workflow/type/node.d.ts
vendored
@ -43,6 +43,17 @@ export type FlowNodeCommonType = {
|
|||||||
pluginId?: string;
|
pluginId?: string;
|
||||||
isFolder?: boolean;
|
isFolder?: boolean;
|
||||||
// pluginType?: AppTypeEnum;
|
// pluginType?: AppTypeEnum;
|
||||||
|
pluginData?: PluginDataType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PluginDataType = {
|
||||||
|
version: string;
|
||||||
|
diagram?: string;
|
||||||
|
userGuide?: string;
|
||||||
|
courseUrl?: string;
|
||||||
|
name?: string;
|
||||||
|
avatar?: string;
|
||||||
|
error?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type HandleType = {
|
type HandleType = {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<svg t="1705054369902" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3174"
|
<svg viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="128" height="128">
|
<rect x="0.187134" width="16" height="16" rx="8" fill="#F04438"/>
|
||||||
<path
|
<path d="M8.18717 4.78638C7.81898 4.78638 7.52051 5.08485 7.52051 5.45304V8.44501C7.52051 8.8132 7.81898 9.11168 8.18717 9.11168C8.55536 9.11168 8.85384 8.8132 8.85384 8.44501V5.45304C8.85384 5.08485 8.55536 4.78638 8.18717 4.78638Z" fill="white"/>
|
||||||
d="M512 0C229.205333 0 0 229.205333 0 512s229.205333 512 512 512 512-229.205333 512-512S794.794667 0 512 0z m0 796.458667A56.917333 56.917333 0 1 1 511.957333 682.666667 56.917333 56.917333 0 0 1 512 796.458667z m54.186667-227.797334h0.128a60.501333 60.501333 0 0 1-53.802667 55.893334c2.048 0.256 3.882667 1.152 5.973333 1.152h-11.818666c2.048 0 3.84-0.981333 5.845333-1.109334a59.093333 59.093333 0 0 1-53.162667-55.893333l-13.056-284.16a54.314667 54.314667 0 0 1 54.613334-57.045333h26.282666a52.992 52.992 0 0 1 54.186667 57.002666l-15.146667 284.16z"
|
<path d="M8.18717 9.76652C7.81898 9.76652 7.52051 10.065 7.52051 10.4332C7.52051 10.8014 7.81898 11.0998 8.18717 11.0998C8.55536 11.0998 8.85384 10.8014 8.85384 10.4332C8.85384 10.065 8.55536 9.76652 8.18717 9.76652Z" fill="white"/>
|
||||||
fill="#D92D20" p-id="3175"></path>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 774 B After Width: | Height: | Size: 628 B |
@ -7,8 +7,12 @@
|
|||||||
"ai_settings": "AI Configuration",
|
"ai_settings": "AI Configuration",
|
||||||
"all_apps": "All Applications",
|
"all_apps": "All Applications",
|
||||||
"app.Version name": "Version Name",
|
"app.Version name": "Version Name",
|
||||||
|
"app.error.publish_unExist_app": "Release failed, please check whether the tool call is normal",
|
||||||
|
"app.error.unExist_app": "Some components are missing, please delete them",
|
||||||
"app.modules.click to update": "Click to Refresh",
|
"app.modules.click to update": "Click to Refresh",
|
||||||
"app.modules.has new version": "New Version Available",
|
"app.modules.has new version": "New Version Available",
|
||||||
|
"app.modules.not_found": "Not Found",
|
||||||
|
"app.modules.not_found_tips": "This component cannot be found in the system, please delete it, otherwise the process will not run normally",
|
||||||
"app.version_current": "Current Version",
|
"app.version_current": "Current Version",
|
||||||
"app.version_initial": "Initial Version",
|
"app.version_initial": "Initial Version",
|
||||||
"app.version_name_tips": "Version name cannot be empty",
|
"app.version_name_tips": "Version name cannot be empty",
|
||||||
|
|||||||
@ -448,6 +448,7 @@
|
|||||||
"core.chat.markdown.Edit Question": "Edit Question",
|
"core.chat.markdown.Edit Question": "Edit Question",
|
||||||
"core.chat.markdown.Quick Question": "Click to Ask Immediately",
|
"core.chat.markdown.Quick Question": "Click to Ask Immediately",
|
||||||
"core.chat.markdown.Send Question": "Send Question",
|
"core.chat.markdown.Send Question": "Send Question",
|
||||||
|
"core.chat.module_unexist": "Running failed: Application missing components",
|
||||||
"core.chat.quote.Quote Tip": "Only the actual quoted content is displayed here. If the data is updated, it will not be updated in real-time here.",
|
"core.chat.quote.Quote Tip": "Only the actual quoted content is displayed here. If the data is updated, it will not be updated in real-time here.",
|
||||||
"core.chat.quote.Read Quote": "View Quote",
|
"core.chat.quote.Read Quote": "View Quote",
|
||||||
"core.chat.response.Complete Response": "Complete Response",
|
"core.chat.response.Complete Response": "Complete Response",
|
||||||
@ -787,7 +788,7 @@
|
|||||||
"core.view_chat_detail": "View Chat Details",
|
"core.view_chat_detail": "View Chat Details",
|
||||||
"core.workflow.Can not delete node": "This Node Cannot Be Deleted",
|
"core.workflow.Can not delete node": "This Node Cannot Be Deleted",
|
||||||
"core.workflow.Change input type tip": "Changing the input type will clear the filled values, please confirm!",
|
"core.workflow.Change input type tip": "Changing the input type will clear the filled values, please confirm!",
|
||||||
"core.workflow.Check Failed": "Workflow Validation Failed, Please Check If the Nodes Are Correctly Filled and the Connections Are Normal",
|
"core.workflow.Check Failed": "Workflow verification failed, please check whether the value is missing, and whether the connection is normal.",
|
||||||
"core.workflow.Confirm stop debug": "Confirm to Stop Debugging? Debug Information Will Not Be Retained.",
|
"core.workflow.Confirm stop debug": "Confirm to Stop Debugging? Debug Information Will Not Be Retained.",
|
||||||
"core.workflow.Copy node": "Node Copied",
|
"core.workflow.Copy node": "Node Copied",
|
||||||
"core.workflow.Custom inputs": "Custom Inputs",
|
"core.workflow.Custom inputs": "Custom Inputs",
|
||||||
|
|||||||
@ -7,8 +7,12 @@
|
|||||||
"ai_settings": "AI 配置",
|
"ai_settings": "AI 配置",
|
||||||
"all_apps": "全部应用",
|
"all_apps": "全部应用",
|
||||||
"app.Version name": "版本名称",
|
"app.Version name": "版本名称",
|
||||||
|
"app.error.publish_unExist_app": "发布失败,请检查工具调用是否正常",
|
||||||
|
"app.error.unExist_app": "部分组件缺失,请删除",
|
||||||
"app.modules.click to update": "点击更新",
|
"app.modules.click to update": "点击更新",
|
||||||
"app.modules.has new version": "有新版本",
|
"app.modules.has new version": "有新版本",
|
||||||
|
"app.modules.not_found": "组件缺失",
|
||||||
|
"app.modules.not_found_tips": "系统内无法查找到该组件,请删除,否则流程无法正常运行",
|
||||||
"app.version_current": "当前版本",
|
"app.version_current": "当前版本",
|
||||||
"app.version_initial": "初始版本",
|
"app.version_initial": "初始版本",
|
||||||
"app.version_name_tips": "版本名称不能为空",
|
"app.version_name_tips": "版本名称不能为空",
|
||||||
|
|||||||
@ -451,6 +451,7 @@
|
|||||||
"core.chat.markdown.Edit Question": "编辑问题",
|
"core.chat.markdown.Edit Question": "编辑问题",
|
||||||
"core.chat.markdown.Quick Question": "点我立即提问",
|
"core.chat.markdown.Quick Question": "点我立即提问",
|
||||||
"core.chat.markdown.Send Question": "发送问题",
|
"core.chat.markdown.Send Question": "发送问题",
|
||||||
|
"core.chat.module_unexist": "运行失败:应用缺失组件",
|
||||||
"core.chat.quote.Quote Tip": "此处仅显示实际引用内容,若数据有更新,此处不会实时更新",
|
"core.chat.quote.Quote Tip": "此处仅显示实际引用内容,若数据有更新,此处不会实时更新",
|
||||||
"core.chat.quote.Read Quote": "查看引用",
|
"core.chat.quote.Read Quote": "查看引用",
|
||||||
"core.chat.response.Complete Response": "完整响应",
|
"core.chat.response.Complete Response": "完整响应",
|
||||||
@ -790,7 +791,7 @@
|
|||||||
"core.view_chat_detail": "查看对话详情",
|
"core.view_chat_detail": "查看对话详情",
|
||||||
"core.workflow.Can not delete node": "该节点不允许删除",
|
"core.workflow.Can not delete node": "该节点不允许删除",
|
||||||
"core.workflow.Change input type tip": "修改输入类型会清空已填写的值,请确认!",
|
"core.workflow.Change input type tip": "修改输入类型会清空已填写的值,请确认!",
|
||||||
"core.workflow.Check Failed": "工作流校验失败,请检查节点是否正确填值,以及连线是否正常",
|
"core.workflow.Check Failed": "工作流校验失败,请检查是否缺失、缺值,连线是否正常",
|
||||||
"core.workflow.Confirm stop debug": "确认终止调试?调试信息将会不保留。",
|
"core.workflow.Confirm stop debug": "确认终止调试?调试信息将会不保留。",
|
||||||
"core.workflow.Copy node": "已复制节点",
|
"core.workflow.Copy node": "已复制节点",
|
||||||
"core.workflow.Custom inputs": "自定义输入",
|
"core.workflow.Custom inputs": "自定义输入",
|
||||||
|
|||||||
@ -7,8 +7,12 @@
|
|||||||
"ai_settings": "AI 設定",
|
"ai_settings": "AI 設定",
|
||||||
"all_apps": "所有應用程式",
|
"all_apps": "所有應用程式",
|
||||||
"app.Version name": "版本名稱",
|
"app.Version name": "版本名稱",
|
||||||
|
"app.error.publish_unExist_app": "發布失敗,請檢查工具調用是否正常",
|
||||||
|
"app.error.unExist_app": "部分組件缺失,請刪除",
|
||||||
"app.modules.click to update": "點選更新",
|
"app.modules.click to update": "點選更新",
|
||||||
"app.modules.has new version": "有新版本",
|
"app.modules.has new version": "有新版本",
|
||||||
|
"app.modules.not_found": "組件缺失",
|
||||||
|
"app.modules.not_found_tips": "系統內無法查找到該組件,請刪除,否則流程無法正常運行",
|
||||||
"app.version_current": "目前版本",
|
"app.version_current": "目前版本",
|
||||||
"app.version_initial": "初始版本",
|
"app.version_initial": "初始版本",
|
||||||
"app.version_name_tips": "版本名稱不能空白",
|
"app.version_name_tips": "版本名稱不能空白",
|
||||||
|
|||||||
@ -447,6 +447,7 @@
|
|||||||
"core.chat.markdown.Edit Question": "編輯問題",
|
"core.chat.markdown.Edit Question": "編輯問題",
|
||||||
"core.chat.markdown.Quick Question": "點我立即發問",
|
"core.chat.markdown.Quick Question": "點我立即發問",
|
||||||
"core.chat.markdown.Send Question": "傳送問題",
|
"core.chat.markdown.Send Question": "傳送問題",
|
||||||
|
"core.chat.module_unexist": "運行失敗:應用缺失組件",
|
||||||
"core.chat.quote.Quote Tip": "此處僅顯示實際引用內容,若資料有更新,此處不會即時更新",
|
"core.chat.quote.Quote Tip": "此處僅顯示實際引用內容,若資料有更新,此處不會即時更新",
|
||||||
"core.chat.quote.Read Quote": "檢視引用",
|
"core.chat.quote.Read Quote": "檢視引用",
|
||||||
"core.chat.response.Complete Response": "完整回應",
|
"core.chat.response.Complete Response": "完整回應",
|
||||||
@ -786,7 +787,7 @@
|
|||||||
"core.view_chat_detail": "檢視對話詳細資料",
|
"core.view_chat_detail": "檢視對話詳細資料",
|
||||||
"core.workflow.Can not delete node": "此節點不允許刪除",
|
"core.workflow.Can not delete node": "此節點不允許刪除",
|
||||||
"core.workflow.Change input type tip": "修改輸入類型將清空已填寫的值,請確認!",
|
"core.workflow.Change input type tip": "修改輸入類型將清空已填寫的值,請確認!",
|
||||||
"core.workflow.Check Failed": "工作流程驗證失敗,請檢查節點是否正確填值,以及連線是否正常",
|
"core.workflow.Check Failed": "工作流校驗失敗,請檢查是否缺失、缺值,連線是否正常",
|
||||||
"core.workflow.Confirm stop debug": "確認停止除錯?除錯資訊將不會保留。",
|
"core.workflow.Confirm stop debug": "確認停止除錯?除錯資訊將不會保留。",
|
||||||
"core.workflow.Copy node": "已複製節點",
|
"core.workflow.Copy node": "已複製節點",
|
||||||
"core.workflow.Custom inputs": "自訂輸入",
|
"core.workflow.Custom inputs": "自訂輸入",
|
||||||
|
|||||||
@ -196,7 +196,7 @@ const Header = () => {
|
|||||||
<SaveButton
|
<SaveButton
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
onClickSave={onClickSave}
|
onClickSave={onClickSave}
|
||||||
checkData={flowData2StoreDataAndCheck}
|
checkData={() => !!flowData2StoreDataAndCheck()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@ -30,6 +30,12 @@ import PublishHistories from '../PublishHistoriesSlider';
|
|||||||
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||||
import { useBeforeunload } from '@fastgpt/web/hooks/useBeforeunload';
|
import { useBeforeunload } from '@fastgpt/web/hooks/useBeforeunload';
|
||||||
import { isProduction } from '@fastgpt/global/common/system/constants';
|
import { isProduction } from '@fastgpt/global/common/system/constants';
|
||||||
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
|
import {
|
||||||
|
checkWorkflowNodeAndConnection,
|
||||||
|
storeEdgesRenderEdge,
|
||||||
|
storeNode2FlowNode
|
||||||
|
} from '@/web/core/workflow/utils';
|
||||||
|
|
||||||
const Header = ({
|
const Header = ({
|
||||||
forbiddenSaveSnapshot,
|
forbiddenSaveSnapshot,
|
||||||
@ -48,6 +54,7 @@ const Header = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isPc } = useSystem();
|
const { isPc } = useSystem();
|
||||||
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const appId = useContextSelector(AppContext, (v) => v.appId);
|
const appId = useContextSelector(AppContext, (v) => v.appId);
|
||||||
const onSaveApp = useContextSelector(AppContext, (v) => v.onSaveApp);
|
const onSaveApp = useContextSelector(AppContext, (v) => v.onSaveApp);
|
||||||
@ -231,7 +238,26 @@ const Header = ({
|
|||||||
variant={'whitePrimary'}
|
variant={'whitePrimary'}
|
||||||
onClick={setIsShowHistories}
|
onClick={setIsShowHistories}
|
||||||
/>
|
/>
|
||||||
<SaveButton isLoading={loading} onClickSave={onClickSave} />
|
<SaveButton
|
||||||
|
isLoading={loading}
|
||||||
|
onClickSave={onClickSave}
|
||||||
|
checkData={() => {
|
||||||
|
const { nodes: storeNodes, edges: storeEdges } = form2AppWorkflow(appForm, t);
|
||||||
|
|
||||||
|
const nodes = storeNodes.map((item) => storeNode2FlowNode({ item, t }));
|
||||||
|
const edges = storeEdges.map((item) => storeEdgesRenderEdge({ edge: item }));
|
||||||
|
|
||||||
|
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
||||||
|
|
||||||
|
if (checkResults) {
|
||||||
|
toast({
|
||||||
|
title: t('app:app.error.publish_unExist_app'),
|
||||||
|
status: 'warning'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return !checkResults;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
|
|||||||
import ConfigToolModal from './ConfigToolModal';
|
import ConfigToolModal from './ConfigToolModal';
|
||||||
import { getWebLLMModel } from '@/web/common/system/utils';
|
import { getWebLLMModel } from '@/web/common/system/utils';
|
||||||
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
|
||||||
|
import { checkAppUnExistError } from '@fastgpt/global/core/app/utils';
|
||||||
|
|
||||||
const ToolSelect = ({
|
const ToolSelect = ({
|
||||||
appForm,
|
appForm,
|
||||||
@ -60,7 +61,10 @@ const ToolSelect = ({
|
|||||||
gridTemplateColumns={'repeat(2, minmax(0, 1fr))'}
|
gridTemplateColumns={'repeat(2, minmax(0, 1fr))'}
|
||||||
gridGap={[2, 4]}
|
gridGap={[2, 4]}
|
||||||
>
|
>
|
||||||
{appForm.selectedTools.map((item) => (
|
{appForm.selectedTools.map((item) => {
|
||||||
|
const hasError = checkAppUnExistError(item.pluginData?.error);
|
||||||
|
|
||||||
|
return (
|
||||||
<MyTooltip key={item.id} label={item.intro}>
|
<MyTooltip key={item.id} label={item.intro}>
|
||||||
<Flex
|
<Flex
|
||||||
overflow={'hidden'}
|
overflow={'hidden'}
|
||||||
@ -70,9 +74,10 @@ const ToolSelect = ({
|
|||||||
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
|
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
|
||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
border={theme.borders.base}
|
border={theme.borders.base}
|
||||||
|
borderColor={hasError ? 'red.600' : ''}
|
||||||
_hover={{
|
_hover={{
|
||||||
...hoverDeleteStyles,
|
...hoverDeleteStyles,
|
||||||
borderColor: 'primary.300'
|
borderColor: hasError ? 'red.600' : 'primary.300'
|
||||||
}}
|
}}
|
||||||
cursor={'pointer'}
|
cursor={'pointer'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -84,7 +89,8 @@ const ToolSelect = ({
|
|||||||
input.toolDescription ||
|
input.toolDescription ||
|
||||||
input.renderTypeList.includes(FlowNodeInputTypeEnum.selectLLMModel) ||
|
input.renderTypeList.includes(FlowNodeInputTypeEnum.selectLLMModel) ||
|
||||||
input.renderTypeList.includes(FlowNodeInputTypeEnum.fileSelect)
|
input.renderTypeList.includes(FlowNodeInputTypeEnum.fileSelect)
|
||||||
)
|
) ||
|
||||||
|
hasError
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -93,16 +99,33 @@ const ToolSelect = ({
|
|||||||
>
|
>
|
||||||
<Avatar src={item.avatar} w={'1.5rem'} h={'1.5rem'} borderRadius={'sm'} />
|
<Avatar src={item.avatar} w={'1.5rem'} h={'1.5rem'} borderRadius={'sm'} />
|
||||||
<Box
|
<Box
|
||||||
ml={2}
|
|
||||||
flex={'1 0 0'}
|
flex={'1 0 0'}
|
||||||
w={0}
|
ml={2}
|
||||||
|
gap={2}
|
||||||
className={'textEllipsis'}
|
className={'textEllipsis'}
|
||||||
fontSize={'sm'}
|
fontSize={'sm'}
|
||||||
color={'myGray.900'}
|
color={'myGray.900'}
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Box>
|
</Box>
|
||||||
|
{hasError && (
|
||||||
|
<MyTooltip label={t('app:app.modules.not_found_tips')}>
|
||||||
|
<Flex
|
||||||
|
bg={'red.50'}
|
||||||
|
alignItems={'center'}
|
||||||
|
h={6}
|
||||||
|
px={2}
|
||||||
|
rounded={'6px'}
|
||||||
|
fontSize={'xs'}
|
||||||
|
fontWeight={'medium'}
|
||||||
|
>
|
||||||
|
<MyIcon name={'common/errorFill'} w={'14px'} mr={1} />
|
||||||
|
<Box color={'red.600'}>{t('app:app.modules.not_found')}</Box>
|
||||||
|
</Flex>
|
||||||
|
</MyTooltip>
|
||||||
|
)}
|
||||||
<DeleteIcon
|
<DeleteIcon
|
||||||
|
ml={2}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setAppForm((state: AppSimpleEditFormType) => ({
|
setAppForm((state: AppSimpleEditFormType) => ({
|
||||||
@ -113,7 +136,8 @@ const ToolSelect = ({
|
|||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</MyTooltip>
|
</MyTooltip>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{isOpenToolsSelect && (
|
{isOpenToolsSelect && (
|
||||||
|
|||||||
@ -200,7 +200,7 @@ const Header = () => {
|
|||||||
<SaveButton
|
<SaveButton
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
onClickSave={onClickSave}
|
onClickSave={onClickSave}
|
||||||
checkData={flowData2StoreDataAndCheck}
|
checkData={() => !!flowData2StoreDataAndCheck()}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import { useTranslation } from 'next-i18next';
|
|||||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
import SaveAndPublishModal from '../../WorkflowComponents/Flow/components/SaveAndPublish';
|
import SaveAndPublishModal from '../../WorkflowComponents/Flow/components/SaveAndPublish';
|
||||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
|
||||||
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
|
||||||
|
|
||||||
const SaveButton = ({
|
const SaveButton = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -16,12 +14,7 @@ const SaveButton = ({
|
|||||||
}: {
|
}: {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
onClickSave: (options: { isPublish?: boolean; versionName?: string }) => Promise<void>;
|
onClickSave: (options: { isPublish?: boolean; versionName?: string }) => Promise<void>;
|
||||||
checkData?: (hideTip?: boolean) =>
|
checkData?: () => boolean | undefined;
|
||||||
| {
|
|
||||||
nodes: StoreNodeItemType[];
|
|
||||||
edges: StoreEdgeItemType[];
|
|
||||||
}
|
|
||||||
| undefined;
|
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isSave, setIsSave] = useState(false);
|
const [isSave, setIsSave] = useState(false);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import { Box, Button, Card, Flex, FlexProps } from '@chakra-ui/react';
|
import { Box, Button, Card, Flex, FlexProps } from '@chakra-ui/react';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
import Avatar from '@fastgpt/web/components/common/Avatar';
|
import Avatar from '@fastgpt/web/components/common/Avatar';
|
||||||
@ -99,14 +99,15 @@ const NodeCard = (props: Props) => {
|
|||||||
|
|
||||||
const { data: nodeTemplate } = useRequest2(
|
const { data: nodeTemplate } = useRequest2(
|
||||||
async () => {
|
async () => {
|
||||||
|
if (node?.pluginData?.error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
node?.flowNodeType === FlowNodeTypeEnum.pluginModule ||
|
node?.flowNodeType === FlowNodeTypeEnum.pluginModule ||
|
||||||
node?.flowNodeType === FlowNodeTypeEnum.appModule
|
node?.flowNodeType === FlowNodeTypeEnum.appModule
|
||||||
) {
|
) {
|
||||||
if (!node?.pluginId) return;
|
return { ...node, ...node.pluginData };
|
||||||
const template = await getPreviewPluginNode({ appId: node.pluginId });
|
|
||||||
|
|
||||||
return template;
|
|
||||||
} else {
|
} else {
|
||||||
const template = moduleTemplatesFlat.find(
|
const template = moduleTemplatesFlat.find(
|
||||||
(item) => item.flowNodeType === node?.flowNodeType
|
(item) => item.flowNodeType === node?.flowNodeType
|
||||||
@ -141,10 +142,13 @@ const NodeCard = (props: Props) => {
|
|||||||
|
|
||||||
const { runAsync: onClickSyncVersion } = useRequest2(
|
const { runAsync: onClickSyncVersion } = useRequest2(
|
||||||
async () => {
|
async () => {
|
||||||
if (!!nodeTemplate) {
|
if (!node?.pluginId) return;
|
||||||
|
const template = await getPreviewPluginNode({ appId: node.pluginId });
|
||||||
|
|
||||||
|
if (!!template) {
|
||||||
onResetNode({
|
onResetNode({
|
||||||
id: nodeId,
|
id: nodeId,
|
||||||
node: nodeTemplate
|
node: template
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onCloseConfirmSync();
|
onCloseConfirmSync();
|
||||||
@ -286,6 +290,22 @@ const NodeCard = (props: Props) => {
|
|||||||
)}
|
)}
|
||||||
</UseGuideModal>
|
</UseGuideModal>
|
||||||
)}
|
)}
|
||||||
|
{!!node?.pluginData?.error && (
|
||||||
|
<MyTooltip label={t('app:app.modules.not_found_tips')}>
|
||||||
|
<Flex
|
||||||
|
bg={'red.50'}
|
||||||
|
alignItems={'center'}
|
||||||
|
h={8}
|
||||||
|
px={2}
|
||||||
|
rounded={'6px'}
|
||||||
|
fontSize={'xs'}
|
||||||
|
fontWeight={'medium'}
|
||||||
|
>
|
||||||
|
<MyIcon name={'common/errorFill'} w={'14px'} mr={1} />
|
||||||
|
<Box color={'red.600'}>{t('app:app.modules.not_found')}</Box>
|
||||||
|
</Flex>
|
||||||
|
</MyTooltip>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<NodeIntro nodeId={nodeId} intro={intro} />
|
<NodeIntro nodeId={nodeId} intro={intro} />
|
||||||
</Box>
|
</Box>
|
||||||
@ -297,6 +317,7 @@ const NodeCard = (props: Props) => {
|
|||||||
}, [
|
}, [
|
||||||
node?.flowNodeType,
|
node?.flowNodeType,
|
||||||
node?.courseUrl,
|
node?.courseUrl,
|
||||||
|
node?.pluginData?.error,
|
||||||
showToolHandle,
|
showToolHandle,
|
||||||
nodeId,
|
nodeId,
|
||||||
isFolded,
|
isFolded,
|
||||||
|
|||||||
@ -1,4 +1,12 @@
|
|||||||
import { Dispatch, ReactNode, SetStateAction, useCallback, useMemo, useState } from 'react';
|
import {
|
||||||
|
Dispatch,
|
||||||
|
ReactNode,
|
||||||
|
SetStateAction,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
import { createContext } from 'use-context-selector';
|
import { createContext } from 'use-context-selector';
|
||||||
import { defaultApp } from '@/web/core/app/constants';
|
import { defaultApp } from '@/web/core/app/constants';
|
||||||
import { delAppById, getAppDetailById, putAppById } from '@/web/core/app/api';
|
import { delAppById, getAppDetailById, putAppById } from '@/web/core/app/api';
|
||||||
@ -14,6 +22,8 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
|||||||
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||||
import type { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
import type { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||||
|
import { checkAppUnExistError } from '@fastgpt/global/core/app/utils';
|
||||||
|
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||||
|
|
||||||
const InfoModal = dynamic(() => import('./InfoModal'));
|
const InfoModal = dynamic(() => import('./InfoModal'));
|
||||||
const TagsEditModal = dynamic(() => import('./TagsEditModal'));
|
const TagsEditModal = dynamic(() => import('./TagsEditModal'));
|
||||||
@ -84,6 +94,7 @@ export const AppContext = createContext<AppContextType>({
|
|||||||
|
|
||||||
const AppContextProvider = ({ children }: { children: ReactNode }) => {
|
const AppContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { appId, currentTab = TabEnum.appEdit } = router.query as {
|
const { appId, currentTab = TabEnum.appEdit } = router.query as {
|
||||||
appId: string;
|
appId: string;
|
||||||
@ -194,6 +205,16 @@ const AppContextProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
[appDetail.name, deleteApp, openConfirmDel, t]
|
[appDetail.name, deleteApp, openConfirmDel, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// check app unExist error
|
||||||
|
useEffect(() => {
|
||||||
|
if (appDetail.modules.some((module) => checkAppUnExistError(module.pluginData?.error))) {
|
||||||
|
toast({
|
||||||
|
title: t('app:app.error.unExist_app'),
|
||||||
|
status: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [appDetail.modules, t, toast]);
|
||||||
|
|
||||||
const contextValue: AppContextType = useMemo(
|
const contextValue: AppContextType = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
appId,
|
appId,
|
||||||
|
|||||||
@ -3,8 +3,9 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
|||||||
import { NextAPI } from '@/service/middleware/entry';
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||||
|
import { checkNode } from '@/service/core/app/utils';
|
||||||
|
|
||||||
/* 获取我的模型 */
|
/* 获取应用详情 */
|
||||||
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
const { appId } = req.query as { appId: string };
|
const { appId } = req.query as { appId: string };
|
||||||
|
|
||||||
@ -15,11 +16,19 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
|||||||
const { app } = await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
|
const { app } = await authApp({ req, authToken: true, appId, per: ReadPermissionVal });
|
||||||
|
|
||||||
if (!app.permission.hasWritePer) {
|
if (!app.permission.hasWritePer) {
|
||||||
app.modules = [];
|
return {
|
||||||
app.edges = [];
|
...app,
|
||||||
|
modules: [],
|
||||||
|
edges: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return app;
|
return {
|
||||||
|
...app,
|
||||||
|
modules: await Promise.all(
|
||||||
|
app.modules.map((node) => checkNode({ node, ownerTmbId: app.tmbId }))
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NextAPI(handler);
|
export default NextAPI(handler);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
|
|||||||
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
|
||||||
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
import { formatTime2YMDHM } from '@fastgpt/global/common/string/time';
|
||||||
|
import { checkNode } from '@/service/core/app/utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
versionId: string;
|
versionId: string;
|
||||||
@ -17,7 +18,7 @@ async function handler(
|
|||||||
): Promise<AppVersionSchemaType> {
|
): Promise<AppVersionSchemaType> {
|
||||||
const { versionId, appId } = req.query as Props;
|
const { versionId, appId } = req.query as Props;
|
||||||
|
|
||||||
await authApp({ req, authToken: true, appId, per: WritePermissionVal });
|
const { app } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
|
||||||
const result = await MongoAppVersion.findById(versionId).lean();
|
const result = await MongoAppVersion.findById(versionId).lean();
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@ -26,6 +27,9 @@ async function handler(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
|
nodes: await Promise.all(
|
||||||
|
result.nodes.map((n) => checkNode({ node: n, ownerTmbId: app.tmbId }))
|
||||||
|
),
|
||||||
versionName: result?.versionName || formatTime2YMDHM(result?.time)
|
versionName: result?.versionName || formatTime2YMDHM(result?.time)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,6 @@ async function handler(
|
|||||||
|
|
||||||
// get app and history
|
// get app and history
|
||||||
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
|
const { nodes, chatConfig } = await getAppLatestVersion(app._id, app);
|
||||||
|
|
||||||
const pluginInputs =
|
const pluginInputs =
|
||||||
chat?.pluginInputs ??
|
chat?.pluginInputs ??
|
||||||
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
|
nodes?.find((node) => node.flowNodeType === FlowNodeTypeEnum.pluginInput)?.inputs ??
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
|||||||
import { jsonRes } from '@fastgpt/service/common/response';
|
import { jsonRes } from '@fastgpt/service/common/response';
|
||||||
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
|
import type { InitChatResponse, InitOutLinkChatProps } from '@/global/core/chat/api.d';
|
||||||
import { getGuideModule, getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
import { getGuideModule, getAppChatConfig } from '@fastgpt/global/core/workflow/utils';
|
||||||
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
|
|
||||||
import { authOutLink } from '@/service/support/permission/auth/outLink';
|
import { authOutLink } from '@/service/support/permission/auth/outLink';
|
||||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||||
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
|
||||||
@ -11,7 +10,6 @@ import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
|
|||||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
||||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||||
import { NextAPI } from '@/service/middleware/entry';
|
import { NextAPI } from '@/service/middleware/entry';
|
||||||
import { UserModelSchema } from '@fastgpt/global/support/user/type';
|
|
||||||
import { getRandomUserAvatar } from '@fastgpt/global/support/user/utils';
|
import { getRandomUserAvatar } from '@fastgpt/global/support/user/utils';
|
||||||
|
|
||||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
|||||||
@ -36,7 +36,6 @@ import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools';
|
|||||||
import { getUserChatInfoAndAuthTeamPoints } from '@fastgpt/service/support/permission/auth/team';
|
import { getUserChatInfoAndAuthTeamPoints } from '@fastgpt/service/support/permission/auth/team';
|
||||||
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
|
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||||
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
import { MongoApp } from '@fastgpt/service/core/app/schema';
|
||||||
import { UserModelSchema } from '@fastgpt/global/support/user/type';
|
|
||||||
import { AppSchema } from '@fastgpt/global/core/app/type';
|
import { AppSchema } from '@fastgpt/global/core/app/type';
|
||||||
import { AuthOutLinkChatProps } from '@fastgpt/global/support/outLink/api';
|
import { AuthOutLinkChatProps } from '@fastgpt/global/support/outLink/api';
|
||||||
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
|
||||||
|
|||||||
@ -22,6 +22,14 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
|
|||||||
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { saveChat } from '@fastgpt/service/core/chat/saveChat';
|
import { saveChat } from '@fastgpt/service/core/chat/saveChat';
|
||||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controller';
|
||||||
|
import {
|
||||||
|
getChildAppPreviewNode,
|
||||||
|
splitCombinePluginId
|
||||||
|
} from '@fastgpt/service/core/app/plugin/controller';
|
||||||
|
import { PluginSourceEnum } from '@fastgpt/global/core/plugin/constants';
|
||||||
|
import { authAppByTmbId } from '@fastgpt/service/support/permission/app/auth';
|
||||||
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
|
import { PluginDataType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
|
||||||
|
|
||||||
export const getScheduleTriggerApp = async () => {
|
export const getScheduleTriggerApp = async () => {
|
||||||
// 1. Find all the app
|
// 1. Find all the app
|
||||||
@ -125,3 +133,46 @@ export const getScheduleTriggerApp = async () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const checkNode = async ({
|
||||||
|
node,
|
||||||
|
ownerTmbId
|
||||||
|
}: {
|
||||||
|
node: StoreNodeItemType;
|
||||||
|
ownerTmbId: string;
|
||||||
|
}) => {
|
||||||
|
const { pluginId } = node;
|
||||||
|
if (!pluginId) return node;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { source } = await splitCombinePluginId(pluginId);
|
||||||
|
if (source === PluginSourceEnum.personal) {
|
||||||
|
await authAppByTmbId({
|
||||||
|
tmbId: ownerTmbId,
|
||||||
|
appId: pluginId,
|
||||||
|
per: ReadPermissionVal
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const preview = await getChildAppPreviewNode({ id: pluginId });
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
pluginData: {
|
||||||
|
version: preview.version,
|
||||||
|
diagram: preview.diagram,
|
||||||
|
userGuide: preview.userGuide,
|
||||||
|
courseUrl: preview.courseUrl,
|
||||||
|
name: preview.name,
|
||||||
|
avatar: preview.avatar
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
isError: true,
|
||||||
|
pluginData: {
|
||||||
|
error
|
||||||
|
} as PluginDataType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -388,6 +388,7 @@ export function form2AppWorkflow(
|
|||||||
},
|
},
|
||||||
// 这里不需要固定版本,给一个不存在的版本,每次都会用最新版
|
// 这里不需要固定版本,给一个不存在的版本,每次都会用最新版
|
||||||
version: defaultNodeVersion,
|
version: defaultNodeVersion,
|
||||||
|
pluginData: tool.pluginData,
|
||||||
inputs: tool.inputs.map((input) => {
|
inputs: tool.inputs.map((input) => {
|
||||||
// Special key value
|
// Special key value
|
||||||
if (input.key === NodeInputKeyEnum.forbidStream) {
|
if (input.key === NodeInputKeyEnum.forbidStream) {
|
||||||
|
|||||||
@ -349,6 +349,10 @@ export const checkWorkflowNodeAndConnection = ({
|
|||||||
edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === node.data.nodeId
|
edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === node.data.nodeId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (data.pluginData?.error) {
|
||||||
|
return [data.nodeId];
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
data.flowNodeType === FlowNodeTypeEnum.systemConfig ||
|
data.flowNodeType === FlowNodeTypeEnum.systemConfig ||
|
||||||
data.flowNodeType === FlowNodeTypeEnum.pluginConfig ||
|
data.flowNodeType === FlowNodeTypeEnum.pluginConfig ||
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user