Overview

Changes made to code components in global regions are not reflected in the preview until changes to the code component are published, and page is refreshed.

Steps to reproduce

  1. Add a code component to a global region (e.g., header or footer).
  2. Make a change to the code component (e.g., update text or styles).
  3. Save the changes.
  4. Observe that the changes are not visible until the changes are explicitly published, and page is refreshed.

Proposed resolution

  1. update XbPageVariant to implement ContextAwareVariantInterface. Then do something like \Drupal\display_variant_test\EventSubscriber\TestPageDisplayVariantSubscriber::onSelectPageDisplayVariant() to provide a yet-to-be-created "XB preview" context, which can then be respected by XbPageVariant, and which would result in $page_display->setContrexts(['xb_preview' => TRUE]);.
  2. Force the entire XB codebase to make conscious decisions wrt preview or not:
    diff --git a/src/ComponentSource/ComponentSourceInterface.php b/src/ComponentSource/ComponentSourceInterface.php
    index 94a2b9150..15b9a0982 100644
    --- a/src/ComponentSource/ComponentSourceInterface.php
    +++ b/src/ComponentSource/ComponentSourceInterface.php
    @@ -74,7 +74,7 @@ interface ComponentSourceInterface extends PluginInspectionInterface, Derivative
        * @return array
        *   Render array.
        */
    -  public function renderComponent(array $inputs, string $componentUuid, bool $isPreview = FALSE): array;
    +  public function renderComponent(array $inputs, string $componentUuid, bool $isPreview): array;
     
       /**
        * Whether this component requires explicit input or not.
    

    👆 That would've likely prevented this bug.

User interface changes

CommentFileSizeAuthor
#28 CleanShot 2025-04-24 at 15.17.51.gif1.8 MBlauriii
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

lauriii created an issue. See original summary.

wim leers’s picture

Assigned: Unassigned » lauriii
Status: Active » Postponed (maintainer needs more info)
Related issues: +#3500386: Code Components should render with their auto-saved state (if any) when rendered in the XB UI

So this does not happen when the auto-saved code component is in a content entity's XB field, and only if it is in a PageRegion?

If so, this would be a missed edge case in #3500386: Code Components should render with their auto-saved state (if any) when rendered in the XB UI.

Or are you referring to the PageRegion itself being auto-saved?

lauriii’s picture

Assigned: lauriii » Unassigned
Status: Postponed (maintainer needs more info) » Active

So this does not happen when the auto-saved code component is in a content entity's XB field, and only if it is in a PageRegion?

Yes, exactly. This is what I tried to describe in the steps to reproduce.

wim leers’s picture

Component: Theme builder » Internal HTTP API
Issue summary: View changes
Issue tags: +sprint

25-min deep dive suggests this is because #3500386: Code Components should render with their auto-saved state (if any) when rendered in the XB UI only modified \Drupal\experience_builder\Controller\ApiLayoutController::buildPreviewRenderable() to do:

$renderable = $item->toRenderable(TRUE);

which results in a JsComponent::renderComponent(isPreview: TRUE) call, rendering the auto-save (draft).

But the page regions are not rendered in ::buildPreviewRenderable(), but in \Drupal\experience_builder\Plugin\DisplayVariant\XbPageVariant::build(), where there's still this:

      $fiber = new \Fiber(fn() => $component_tree->toRenderable());

(note the absence of isPreview: TRUE)

It'll be up to \Drupal\experience_builder\EventSubscriber\PreviewEnvelopeViewSubscriber::onViewPreviewEnvelope() to pass that information to XbPageVariant somehow.

AFAICT the only feasible approach is to rely on this bit in HtmlRenderer:

      // Instantiate the page display, and give it the main content.
      $page_display = $this->displayVariantManager->createInstance($variant_id, $variant_configuration);
      if (!$page_display instanceof PageVariantInterface) {
        throw new \LogicException('Cannot render the main content for this page because the provided display variant does not implement PageVariantInterface.');
      }
      $page_display
        ->setMainContent($main_content)
        ->setTitle($title)
        ->addCacheableDependency($event);
      // Some display variants need to be passed an array of contexts with
      // values because they can't get all their contexts globally. For example,
      // in Page Manager, you can create a Page which has a specific static
      // context (e.g. a context that refers to the Node with nid 6), if any
      // such contexts were added to the $event, pass them to the $page_display.
      if ($page_display instanceof ContextAwareVariantInterface) {
        $page_display->setContexts($event->getContexts());
      }

IOW: update XbPageVariant to implement ContextAwareVariantInterface. Then do something like \Drupal\display_variant_test\EventSubscriber\TestPageDisplayVariantSubscriber::onSelectPageDisplayVariant() to provide a yet-to-be-created "XB preview" context, which can then be respected by XbPageVariant, and which would result in $page_display->setContrexts(['xb_preview' => TRUE]);.

The only alternative I see: add a #xb_preview => TRUE key-value pair to the "main content", which then is detected by XbPageVariant.

wim leers’s picture

Title: Changes to code components in global regions is not loaded until published » Changes to code components are not visible in A) preview-on-hover, B) global regions until published

⚠️ AFAICT this also affects the component preview upon hovering the list of available components:

diff --git a/src/Plugin/ExperienceBuilder/ComponentSource/BlockComponent.php b/src/Plugin/ExperienceBuilder/ComponentSource/BlockComponent.php
index 4fbac989c..adb573f8d 100644
--- a/src/Plugin/ExperienceBuilder/ComponentSource/BlockComponent.php
+++ b/src/Plugin/ExperienceBuilder/ComponentSource/BlockComponent.php
@@ -302,7 +302,7 @@ final class BlockComponent extends ComponentSourceBase implements ContainerFacto
       return ['build' => []];
     }
 
-    return ['build' => $this->renderComponent([], $component->uuid())];
+    return ['build' => $this->renderComponent([], $component->uuid(), TRUE)];
   }
 
   /**
diff --git a/src/Plugin/ExperienceBuilder/ComponentSource/GeneratedFieldExplicitInputUxComponentSourceBase.php b/src/Plugin/ExperienceBuilder/ComponentSource/GeneratedFieldExplicitInputUxComponentSourceBase.php
index c55528b5b..39653166a 100644
--- a/src/Plugin/ExperienceBuilder/ComponentSource/GeneratedFieldExplicitInputUxComponentSourceBase.php
+++ b/src/Plugin/ExperienceBuilder/ComponentSource/GeneratedFieldExplicitInputUxComponentSourceBase.php
@@ -603,7 +603,7 @@ abstract class GeneratedFieldExplicitInputUxComponentSourceBase extends Componen
 
     return [
       'source' => (string) $this->getSourceLabel(),
-      'build' => $this->renderComponent([self::EXPLICIT_INPUT_NAME => $default_props_for_default_markup], $component->uuid()),
+      'build' => $this->renderComponent([self::EXPLICIT_INPUT_NAME => $default_props_for_default_markup], $component->uuid(), TRUE),
       // Additional data only needed for SDCs.
       // @todo UI does not use any other metadata - should `slots` move to top level?
       'metadata' => ['slots' => $this->getSlotDefinitions()],
wim leers’s picture

Title: Changes to code components are not visible in A) preview-on-hover, B) global regions until published » Changes to code components are not visible in global regions until published
Issue tags: +stable blocker
Related issues: +#3516705: Auto-saved changes to code components are not visible in preview-on-hover-component-list until published

Extracting #5 into a separate issue, because as @f.mazeikis and @longwave pointed out: there's cache invalidation challenges there. So extracted A) preview-on-hover into #3516705: Auto-saved changes to code components are not visible in preview-on-hover-component-list until published.

wim leers’s picture

While reviewing another MR, I stumbled upon \Drupal\experience_builder\EventSubscriber\RenderEventsSubscriber::onSelectPageDisplayVariant(), which made me doubt my proposal for a second!

But … that solves a different problem: that's for loading the auto-saved PageRegions when appropriate, not for loading the auto-saved JavaScriptComponents when appropriate.

So: all good AFAICT 👍

tedbow’s picture

Assigned: Unassigned » tedbow

working on this

tedbow’s picture

Assigned: tedbow » Unassigned
Status: Active » Needs work
Issue tags: +Needs tests

Gave this a start, I put a couple todo's in where I was user how to get the preview context.

Manually testing it, it does work to pick up the autosaved Code component changes

I can work on it tomorrow but if someone wants to take it over before then that works too

wim leers’s picture

Assigned: Unassigned » tedbow

Manually testing it, it does work to pick up the autosaved Code component changes

🥳

Nice progress here! 😄

tedbow’s picture

Assigning to myself to add tests. I looked at this last week but confused about the number of places/ways I could test this.

Hopefully a couple days break will have given me clarity 🤞🏻

wim leers’s picture

tedbow’s picture

To write a test I really wanted to understand how this all works

Just noting that I just now realize how the html previewing works. I wasn't involved in these issue but wondering if we should document better how these classes relate to each other

  1. PreviewEnvelopeViewSubscriber
  2. PreviewEnvelope
  3. XBPreviewRenderer
  4. XbPageVariant
  5. RenderEventsSubscriber
  6. ApiLayoutController

I will re-read the class docs again and see if they are clear but I think they might be clear only because I have actually done some research to see how all these classes fit together.

I think each one this classes have good `@see` links to 1 or 2 of the other classes but I haven't yet found a place where it is clear how on the parts fit together.

wim leers’s picture

#15++ for improving docs here. I propose a class-level docblock on \Drupal\experience_builder\Controller\ApiLayoutController.

wim leers’s picture

Issue tags: -Needs tests

Very nice work here — only trivial feedback, I think that once the docs exist, this is ready! 😄

tedbow’s picture

@wim leers re #15 and #16

Could we actually do that in another issue? I think doing it in another issue would allow us to rename a class or 2 to make the relationship more clear, if needed. Whereas if we just do it here I think we might just do quick job and keep the whole flow a bit hard to understand

tedbow’s picture

tedbow’s picture

Assigned: tedbow » wim leers
Status: Needs work » Needs review
wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs review » Reviewed & tested by the community
wim leers’s picture

Status: Reviewed & tested by the community » Fixed

  • wim leers committed 21fc148d on 0.x authored by tedbow
    Issue #3512385 by tedbow, wim leers, lauriii, larowlan: Changes to code...
mayur-sose’s picture

Status: Fixed » Needs work

There are two scenarios, one of which is working as expected, and the other is not:

Working Scenario:
When we click "Add to components" from the right-hand side section, changes made to code components in global regions are reflected in the preview immediately without needing to publish or refresh the page.

Non-Working Scenario:
When creating a code component and clicking "Add to components" from the left-hand side section, changes do not reflect in the preview. Below are the steps to reproduce the issue:

  1. Click "Add new"
  2. Enter the component name (e.g., myCode7).
  3. Do not make any changes to the code.
  4. Navigate to the left-hand side under the "Code" block.
  5. Click on the three dots of myCode7 component and select "Add to components".

Hover functionality doesn’t work, drag-and-drop of myCode7 does not show anything, and the preview remains blank.

lauriii’s picture

Status: Needs work » Fixed
nagwani’s picture

Issue tags: -sprint
lauriii’s picture

Status: Fixed » Needs work
StatusFileSize
new1.8 MB

I don't think this has been fixed yet at least for components that had been previously added to the component library, and then changed when they are placed in a global region:

lauriii’s picture

Status: Needs work » Fixed

I'm actually now realizing that my component wasn't in the header region so this isn't related to global regions 🤔 I'll report this as a new bug.

Status: Fixed » Closed (fixed)

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