Merge pull request #2013 from AstrBotDevs/feat/danger-plugin
[Copilot] feat: 添加风险插件安装确认对话框以及风险插件标签特殊处理
This commit is contained in:
@@ -49,6 +49,11 @@ const reloadExtension = () => {
|
||||
};
|
||||
|
||||
const $confirm = inject("$confirm");
|
||||
|
||||
const installExtension = async () => {
|
||||
emit('install', props.extension);
|
||||
};
|
||||
|
||||
const uninstallExtension = async () => {
|
||||
if (typeof $confirm !== "function") {
|
||||
console.error(tm("card.errors.confirmNotRegistered"));
|
||||
@@ -117,6 +122,10 @@ const viewReadme = () => {
|
||||
<v-icon icon="mdi-cogs" start></v-icon>
|
||||
{{ extension.handlers?.length }}{{ tm("card.status.handlersCount") }}
|
||||
</v-chip>
|
||||
<v-chip v-for="tag in extension.tags" :key="tag" :color="tag === 'danger' ? 'error' : 'primary'" label
|
||||
size="small" class="ml-2">
|
||||
{{ tag === 'danger' ? tm('tags.danger') : tag }}
|
||||
</v-chip>
|
||||
</div>
|
||||
|
||||
<div class="mt-2" :class="{ 'text-caption': $vuetify.display.xs }" style="max-height: 65px; overflow-y: auto;">
|
||||
@@ -139,7 +148,7 @@ const viewReadme = () => {
|
||||
<v-btn color="teal-accent-4" :text="tm('buttons.viewDocs')" variant="text" @click="viewReadme"></v-btn>
|
||||
<v-btn v-if="!marketMode" color="teal-accent-4" :text="tm('buttons.actions')" variant="text" @click="reveal = true"></v-btn>
|
||||
<v-btn v-if="marketMode && !extension?.installed" color="teal-accent-4" :text="tm('buttons.install')" variant="text"
|
||||
@click="emit('install', extension)"></v-btn>
|
||||
@click="installExtension"></v-btn>
|
||||
<v-btn v-if="marketMode && extension?.installed" color="teal-accent-4" :text="tm('status.installed')" variant="text" disabled></v-btn>
|
||||
</v-card-actions>
|
||||
|
||||
@@ -200,6 +209,7 @@ const viewReadme = () => {
|
||||
</v-card>
|
||||
</v-expand-transition>
|
||||
</v-card>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
"devDocs": "Extension Development Docs",
|
||||
"submitRepo": "Submit Extension Repository"
|
||||
},
|
||||
"tags": {
|
||||
"danger": "Danger"
|
||||
},
|
||||
"dialogs": {
|
||||
"error": {
|
||||
"title": "Error Information",
|
||||
@@ -112,6 +115,12 @@
|
||||
"title": "Install Extension",
|
||||
"fromFile": "Install from File",
|
||||
"fromUrl": "Install from URL"
|
||||
},
|
||||
"danger_warning": {
|
||||
"title": "Dangerous Plugin Warning",
|
||||
"message": "This plugin has been flagged as containing security risks, including unsafe code or functionalities that may cause system malfunctions or data loss. Do you wish to proceed with the installation?",
|
||||
"confirm": "Continue",
|
||||
"cancel": "Cancel"
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
@@ -164,4 +173,4 @@
|
||||
"confirmNotRegistered": "$confirm not properly registered"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
"devDocs": "插件开发文档",
|
||||
"submitRepo": "提交插件仓库"
|
||||
},
|
||||
"tags": {
|
||||
"danger": "危险"
|
||||
},
|
||||
"dialogs": {
|
||||
"error": {
|
||||
"title": "错误信息",
|
||||
@@ -112,6 +115,12 @@
|
||||
"title": "安装插件",
|
||||
"fromFile": "从文件安装",
|
||||
"fromUrl": "从链接安装"
|
||||
},
|
||||
"danger_warning": {
|
||||
"title": "警告",
|
||||
"message": "该插件可能包含不安全的代码或功能,可能导致系统异常或数据损失等。请确认是否继续安装?",
|
||||
"confirm": "继续",
|
||||
"cancel": "取消"
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
@@ -164,4 +173,4 @@
|
||||
"confirmNotRegistered": "$confirm 未正确注册"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@ const isListView = ref(false);
|
||||
const pluginSearch = ref("");
|
||||
const loading_ = ref(false);
|
||||
|
||||
// 危险插件确认对话框
|
||||
const dangerConfirmDialog = ref(false);
|
||||
const selectedDangerPlugin = ref(null);
|
||||
|
||||
// 插件市场相关
|
||||
const extension_url = ref("");
|
||||
const dialog = ref(false);
|
||||
@@ -421,6 +425,35 @@ const open = (link) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 为表格视图创建一个处理安装插件的函数
|
||||
const handleInstallPlugin = async (plugin) => {
|
||||
if (plugin.tags && plugin.tags.includes('danger')) {
|
||||
selectedDangerPlugin.value = plugin;
|
||||
dangerConfirmDialog.value = true;
|
||||
} else {
|
||||
extension_url.value = plugin.repo;
|
||||
dialog.value = true;
|
||||
uploadTab.value = 'url';
|
||||
}
|
||||
};
|
||||
|
||||
// 确认安装危险插件
|
||||
const confirmDangerInstall = () => {
|
||||
if (selectedDangerPlugin.value) {
|
||||
extension_url.value = selectedDangerPlugin.value.repo;
|
||||
dialog.value = true;
|
||||
uploadTab.value = 'url';
|
||||
}
|
||||
dangerConfirmDialog.value = false;
|
||||
selectedDangerPlugin.value = null;
|
||||
};
|
||||
|
||||
// 取消安装危险插件
|
||||
const cancelDangerInstall = () => {
|
||||
dangerConfirmDialog.value = false;
|
||||
selectedDangerPlugin.value = null;
|
||||
};
|
||||
|
||||
// 插件市场显示完整插件名称
|
||||
const trimExtensionName = () => {
|
||||
pluginMarketData.value.forEach(plugin => {
|
||||
@@ -823,7 +856,7 @@ onMounted(async () => {
|
||||
<v-row style="margin-top: 8px;">
|
||||
<v-col cols="12" md="6" lg="6" v-for="plugin in pinnedPlugins" :key="plugin.name">
|
||||
<ExtensionCard :extension="plugin" class="h-120 rounded-lg" market-mode="true" :highlight="true"
|
||||
@install="extension_url = plugin.repo; dialog = true; uploadTab = 'url'" @view-readme="open(plugin.repo)">
|
||||
@install="handleInstallPlugin(plugin)" @view-readme="open(plugin.repo)">
|
||||
</ExtensionCard>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@@ -871,12 +904,12 @@ onMounted(async () => {
|
||||
</template>
|
||||
<template v-slot:item.tags="{ item }">
|
||||
<span v-if="item.tags.length === 0">-</span>
|
||||
<v-chip v-for="tag in item.tags" :key="tag" color="primary" size="x-small">
|
||||
<v-chip v-for="tag in item.tags" :key="tag" :color="tag === 'danger' ? 'error' : 'primary'" size="x-small" v-show="tag !== 'danger'">
|
||||
{{ tag }}</v-chip>
|
||||
</template>
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn v-if="!item.installed" class="text-none mr-2" size="x-small" variant="flat"
|
||||
@click="extension_url = item.repo; dialog = true; uploadTab = 'url'">
|
||||
@click="handleInstallPlugin(item)">
|
||||
<v-icon>mdi-download</v-icon></v-btn>
|
||||
<v-btn v-else class="text-none mr-2" size="x-small" variant="flat" border
|
||||
disabled><v-icon>mdi-check</v-icon></v-btn>
|
||||
@@ -960,7 +993,7 @@ onMounted(async () => {
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -1078,6 +1111,28 @@ onMounted(async () => {
|
||||
<ReadmeDialog v-model:show="readmeDialog.show" :plugin-name="readmeDialog.pluginName"
|
||||
:repo-url="readmeDialog.repoUrl" />
|
||||
|
||||
<!-- 危险插件确认对话框 -->
|
||||
<v-dialog v-model="dangerConfirmDialog" width="500" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5 d-flex align-center">
|
||||
<v-icon color="warning" class="mr-2">mdi-alert-circle</v-icon>
|
||||
{{ tm('dialogs.danger_warning.title') }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div>{{ tm('dialogs.danger_warning.message') }}</div>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" @click="cancelDangerInstall">
|
||||
{{ tm('dialogs.danger_warning.cancel') }}
|
||||
</v-btn>
|
||||
<v-btn color="warning" @click="confirmDangerInstall">
|
||||
{{ tm('dialogs.danger_warning.confirm') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 上传插件对话框 -->
|
||||
<v-dialog v-model="dialog" width="500">
|
||||
<v-card>
|
||||
|
||||
Reference in New Issue
Block a user