Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add plugin unexist error tips #3717

Merged
merged 6 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/global/core/app/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { StoreNodeItemType } from '../workflow/type/node';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { WorkflowTemplateBasicType } from '../workflow/type';
import { AppTypeEnum } from './constants';
import { AppErrEnum } from '../../common/error/code/app';
import { PluginErrEnum } from '../../common/error/code/plugin';

export const getDefaultAppForm = (): AppSimpleEditFormType => {
return {
Expand Down Expand Up @@ -117,6 +119,7 @@ export const appWorkflow2Form = ({
version: node.version,
inputs: node.inputs,
outputs: node.outputs,
error: node.error,
templateType: FlowNodeTemplateTypeEnum.other
});
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
Expand Down Expand Up @@ -147,3 +150,17 @@ export const getAppType = (config?: WorkflowTemplateBasicType | AppSimpleEditFor
}
return '';
};

export const checkAppUnExistError = (error?: string) => {
return (
!!error &&
(
[
AppErrEnum.unAuthApp,
AppErrEnum.unExist,
PluginErrEnum.unAuth,
PluginErrEnum.unExist
] as Array<string>
).includes(error)
);
};
1 change: 1 addition & 0 deletions packages/global/core/workflow/type/node.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type FlowNodeCommonType = {
parentNodeId?: string;
flowNodeType: FlowNodeTypeEnum; // render node card
abandon?: boolean; // abandon node
error?: string; // error message

avatar?: string;
name: string;
Expand Down
4 changes: 4 additions & 0 deletions packages/web/i18n/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
"ai_settings": "AI Configuration",
"all_apps": "All Applications",
"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.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_initial": "Initial Version",
"app.version_name_tips": "Version name cannot be empty",
Expand Down
3 changes: 2 additions & 1 deletion packages/web/i18n/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@
"core.chat.markdown.Edit Question": "Edit Question",
"core.chat.markdown.Quick Question": "Click to Ask Immediately",
"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.Read Quote": "View Quote",
"core.chat.response.Complete Response": "Complete Response",
Expand Down Expand Up @@ -787,7 +788,7 @@
"core.view_chat_detail": "View Chat Details",
"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.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.Copy node": "Node Copied",
"core.workflow.Custom inputs": "Custom Inputs",
Expand Down
4 changes: 4 additions & 0 deletions packages/web/i18n/zh-CN/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
"ai_settings": "AI 配置",
"all_apps": "全部应用",
"app.Version name": "版本名称",
"app.error.publish_unExist_app": "发布失败,请检查工具调用是否正常",
"app.error.unExist_app": "部分组件缺失,请删除",
"app.modules.click to update": "点击更新",
"app.modules.has new version": "有新版本",
"app.modules.not_found": "组件缺失",
"app.modules.not_found_tips": "系统内无法查找到该组件,请删除,否则流程无法正常运行",
"app.version_current": "当前版本",
"app.version_initial": "初始版本",
"app.version_name_tips": "版本名称不能为空",
Expand Down
3 changes: 2 additions & 1 deletion packages/web/i18n/zh-CN/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@
"core.chat.markdown.Edit Question": "编辑问题",
"core.chat.markdown.Quick Question": "点我立即提问",
"core.chat.markdown.Send Question": "发送问题",
"core.chat.module_unexist": "运行失败:应用缺失组件",
"core.chat.quote.Quote Tip": "此处仅显示实际引用内容,若数据有更新,此处不会实时更新",
"core.chat.quote.Read Quote": "查看引用",
"core.chat.response.Complete Response": "完整响应",
Expand Down Expand Up @@ -790,7 +791,7 @@
"core.view_chat_detail": "查看对话详情",
"core.workflow.Can not delete node": "该节点不允许删除",
"core.workflow.Change input type tip": "修改输入类型会清空已填写的值,请确认!",
"core.workflow.Check Failed": "工作流校验失败,请检查节点是否正确填值,以及连线是否正常",
"core.workflow.Check Failed": "工作流校验失败,请检查是否缺失、缺值,连线是否正常",
"core.workflow.Confirm stop debug": "确认终止调试?调试信息将会不保留。",
"core.workflow.Copy node": "已复制节点",
"core.workflow.Custom inputs": "自定义输入",
Expand Down
4 changes: 4 additions & 0 deletions packages/web/i18n/zh-Hant/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
"ai_settings": "AI 設定",
"all_apps": "所有應用程式",
"app.Version name": "版本名稱",
"app.error.publish_unExist_app": "發布失敗,請檢查工具調用是否正常",
"app.error.unExist_app": "部分組件缺失,請刪除",
"app.modules.click to update": "點選更新",
"app.modules.has new version": "有新版本",
"app.modules.not_found": "組件缺失",
"app.modules.not_found_tips": "系統內無法查找到該組件,請刪除,否則流程無法正常運行",
"app.version_current": "目前版本",
"app.version_initial": "初始版本",
"app.version_name_tips": "版本名稱不能空白",
Expand Down
3 changes: 2 additions & 1 deletion packages/web/i18n/zh-Hant/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@
"core.chat.markdown.Edit Question": "編輯問題",
"core.chat.markdown.Quick Question": "點我立即發問",
"core.chat.markdown.Send Question": "傳送問題",
"core.chat.module_unexist": "運行失敗:應用缺失組件",
"core.chat.quote.Quote Tip": "此處僅顯示實際引用內容,若資料有更新,此處不會即時更新",
"core.chat.quote.Read Quote": "檢視引用",
"core.chat.response.Complete Response": "完整回應",
Expand Down Expand Up @@ -786,7 +787,7 @@
"core.view_chat_detail": "檢視對話詳細資料",
"core.workflow.Can not delete node": "此節點不允許刪除",
"core.workflow.Change input type tip": "修改輸入類型將清空已填寫的值,請確認!",
"core.workflow.Check Failed": "工作流程驗證失敗,請檢查節點是否正確填值,以及連線是否正常",
"core.workflow.Check Failed": "工作流校驗失敗,請檢查是否缺失、缺值,連線是否正常",
"core.workflow.Confirm stop debug": "確認停止除錯?除錯資訊將不會保留。",
"core.workflow.Copy node": "已複製節點",
"core.workflow.Custom inputs": "自訂輸入",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type useChatStoreType = ChatProviderProps & {
chatInputGuide: ChatInputGuideConfigType;
getHistoryResponseData: ({ dataId }: { dataId: string }) => Promise<ChatHistoryItemResType[]>;
fileSelectConfig: AppFileSelectConfigType;
hasError?: boolean;

appId: string;
chatId: string;
Expand All @@ -86,6 +87,7 @@ export const ChatBoxContext = createContext<useChatStoreType>({
autoSend: false,
autoTTSResponse: false
},
hasError: false,
autoTTSResponse: false,
startSegmentedAudio: function (): Promise<any> {
throw new Error('Function not implemented.');
Expand Down Expand Up @@ -169,6 +171,7 @@ const Provider = ({
ChatItemContext,
(v) => v.chatBoxData?.app?.chatConfig?.fileSelectConfig ?? defaultAppSelectFileConfig
);
const hasError = useContextSelector(ChatItemContext, (v) => v.chatBoxData?.app?.hasError);

const chatRecords = useContextSelector(ChatRecordContext, (v) => v.chatRecords);
const setChatRecords = useContextSelector(ChatRecordContext, (v) => v.setChatRecords);
Expand Down Expand Up @@ -227,6 +230,7 @@ const Provider = ({
questionGuide,
ttsConfig,
fileSelectConfig,
hasError,
whisperConfig,
autoTTSResponse,
startSegmentedAudio,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const ChatBox = ({
const setAudioPlayingChatId = useContextSelector(ChatBoxContext, (v) => v.setAudioPlayingChatId);
const splitText2Audio = useContextSelector(ChatBoxContext, (v) => v.splitText2Audio);
const isChatting = useContextSelector(ChatBoxContext, (v) => v.isChatting);
const hasError = useContextSelector(ChatBoxContext, (v) => v.hasError);

// Workflow running, there are user input or selection
const isInteractive = useMemo(() => checkIsInteractiveByHistories(chatRecords), [chatRecords]);
Expand Down Expand Up @@ -857,7 +858,8 @@ const ChatBox = ({
chatBoxData?.app?.chatConfig?.autoExecute?.open &&
chatStarted &&
chatRecords.length === 0 &&
isChatRecordsLoaded
isChatRecordsLoaded &&
!hasError
) {
sendPrompt({
text: chatBoxData?.app?.chatConfig?.autoExecute?.defaultPrompt || 'AUTO_EXECUTE',
Expand Down
1 change: 1 addition & 0 deletions projects/app/src/global/core/chat/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export type InitChatResponse = {
canUse?: boolean;
type: `${AppTypeEnum}`;
pluginInputs: FlowNodeInputItemType[];
hasError?: boolean;
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ const Header = () => {
<SaveButton
isLoading={loading}
onClickSave={onClickSave}
checkData={flowData2StoreDataAndCheck}
checkData={() => !!flowData2StoreDataAndCheck()}
/>
)}
</HStack>
Expand Down
17 changes: 16 additions & 1 deletion projects/app/src/pageComponents/app/detail/SimpleApp/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import PublishHistories from '../PublishHistoriesSlider';
import { AppVersionSchemaType } from '@fastgpt/global/core/app/version';
import { useBeforeunload } from '@fastgpt/web/hooks/useBeforeunload';
import { isProduction } from '@fastgpt/global/common/system/constants';
import { useToast } from '@fastgpt/web/hooks/useToast';

const Header = ({
forbiddenSaveSnapshot,
Expand All @@ -48,6 +49,7 @@ const Header = ({
}) => {
const { t } = useTranslation();
const { isPc } = useSystem();
const { toast } = useToast();
const router = useRouter();
const appId = useContextSelector(AppContext, (v) => v.appId);
const onSaveApp = useContextSelector(AppContext, (v) => v.onSaveApp);
Expand Down Expand Up @@ -231,7 +233,20 @@ const Header = ({
variant={'whitePrimary'}
onClick={setIsShowHistories}
/>
<SaveButton isLoading={loading} onClickSave={onClickSave} />
<SaveButton
isLoading={loading}
onClickSave={onClickSave}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkData 直接在 onclickSave 里做是不是就可以了?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onclickSave在modal确认的时候才触发,checkData放在打开modal前判断

checkData={() => {
const hasErrors = appForm.selectedTools.some((tool) => tool.error);
if (hasErrors) {
toast({
title: t('app:app.error.publish_unExist_app'),
status: 'warning'
});
}
return !hasErrors;
}}
/>
</>
)}
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import ConfigToolModal from './ConfigToolModal';
import { getWebLLMModel } from '@/web/common/system/utils';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { checkAppUnExistError } from '@fastgpt/global/core/app/utils';

const ToolSelect = ({
appForm,
Expand Down Expand Up @@ -92,16 +93,27 @@ const ToolSelect = ({
}}
>
<Avatar src={item.avatar} w={'1.5rem'} h={'1.5rem'} borderRadius={'sm'} />
<Box
ml={2}
flex={'1 0 0'}
w={0}
className={'textEllipsis'}
fontSize={'sm'}
color={'myGray.900'}
>
{item.name}
</Box>
<Flex flex={'1 0 0'} ml={2} gap={2}>
<Box maxW={24} className={'textEllipsis'} fontSize={'sm'} color={'myGray.900'}>
{item.name}
</Box>
{checkAppUnExistError(item.error) && (
<MyTooltip label={t('app:app.modules.not_found_tips')}>
<Flex
bg={'red.100'}
color={'red.700'}
alignItems={'center'}
h={6}
px={2}
rounded={'6px'}
fontSize={'xs'}
fontWeight={'medium'}
>
<Box>{t('app:app.modules.not_found')}</Box>
</Flex>
</MyTooltip>
)}
</Flex>
<DeleteIcon
onClick={(e) => {
e.stopPropagation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ const Header = () => {
<SaveButton
isLoading={loading}
onClickSave={onClickSave}
checkData={flowData2StoreDataAndCheck}
checkData={() => !!flowData2StoreDataAndCheck()}
/>
)}
</HStack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ const SaveButton = ({
}: {
isLoading: boolean;
onClickSave: (options: { isPublish?: boolean; versionName?: string }) => Promise<void>;
checkData?: (hideTip?: boolean) =>
| {
nodes: StoreNodeItemType[];
edges: StoreEdgeItemType[];
}
| undefined;
checkData?: () => boolean | undefined;
}) => {
const { t } = useTranslation();
const [isSave, setIsSave] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ const NodeCard = (props: Props) => {

const { data: nodeTemplate } = useRequest2(
async () => {
if (!!node?.error) {
return undefined;
}
if (
node?.flowNodeType === FlowNodeTypeEnum.pluginModule ||
node?.flowNodeType === FlowNodeTypeEnum.appModule
Expand Down Expand Up @@ -286,6 +289,22 @@ const NodeCard = (props: Props) => {
)}
</UseGuideModal>
)}
{!!node?.error && (
<MyTooltip label={t('app:app.modules.not_found_tips')}>
<Flex
bg={'red.100'}
color={'red.700'}
alignItems={'center'}
h={8}
px={2}
rounded={'6px'}
fontSize={'xs'}
fontWeight={'medium'}
>
<Box>{t('app:app.modules.not_found')}</Box>
</Flex>
</MyTooltip>
)}
</Flex>
<NodeIntro nodeId={nodeId} intro={intro} />
</Box>
Expand All @@ -297,6 +316,7 @@ const NodeCard = (props: Props) => {
}, [
node?.flowNodeType,
node?.courseUrl,
node?.error,
showToolHandle,
nodeId,
isFolded,
Expand Down
23 changes: 22 additions & 1 deletion projects/app/src/pageComponents/app/detail/context.tsx
Original file line number Diff line number Diff line change
@@ -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 { defaultApp } from '@/web/core/app/constants';
import { delAppById, getAppDetailById, putAppById } from '@/web/core/app/api';
Expand All @@ -14,6 +22,8 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import type { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
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 TagsEditModal = dynamic(() => import('./TagsEditModal'));
Expand Down Expand Up @@ -84,6 +94,7 @@ export const AppContext = createContext<AppContextType>({

const AppContextProvider = ({ children }: { children: ReactNode }) => {
const { t } = useTranslation();
const { toast } = useToast();
const router = useRouter();
const { appId, currentTab = TabEnum.appEdit } = router.query as {
appId: string;
Expand Down Expand Up @@ -194,6 +205,16 @@ const AppContextProvider = ({ children }: { children: ReactNode }) => {
[appDetail.name, deleteApp, openConfirmDel, t]
);

// check app unExist error
useEffect(() => {
if (appDetail.modules.some((module) => checkAppUnExistError(module.error))) {
toast({
title: t('app:app.error.unExist_app'),
status: 'error'
});
}
}, [appDetail.modules, t, toast]);

const contextValue: AppContextType = useMemo(
() => ({
appId,
Expand Down
Loading
Loading