[7418] plugin - serializers/retrievers/validators - #8882
Conversation
WalkthroughFE2 control plugins now support value retrieval, serialization, and validation hooks. Forms Engine preloads referenced plugins before form initialization. The controls host exposes hook lookups and ChangesFE2 control plugin lifecycle
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Plugin
participant registerPlugin
participant ControlRegistry
participant FormsEngine
participant PluginLoader
Plugin->>registerPlugin: provide control hooks
registerPlugin->>ControlRegistry: register contribution
FormsEngine->>PluginLoader: preload plugins for form fields
PluginLoader-->>FormsEngine: resolve loaded plugins
FormsEngine->>ControlRegistry: resolve retriever, serializer, or validator
ControlRegistry-->>FormsEngine: return registered hook
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@studio-ui/docs/type-builder-forms-engine.md`:
- Around line 667-670: Synchronize the Progress and Open decisions sections in
the Forms Engine documentation with the completed control cleanup: remove or
mark resolved the entries for retired IDs link-input, link-textarea,
linked-dropdown and the remapped disabled/internal-name aliases, ensuring no
unresolved null-map-slot item remains.
In `@studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx`:
- Around line 539-543: In
studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx:539-543, update the
preload promise handling around initCreateForm to set the preparation error and
prevent initCreateForm from running when preloadControlPluginsForFields fails.
Apply the same behavior in
studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx:586-621: set the
preparation error and do not call createParsedValuesObject after preload
failure; retain the existing success paths.
- Around line 539-546: Update the embedded-component initialization flow around
prepareEmbeddedItemForm and invokePrepareFn so the embedded content type’s
fields are preloaded before invokePrepareFn parses or validates values. Reuse
the existing preloadControlPluginsForFields mechanism, awaiting or chaining it
before invokePrepareFn, while preserving the current parent-field preload and
initCreateForm behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 98e61389-0047-4be3-bb0d-ac26f0c1ae00
📒 Files selected for processing (14)
studio-ui/docs/type-builder-forms-engine-plugins.mdstudio-ui/docs/type-builder-forms-engine.mdstudio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsxstudio-ui/ui/app/src/components/FormsEngine/components/TableOfContents.tsxstudio-ui/ui/app/src/components/FormsEngine/controls/registry.tsstudio-ui/ui/app/src/components/FormsEngine/dataSources/host.tsstudio-ui/ui/app/src/components/FormsEngine/lib/controlPluginLoader.tsstudio-ui/ui/app/src/components/FormsEngine/lib/controlValueTypes.tsstudio-ui/ui/app/src/components/FormsEngine/lib/rteUtils.tsstudio-ui/ui/app/src/components/FormsEngine/lib/validators.tsstudio-ui/ui/app/src/components/FormsEngine/lib/valueRetrievers.tsstudio-ui/ui/app/src/components/FormsEngine/lib/valueSerializers.tsstudio-ui/ui/app/src/models/PluginDescriptor.tsstudio-ui/ui/app/src/services/plugin.ts
| - **2026-08-07** — Expose `FormsEngineField` on `craftercms.formsEngine.controls`. Plugin controls render bare (built-ins wrap themselves), so a failing plugin validator previously showed only in the ToC; wrapping in the host field chrome restores parity (label, invalid styling, validity messages). | ||
| - **2026-08-07** — Plugin control validators: optional `ControlPluginContribution.validator` installed by `registerPlugin`; `getFieldValidator` / `hasFieldValidator` fall back after built-in `validatorsMap`; host `getValidator`; sample rejects angle brackets. Same preload path as IO hooks. | ||
| - **2026-08-07** — Plugin control IO hooks: `ControlPluginContribution.valueRetriever` / `valueSerializer` installed by `registerPlugin`, looked up after built-in maps in `valueRetrievers` / `valueSerializers`. Form bootstrap + save preload plugin locators via `preloadControlPluginsForFields` so hooks exist before parse/serialize. Host: `craftercms.formsEngine.controls.getValueRetriever` / `getValueSerializer`. Sample updated. | ||
| - **2026-08-06** — Controls cleanup (`7418`): retired unused `link-input` / `link-textarea` / `linked-dropdown` from FE2 maps + TB descriptors. Closed the former “non-rendering control-map entries” open item: those three are removed; `disabled` / `internal-name` remain TB catalog ids that remap on insert via `systemFieldsTypesMap` to `checkbox` / `input` (locked field ids). Documented under completed design decisions. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Synchronize the retired control entries with Open decisions.
Line 670 says link-input, link-textarea, and linked-dropdown were removed. It also says the former open item is closed. Line 654 still lists retired IDs and remapped aliases as unresolved. Update Line 654, or remove the entry if no null map slots remain, so the document has one completion status.
Proposed documentation fix
- - [ ] **Non-rendering control-map entries** — `disabled`, `internal-name`, `link-input`, `link-textarea` (and any other null map slots) need real FE2 controls or an explicit retire/alias decision.
+ - [ ] **Non-rendering control-map entries** — audit only remaining null map slots; `disabled` and `internal-name` remap on insertion, while `link-input`, `link-textarea`, and `linked-dropdown` are retired.As per path instructions, update the Progress and Open decisions sections in studio-ui/docs/type-builder-forms-engine.md in the same effort.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@studio-ui/docs/type-builder-forms-engine.md` around lines 667 - 670,
Synchronize the Progress and Open decisions sections in the Forms Engine
documentation with the completed control cleanup: remove or mark resolved the
entries for retired IDs link-input, link-textarea, linked-dropdown and the
remapped disabled/internal-name aliases, ensuring no unresolved null-map-slot
item remains.
Source: Coding guidelines
| preloadControlPluginsForFields(siteId, contentType.fields) | ||
| .catch((error) => { | ||
| console.error('Failed to preload control plugins before create-form value parse.', error); | ||
| }) | ||
| .then(initCreateForm); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Stop form initialization when control-plugin preload fails.
Both paths catch the preload rejection and then parse values without plugin hooks. This can load or save plugin field data with incorrect conversions.
studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx#L539-L543: set a preparation error and do not callinitCreateFormafter preload failure.studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx#L586-L621: set a preparation error and do not callcreateParsedValuesObjectafter preload failure.
📍 Affects 1 file
studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx#L539-L543(this comment)studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx#L586-L621
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx` around lines 539
- 543, In studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx:539-543,
update the preload promise handling around initCreateForm to set the preparation
error and prevent initCreateForm from running when
preloadControlPluginsForFields fails. Apply the same behavior in
studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx:586-621: set the
preparation error and do not call createParsedValuesObject after preload
failure; retain the existing success paths.
| preloadControlPluginsForFields(siteId, contentType.fields) | ||
| .catch((error) => { | ||
| console.error('Failed to preload control plugins before create-form value parse.', error); | ||
| }) | ||
| .then(initCreateForm); | ||
| return () => { | ||
| disposed = true; | ||
| }; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Preload plugins for embedded child forms.
The embedded-component branch at Lines 443-478 calls prepareEmbeddedItemForm before either preload path runs. If that component content type uses a plugin control that is not also present in the parent field tree, its hooks are unavailable during value parsing and validation.
Preload the embedded content type fields before invokePrepareFn parses them.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@studio-ui/ui/app/src/components/FormsEngine/FormsEngine.tsx` around lines 539
- 546, Update the embedded-component initialization flow around
prepareEmbeddedItemForm and invokePrepareFn so the embedded content type’s
fields are preloaded before invokePrepareFn parses or validates values. Reuse
the existing preloadControlPluginsForFields mechanism, awaiting or chaining it
before invokePrepareFn, while preserving the current parent-field preload and
initCreateForm behavior.
#7418
Summary by CodeRabbit