Problem/Motivation

Layout Builder misbehaves with new extra fields. New pseudo-fields cannot be removed, InvalidArgumentException thrown

Steps to reproduce

  1. Do a standard site install
  2. Enable Layout Builder
  3. Set Article content type to "Use Layout Builder" by checking the box on Manage Display and saving.
  4. Enable a module that adds a visible extra field. For example this sandbox project: Extra Field Example
  5. Clear cache
  6. Go to manage the Layout at /admin/structure/types/manage/article/display/default/layout
  7. Attempt to remove the new extra field block by using the contextually link
  8. See the ajax operation fail with a InvalidArgumentException: Invalid UUID in Drupal\layout_builder\Section->getComponent() (line 177 of web/core/modules/layout_builder/src/Section.php).

Proposed resolution

Current work-around is to first save the layout with the new field present. I suppose that generates a UUID for that new pseudo-field. Edit the layout again and you can remove the field.

A real fix would involve getting the section storage into the tempstore more quickly. In 9.1.x that happens in the PrepareLayout EventSubscriber. Prior to 9.1.x, that would happen in the prepareLayout function in Drupal\layout_builder\Element\LayoutBuilder.

Remaining tasks

The current patch does not address 9.0.x or 8.9.x. Those may be out of scope, depending on how "major" this bug is considered.

User interface changes

None

API changes

None

Data model changes

None

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

chrisolof created an issue. See original summary.

cilefen’s picture

Priority: Minor » Major

Exceptions that can be easily thrown by UI actions are major priority.

Sivaji_Ganesh_Jojodae’s picture

If you can attach an example module with hook_entity_extra_field_info() and hook_entity_view() it would be handy to test the issue.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

danflanagan8’s picture

I was able to reproduce following the steps in the description. I did a Standard site install. Then I set the default view mode of Article content type to display with Layout Builder.

Then I added the code below to the core telephone module for convenience, enabled telephone, and cleared cache. I went to the Article layout and tried to remove the Test Pseudofield. I saw the same error in the console relating to invalid UUID.

/**
 * Implements hook_entity_extra_field_info().
 */
function telephone_entity_extra_field_info() {
  $extra = array();

  $extra['node']['article']['display']['test_pseudo_field'] = array(
    'label' => t('Test Pseudofield'),
    'description' => t('This is a test pseudo-field'),
    'weight' => 100,
    'visible' => TRUE,
  );

  return $extra;
}

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function telephone_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if ($display->getComponent('test_pseudo_field')) {
    $build['test_pseudo_field'] = [
      '#type' => 'markup',
      '#markup' => 'This is a test pseudo-field',
    ];
  }
}
tim.plunkett’s picture

Version: 8.9.x-dev » 9.1.x-dev
Priority: Major » Normal
Issue tags: +Needs tests

Great, thanks for that. I was able to reproduce.
In the short-term, here's the very silly workaround:

Once you save the layout (including the extra field), you can then remove it.

It's only during the time that it is *not yet saved* that this can break.
Which is because it is being dynamically added in \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::setComponent(), with a fresh call to \Drupal::service('uuid')->generate()/code> on every page.
Which means the UUID is one thing when the UI is printed (with the link to remove or configure), and another UUID by the time the form is loaded to remove/configure it.

This is still a very annoying bug (and an embarrassing one as the person who wrote the code) but since it has a straightforward workaround I'm downgrading to major.

The next step is to write tests that expose the bug.

danflanagan8’s picture

Here's a patch that adds a new test to LayoutBuilderUiTest (FunctionalJavascript) that covers this issue. The new test is called testNewExtraFieldRemoval().

This function includes a couple of commented lines that recreate the current workaround. Uncommenting these lines results in the test passing. Not sure if that will help us, but it's in there.

tim.plunkett’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 7: 3144010--7--FAIL.patch, failed testing. View results

danflanagan8’s picture

Status: Needs work » Needs review
Related issues: +#3069578: Layout builder doesn't show new "extra fields"
FileSize
4.35 KB

I *think* this patch does the trick. Fingers crossed on the tests. This patch also resolves #3069578: Layout builder doesn't show new "extra fields" I think, which I've added as a related issue. I cross posted the patch so it gets visibility there.

I'm not great at git so here's a copy/past interdiff!

diff --git a/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php b/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
index b68092ce83..74cced9c2b 100644
--- a/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
+++ b/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
@@ -76,8 +76,8 @@ public function onPrepareLayout(PrepareLayoutEvent $event) {
       foreach ($sections as $section) {
         $section_storage->appendSection($section);
       }
-      $this->layoutTempstoreRepository->set($section_storage);
     }
+    $this->layoutTempstoreRepository->set($section_storage);
   }
 
 }
danflanagan8’s picture

Yes! It passed! The "idea" of the patch is that it looks like we need to get the section storage into the tempstore as soon as possible.

I noticed that to work around the bug you don't even need to save the layout, which is the workaround described in the issue summary. It's sufficient to do any action on the form that results in the section storage getting added to tempstore, like moving any block or removing any block. After taking such an action you can do whatever you want with the buggy extra field block.

samiullah’s picture

Looks good
If further code review is not needed, this can be moved to RTBC

tim.plunkett’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests +Blocks-Layouts

