From f01795ea97887175a17c8909d1e2551d96770824 Mon Sep 17 00:00:00 2001 From: Pine Date: Fri, 14 Aug 2026 13:53:36 +0800 Subject: [PATCH] feat(ui): add enable/disable toggle to the plugin-list tab Each expanded plugin card gains an enable/disable button wired to pluginInventory.setEnabled; the tab re-lists after toggling. Adds zh/en copy for the toggle states. Co-Authored-By: Claude --- .../PluginInventorySettingsTab.module.css | 5 ++++ .../src/client/PluginInventorySettingsTab.tsx | 26 +++++++++++++++++-- .../src/client/index.ts | 8 +++++- .../src/client/locales.ts | 6 +++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.module.css b/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.module.css index de10a3bd36..6ceb7158ac 100644 --- a/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.module.css +++ b/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.module.css @@ -277,3 +277,8 @@ grid-template-columns: minmax(0, 1fr); } } + +.toggle { + margin-top: 0.5rem; + align-self: flex-start; +} diff --git a/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx b/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx index 12fd3d2a7a..9f376a5c61 100644 --- a/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx +++ b/packages/client/ui-settings-plugin-inventory/src/client/PluginInventorySettingsTab.tsx @@ -12,6 +12,8 @@ import css from './PluginInventorySettingsTab.module.css' export interface PluginInventorySettingsTabInjected { /** Read a current Host inventory snapshot. */ list: () => Promise + /** Toggle one plugin entry on or off; persists across a restart. */ + setEnabled: (entryId: PluginInventoryEntry['entryId'], enabled: boolean) => Promise } type PluginInventoryEntry = PluginInventorySnapshot['entries'][number] @@ -60,13 +62,14 @@ function matches(entry: PluginInventoryEntry, normalizedQuery: string): boolean .some(value => value.toLocaleLowerCase().includes(normalizedQuery)) } -/** Render the read-only current Loader inventory. */ -export function PluginInventorySettingsTab({ list, t }: PluginInventorySettingsTabProps): ReactNode { +/** Render the current Loader inventory with per-plugin enable/disable. */ +export function PluginInventorySettingsTab({ list, setEnabled, t }: PluginInventorySettingsTabProps): ReactNode { const catalogId = useId() const [request, setRequest] = useState(0) const [query, setQuery] = useState('') const [expanded, setExpanded] = useState(null) const [state, setState] = useState({ status: 'loading' }) + const [busy, setBusy] = useState(null) useEffect(() => { let current = true @@ -77,6 +80,16 @@ export function PluginInventorySettingsTab({ list, t }: PluginInventorySettingsT return () => { current = false } }, [list, request]) + /** Toggle one entry then re-read the inventory. */ + const toggle = (entryId: PluginInventoryEntry['entryId'], enabled: boolean): void => { + if (busy !== null) return + setBusy(entryId) + void setEnabled(entryId, enabled).then( + () => setRequest(value => value + 1), + () => { /* the next list reflects the unchanged state */ }, + ).finally(() => setBusy(null)) + } + const normalizedQuery = query.trim().toLocaleLowerCase() const filteredEntries = useMemo( () => state.status === 'ready' @@ -183,6 +196,15 @@ export function PluginInventorySettingsTab({ list, t }: PluginInventorySettingsT ) : null} + ) : null} diff --git a/packages/client/ui-settings-plugin-inventory/src/client/index.ts b/packages/client/ui-settings-plugin-inventory/src/client/index.ts index ccfd8bda5a..8034101a33 100644 --- a/packages/client/ui-settings-plugin-inventory/src/client/index.ts +++ b/packages/client/ui-settings-plugin-inventory/src/client/index.ts @@ -34,7 +34,13 @@ export function apply(ctx: ClientContext): void { } return result.value } - const injected = (): PluginInventorySettingsTabInjected => ({ list }) + const setEnabled: PluginInventorySettingsTabInjected['setEnabled'] = async (entryId, enabled) => { + const result = await ctx.remote.pluginInventory.setEnabled(entryId, enabled) + if (!result.ok) { + throw new Error(`pluginInventory.setEnabled failed: ${result.error.code}: ${result.error.message}`) + } + } + const injected = (): PluginInventorySettingsTabInjected => ({ list, setEnabled }) ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({ name: 'settings.plugins.tab', diff --git a/packages/client/ui-settings-plugin-inventory/src/client/locales.ts b/packages/client/ui-settings-plugin-inventory/src/client/locales.ts index 866937016c..9939267f05 100644 --- a/packages/client/ui-settings-plugin-inventory/src/client/locales.ts +++ b/packages/client/ui-settings-plugin-inventory/src/client/locales.ts @@ -20,6 +20,9 @@ export const zh = { active: '已挂载', failed: '挂载失败', unloading: '卸载中', + enable: '启用', + disable: '停用', + toggling: '切换中…', } satisfies Record /** Plugin inventory locale key union. */ @@ -45,4 +48,7 @@ export const en = { active: 'Mounted', failed: 'Mount failed', unloading: 'Unloading', + enable: 'Enable', + disable: 'Disable', + toggling: 'Toggling…', } satisfies Record