Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 18 additions & 0 deletions astrbot/core/star/error_messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Shared plugin error message templates for star manager flows."""

PLUGIN_ERROR_TEMPLATES = {
"not_found_in_failed_list": "插件不存在于失败列表中。",
"reserved_plugin_cannot_uninstall": "该插件是 AstrBot 保留插件,无法卸载。",
"failed_plugin_dir_remove_error": (
"移除失败插件成功,但是删除插件文件夹失败: {error}。"
"您可以手动删除该文件夹,位于 addons/plugins/ 下。"
),
}


def format_plugin_error(key: str, **kwargs) -> str:
template = PLUGIN_ERROR_TEMPLATES.get(key, key)
try:
return template.format(**kwargs)
except Exception:
return template
300 changes: 230 additions & 70 deletions astrbot/core/star/star_manager.py

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions astrbot/dashboard/routes/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def __init__(
"/plugin/update": ("POST", self.update_plugin),
"/plugin/update-all": ("POST", self.update_all_plugins),
"/plugin/uninstall": ("POST", self.uninstall_plugin),
"/plugin/uninstall-failed": ("POST", self.uninstall_failed_plugin),
"/plugin/market_list": ("GET", self.get_online_plugins),
"/plugin/off": ("POST", self.off_plugin),
"/plugin/on": ("POST", self.on_plugin),
Expand Down Expand Up @@ -565,6 +566,34 @@ async def uninstall_plugin(self):
logger.error(traceback.format_exc())
return Response().error(str(e)).__dict__

async def uninstall_failed_plugin(self):
if DEMO_MODE:
return (
Response()
.error("You are not permitted to do this operation in demo mode")
.__dict__
)

post_data = await request.get_json()
dir_name = post_data.get("dir_name", "")
delete_config = post_data.get("delete_config", False)
delete_data = post_data.get("delete_data", False)
if not dir_name:
return Response().error("缺少失败插件目录名").__dict__

try:
logger.info(f"正在卸载失败插件 {dir_name}")
await self.plugin_manager.uninstall_failed_plugin(
dir_name,
delete_config=delete_config,
delete_data=delete_data,
)
logger.info(f"卸载失败插件 {dir_name} 成功")
return Response().ok(None, "卸载成功").__dict__
except Exception as e:
logger.error(traceback.format_exc())
return Response().error(str(e)).__dict__

async def update_plugin(self):
if DEMO_MODE:
return (
Expand Down
19 changes: 4 additions & 15 deletions dashboard/src/components/shared/ExtensionCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -189,28 +189,15 @@ const viewChangelog = () => {
class="ml-2"
icon="mdi-update"
size="small"
style="cursor: pointer"
@click.stop="updateExtension"
></v-icon>
</template>
<span
>{{ tm("card.status.hasUpdate") }}:
{{ extension.online_version }}</span
>
</v-tooltip>
<v-tooltip
location="top"
v-if="!extension.activated && !marketMode"
>
<template v-slot:activator="{ props: tooltipProps }">
<v-icon
v-bind="tooltipProps"
color="error"
class="ml-2"
icon="mdi-cancel"
size="small"
></v-icon>
</template>
<span>{{ tm("card.status.disabled") }}</span>
</v-tooltip>
</p>

<template v-if="!marketMode">
Expand Down Expand Up @@ -299,6 +286,8 @@ const viewChangelog = () => {
color="warning"
label
size="small"
style="cursor: pointer"
@click="updateExtension"
>
<v-icon icon="mdi-arrow-up-bold" start></v-icon>
{{ extension.online_version }}
Expand Down
12 changes: 12 additions & 0 deletions dashboard/src/i18n/locales/en-US/features/extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
"titles": {
"installedAstrBotPlugins": "Installed AstrBot Plugins"
},
"failedPlugins": {
"title": "Failed to Load Plugins ({count})",
"hint": "These plugins failed to load. You can try reload or uninstall them directly.",
"columns": {
"plugin": "Plugin",
"error": "Error"
}
},
"search": {
"placeholder": "Search extensions...",
"marketPlaceholder": "Search market extensions..."
Expand Down Expand Up @@ -109,6 +117,8 @@
"sourceExists": "This source already exists",
"installPlugin": "Install Plugin",
"randomPlugins": "🎲 Random Plugins",
"showRandomPlugins": "Show Random Plugins",
"hideRandomPlugins": "Hide Random Plugins",
"sourceSafetyWarning": "Even with the default source, plugin stability and security cannot be fully guaranteed. Please verify carefully before use."
},
"sort": {
Expand Down Expand Up @@ -177,7 +187,9 @@
"refreshing": "Refreshing extension list...",
"refreshSuccess": "Extension list refreshed!",
"refreshFailed": "Error occurred while refreshing extension list",
"operationFailed": "Operation failed",
"reloadSuccess": "Reload successful",
"reloadFailed": "Reload failed",
"updateSuccess": "Update successful!",
"addSuccess": "Add successful!",
"saveSuccess": "Save successful!",
Expand Down
12 changes: 12 additions & 0 deletions dashboard/src/i18n/locales/zh-CN/features/extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
"titles": {
"installedAstrBotPlugins": "已安装的 AstrBot 插件"
},
"failedPlugins": {
"title": "加载失败插件({count})",
"hint": "这些插件加载失败,仍可尝试重载或直接卸载。",
"columns": {
"plugin": "插件",
"error": "错误"
}
},
"search": {
"placeholder": "搜索插件...",
"marketPlaceholder": "搜索市场插件..."
Expand Down Expand Up @@ -109,6 +117,8 @@
"sourceExists": "该插件源已存在",
"installPlugin": "安装插件",
"randomPlugins": "🎲 随机插件",
"showRandomPlugins": "显示随机插件",
"hideRandomPlugins": "隐藏随机插件",
"sourceSafetyWarning": "即使是默认插件源,我们也不能完全保证插件的稳定性和安全性,使用前请谨慎核查。"
},
"sort": {
Expand Down Expand Up @@ -177,7 +187,9 @@
"refreshing": "正在刷新插件列表...",
"refreshSuccess": "插件列表已刷新!",
"refreshFailed": "刷新插件列表时发生错误",
"operationFailed": "操作失败",
"reloadSuccess": "重载成功",
"reloadFailed": "重载失败",
"updateSuccess": "更新成功!",
"addSuccess": "添加成功!",
"saveSuccess": "保存成功!",
Expand Down
44 changes: 44 additions & 0 deletions dashboard/src/utils/errorUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const INVALID_ERROR_STRINGS = new Set(["[object Object]", "undefined", "null", ""]);

const pickResponseMessage = (responseData) => {
if (typeof responseData === "string") {
return responseData.trim();
}
if (!responseData || typeof responseData !== "object") {
return "";
}

const keys = ["message", "error", "detail", "details", "msg"];
for (const key of keys) {
const value = responseData[key];
if (typeof value === "string" && value.trim()) {
return value.trim();
}
}
return "";
};

export const resolveErrorMessage = (err, fallbackMessage = "") => {
if (typeof err === "string") {
return err.trim() || fallbackMessage;
}
if (typeof err === "number" || typeof err === "boolean") {
return String(err);
}

const fromResponse =
pickResponseMessage(err?.response?.data) ||
(typeof err?.response?.statusText === "string"
? err.response.statusText.trim()
: "");
const fromError =
typeof err?.message === "string" ? err.message.trim() : "";

let fromString = "";
if (typeof err?.toString === "function") {
const value = err.toString().trim();
fromString = INVALID_ERROR_STRINGS.has(value) ? "" : value;
}

return fromResponse || fromError || fromString || fallbackMessage;
};
2 changes: 1 addition & 1 deletion dashboard/src/views/ExtensionPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const {
installCompat,
versionCompatibilityDialog,
showUninstallDialog,
pluginToUninstall,
uninstallTarget,
showSourceDialog,
showSourceManagerDialog,
sourceName,
Expand Down
Loading