I'm closing #3069578: Layout builder doesn't show new "extra fields" as a duplicate, because this issue is further along. It's still not 100% clear to me why this change fixes the bug from the other issue, but it does... And it is clear why it fixes this one.

  1. +++ b/core/modules/layout_builder/src/EventSubscriber/PrepareLayout.php
    @@ -76,8 +76,8 @@ public function onPrepareLayout(PrepareLayoutEvent $event) {
    -      $this->layoutTempstoreRepository->set($section_storage);
         }
    +    $this->layoutTempstoreRepository->set($section_storage);
    

    Can't see from the patch context, but this means an extra set() even when it's already there.

    Currently we have an if/elseif, and no else. The if case does not need this set(), but the elseif and unwritten else case do.

    Let's switch to only having an if/else, make the current elseif a standalone if inside the else, and have the set() call at the end of that else. (hope that makes sense)
    Also add an inline comment explaining that we're adding it to tempstore regardless of what the storage is.

  2. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
    @@ -240,6 +240,31 @@ public function testAddHighlights() {
    +    drupal_flush_all_caches();
    

    Replace this with the actual cache needing clearing:
    \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();

  3. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
    @@ -240,6 +240,31 @@ public function testAddHighlights() {
    +    // Uncomment next two lines to make test pass, workaround for #3144010.
    +    // $this->drupalGet(static::FIELD_UI_PREFIX . '/display/default/layout');
    +    // $page->pressButton('Save layout');
    +
    

    Let's remove this

  4. +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
    @@ -240,6 +240,31 @@ public function testAddHighlights() {
    +    $this->clickContextualLink('.block-extra-field-blocknodebundle-with-section-fieldlayout-builder-extrafield-test', 'Remove block');
    +    $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas'));
    +    $assert_session->assertWaitOnAjaxRequest();
    +    $assert_session->pageTextContains('Are you sure you want to remove');
    

    Might as well finish removing it, just to prove the whole process works

danflanagan8’s picture

Thanks @tim.plunkett. All those notes look good. I have some free time now so I can make those changes.

Regarding #3069578: Layout builder doesn't show new "extra fields", do you think we should include a test addressing that specific situation? It would be easy enough to add a second extra field that has visible => FALSE. It wouldn't even have to be a whole new function. It could just be a few lines added to the test we're already working on here.

tim.plunkett’s picture

Yes please!
And can you expand the issue summary here to include that?
Thanks

sorlov’s picture

I have tried to check issue from https://www.drupal.org/project/drupal/issues/3069578 with patch #10, but have no success.

Extra field with visible => FALSE is not shown in LB.

Same problem, if you have visible => TRUE, but then disable layout_builder, move the extra_field to "Disabled" and then re-enable layout_builder.

While patch #21 from original issue solves the problem, so I'm not sure that it should be closed as duplicate.

danflanagan8’s picture

You're right, @sorlov. I'll re-open that issue (#3069578: Layout builder doesn't show new "extra fields") and comment there.

Thanks for testing. Sorry for the confusion I caused!

danflanagan8’s picture

Here's a patch incorporating all the feedback from comment #13.

And as @sorlov pointed out, I was mistaken that this also fixed #3069578: Layout builder doesn't show new "extra fields". So this patch does not increase the scope at all; my ambition in #14 was misguided!

danflanagan8’s picture

Status: Needs work » Needs review
danflanagan8’s picture

Removing "Needs issue summary update" tag. That was added based on my confusion regarding the connection to #3069578: Layout builder doesn't show new "extra fields".

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

danflanagan8’s picture

Issue summary: View changes

Updating the issue summary.

tim.plunkett’s picture

+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php
@@ -240,6 +240,30 @@ public function testAddHighlights() {
+   * Tests removing newly added extra field. See issue #3144010.

We usually don't reference issues like this, that info can be gotten from the git log/blame

Otherwise I think this is ready to go!

danflanagan8’s picture

Here's a new patch with that small change to the test description.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

catch’s picture

Status: Reviewed & tested by the community » Needs work

Looks really good but some cspell issues - either needs the words splitting or added to the dictionary:

core/modules/layout_builder/tests/modules/layout_builder_extrafield_test/layout_builder_extrafield_test.module:14:25 - Unknown word (extrafield)
core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php:258:81 - Unknown word (fieldlayout)
ravi.shankar’s picture

Status: Needs work » Needs review
FileSize
5.62 KB
406 bytes

Addressed comment #26, added extrafield and fieldlayout into dictionary.

danflanagan8’s picture

If extrafield isn't already in the dictionary, there's no reason to add it for this. I should have put a space in that from the beginning. Here's a new patch that changes extrafield to extra_field. There's no way around adding fieldlayout to the dictionary since it comes from a programmatically created css class.

If reviewers prefer #27 though, that's fine.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

#28 looks good to me, thanks!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 28: 3144010--28.patch, failed testing. View results

andypost’s picture

Status: Needs work » Reviewed & tested by the community
Related issues: +#3192260: [random test failure] Random fail in media_library CKEditorIntegrationTest

Send retest as it failed

  • catch committed 9c7b7f7 on 9.2.x
    Issue #3144010 by danflanagan8, ravi.shankar, tim.plunkett, chrisolof,...

  • catch committed 2a15548 on 9.1.x
    Issue #3144010 by danflanagan8, ravi.shankar, tim.plunkett, chrisolof,...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Splitting rather than adding to cspell makes sense to me as well.

Committed/pushed to 9.2.x and cherry-picked to 9.1.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

heddn’s picture