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
Issue fork experience_builder-3524298
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
Comment #2
wim leersThis 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. 😬
Comment #3
wim leers@tedbow, thoughts? :D
Comment #4
larowlanThe 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
Comment #5
larowlanComment #6
larowlanYes! this worked, updating issue summary and opening an MR, snuck in just under my 1hr timebox I allowed for it.
Comment #8
larowlanComment #9
wim leersWow, very cool to see that:
Very cool!
Comment #10
effulgentsia commentedWith 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.
Comment #11
larowlanThe 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.
Comment #12
larowlanRebased 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.
Comment #14
wim leersGreat 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.
Comment #15
wim leersI'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 theFallbackplugin 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… 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:
\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 samealtthat is being asserted!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 eachComponentSourceTestBaseshould implement, because then we could call that method after this assertion at the end of::testFallback()👆 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.
Comment #16
larowlanRe #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
Comment #17
larowlanActually, 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.
Comment #18
wim leers👍 Thanks!
Comment #19
tedbow#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 is in!
Comment #20
tedbowComment #21
wim leersNo longer applies due to #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 :)
Comment #22
tedbowRerolling
Comment #23
tedbowmerged 0.x but tests will fail because it still needs for the new way we store auto-save data
Comment #24
wim leersComment #25
larowlanThis 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 🎉
Comment #26
wim leersComment #27
wim leers🥳