Problem/Motivation

layout_builder_lock is a popular module from Layout Builder ecosystem

We didn't work on such mechanism yet with the hope #3542276: Embedding a display in an other with a formatter will cover the need (by placing overridable displays as field formatters into non overridable displays), but talking with agencies the last weeks have shown the limit of the proposal: Layout Builder Lock is not only about overrides.

Layout Builder Lock:

  • At layout level, many settings:
    • Do not allow updating default blocks
    • Do not allow deleting default blocks
    • Do not allow moving default blocks
    • Do not allow adding new blocks
    • Do not allow configuring the section
    • Do not allow adding a new section before this section
    • Do not allow adding a new section after this section
    • Do not allow moving blocks into this section
  • At region level, only one setting by region: "Disallow block operations in following regions: Users won't be able to add, move, delete or add blocks in this region. This setting can also be applied in overridden layouts"
  • At block level: nothing

And then, those permissions:

  • Bypass lock settings on layout overrides
  • Manage lock settings on default display
  • Manage lock settings on overrides
  • Remove sections with lock settings

Proposal 1: Lock by source

The simpler solution:

  1. Add a MenuLock island plugin, triggering PUT /api/display-builder/{builder}/node/{node_id}/lock, with a label "Unlock" or "Lock" according to the source data. So the capacity to alter the lock status is according to the profile.
  2. Add a InstanceInterface::onLockSwitch(string $builder_id, string $instance_id) method to alter a boolean value in each slot (where? As a first level property alongside node_id, source and source_id ? As a third-party_settings? Missing value === unlocked.
  3. Add a ON_LOCK_SWITCH event and IslandEventSubscriberInterface::onLockSwitch(string $builder_id, string $instance_id): array method
  4. Implement this method in island where we show the locked/unlocked status
  5. Prevent any modification of a source locked or with locked source parent: Contextual panel is not loading or are read-only, Menu island are disabled, dropzone are disabled...

The lock status is a permanent part of the source data:

  • The lock status is kept when creating pattern presets, until someone is unlocking it
  • The lock status is kept when initiating entity overrides from entity view displays, until someone is unlockign it

Proposal 2: Lock by component slot

TODO

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

pdureau created an issue. See original summary.

pdureau’s picture

Status: Active » Needs work

Some work following Proposal 1 has been pushed. It may be an useful starting point.

pdureau’s picture

The work on #3561513: Provide a way to show styles with the introduction of ThirdPartySettingsInterface::getSummary() could be a good way of manage the lock indicator, and the opportunity to:

  • move to third_party_settings instead of having our own first level key which will be not managed by ui_patterns_field anyway
  • use InstanceInterface::setThirdPartySettings() instead of specific InstanceInterface::switchLock()
  • use ApiControllerInterface::thirdPartySettingsUpdate() instead of specific ApiControllerInterface::switchLock()
  • use DisplayBuilderEvents::ON_UPDATE instead of specific , or introduce something like DisplayBuilderEvents::ON_INVISIBLE_UPDATE for updates which are not updating the renderable like this one

Also, instead of a boolean, it would be better to have a ternary value:

  • locked
  • unlocked
  • neutral: following the locked or unlocked status of the closest ancestor
pdureau’s picture

The work on #3561513: Provide a way to show styles with the introduction of ThirdPartySettingsInterface::getSummary() could be a good way of manage the lock indicator, and the opportunity to:

  • move to third_party_settings instead of having our own first level key which will be not managed by ui_patterns_field anyway
  • use InstanceInterface::setThirdPartySettings() instead of specific InstanceInterface::switchLock()
  • use ApiControllerInterface::thirdPartySettingsUpdate() instead of specific ApiControllerInterface::switchLock()
  • use DisplayBuilderEvents::ON_UPDATE instead of specific , or introduce something like DisplayBuilderEvents::ON_INVISIBLE_UPDATE for updates which are not updating the renderable like this one

✅ Done. DisplayBuilderEvents::ON_INVISIBLE_UPDATE has not been added but the proposal is not discarded.

Also, instead of a boolean, it would be better to have a ternary value:

  • locked
  • unlocked
  • neutral: following the locked or unlocked status of the closest ancestor

✅ Done.

So we are nearly there. The remaining part is blocking actions.

There are 2 way of doing that:

  • the current work has started altering the UI. See :ThirdPartySettingsInterface::alterNodeRenderable() in https://git.drupalcode.org/issue/display_builder-3551232/-/blob/3551232-... It is not good because UI change from panel to panel (ex: BuilderPanel & LayerPanel) and we are not really "securing" the storage.
  • a better solution would be to leverage mechanisms which will be added to #3544026: Cardinality constraints for slots so we don't need to manipulate the UI ourselves.: a lock slot is a slot with a minimum, maximum and suggested equal to the current content. This may not be enough (how to prevent dragging out? for example), but it is a good way of doing most of the job as a start)
pdureau’s picture

Discussed in meeting with Jean. No mandatory for 1.0.0, but let's check we are not blocking it.