feat(plugins): per-session activation + config UI (dashboard) - #445
Merged
Conversation
Surfaces the two per-session backends that shipped without UI (#438 activation, #441 per-session config) in a tabbed plugin config modal. - API client: Plugin type gains sessionScoped/activeSessions/sessionConfig; setSessions (PUT /plugins/:id/sessions) + updateSessionConfig (PUT /plugins/:id/config/:sessionId). - Config modal: session-scoped non-engine plugins get [Configuration] [Sessions] tabs. Configuration is unchanged. Sessions has: - Activation: All sessions vs a chosen set -> setSessions. - Per-session config override (when the plugin has a configSchema/configUi): a session picker -> the B-lite form (seeded from the resolved slice) or the sandboxed iframe (sessionId passed to the bridge). Save writes only non-secret keys that differ from base + all secret keys (sparse override: untouched keys inherit Global; the backend restores untouched secrets), so editing Global still propagates to a session's unchanged fields. Clear override resets to Global. - i18n: 13 new keys across all 9 locales (parity gate passes). CSS for tabs + Sessions sections. Dashboard-only; all backend APIs pre-existed. Build (tsc) + lint + i18n parity green.
… live modal state) Adversarial review of the per-session dashboard UI found 7 issues; fixes: - HIGH: resolvePluginConfig now DEEP-merges the override over the base (was shallow). A sparse override (e.g. an object whose nested secret the operator didn't touch) no longer drops the base's untouched nested keys at runtime; arrays/scalars still replace. (+unit tests for nested merge + array replace.) - The per-session override save is centralized in sparseSessionOverride(): only non-secret keys that differ from base, plus all secret keys; an untouched optional field with no Global value no longer creates a spurious empty override. Used by BOTH the B-lite form and the iframe per-session save (the iframe path was writing every resolved key as an override). - The config modal derives the open plugin from the LIVE plugins query instead of an open-time snapshot, so the Sessions tab reflects fresh activeSessions/sessionConfig after a save + invalidate. - The per-session form renders the localized schema (labels/descriptions), matching the Configuration tab. Backend tsc + 1231 jest; dashboard build + lint + i18n parity green.
…d refetch configPlugin is derived from the live query, so the plugin prop gets a new reference on every refetch (refetchOnWindowFocus). Key the override-seed effect on [selSession, plugin.id] instead of the plugin object so it reseeds only when the selected session/plugin changes — a window-focus refetch mid-edit no longer clobbers the operator's unsaved override.
…f-rows secret caveat) Re-review noted the docstring overstated the 'untouched secret inherits' promise: it holds for top-level + object-nested secrets, but NOT a secret column inside an array-of-rows (arrays replace wholesale on resolve; the redacted dashboard can't resend untouched rows' real secrets). Documented the limitation; no bundled plugin ships that shape. Comment-only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Completes the v0.7 per-session story in the dashboard — surfaces the two backends that shipped without UI (#438 activation, #441 per-session config) in a tabbed plugin config modal.
PlugingainssessionScoped/activeSessions/sessionConfig;setSessions+updateSessionConfig.PUT /plugins/:id/sessions.configSchema/configUi): pick a session → edit via the B-lite form (seeded from the resolved slice) or the sandboxed iframe (sessionIdto the bridge). Clear override resets to Global.Dashboard + one backend correctness fix; design spec in
docs/superpowers/specs/.Review (adversarial, 2 dimensions → verified)
Found 7 issues — all fixed:
resolvePluginConfignow deep-merges (was shallow), so a sparse override can't drop an untouched nested base key (e.g. a nested secret) at runtime; arrays/scalars still replace (+unit tests).sparseSessionOverride(): only non-secret keys differing from base + all secret keys; no spurious empty override for untouched optional fields; used by both the B-lite form and the iframe path.[]= none).Testing
Backend
tsc+ 1231 jest (deep-merge resolver tests + per-session + worker integration); dashboardbuild(tsc) + lint + i18n parity (556 keys × 9). No dashboard jest (project convention).Sandboxed-iframe per-session is included; the secret round-trip stays server-side (
restoreSecretConfig).