Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block transforms don't run for control panels #1868

Open
JeffersonBledsoe opened this issue Jan 24, 2025 · 2 comments · May be fixed by #1875
Open

Block transforms don't run for control panels #1868

JeffersonBledsoe opened this issue Jan 24, 2025 · 2 comments · May be fixed by #1875

Comments

@JeffersonBledsoe
Copy link
Member

JeffersonBledsoe commented Jan 24, 2025

NOTE

Need to do some more research, this might be a problem with my addon, will update as I go...

There doesn't seem to be an adapter for control panels, so if you try to use blocks in a control panel, the block transforms will never run, meaning we lose out on functionality like create a resolveuid link for links.

Steps to reproduce

  1. Create a control panel with blocks in it (e.g. enable https://github.com/pretagov/volto-slots-editor)
  2. Create a text block with a link in it
  3. Save the control panel
  4. View the data stored from the control panel

Expected result

The URL of the link has been changed to resolveuid

Actual result

The URL stays as the absolute URL created from the POST request.

Investigation

  • deserializer = queryMultiAdapter(
    (field, fake_context, self.request), IFieldDeserializer
    )
    should trigger the Blocks field deserialization handler
  • It does correctly trigger it, but iter_block_transform_handlers doesn't return the handlers correctly in the subscribers request in
    def iter_block_transform_handlers(context, block_value, interface):
    """Find valid handlers for a particular block transformation.
    Looks for adapters of the context and request to this interface.
    Then skips any that are disabled or don't match the block type,
    and returns the remaining handlers sorted by `order`.
    """
    block_type = block_value.get("@type", "")
    handlers = []
    for handler in subscribers((context, getRequest()), interface):
    if handler.block_type == block_type or handler.block_type is None:
    handler.blockid = id
    handlers.append(handler)
    for handler in sorted(handlers, key=lambda h: h.order):
    if not getattr(handler, "disabled", False):
    yield handler
  • Looks like the FakeDXContext doesn't get the subscriptions correctly. If I put a debugger in the subscription code above and swap the context passed in (i.e. the FakeDXContext) for a real object (e.g. with plone.api.portal.get() or an unrestrictedTraverse to a page) the subscribers are correctly found and triggered
@davisagli
Copy link
Member

@JeffersonBledsoe Er, what endpoint are you using to save and fetch the blocks? The transforms are done by a deserializer and serializer registered for the IBlocks behavior, so I wouldn't expect it to work outside the context of (de)serializing a content item with that behavior.

We probably do need to generalize it somehow -- @sneridagh was also recently wanting to store blocks in a different field on content items. But which endpoints need to support it and how should they know which parts of the data structure contain blocks that need to be processed?

@JeffersonBledsoe
Copy link
Member Author

@davisagli In this specific case I'm storing the blocks in the registry and using a custom widget to render the blocks form (multiple actually, but that's besides the point). A custom endpoint which essentially just returns this registry value is used outside of the control panel.

I've made some notes while investigating this in the issue description. The control panel deserialisation code has a FakeDXContext created which I thought would handle this correctly, but it looks like however the subscribers for the block handlers are registered doesn't work with this setup (apologies for the terminology, I don't with the ZCA this deeply very often). While I've tested adding IBlocks to the implementer list for the FakeDXContext fixes the subscriber issue, it not being a real DX object just causes further issues down the line (such as request, REQUEST and absolute_url being missing).

I agree it should be generalised so we can re-use the blocks in other ways more easily and appreciate it's hard problem to solve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants