Overview

At present the autosave data stores the client-side representation of the model.
After #3519168: Handle components provided by ComponentSources EXPLICITLY disappearing — enables deleting JS components that are in use goes in, the data in the autosave store may be for a different source plugin to when it was stored. As a result we cannot perform the correct transformation to/from client input models.

Proposed resolution

AutoSaveManager already listens for config API crud events.
Extend the current listener to detect when a source plugin changes on a component and have it auto-update any saved data to the client side model of the new source plugin.

User interface changes

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

larowlan created an issue. See original summary.

wim leers’s picture

This would be a massive change in the auto-save architecture.

Unfortunately, the ADR for that still hasn't landed: #3512616: Document the reasons for not using Workspaces for saving in XB 1.0.0. 😬

wim leers’s picture

Assigned: Unassigned » tedbow

@tedbow, thoughts? :D

larowlan’s picture

The only other way I can see us 'recovering' when a fallback component is stored in auto save AND the component it replaced reappears is if we have an event listener that listens to config events and detects the change of source plugin in a config entity from fallback to something else. The listener would have to loop over autosave data and pass the component props to the new source plugin and ask it to transform input data to client data and then re-save the entry. Now that I type that out, it might be less effort and more perfomant than making autosave do to/from client data on every read and write

I think it's worth exploring if we can detect that scenario with existing config events

larowlan’s picture

Title: [PP-1] Autosave data should store converted server-side representation of model » Autosave data should store converted server-side representation of model
Status: Postponed » Active
larowlan’s picture

Title: Autosave data should store converted server-side representation of model » Autosave data should be update itself when a component's source plugin changes
Issue summary: View changes
Status: Active » Needs review

Yes! this worked, updating issue summary and opening an MR, snuck in just under my 1hr timebox I allowed for it.

larowlan’s picture

Title: Autosave data should be update itself when a component's source plugin changes » Autosave data should update itself when a component's source plugin changes
wim leers’s picture

Title: Autosave data should update itself when a component's source plugin changes » Auto-save data should update itself when a component's source plugin changes
Related issues: +#3515629: FieldWidget's XB transforms must be bubbled by the Field Widget rendering to inform the client, +#3519634: Modifying a XB config entity's `status` or `label` should update the auto-save entry too, rather than delete it
effulgentsia’s picture

Issue tags: +beta blocker

With all of the other changes that have landed in the last few weeks, is this issue still relevant? If so, what are the steps to create a broken auto-save state?

Tagging as a beta blocker to answer this question and evaluate. Depending on the answer, we might decide that actually fixing it doesn't necessarily have to block a beta.

larowlan’s picture

Assigned: tedbow » larowlan

The steps to reproduce would be:

* Create a new menu
* Place an XB version of that menu's block in an unsaved page
* Delete the menu
* Try to render the component preview

But having said that, with the introduction of component versions, it might not be an issue.

I'll do some digging.

larowlan’s picture

Assigned: larowlan » Unassigned

Rebased this off 0.x

We do still need it because when $component->getComponentSource() is using the fallback as the last version, the shape of the input data server side is different to that on for the default generated components.

Updated the logic to allow for the new versioned properties and got the test passing again.

wim leers credited tedbow.

wim leers’s picture

Title: Auto-save data should update itself when a component's source plugin changes » Auto-save data should update itself when the Fallback plugin is (de)activated

Great call, @effulgentsia!

+1 to @larowlan's analysis in #11 + #12.

Test-only CI job fails 👍}

Clarifying the issue scope per #4 and what's in the MR.

wim leers’s picture

Status: Needs review » Needs work

I'm wondering if \Drupal\Tests\experience_builder\Kernel\Plugin\ExperienceBuilder\ComponentSource\FallbackInputTest::testFallbackInputCanBeRecovered() is not essentially obsolete thanks to \Drupal\Tests\experience_builder\Kernel\Plugin\ExperienceBuilder\ComponentSource\ComponentSourceTestBase::testFallback() since recent changes wrt when the Fallback plugin becomes active (#3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions ⇒ less data to store per XB field row, #3528723: Component::onDependencyRemoval() should be an uninstall validator if the dependency being removed is a module or theme etc.).

