diff --git a/pkg/plugin/handler.py b/pkg/plugin/handler.py index bc151321..5a8f9d9a 100644 --- a/pkg/plugin/handler.py +++ b/pkg/plugin/handler.py @@ -3,6 +3,7 @@ from __future__ import annotations import typing from typing import Any import base64 +import traceback import sqlalchemy @@ -48,33 +49,39 @@ class RuntimeConnectionHandler(handler.Handler): install_source = data['install_source'] install_info = data['install_info'] - result = await self.ap.persistence_mgr.execute_async( - sqlalchemy.select(persistence_plugin.PluginSetting) - .where(persistence_plugin.PluginSetting.plugin_author == plugin_author) - .where(persistence_plugin.PluginSetting.plugin_name == plugin_name) - ) - - if result.first() is not None: - # delete plugin setting - await self.ap.persistence_mgr.execute_async( - sqlalchemy.delete(persistence_plugin.PluginSetting) + try: + result = await self.ap.persistence_mgr.execute_async( + sqlalchemy.select(persistence_plugin.PluginSetting) .where(persistence_plugin.PluginSetting.plugin_author == plugin_author) .where(persistence_plugin.PluginSetting.plugin_name == plugin_name) ) - # create plugin setting - await self.ap.persistence_mgr.execute_async( - sqlalchemy.insert(persistence_plugin.PluginSetting).values( - plugin_author=plugin_author, - plugin_name=plugin_name, - install_source=install_source, - install_info=install_info, - ) - ) + if result.first() is not None: + # delete plugin setting + await self.ap.persistence_mgr.execute_async( + sqlalchemy.delete(persistence_plugin.PluginSetting) + .where(persistence_plugin.PluginSetting.plugin_author == plugin_author) + .where(persistence_plugin.PluginSetting.plugin_name == plugin_name) + ) - return handler.ActionResponse.success( - data={}, - ) + # create plugin setting + await self.ap.persistence_mgr.execute_async( + sqlalchemy.insert(persistence_plugin.PluginSetting).values( + plugin_author=plugin_author, + plugin_name=plugin_name, + install_source=install_source, + install_info=install_info, + ) + ) + + return handler.ActionResponse.success( + data={}, + ) + except Exception as e: + traceback.print_exc() + return handler.ActionResponse.error( + message=f'Failed to initialize plugin settings: {e}', + ) @self.action(RuntimeToLangBotAction.GET_PLUGIN_SETTINGS) async def get_plugin_settings(data: dict[str, Any]) -> handler.ActionResponse: diff --git a/web/src/app/home/plugins/page.tsx b/web/src/app/home/plugins/page.tsx index e706e6fe..8274d025 100644 --- a/web/src/app/home/plugins/page.tsx +++ b/web/src/app/home/plugins/page.tsx @@ -293,7 +293,12 @@ export default function PluginConfigPage() { )} {pluginInstallStatus === PluginInstallStatus.ASK_CONFIRM && (
-

{t('plugins.askConfirm')}

+

