Skip to content

Commit

Permalink
add plugin unexist error tips (labring#3717)
Browse files Browse the repository at this point in the history
* add plugin unexist error tips

* throw error when run plugin

* check workflow

* plugin data avoid request twice

* auth owner tmbId

* fix
  • Loading branch information
newfish-cmyk authored and OnesZhang committed Feb 14, 2025
1 parent 2344769 commit 202b0f2
Show file tree
Hide file tree
Showing 24 changed files with 284 additions and 91 deletions.
20 changes: 19 additions & 1 deletion 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,7 +119,8 @@ export const appWorkflow2Form = ({
version: node.version,
inputs: node.inputs,
outputs: node.outputs,
templateType: FlowNodeTemplateTypeEnum.other
templateType: FlowNodeTemplateTypeEnum.other,
pluginData: node.pluginData
});
} else if (node.flowNodeType === FlowNodeTypeEnum.systemConfig) {
defaultAppForm.chatConfig = getAppChatConfig({
Expand Down Expand Up @@ -147,3 +150,18 @@ export const getAppType = (config?: WorkflowTemplateBasicType | AppSimpleEditFor
}
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 changes: 11 additions & 0 deletions packages/global/core/workflow/type/node.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ export type FlowNodeCommonType = {
pluginId?: string;
isFolder?: boolean;
// pluginType?: AppTypeEnum;
pluginData?: PluginDataType;
};

export type PluginDataType = {
version: string;
diagram?: string;
userGuide?: string;
courseUrl?: string;
name?: string;
avatar?: string;
error?: string;
};

type HandleType = {
Expand Down
11 changes: 5 additions & 6 deletions packages/web/components/common/Icon/icons/common/errorFill.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 @@ -196,7 +196,7 @@ const Header = () => {
<SaveButton
isLoading={loading}
onClickSave={onClickSave}
checkData={flowData2StoreDataAndCheck}
checkData={() => !!flowData2StoreDataAndCheck()}
/>
)}
</HStack>
Expand Down
28 changes: 27 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,12 @@ 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';
import {
checkWorkflowNodeAndConnection,
storeEdgesRenderEdge,
storeNode2FlowNode
} from '@/web/core/workflow/utils';

const Header = ({
forbiddenSaveSnapshot,
Expand All @@ -48,6 +54,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 +238,26 @@ const Header = ({
variant={'whitePrimary'}
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>
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 @@ -60,60 +61,83 @@ const ToolSelect = ({
gridTemplateColumns={'repeat(2, minmax(0, 1fr))'}
gridGap={[2, 4]}
>
{appForm.selectedTools.map((item) => (
<MyTooltip key={item.id} label={item.intro}>
<Flex
overflow={'hidden'}
alignItems={'center'}
p={2.5}
bg={'white'}
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
borderRadius={'md'}
border={theme.borders.base}
_hover={{
...hoverDeleteStyles,
borderColor: 'primary.300'
}}
cursor={'pointer'}
onClick={() => {
if (
item.inputs
.filter((input) => !childAppSystemKey.includes(input.key))
.every(
(input) =>
input.toolDescription ||
input.renderTypeList.includes(FlowNodeInputTypeEnum.selectLLMModel) ||
input.renderTypeList.includes(FlowNodeInputTypeEnum.fileSelect)
)
) {
return;
}
setConfigTool(item);
}}
>
<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>
<DeleteIcon
onClick={(e) => {
e.stopPropagation();
setAppForm((state: AppSimpleEditFormType) => ({
...state,
selectedTools: state.selectedTools.filter((tool) => tool.id !== item.id)
}));
{appForm.selectedTools.map((item) => {
const hasError = checkAppUnExistError(item.pluginData?.error);

return (
<MyTooltip key={item.id} label={item.intro}>
<Flex
overflow={'hidden'}
alignItems={'center'}
p={2.5}
bg={'white'}
boxShadow={'0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06)'}
borderRadius={'md'}
border={theme.borders.base}
borderColor={hasError ? 'red.600' : ''}
_hover={{
...hoverDeleteStyles,
borderColor: hasError ? 'red.600' : 'primary.300'
}}
/>
</Flex>
</MyTooltip>
))}
cursor={'pointer'}
onClick={() => {
if (
item.inputs
.filter((input) => !childAppSystemKey.includes(input.key))
.every(
(input) =>
input.toolDescription ||
input.renderTypeList.includes(FlowNodeInputTypeEnum.selectLLMModel) ||
input.renderTypeList.includes(FlowNodeInputTypeEnum.fileSelect)
) ||
hasError
) {
return;
}
setConfigTool(item);
}}
>
<Avatar src={item.avatar} w={'1.5rem'} h={'1.5rem'} borderRadius={'sm'} />
<Box
flex={'1 0 0'}
ml={2}
gap={2}
className={'textEllipsis'}
fontSize={'sm'}
color={'myGray.900'}
>
{item.name}
</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
ml={2}
onClick={(e) => {
e.stopPropagation();
setAppForm((state: AppSimpleEditFormType) => ({
...state,
selectedTools: state.selectedTools.filter((tool) => tool.id !== item.id)
}));
}}
/>
</Flex>
</MyTooltip>
);
})}
</Grid>

{isOpenToolsSelect && (
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 @@ -6,8 +6,6 @@ import { useTranslation } from 'next-i18next';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { useToast } from '@fastgpt/web/hooks/useToast';
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 = ({
isLoading,
Expand All @@ -16,12 +14,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
Loading

0 comments on commit 202b0f2

Please sign in to comment.