In that ::testFallback() test coverage I also spotted

    if (static::class === BlockComponentTest::class) {
      // @todo Update Component entities with BlockComponent source plugin: https://drupal.org/i/3484682
      $this->markTestIncomplete('Block components do not yet update component config entities');
    }

… but #3484682: Handle update and delete of Block `Component`s, plus react to dependency removal landed a while ago. We forgot this bit. We can remove it with zero changes AFAICT.


AFAICT:

  1. \Drupal\Tests\experience_builder\Kernel\Plugin\ExperienceBuilder\ComponentSource\FallbackInputTest::testFallbackInputCanBeRecovered() is now pretty much a duplicate of \Drupal\Tests\experience_builder\Kernel\Plugin\ExperienceBuilder\ComponentSource\SingleDirectoryComponentTest::getPropsForComponentFallbackTesting() — down to the same alt that is being asserted!
  2. We only need to move assertions such as self::assertCount(1, $crawler->filter('img[alt="An image so amazing that to gaze upon it would melt your face"]')); into a new abstract method that each ComponentSourceTestBase should implement, because then we could call that method after this assertion at the end of ::testFallback()
        // Should be no fallback container.
        self::assertCount(0, $out->filter('[data-fallback]'));
        foreach ($slots as $slot) {
          // Children should still render in the slots.
          self::assertCount(1, $out->filter(\sprintf('h1:contains("This is %s")', $slot)));
        }
    

    👆 that tests after fallback recovery the A) absence of the fallback container, B) the presence of the slots, so adding C) presence of rendered props to that would make it complete.

I belive that this would benefit the overall maintainability.

larowlan’s picture

Re #15 this test actually provides additional test coverage for when you update another component in the preview.

Because when that happens the source plugin's ::clientModelToInput method is called and that changes the stored values.

For example, when a stored component that previously used a generated source plugin (Sdc, JS) is stored in autosave it has a source and resolved key, these come from it's ::inputToClientModel method.

When we call ::patch we rebuild the layout and that calls ::inputToClientModel on a different component, but is passed the old client model from autosave.

So we still need this test, as it covers that scenario

larowlan’s picture

Title: Auto-save data should update itself when the Fallback plugin is (de)activated » [PP-1] Auto-save data should update itself when the Fallback plugin is (de)activated
Status: Needs work » Postponed

Actually, I think the new approach in #3529622: Make auto-save manager only support passing and returning entity objects, remove support for arbitrary data, use deterministic hashing to ensure entries are actually updates makes this redundant. Because conversion happens immediately, so the data stored in the auto save store cannot get out of date w.r.t the source plugin/version.

Postponing on that.

wim leers’s picture

👍 Thanks!

tedbow’s picture

Title: [PP-1] Auto-save data should update itself when the Fallback plugin is (de)activated » Auto-save data should update itself when the Fallback plugin is (de)activated
tedbow’s picture

Assigned: Unassigned » tedbow

Rerolling

tedbow’s picture

Assigned: tedbow » Unassigned

merged 0.x but tests will fail because it still needs for the new way we store auto-save data

wim leers’s picture

Assigned: Unassigned » larowlan
larowlan’s picture

Assigned: larowlan » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll

Actually, I think the new approach in #3529622: Requests to ApiLayoutController::post() that contain the same data as the saved entity will cause a auto-save entry to needlessly be be created makes this redundant. Because conversion happens immediately, so the data stored in the auto save store cannot get out of date w.r.t the source plugin/version.

This is correct, and the test only-change in the MR shows it

Another win for #3529622: Make auto-save manager only support passing and returning entity objects, remove support for arbitrary data, use deterministic hashing to ensure entries are actually updates 🎉

wim leers’s picture

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

Status: Reviewed & tested by the community » Fixed

🥳

  • wim leers committed 3526406b on 0.x authored by larowlan
    Issue #3524298 by larowlan, tedbow, wim leers, effulgentsia: Auto-save...

Status: Fixed » Closed (fixed)

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