feat(plugin-inventory): group by enabled state and allow re-enabling disabled plugins

The plugin-list tab now splits by current state: disabled plugins sit in the
main list with an enable button (so a bundle-default-disabled plugin can be
re-enabled), while enabled plugins sit in the collapsible system section —
a user-added enabled plugin keeps a disable toggle, a required one shows
none. setEnabled refuses to disable a required plugin but allows re-enabling
a disabled one, verifying the fiber activates and reverting a
dependency-missing enable.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-14 14:30:13 +08:00
parent d385b7cf05
commit cbec8cd6a9
7 changed files with 46 additions and 24 deletions
@@ -98,10 +98,11 @@ export function PluginInventorySettingsTab({ list, setEnabled, t }: PluginInvent
: [],
[normalizedQuery, state],
)
// User-added (opt-in bundle) plugins are toggleable; the rest are required
// system plugins shown in a separate collapsible section without toggles.
const userEntries = filteredEntries.filter(entry => !entry.protected)
const systemEntries = filteredEntries.filter(entry => entry.protected)
// Disabled plugins sit in the main list with an enable toggle so they can be
// re-enabled; enabled plugins are grouped into a collapsible system section
// (a user-added enabled plugin still carries a disable toggle).
const userEntries = filteredEntries.filter(entry => !entry.enabled)
const systemEntries = filteredEntries.filter(entry => entry.enabled)
useEffect(() => {
if (expanded !== null && !filteredEntries.some(entry => entry.entryId === expanded)) {
@@ -170,7 +171,17 @@ export function PluginInventorySettingsTab({ list, setEnabled, t }: PluginInvent
</div>
) : null}
</dl>
{entry.protected ? (
{!entry.enabled ? (
<button
className={css.toggle}
type="button"
disabled={busy === entry.entryId}
aria-busy={busy === entry.entryId || undefined}
onClick={() => { toggle(entry.entryId, true) }}
>
{busy === entry.entryId ? t('toggling') : t('enable')}
</button>
) : entry.protected ? (
<p className={css.required}>{t('required')}</p>
) : (
<button
@@ -178,9 +189,9 @@ export function PluginInventorySettingsTab({ list, setEnabled, t }: PluginInvent
type="button"
disabled={busy === entry.entryId}
aria-busy={busy === entry.entryId || undefined}
onClick={() => { toggle(entry.entryId, !entry.enabled) }}
onClick={() => { toggle(entry.entryId, false) }}
>
{busy === entry.entryId ? t('toggling') : entry.enabled ? t('disable') : t('enable')}
{busy === entry.entryId ? t('toggling') : t('disable')}
</button>
)}
</div>