VAPP-17: Plugin management: add, install, enable/disable, remove, reload #30

Merged
David merged 2 commits from feat/plugin-management-vapp-17 into main 2026-06-07 21:10:43 +02:00
Owner

What

Wires the Plugins page to vervain-server's plugin lifecycle over the control channel, replacing the read-only page whose enable/disable control was a dead href="#" link and whose Plugin.enabled was hardcoded true.

Changes

  • Model: replace the boolean Plugin.enabled with a status string (added / installed / disabled). list_plugins surfaces the real per-plugin status from the updatePluginList reply, falling back to unknown when the field is absent.
  • Server fns (admin-only, control channel, ack-checked): add_plugin(manifest_url), install_plugin(name), disable_plugin(name), reload_plugin(name), remove_plugin(name). Each maps a non-ok ack result (missing rights, bad name) to an inline error. install_plugin awaits the server's actual ack envelope, which comes back as for: "addplugin" with result: "ok:<name>" rather than the generic for: "installplugin" / bare ok.
  • UI (rebuilt from the meshes-page patterns): a "+ Add plugin" header button opening a manifest-URL dialog; per-row actions driven by status (added/disabled show install + remove, installed shows disable + reload, unknown shows all); a confirm dialog before remove; a real status badge; inline server errors (including the admin-only timeout) in place of the dead anchor.

Known server gap

The server's updatePluginList reply is sourced from the on-disk plugin catalog (plugin_catalog.rs::manifests()) and omits the lifecycle status written to the plugin/<name> docs, so status currently renders as unknown and rows offer every action. The frontend is ready for the real status; exposing it (and the installplugin ack-envelope mismatch) is tracked in a vervain-server issue. This is the contingency the VAPP-17 spec anticipated.

Acceptance criteria

  • Plugin rows show the real status (added / installed / disabled), not a hardcoded "on" (renders unknown until the server exposes status)
  • "+ Add plugin" accepts a manifest URL and refreshes the list
  • Install, disable, reload, and remove actions are wired per status and refresh the list on success
  • Remove asks for confirmation before deleting
  • Server-side errors (including non-admin access) surface inline rather than as dead controls
  • just check passes

Closes VAPP-17.

🤖 Generated with Claude Code

## What Wires the Plugins page to vervain-server's plugin lifecycle over the control channel, replacing the read-only page whose enable/disable control was a dead `href="#"` link and whose `Plugin.enabled` was hardcoded `true`. ## Changes - Model: replace the boolean `Plugin.enabled` with a `status` string (`added` / `installed` / `disabled`). `list_plugins` surfaces the real per-plugin status from the `updatePluginList` reply, falling back to `unknown` when the field is absent. - Server fns (admin-only, control channel, ack-checked): `add_plugin(manifest_url)`, `install_plugin(name)`, `disable_plugin(name)`, `reload_plugin(name)`, `remove_plugin(name)`. Each maps a non-`ok` ack result (missing rights, bad name) to an inline error. `install_plugin` awaits the server's actual ack envelope, which comes back as `for: "addplugin"` with `result: "ok:<name>"` rather than the generic `for: "installplugin"` / bare `ok`. - UI (rebuilt from the meshes-page patterns): a "+ Add plugin" header button opening a manifest-URL dialog; per-row actions driven by status (added/disabled show install + remove, installed shows disable + reload, unknown shows all); a confirm dialog before remove; a real status badge; inline server errors (including the admin-only timeout) in place of the dead anchor. ## Known server gap The server's `updatePluginList` reply is sourced from the on-disk plugin catalog (`plugin_catalog.rs::manifests()`) and omits the lifecycle `status` written to the `plugin/<name>` docs, so status currently renders as `unknown` and rows offer every action. The frontend is ready for the real status; exposing it (and the `installplugin` ack-envelope mismatch) is tracked in a vervain-server issue. This is the contingency the VAPP-17 spec anticipated. ## Acceptance criteria - [x] Plugin rows show the real status (added / installed / disabled), not a hardcoded "on" (renders `unknown` until the server exposes status) - [x] "+ Add plugin" accepts a manifest URL and refreshes the list - [x] Install, disable, reload, and remove actions are wired per status and refresh the list on success - [x] Remove asks for confirmation before deleting - [x] Server-side errors (including non-admin access) surface inline rather than as dead controls - [x] `just check` passes Closes VAPP-17. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(plugins): manage full plugin lifecycle from the Plugins page
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 56s
80ae541bce
The Plugins page was read-only: the per-row enable/disable control was a dead `href="#"` link and `Plugin.enabled` was hardcoded `true`, ignoring any server status. This wires the page to vervain-server's plugin lifecycle over the control channel.

Replace the boolean `Plugin.enabled` with a `status` string (`added` / `installed` / `disabled`). `list_plugins` surfaces the real per-plugin status from the `updatePluginList` reply, falling back to `unknown` when the field is absent so the row still offers every action.

Add admin-only control-channel server fns mirroring the server dispatch: `add_plugin(manifest_url)` (`addplugin`), `install_plugin(name)` (`installplugin`), `disable_plugin(name)` (`disableplugin`), `reload_plugin(name)` (`reloadplugin`), `remove_plugin(name)` (`removeplugin`). Each is ack-checked so a non-`ok` result (missing rights, bad name) surfaces inline. `install_plugin` awaits the server's actual ack envelope, which comes back as `for: "addplugin"` with `result: "ok:<name>"` rather than the generic `for: "installplugin"` / bare `ok`.

Rebuild the UI from the meshes-page patterns: a "+ Add plugin" header button opening a manifest-URL dialog, per-row actions driven by status (added/disabled -> install, remove; installed -> disable, reload; unknown -> all), a confirm dialog before remove, a real status badge, and inline server errors (including the admin-only timeout) in place of the dead anchor.

The server's `updatePluginList` reply is sourced from the on-disk plugin catalog and omits the lifecycle `status`, so status renders as `unknown` for now; tracked in a vervain-server issue.

#VAPP-17

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge remote-tracking branch 'origin/main' into feat/plugin-management-vapp-17
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 1m3s
Create release / Create release from merged PR (pull_request) Has been skipped
5e56fae8c5
# Conflicts:
#	src/server_fns/mod.rs
David merged commit c919e56d7e into main 2026-06-07 21:10:43 +02:00
David deleted branch feat/plugin-management-vapp-17 2026-06-07 21:10:43 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-apps!30
No description provided.