Feat/plugin instance actions (#2209)

* feat(shared): scope plugin action descriptors

* feat(plugin-sdk): instance-scoped settings actions

* feat(plugins): run instance-scoped actions from the admin settings dialog

* feat(admin): instance-scoped plugin actions in the settings dialog

* fix(plugins): surface instance actions without instance fields and harden the action gate

* docs(plugin-sdk): note that hosts before 4.2.0 ignore action scope

* fix(admin): open the dialog for instance actions, explain inactive 404s, guard the save window

* docs(wiki): plugin pages for instance actions and the admin panel changes
This commit is contained in:
jubnl
2026-09-02 23:06:03 +02:00
committed by GitHub
parent b1ce7c303d
commit b82962f95b
59 changed files with 1133 additions and 128 deletions
@@ -79,6 +79,9 @@ export interface PluginListItem {
/** How many `scope:'instance'` settings fields the plugin declares — gates the admin
* settings menu item without a per-plugin fetch. */
instanceSettingsCount: number;
/** How many `scope:'instance'` actions the plugin declares — gates the admin settings
* menu item together with instanceSettingsCount (a plugin can have actions and no fields). */
instanceActionsCount: number;
/** Declared dependencies (parsed) — required addons + plugin deps. */
dependencies: PluginDependencies;
/** Whether this plugin can currently activate, and why not if it can't. */
@@ -136,6 +139,16 @@ export class PluginsService {
}
}
private instanceActionsCount(id: string): number {
try {
return (
this.db.prepare("SELECT COUNT(*) AS n FROM plugin_actions WHERE plugin_id = ? AND scope = 'instance'").get(id) as { n: number }
).n;
} catch {
return 0; // table absent (a slimmed test app)
}
}
list(): { enabled: boolean; devLink: boolean; plugins: PluginListItem[] } {
const rows = this.db
.prepare(
@@ -178,6 +191,7 @@ export class PluginsService {
operatorEgress: _oe === 1,
egressHostCount: this.egressHostCount(r.id),
instanceSettingsCount: this.instanceSettingsCount(r.id),
instanceActionsCount: this.instanceActionsCount(r.id),
dependencies: deps,
dependencyStatus,
trekRange: trek_range,