From 14b767fea5b53605b05b5bf63a90b14f12d98d05 Mon Sep 17 00:00:00 2001 From: guopenghui Date: Tue, 2 Jun 2026 14:08:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E6=90=9C=E7=B4=A2=E6=A0=8F=E6=8E=A8=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/PluginDetail/PluginDetail.vue | 6 ++ .../PluginDetail/PluginDetailToolbar.vue | 17 ++++++ .../components/common/PluginDetail/types.ts | 1 + .../common/PluginDetail/usePluginDetail.ts | 51 +++++++++++++--- internal-plugins/setting/src/env.d.ts | 4 ++ pnpm-workspace.yaml | 8 +++ resources/preload.js | 6 ++ src/main/api/plugin/internal.ts | 10 ++++ src/main/api/renderer/plugins.ts | 51 ++++++++++++++++ .../components/detached/DetachedTitlebar.vue | 8 +-- .../src/components/search/SearchBox.vue | 9 +-- src/renderer/src/stores/commandDataStore.ts | 55 +++++++++++++----- src/shared/pluginSettings.ts | 22 +++++++ tests/main/pluginRemovalCleanup.test.ts | 58 +++++++++++++++++++ 14 files changed, 270 insertions(+), 36 deletions(-) create mode 100644 pnpm-workspace.yaml create mode 100644 src/shared/pluginSettings.ts diff --git a/internal-plugins/setting/src/components/common/PluginDetail/PluginDetail.vue b/internal-plugins/setting/src/components/common/PluginDetail/PluginDetail.vue index e9188ef1..8da96cf0 100644 --- a/internal-plugins/setting/src/components/common/PluginDetail/PluginDetail.vue +++ b/internal-plugins/setting/src/components/common/PluginDetail/PluginDetail.vue @@ -44,10 +44,13 @@ const { isAutoKill, isAutoDetach, isAutoStart, + isMainPushEnabled, + pluginHasMainPush, toggleSettingsDropdown, toggleAutoKill, toggleAutoDetach, toggleAutoStart, + toggleMainPushEnabled, // Tab activeTab, availableTabs, @@ -102,6 +105,8 @@ function onSwitchTab(tabId: TabId): void { :is-auto-kill="isAutoKill" :is-auto-detach="isAutoDetach" :is-auto-start="isAutoStart" + :is-main-push-enabled="isMainPushEnabled" + :show-main-push-toggle="pluginHasMainPush" @open="emit('open')" @kill="emit('kill')" @open-folder="emit('open-folder')" @@ -112,6 +117,7 @@ function onSwitchTab(tabId: TabId): void { @toggle-auto-kill="toggleAutoKill" @toggle-auto-detach="toggleAutoDetach" @toggle-auto-start="toggleAutoStart" + @toggle-main-push-enabled="toggleMainPushEnabled" /> diff --git a/internal-plugins/setting/src/components/common/PluginDetail/PluginDetailToolbar.vue b/internal-plugins/setting/src/components/common/PluginDetail/PluginDetailToolbar.vue index 73155acd..759a1136 100644 --- a/internal-plugins/setting/src/components/common/PluginDetail/PluginDetailToolbar.vue +++ b/internal-plugins/setting/src/components/common/PluginDetail/PluginDetailToolbar.vue @@ -14,6 +14,8 @@ defineProps<{ isAutoKill: boolean isAutoDetach: boolean isAutoStart: boolean + isMainPushEnabled: boolean + showMainPushToggle?: boolean }>() const emit = defineEmits<{ @@ -27,6 +29,7 @@ const emit = defineEmits<{ (e: 'toggle-auto-kill'): void (e: 'toggle-auto-detach'): void (e: 'toggle-auto-start'): void + (e: 'toggle-main-push-enabled'): void }>() function handleDisabledToggle(event: Event): void { @@ -108,6 +111,20 @@ function handleDisabledToggle(event: Event): void { +
+
+ 搜索栏推送 + 关闭后不在搜索栏动态推送内容 +
+ +
退出即结束 diff --git a/internal-plugins/setting/src/components/common/PluginDetail/types.ts b/internal-plugins/setting/src/components/common/PluginDetail/types.ts index 902b8787..b692260b 100644 --- a/internal-plugins/setting/src/components/common/PluginDetail/types.ts +++ b/internal-plugins/setting/src/components/common/PluginDetail/types.ts @@ -4,6 +4,7 @@ export interface PluginFeature { explain?: string icon?: string cmds?: any[] + mainPush?: boolean } export interface PluginItem { diff --git a/internal-plugins/setting/src/components/common/PluginDetail/usePluginDetail.ts b/internal-plugins/setting/src/components/common/PluginDetail/usePluginDetail.ts index 704a88b8..ec52315c 100644 --- a/internal-plugins/setting/src/components/common/PluginDetail/usePluginDetail.ts +++ b/internal-plugins/setting/src/components/common/PluginDetail/usePluginDetail.ts @@ -2,6 +2,11 @@ import { marked } from 'marked' import { computed, onMounted, onUnmounted, ref, watch, type Ref } from 'vue' import { useToast } from '@/components' import type { DocItem, PluginItem, PluginUninstallOptions, TabId, TabItem } from './types' +import { + DISABLED_MAIN_PUSH_PLUGINS_KEY, + normalizeConfigList, + isMainPushPluginEnabled +} from '@shared/pluginSettings' // 配置 marked marked.setOptions({ @@ -26,17 +31,17 @@ export function usePluginDetail(options: UsePluginDetailOptions) { const isAutoKill = ref(false) const isAutoDetach = ref(false) const isAutoStart = ref(false) + const isMainPushEnabled = ref(true) // 当前详情页插件的有效名称(已包含 __dev 后缀) const currentPluginName = computed(() => plugin.value.name || null) - - /** 解析配置列表,兼容旧式 { pluginName, source } 和新式 string */ - function normalizeConfigList(data: unknown): string[] { - if (!Array.isArray(data)) return [] - return data - .map((item) => (typeof item === 'string' ? item : (item?.pluginName ?? ''))) - .filter(Boolean) - } + const pluginHasMainPush = computed(() => + Boolean( + plugin.value.features?.some( + (feature: any) => feature?.mainPush && Array.isArray(feature.cmds) + ) + ) + ) /** 切换字符串列表中的某项 */ function toggleInList(list: string[], name: string): string[] { @@ -83,6 +88,18 @@ export function usePluginDetail(options: UsePluginDetailOptions) { } catch (err) { console.debug('未找到 autoStartPlugin 配置', err) } + + try { + const mainPushData = await window.ztools.internal.dbGet(DISABLED_MAIN_PUSH_PLUGINS_KEY) + if (currentPluginName.value) { + isMainPushEnabled.value = isMainPushPluginEnabled( + currentPluginName.value, + normalizeConfigList(mainPushData) + ) + } + } catch (err) { + console.debug('未找到 disabledMainPushPlugin 配置', err) + } } // 切换「退出即结束」 @@ -136,6 +153,21 @@ export function usePluginDetail(options: UsePluginDetailOptions) { isAutoStart.value = list.includes(currentPluginName.value) } + async function toggleMainPushEnabled(): Promise { + if (!currentPluginName.value) return + + const nextDisabled = isMainPushEnabled.value + const result = await window.ztools.internal.setPluginMainPushDisabled( + currentPluginName.value, + nextDisabled + ) + if (result.success) { + isMainPushEnabled.value = !nextDisabled + } else { + error(`更新搜索栏推送状态失败: ${result.error || '未知错误'}`) + } + } + // Tab 状态 const activeTab = ref('detail') @@ -493,11 +525,14 @@ export function usePluginDetail(options: UsePluginDetailOptions) { isAutoKill, isAutoDetach, isAutoStart, + isMainPushEnabled, + pluginHasMainPush, currentPluginName, toggleSettingsDropdown, toggleAutoKill, toggleAutoDetach, toggleAutoStart, + toggleMainPushEnabled, // Tab 状态 activeTab, diff --git a/internal-plugins/setting/src/env.d.ts b/internal-plugins/setting/src/env.d.ts index 25e568dd..a267047e 100644 --- a/internal-plugins/setting/src/env.d.ts +++ b/internal-plugins/setting/src/env.d.ts @@ -57,6 +57,10 @@ declare global { pluginPath: string, disabled: boolean ) => Promise<{ success: boolean; error?: string }> + setPluginMainPushDisabled: ( + pluginName: string, + disabled: boolean + ) => Promise<{ success: boolean; error?: string }> getAllPlugins: () => Promise< Array<{ name: string diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..4a0514e1 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,8 @@ +allowBuilds: + electron: true + electron-winstaller: true + esbuild: true + lmdb: true + msgpackr-extract: true + sharp: true + uiohook-napi: true diff --git a/resources/preload.js b/resources/preload.js index 3e2f7fcf..c7cf72e8 100644 --- a/resources/preload.js +++ b/resources/preload.js @@ -834,6 +834,12 @@ window.ztools = { setPluginDisabled: async (pluginPath, disabled) => await electron.ipcRenderer.invoke('internal:set-plugin-disabled', pluginPath, disabled), getAllPlugins: async () => await electron.ipcRenderer.invoke('internal:get-all-plugins'), + setPluginMainPushDisabled: async (pluginName, disabled) => + await electron.ipcRenderer.invoke( + 'internal:set-plugin-main-push-disabled', + pluginName, + disabled + ), selectPluginFile: async () => await electron.ipcRenderer.invoke('internal:select-plugin-file'), importPlugin: async () => await electron.ipcRenderer.invoke('internal:import-plugin'), getDevProjects: async () => await electron.ipcRenderer.invoke('internal:get-dev-projects'), diff --git a/src/main/api/plugin/internal.ts b/src/main/api/plugin/internal.ts index 0f53deee..af05e590 100644 --- a/src/main/api/plugin/internal.ts +++ b/src/main/api/plugin/internal.ts @@ -213,6 +213,16 @@ export class InternalPluginAPI { return await pluginsAPI.getAllPlugins() }) + ipcMain.handle( + 'internal:set-plugin-main-push-disabled', + async (event, pluginName: string, disabled: boolean) => { + if (!requireInternalPlugin(this.pluginManager, event)) { + throw new PermissionDeniedError('internal:set-plugin-main-push-disabled') + } + return await pluginsAPI.setPluginMainPushDisabled(pluginName, disabled) + } + ) + ipcMain.handle('internal:select-plugin-file', async (event) => { if (!requireInternalPlugin(this.pluginManager, event)) { throw new PermissionDeniedError('internal:select-plugin-file') diff --git a/src/main/api/renderer/plugins.ts b/src/main/api/renderer/plugins.ts index 84af4954..526f9623 100644 --- a/src/main/api/renderer/plugins.ts +++ b/src/main/api/renderer/plugins.ts @@ -18,9 +18,20 @@ import { getPluginDataPrefix, isDevelopmentPluginName } from '../../../shared/pluginRuntimeNamespace' +import { + DISABLED_MAIN_PUSH_PLUGINS_KEY, + normalizeConfigList, + removePluginNameFromSettingList +} from '../../../shared/pluginSettings' // 插件目录 const DISABLED_PLUGINS_KEY = 'disabled-plugins' +const PLUGIN_NAME_SETTING_KEYS = [ + 'outKillPlugin', + 'autoDetachPlugin', + 'autoStartPlugin', + DISABLED_MAIN_PUSH_PLUGINS_KEY +] export interface DeletePluginOptions { deleteData?: boolean @@ -474,6 +485,7 @@ export class PluginsAPI { if (options.deleteData !== false) { await databaseAPI.clearPluginData(pluginInfo.name) + this.removePluginNameConfigs(PLUGIN_NAME_SETTING_KEYS, pluginInfo.name) } // 删除禁用插件标识 @@ -503,6 +515,45 @@ export class PluginsAPI { } } + private removePluginNameConfigs(keys: string[], pluginName: string): void { + for (const key of keys) { + const current = databaseAPI.dbGet(key) + const normalized = normalizeConfigList(current) + const next = removePluginNameFromSettingList(normalized, pluginName) + if (next.length !== normalized.length) { + databaseAPI.dbPut(key, next) + } + } + } + + public async setPluginMainPushDisabled( + pluginName: string, + disabled: boolean + ): Promise<{ success: boolean; error?: string }> { + try { + const disabledPluginNames = new Set( + normalizeConfigList(databaseAPI.dbGet(DISABLED_MAIN_PUSH_PLUGINS_KEY)) + ) + const isCurrentlyDisabled = disabledPluginNames.has(pluginName) + if (isCurrentlyDisabled === disabled) { + return { success: true } + } + + if (disabled) { + disabledPluginNames.add(pluginName) + } else { + disabledPluginNames.delete(pluginName) + } + + databaseAPI.dbPut(DISABLED_MAIN_PUSH_PLUGINS_KEY, [...disabledPluginNames]) + this.notifyPluginsChanged() + return { success: true } + } catch (error: unknown) { + console.error('[Plugins] 更新插件 mainPush 状态失败:', error) + return { success: false, error: error instanceof Error ? error.message : '未知错误' } + } + } + // 获取运行中的插件 public getRunningPlugins(): string[] { if (this.pluginManager) { diff --git a/src/renderer/src/components/detached/DetachedTitlebar.vue b/src/renderer/src/components/detached/DetachedTitlebar.vue index 3cafb9bb..ba93f561 100644 --- a/src/renderer/src/components/detached/DetachedTitlebar.vue +++ b/src/renderer/src/components/detached/DetachedTitlebar.vue @@ -123,6 +123,7 @@