@controlpanels/content-rules/<rule>/action/<idx> omits values for fields in non-default fieldsets
@ericof is already working on this.
Since Apr 24, 2026.
- Dominant language
- Python
- Stars
- 109
- Forks
- 107
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 4
Description
Summary
GET @controlpanels/content-rules/<rule-id>/action/<idx> (and .../condition/<idx>) returns values for only the fields in the default fieldset of the action/condition schema. Fields declared inside non-default fieldset(...) directives appear in @schema but have no corresponding key/value in the response payload, which makes the endpoint unusable for any rule element that groups its fields into tabs.
The same bug affects the update path for the same reason: view.form_instance.applyChanges(data) only applies fields that z3c.form's default-fieldset Fields knows about.
Environment
- plone.restapi 9.15.4
- Plone 6.x, Python 3.13
- Reproduces against any rule action/condition whose schema uses
plone.supermodel.directives.fieldset— e.g.collective/sc.contentrules.groupbydate≥ 3.0.
Root cause
plone/restapi/controlpanels/rules.py, in ContentRulesControlpanel.get():
if view:
view.form_instance.update()
for field in view.form_instance.fields:
fields[field] = getattr(extra_ob, field)
schema = view.form.schema
fields["@schema"] = rule_schema_as_json(schema, self.request)
return fields
view.form_instance.fields is the z3c.form Fields object populated by plone.autoform.form.AutoExtensibleForm.updateFieldsFromSchemata(). That method puts only default-fieldset fields on form_instance.fields; fields declared inside fieldset("...", fields=[...]) directives end up on form_instance.groups[i].fields and are never visited by this loop.
rule_schema_as_json(schema, ...) on the next line walks zope.schema directly, so @schema correctly lists all fields — which is exactly why the mismatch between @schema and the emitted values is so visible to API consumers.
ContentRulesControlpanel.update() suffers the same issue: view.form_instance.applyChanges(data) is bounded by the same default-fieldset Fields, so PATCHing values into non-default-fieldset fields is silently dropped.
Reproduction
-
Install any rule action whose schema uses fieldsets. Minimal example:
from plone.autoform import directives from plone.supermodel.directives import fieldset from zope import schema from zope.interface import Interface class IMyAction(Interface): base_container = schema.TextLine(title="Base", required=True) fieldset( "advanced", label="Advanced", fields=["extra_title", "extra_description"], ) extra_title = schema.TextLine(title="Extra title", default="hello") extra_description = schema.TextLine(title="Extra description", default="world") -
Create a rule that uses this action, populate it.
-
GET /@controlpanels/content-rules/<rule-id>/action/0
Observed: response contains @id, @schema (with all three fields), base_container, but no extra_title / extra_description.
Expected: response should include a value for every field listed under @schema.properties.
Proposed fix
Walk the schema directly rather than iterating form_instance.fields. Two equivalent shapes:
Option A — reuse rule_schema_as_json output
if view:
view.form_instance.update()
schema_json = rule_schema_as_json(view.form.schema, self.request)
fields["@schema"] = schema_json
for name in schema_json.get("properties", {}):
fields[name] = getattr(extra_ob, name, None)
return fields
Option B — iterate the zope.schema interface directly
from zope.schema import getFieldsInOrder
if view:
view.form_instance.update()
for name, _field in getFieldsInOrder(view.form.schema):
fields[name] = getattr(extra_ob, name, None)
fields["@schema"] = rule_schema_as_json(view.form.schema, self.request)
return fields
getattr(..., None) is deliberate: rule action/condition classes commonly use class-level defaults and never write unchanged attributes to __dict__, so getattr with a fallback preserves current behavior while staying safe for classes that simply don't declare a given attribute.
update() should be similarly reworked to set attributes via schema iteration (or apply changes per-group via form.applyChanges on each of form_instance.groups).
Impact
Any third-party rule action/condition that organizes its UI with fieldset() (the idiomatic Plone way) is effectively invisible on the REST control panel. Fixing this is backward-compatible: existing default-fieldset-only schemas keep working unchanged, and consumers gain the values that @schema has been advertising all along.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.