Plugin group config in group requests#502
Draft
barborico wants to merge 11 commits into
Draft
Conversation
Store requester- and resolver-supplied app-group-lifecycle plugin config on the group request, mirroring the requested_/resolved_ pair used for every other field, so plugin config can be collected at request time and applied when the group is created on approval. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds requested_plugin_data to _AppGroupRequestBody (only app groups carry a lifecycle plugin) and GroupRequestDetail, and resolved_plugin_data to ResolveGroupRequestBody and GroupRequestDetail. Both fields default to empty dict / None to remain backwards-compatible with existing callers. Both Any and Optional were already imported; no import changes needed. Tests added for accept/default behavior on create and resolve bodies. The test inputs include requested_group_description to satisfy the REQUIRE_DESCRIPTIONS=true env constraint present in the test environment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uest
Adds requested_plugin_data as an optional kwarg to CreateGroupRequest.__init__
and threads it through to the GroupRequest constructor so the value is
written to the new DB column. Defaults to {} when not supplied, consistent
with the model-level default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reject app-group requests whose plugin group config is missing or invalid (400) by running the app's configured lifecycle plugin's group-config validation at request time, so a request can't be filed with config the plugin would reject. Thread requested_plugin_data into CreateGroupRequest and the response. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve resolved_plugin_data or requested_plugin_data, re-validate it against the resolved app's lifecycle plugin, and set it on the AppGroup before CreateGroup so the group_created hook runs against a configured group. Invalid config surfaces as a 400 via the PUT handler. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy resolved_plugin_data from the resolve body onto the group request before approval so a resolver's plugin-config edits are applied to the group that approval creates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add requested_plugin_data/resolved_plugin_data to GroupRequestDetail, requested_plugin_data to the app-group create body, and resolved_plugin_data to ResolveGroupRequestBody in the generated client. Hand-edited rather than via `npm run codegen`: the @openapi-codegen version resolved in this environment renames the paginated generics (PageTypeVarCustomized* -> PageTCustomized*) across the entire client, which would bury this change under hundreds of lines of unrelated churn. The drift-check workflow explicitly supports hand-editing the generated files; these additions match the spec the backend now emits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render AppGroupLifecyclePluginConfigurationForm for app-group requests whose app has a lifecycle plugin (fetching the app detail to read the plugin id, since search summaries omit it), and submit the collected config as requested_plugin_data. Adds DOM-free helpers with unit tests. Also fixes setupTests.ts to import @testing-library/jest-dom directly (the /extend-expect sub-path was removed in a newer version), which unblocked running vitest for DOM-free test files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Seed the resolve view with the requested plugin config, allow editing, and submit it as resolved_plugin_data on approval. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wrap a long mocker.patch.object line to the configured width and add explicit TypeAdapter[Any] annotations the TypeAdapter() calls so mypy no longer needs a var annotation. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Lets users supply (and resolvers edit) app-group-lifecycle plugin group config when requesting an app group, validates it at submit and approval, and applies it to the group created on approval so the plugin's
group_createdhook runs against a configured group.Urgency: 5 days
Expected review effort: MEDIUM
Motivation
App-group-lifecycle plugins can require per-group config (e.g. the Google Group plugin needs an email prefix + display name). Today that config is only collectable in the direct group-create/edit flow. When a user requests a group for such an app, there is nowhere to supply it, so approval creates the group unconfigured and the
group_createdhook runs against an empty config. This adds a generic "plugin-config-in-requests" capability (not specific to any one plugin).Description of Changes
GroupRequest—requested_plugin_dataandresolved_plugin_data— mirroring the existingrequested_*/resolved_*pairs and the sibling*_group_tagscolumns (JSONB on Postgres,server_default "{}"). Config is stored in the same shape as a group'splugin_data({plugin_id: {configuration: {...}}}); no status is stored (the hook populates that post-creation).requested_plugin_dataon the app-group create body; both fields onGroupRequestDetail;resolved_plugin_dataonResolveGroupRequestBody.CreateGroupRequestpersistsrequested_plugin_data; the POST router validates it against the app's plugin (400 on invalid/missing-required).ApproveGroupRequestresolvesresolved_plugin_data or requested_plugin_data, re-validates, and sets it on the newAppGroupbeforeCreateGroupruns, so thegroup_createdhook sees the configured group. Invalid config surfaces as a 400 via the PUT handler.resolved_plugin_datafrom the resolve body so a resolver can edit before approving.Create.tsxrenders the existingAppGroupLifecyclePluginConfigurationFormfor app-group requests whose app has a plugin (fetchingAppDetailviauseAppByIdsince search summaries omit the plugin id) and submitsrequested_plugin_data;Read.tsxlets the resolver edit and submitsresolved_plugin_data. Small DOM-free helpers (pluginConfig.ts) with unit tests.plugin_datafields were hand-added tosrc/api/apiSchemas.ts. A fullnpm run codegenin this environment renames the paginated generics (PageTypeVarCustomized*→PageTCustomized*) across the entire client, which would bury this change under hundreds of unrelated lines; the drift-check workflow sanctions hand-editing the generated files.src/setupTests.ts(jest-dom v6 dropped the/extend-expectsubpath), which is required for the frontend test suite to run.Validation of Changes
tests/test_group_request_plugin_config.pycovers column defaults/round-trip, schema parsing,CreateGroupRequestpersistence, POST 400-on-invalid + 201-on-valid, approval applying resolved-over-requested onto the created group (asserting thegroup_createdhook fired against it) + fallback-to-requested, and the PUT resolve path end-to-end. Full relevant suite: 134 passed (test_group_request,test_group_request_plugin_config,test_app_group_lifecycle_plugin,test_request_models).npx tsc --noEmitclean;pluginConfig.test.ts5/5.Read.tsxpre-fills with the requester's submitted config (the form seeds via uncontrolleddefaultValue).Guidance for Reviewers
Review commit-by-commit — the history is linear and each commit is one logical layer (model → migration → schemas → create op → POST validation → approve op → PUT → client → Create form → Read form). Most worth a look:
ApproveGroupRequestsettingnew_group.plugin_databeforeCreateGroup.execute()(so the hook sees it), and the hand-edited TS client (see the codegen-churn rationale in that commit).🤖 Generated with Claude Code