From 3239bab696f6738547e55b76b9be501e68691f6c Mon Sep 17 00:00:00 2001 From: KiriAky 107 Date: Sat, 29 Aug 2026 22:49:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E5=AE=8C=E6=88=90Skill?= =?UTF-8?q?=E4=B8=8EPlugin=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/ExtensionListPanel.vue | 36 +++++++++++++ frontend/src/contracts/index.ts | 1 + frontend/src/features/plugins/PluginsView.vue | 45 +++++++++++++++++ frontend/src/features/skills/SkillsView.vue | 50 +++++++++++++++++++ frontend/src/services/pluginService.ts | 3 +- frontend/src/stores/plugin.ts | 45 +++++++++++------ frontend/src/stores/skill.ts | 38 ++++++++------ 7 files changed, 189 insertions(+), 29 deletions(-) create mode 100644 frontend/src/components/common/ExtensionListPanel.vue create mode 100644 frontend/src/features/plugins/PluginsView.vue create mode 100644 frontend/src/features/skills/SkillsView.vue diff --git a/frontend/src/components/common/ExtensionListPanel.vue b/frontend/src/components/common/ExtensionListPanel.vue new file mode 100644 index 0000000..bb18ca0 --- /dev/null +++ b/frontend/src/components/common/ExtensionListPanel.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/frontend/src/contracts/index.ts b/frontend/src/contracts/index.ts index 2497f16..23c9008 100644 --- a/frontend/src/contracts/index.ts +++ b/frontend/src/contracts/index.ts @@ -246,6 +246,7 @@ export interface Plugin { status: PluginStatus enabled: boolean permissions: string[] + granted_permissions?: string[] contributions: PluginContribution[] backend_type?: 'mcp' | 'internal_rpc' | 'none' transport?: 'stdio' | 'http' | 'none' diff --git a/frontend/src/features/plugins/PluginsView.vue b/frontend/src/features/plugins/PluginsView.vue new file mode 100644 index 0000000..67aee07 --- /dev/null +++ b/frontend/src/features/plugins/PluginsView.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/features/skills/SkillsView.vue b/frontend/src/features/skills/SkillsView.vue new file mode 100644 index 0000000..7ae8643 --- /dev/null +++ b/frontend/src/features/skills/SkillsView.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/frontend/src/services/pluginService.ts b/frontend/src/services/pluginService.ts index ae81473..b42fdc7 100644 --- a/frontend/src/services/pluginService.ts +++ b/frontend/src/services/pluginService.ts @@ -20,7 +20,8 @@ function toPlugin(plugin: ApiPlugin): Plugin { description: manifest.description, status: plugin.status, enabled: plugin.enabled, - permissions: plugin.granted_permissions, + permissions: manifest.permissions, + granted_permissions: plugin.granted_permissions, contributions, backend_type: manifest.backend.type, transport: manifest.backend.transport, diff --git a/frontend/src/stores/plugin.ts b/frontend/src/stores/plugin.ts index d1fd8e1..7e742e7 100644 --- a/frontend/src/stores/plugin.ts +++ b/frontend/src/stores/plugin.ts @@ -1,12 +1,13 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' import type { Plugin } from '@/contracts' -import { mockPlugins } from '@/services/pluginService' +import * as pluginService from '@/services/pluginService' export const usePluginStore = defineStore('plugin', () => { - const plugins = ref(mockPlugins) + const plugins = ref(pluginService.mockPlugins) const selectedPluginId = ref(null) const isLoading = ref(false) + const error = ref(null) const selectedPlugin = computed(() => plugins.value.find((p) => p.plugin_id === selectedPluginId.value) || null @@ -19,8 +20,10 @@ export const usePluginStore = defineStore('plugin', () => { async function loadPlugins() { isLoading.value = true try { - const { listPlugins } = await import('@/services/pluginService') - plugins.value = await listPlugins() + plugins.value = await pluginService.listPlugins() + error.value = null + } catch (reason) { + error.value = reason instanceof Error ? reason.message : 'Plugin 加载失败' } finally { isLoading.value = false } @@ -30,23 +33,34 @@ export const usePluginStore = defineStore('plugin', () => { selectedPluginId.value = pluginId } + async function installPlugin(packagePath: string) { + const installed = await pluginService.installPlugin(packagePath) + const index = plugins.value.findIndex((plugin) => plugin.plugin_id === installed.plugin_id) + if (index >= 0) plugins.value[index] = installed + else plugins.value.unshift(installed) + selectedPluginId.value = installed.plugin_id + } + + async function grantPermissions(pluginId: string, permissions: string[]) { + const updated = await pluginService.grantPluginPermissions(pluginId, permissions) + const index = plugins.value.findIndex((plugin) => plugin.plugin_id === pluginId) + if (index >= 0) plugins.value[index] = updated + } + async function enablePlugin(pluginId: string) { - const plugin = plugins.value.find((p) => p.plugin_id === pluginId) - if (plugin) { - plugin.enabled = true - plugin.status = 'ready' - } + const updated = await pluginService.enablePlugin(pluginId) + const index = plugins.value.findIndex((plugin) => plugin.plugin_id === pluginId) + if (index >= 0) plugins.value[index] = updated } async function disablePlugin(pluginId: string) { - const plugin = plugins.value.find((p) => p.plugin_id === pluginId) - if (plugin) { - plugin.enabled = false - plugin.status = 'disabled' - } + const updated = await pluginService.disablePlugin(pluginId) + const index = plugins.value.findIndex((plugin) => plugin.plugin_id === pluginId) + if (index >= 0) plugins.value[index] = updated } async function uninstallPlugin(pluginId: string) { + await pluginService.uninstallPlugin(pluginId) const idx = plugins.value.findIndex((p) => p.plugin_id === pluginId) if (idx > -1) plugins.value.splice(idx, 1) if (selectedPluginId.value === pluginId) selectedPluginId.value = null @@ -60,8 +74,11 @@ export const usePluginStore = defineStore('plugin', () => { readyPlugins, errorPlugins, isLoading, + error, loadPlugins, selectPlugin, + installPlugin, + grantPermissions, enablePlugin, disablePlugin, uninstallPlugin, diff --git a/frontend/src/stores/skill.ts b/frontend/src/stores/skill.ts index 7269ead..8aed4b3 100644 --- a/frontend/src/stores/skill.ts +++ b/frontend/src/stores/skill.ts @@ -1,12 +1,13 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' import type { Skill } from '@/contracts' -import { mockSkills } from '@/services/skillService' +import * as skillService from '@/services/skillService' export const useSkillStore = defineStore('skill', () => { - const skills = ref(mockSkills) + const skills = ref(skillService.mockSkills) const selectedSkillId = ref(null) const isLoading = ref(false) + const error = ref(null) const selectedSkill = computed(() => skills.value.find((s) => s.skill_id === selectedSkillId.value) || null @@ -19,8 +20,10 @@ export const useSkillStore = defineStore('skill', () => { async function loadSkills() { isLoading.value = true try { - const { listSkills } = await import('@/services/skillService') - skills.value = await listSkills() + skills.value = await skillService.listSkills() + error.value = null + } catch (reason) { + error.value = reason instanceof Error ? reason.message : 'Skill 加载失败' } finally { isLoading.value = false } @@ -30,23 +33,28 @@ export const useSkillStore = defineStore('skill', () => { selectedSkillId.value = skillId } + async function installSkill(packagePath: string) { + const installed = await skillService.installSkill(packagePath) + const index = skills.value.findIndex((skill) => skill.skill_id === installed.skill_id) + if (index >= 0) skills.value[index] = installed + else skills.value.unshift(installed) + selectedSkillId.value = installed.skill_id + } + async function enableSkill(skillId: string) { - const skill = skills.value.find((s) => s.skill_id === skillId) - if (skill) { - skill.enabled = true - skill.status = 'ready' - } + const updated = await skillService.enableSkill(skillId) + const index = skills.value.findIndex((skill) => skill.skill_id === skillId) + if (index >= 0) skills.value[index] = updated } async function disableSkill(skillId: string) { - const skill = skills.value.find((s) => s.skill_id === skillId) - if (skill) { - skill.enabled = false - skill.status = 'disabled' - } + const updated = await skillService.disableSkill(skillId) + const index = skills.value.findIndex((skill) => skill.skill_id === skillId) + if (index >= 0) skills.value[index] = updated } async function uninstallSkill(skillId: string) { + await skillService.uninstallSkill(skillId) const idx = skills.value.findIndex((s) => s.skill_id === skillId) if (idx > -1) skills.value.splice(idx, 1) if (selectedSkillId.value === skillId) selectedSkillId.value = null @@ -60,8 +68,10 @@ export const useSkillStore = defineStore('skill', () => { installedSkills, readySkills, isLoading, + error, loadSkills, selectSkill, + installSkill, enableSkill, disableSkill, uninstallSkill,