+ {t('plugins.askConfirm', { + name: installInfo.plugin_name, + version: installInfo.plugin_version, + })} +

)} {pluginInstallStatus === PluginInstallStatus.INSTALLING && ( diff --git a/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx b/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx index bcbc02d4..0aae5f39 100644 --- a/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx +++ b/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx @@ -5,7 +5,7 @@ import { Badge } from '@/components/ui/badge'; import { Switch } from '@/components/ui/switch'; import { toast } from 'sonner'; import { useTranslation } from 'react-i18next'; -import { ExternalLink } from 'lucide-react'; +import { BugIcon, ExternalLink } from 'lucide-react'; import { getCloudServiceClientSync } from '@/app/infra/http'; export default function PluginCardComponent({ @@ -65,48 +65,53 @@ export default function PluginCardComponent({ variant="outline" className="text-[0.7rem] border-orange-400 text-orange-400" > + {t('plugins.debugging')} )} - {cardVO.install_source === 'github' && ( - { - e.stopPropagation(); - window.open(cardVO.install_info.github_url, '_blank'); - }} - > - {t('plugins.fromGithub')} - - - )} - {cardVO.install_source === 'local' && ( - - {t('plugins.fromLocal')} - - )} - {cardVO.install_source === 'marketplace' && ( - { - e.stopPropagation(); - window.open( - getCloudServiceClientSync().getPluginMarketplaceURL( - cardVO.author, - cardVO.name, - ), - '_blank', - ); - }} - > - {t('plugins.fromMarketplace')} - - + {!cardVO.debug && ( + <> + {cardVO.install_source === 'github' && ( + { + e.stopPropagation(); + window.open(cardVO.install_info.github_url, '_blank'); + }} + > + {t('plugins.fromGithub')} + + + )} + {cardVO.install_source === 'local' && ( + + {t('plugins.fromLocal')} + + )} + {cardVO.install_source === 'marketplace' && ( + { + e.stopPropagation(); + window.open( + getCloudServiceClientSync().getPluginMarketplaceURL( + cardVO.author, + cardVO.name, + ), + '_blank', + ); + }} + > + {t('plugins.fromMarketplace')} + + + )} + )} diff --git a/web/src/app/home/plugins/plugins.module.css b/web/src/app/home/plugins/plugins.module.css index 54ede1c6..a65be354 100644 --- a/web/src/app/home/plugins/plugins.module.css +++ b/web/src/app/home/plugins/plugins.module.css @@ -13,7 +13,7 @@ padding-right: 0.8rem; padding-top: 2rem; display: grid; - grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(30rem, 1fr)); gap: 2rem; justify-items: stretch; align-items: start; diff --git a/web/src/app/infra/http/CloudServiceClient.ts b/web/src/app/infra/http/CloudServiceClient.ts index 6d67316e..f7491d5a 100644 --- a/web/src/app/infra/http/CloudServiceClient.ts +++ b/web/src/app/infra/http/CloudServiceClient.ts @@ -21,7 +21,10 @@ export class CloudServiceClient extends BaseHttpClient { sort_order?: string, ): Promise { return this.get('/api/v1/marketplace/plugins', { - params: { page, page_size, sort_by, sort_order }, + page, + page_size, + sort_by, + sort_order, }); } diff --git a/web/src/i18n/locales/en-US.ts b/web/src/i18n/locales/en-US.ts index ec91858c..071930a0 100644 --- a/web/src/i18n/locales/en-US.ts +++ b/web/src/i18n/locales/en-US.ts @@ -189,6 +189,7 @@ const enUS = { uploadSuccess: 'Upload successful', uploadFailed: 'Upload failed', selectFileToUpload: 'Select plugin file to upload', + askConfirm: 'Are you sure to install plugin "{{name}}" ({{version}})?', fromGithub: 'From GitHub', fromLocal: 'From Local', fromMarketplace: 'From Marketplace', diff --git a/web/src/i18n/locales/ja-JP.ts b/web/src/i18n/locales/ja-JP.ts index 2294a254..93d48dc1 100644 --- a/web/src/i18n/locales/ja-JP.ts +++ b/web/src/i18n/locales/ja-JP.ts @@ -189,6 +189,7 @@ const jaJP = { uploadSuccess: 'アップロード成功', uploadFailed: 'アップロード失敗', selectFileToUpload: 'アップロードするプラグインファイルを選択', + askConfirm: 'プラグイン "{{name}}" ({{version}}) をインストールしますか?', fromGithub: 'GitHubから', fromLocal: 'ローカルから', fromMarketplace: 'プラグインマーケットから', diff --git a/web/src/i18n/locales/zh-Hans.ts b/web/src/i18n/locales/zh-Hans.ts index 67e1a9c8..688458e8 100644 --- a/web/src/i18n/locales/zh-Hans.ts +++ b/web/src/i18n/locales/zh-Hans.ts @@ -184,6 +184,7 @@ const zhHans = { uploadSuccess: '上传成功', uploadFailed: '上传失败', selectFileToUpload: '选择要上传的插件文件', + askConfirm: '确定要安装插件 "{{name}}" ({{version}}) 吗?', fromGithub: '来自 GitHub', fromLocal: '来自本地', fromMarketplace: '来自市场',