feat(plugin-inventory): flat plugin list with a default-open toggle guard
The plugin-list tab rendered one flat list of every Loader entry — no separate "system plugins" section — with each card showing its real enabled state and an enable/disable button (a required plugin shows only a read-only note). The enable/disable guard flipped from default-protect to default-open: only the small REQUIRED_PLUGINS core (entry tree, Remote RPC spine, session/agent spines) is protected from being disabled, so the shipped plugins are actually toggleable. Tests, host READMEs, and the enable-disable agent note track the new grouping and guard. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,35 @@ describe('PluginInventorySettingsTab', () => {
|
||||
expect(screen.queryByText(en.unobserved)).toBeNull()
|
||||
})
|
||||
|
||||
it('renders every plugin in one flat list, toggling by state and guarding required plugins', async () => {
|
||||
const grouped = {
|
||||
entries: [
|
||||
{ entryId: 'recog', moduleName: '@deepseek-ai/dsh-image-recognition', enabled: true, protected: false, fiberPhase: 'active' },
|
||||
{ entryId: 'recog-http', moduleName: '@deepseek-ai/dsh-image-recognition-http', enabled: false, protected: false, fiberPhase: null },
|
||||
{ entryId: 'hmr', moduleName: '@deepseek-ai/cordis-plugin-hmr', enabled: true, protected: true, fiberPhase: 'active' },
|
||||
],
|
||||
} as unknown as Snapshot
|
||||
render(<PluginInventorySettingsTab {...props(async () => grouped)} />)
|
||||
|
||||
// No separate system section: all three entries share one flat list.
|
||||
expect(screen.queryByText('System plugins')).toBeNull()
|
||||
expect((await screen.findByRole('searchbox', { name: en.search })).getAttribute('aria-label')).toBeTruthy()
|
||||
expect(screen.getAllByRole('listitem')).toHaveLength(3)
|
||||
|
||||
// A toggleable enabled plugin carries a disable button.
|
||||
fireEvent.click(screen.getByRole('button', { name: 'image-recognition, Mounted, Enabled' }))
|
||||
expect(screen.getByRole('button', { name: en.disable })).toBeTruthy()
|
||||
|
||||
// A toggleable disabled plugin carries an enable button.
|
||||
fireEvent.click(screen.getByRole('button', { name: 'image-recognition-http, Disabled' }))
|
||||
expect(screen.getByRole('button', { name: en.enable })).toBeTruthy()
|
||||
|
||||
// A required plugin shows the required note, never a toggle.
|
||||
fireEvent.click(screen.getByRole('button', { name: 'hmr, Mounted, Enabled' }))
|
||||
expect(screen.getByText(en.required)).toBeTruthy()
|
||||
expect(screen.queryByRole('button', { name: en.disable })).toBeNull()
|
||||
})
|
||||
|
||||
it('filters by module name or Loader entry id', async () => {
|
||||
render(<PluginInventorySettingsTab {...props(async () => SNAPSHOT)} />)
|
||||
const search = await screen.findByRole('searchbox', { name: en.search })
|
||||
|
||||
Reference in New Issue
Block a user