- Issue created by @mglaman
- 🇺🇸United States mglaman WI, USA
laurii, larowlan were part of the debugging crew
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Ah the curse of a unit test with mocking :) https://git.drupalcode.org/project/experience_builder/-/merge_requests/7...
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
I've written a test here
And I think this behavior might be by design.If we delete the JS component then the component is deleted too.
And we don't want that if the component has usages, so that opens a can of worms about finding usages.
Do we want to tackle that here too or more likely we'll have to create issues to handle those pieces and postpone this.I've pushed up a test, but because of the 'are we using this component question - I don't think this one is a simple fix .
Linking a related entity usage system - but we could also implement something like layout builder does for inline block usage.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Assigning to Wim for direction on how we should go here.
I think trying to calculate the usage in real-time in a deletion check is arduous.
I think something like layout builder's inline block usage where we store usage in a table that we write when a component tree is saved AND that can be re-calculated (ala entity usage module) is probably more robust. - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
And we don't want that if the component has usages, so that opens a can of worms about finding usages.
Do we want to tackle that here too or more likely we'll have to create issues to handle those pieces and postpone this.I think trying to calculate the usage in real-time in a deletion check is arduous.
💯 to all this! 🤓
🏓 Detailed thoughts: https://git.drupalcode.org/project/experience_builder/-/merge_requests/9... —
tl;dr
: implementComponent::onDependencyRemoval()
. See #3484682-12: Handle update and delete of Block `Component`s, plus missing config dependencies → , where @longwave is hitting on the exact same problem with a differentComponentSource
plugin! - 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Added a fallback source plugin that can step in and continue to render children when a JS component is removed if any instance exist.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Lots of cleverness here, but also some huge long-term impact decisions!
This is sort of a counterpart to 🌱 [META] Robust component instance error handling Active , at least if I interpreted everything correctly.
I'd like @longwave to take a very critical look at this, because this has just shifted to a critical data integrity issue. 😅
- First commit to issue fork.
- 🇬🇧United Kingdom longwave UK
I think this is the right way forward instead of trying to figure do usage tracking as historically we have never succeeded at proper usage tracking, and it also will help with other cases where e.g. SDCs or block plugins suddenly vanish because a module or theme update dropped them.
Moving to NW for the fundamental question: does this need to be a separate interface, or should it just be something that all component source plugins are forced to support?
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
e.g. SDCs or block plugins suddenly vanish because a module or theme update dropped them.
This.
@longwave: I'm curious about your thoughts on this review remark by me. Also, AFAICT this can't work for vanishing SDCs — what am I missing? 🙈
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
@longwave in #14:
I think this is the right way forward instead of trying to figure do usage tracking as historically we have never succeeded at proper usage tracking,
Two things:
- At DDD, I talked to Alex Pott, and he's been making https://www.drupal.org/project/entity_usage → drastically better. We've never succeeded in core, but that's now starting to look better :)
- For XB purposes, the usage tracking problem is much more narrowly defined, and 📌 Calculate field and component dependencies on save and store them in an easy to retrieve format Active is tackling it. Imagine/assume for a second that component usage tracking is a solved problem. Then … what would change here in your perspective?
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Moving to NW for the fundamental question: does this need to be a separate interface, or should it just be something that all component source plugins are forced to support?
Good question, I guess an SDC component could depend on a theme/module.
thoughts @wim leers?
Fixed tests
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
I guess an SDC component could depend on a theme/module.
WDYM? The
Component
config entity'sprovider
already gets set to the the module/theme that provided the SDC, see\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\SingleDirectoryComponent::createConfigEntity()
.The challenge is: what if a module/theme is updated and the SDC is gone? How then would we figure out the slots it had?
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Pushed changes as follows:
* Store slot definitions for SDC in the component config so we can handle fallback for them
* Remove the new interface and add the method to the base interface
* Make SDC and blocks implement it
* Move the test to the base component test so we have coverage for all.Blocks are currently failing which I suspect is 📌 Handle update and delete of Block component config entities Active
Done for today, but next step is to confirm 📌 Handle update and delete of Block component config entities Active fixes the test
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Plucked in the fix from 📌 Handle update and delete of Block component config entities Active this is ready for review now
- 🇬🇧United Kingdom f.mazeikis Brighton
Tested in my local, a few things stood out:
- Upon deletion, fallback component label reverts to generic `Component` in the sidebar. I wonder if we should add something explicit, to let user know it's a "fallback"/"broken" component?
-
Disabling sdc test module resulted in XB retaining ALL of the Component entities associated with SDC's provided by the module, regardless of whether they were in use anywhere. Not sure if this is correct behaviour, as this would lead to polluting DB with unused components. I would expect only components that were used to create layouts in some way to be retained.
- Upon deletion, fallback component label reverts to generic `Component` in the sidebar. I wonder if we should add something explicit, to let user know it's a "fallback"/"broken" component?
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Great pickups @f.mazeikis - the naming I can fix easily enough
I think we'll need 📌 Calculate field and component dependencies on save and store them in an easy to retrieve format Active to be able to handle straight up deleting - which I agree is a better approach.
@wim leers - should we postpone this issue on that or should we add a todo pointing to it? - 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
The `Component` rendered in the side bar is because once we disable this component (which we do here) it no longer shows in the list controller.
Disabling it prevents it from being reused again, but it does prevent it from showing the old label in the layers.
Not sure what the best approach is here - Component is the fallback the frontend uses https://git.drupalcode.org/project/experience_builder/-/blob/0.x/ui/src/... - defering to @laurii on that one.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
#27: 🌱 [META] Production-ready data storage Active is on the verge of landing, so +1 for waiting for that.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
- 🇬🇧United Kingdom f.mazeikis Brighton
@lauriii
In situation when a Component is used in a Layout on a Node and then the JS Component, Block Plugin or SDC is removed from the Drupal, what is the expected behaviour for such "removed" Components?
Currently this MR assigns "Fallback" plugin as source for such components, allowing us to have graceful error handling when rendering such pages and interacting with tree structures. We should be able to "recover" data completely, if JS Component, Plugin or SDC is re-introduced into Drupal.
There are some questions about UI/UX side of things, specifically:- Is it correct to assume that it is removed from the library listing of available Components?
- Is it correct to assume that it should be rendered as empty div with a placeholder UUID and identifiers for preview purposes?
- Should such component has slots with other Component instances inside of it - should those components still be rendered in preview and in live versions of the page?
- Should "removed" Component still be visible in the Layers section of the sidebar?
- If so, is it ok to use generic "Component" label for all such components?
- If "removed" Components are visible in the Layers section of the sidebar, should it be possible for users to interact with them? What kind of interactions user is allowed to do? (Moving them around in Layers? Editing contents of Slots? Deleting them from Layout?)
- If such components are visible - do we need designs for icons/messages/labels that inform users of "removed"/"fallback" status of such Components?
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
For ease of review for @laurii, here's how the current patch responds to @f.mazeikis's questions 1-7 above
- Currently it is
- Currently it is
- Currently it renders any child slots in order each as a div
- Currently they are visible
- Currently they are named 'Component' only but we could easily make that 'Disabled Component'
- Currently all of these interactions are possible
- Excellent question 🙏 currently there is no affordance
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Rebased on top of 0.x now that 📌 Calculate field and component dependencies on save and store them in an easy to retrieve format Active is in, made a couple of improvements to the audit service while I was touching the code.
Works real nice 😎 - we only do the on dependency removal dance if the item is in use and just let stuff get deleted if its not in use.
Added test coverage that shows that unused things just get deleted.
Still needs product feedback from @laurii but is ready for another review
- 🇬🇧United Kingdom f.mazeikis Brighton
Re-tested it and this feels much closer. Components are deleted based on usage, there's even warning during module uninstall via UI - awesome.
During testing this locally I've still encountered the problem when removing module that provided Component with slots and this Component was used on a Node with slot populated by other Component.
This leads causes XB UI crash with error message "An unexpected error has occurred while rendering preview." prompting to "Try again", which re-triggers same error.
I guess this is a FE side thing and we probably can spin that into separate follow up issue.
- 🇫🇮Finland lauriii Finland
- Yes 👍
- Yes, I'll work with Callum on a design and we can then define based on that what would be needed 👍
- They should not be visible in the preview or in the live version of the page. However, they should be visible in the layers. It is okay to implement this in a follow-up issue.
- Yes 👍
- Yes, I think we would want to somehow indicate that those components are missing / broken. I'll ask Callum to design this.
- The primary use case that we'd want to enable is being able to drag components from the slots outside of them. I'd imagine them working largely the same as other layers with the exception that they are not visible in the preview?
- Callum will design these and provide for you
I wasn't able to test this manually though. I tested this by deleting the
experience_builder:two_column
when I had that component placed on a page. I got following error:
The \u0022experience_builder:two_column\u0022 plugin does not exist. Valid plugin IDs for Drupal\\experience_builder\\Plugin\\ComponentPluginManager are: olivero:teaser, experience_builder:my-section, experience_builder:image, experience_builder:shoe_button, experience_builder:shoe_badge, experience_builder:shoe_icon, experience_builder:shoe_details, experience_builder:video, experience_builder:heading, experience_builder:shoe_tab_panel, experience_builder:shoe_tab, experience_builder:shoe_tab_group, experience_builder:one_column, experience_builder:druplicon, experience_builder:my-hero, navigation:title, navigation:badge, navigation:toolbar-button
- 🇬🇧United Kingdom f.mazeikis Brighton
@lauriii If I understand correctly, you manually (via Drush?) attempted to delete a Component entity and hit the error? If so, this is not what this MR is addressing. This MR addresses situations where due to module uninstall, code change or JS Component removal we encounter Component with missing/invalid Component Sources.
While the problem you're describing is valid and we should introduce some sort of safeguard against deleting Components that are in-use (made possible by #3457504: 📌 Calculate field and component dependencies on save and store them in an easy to retrieve format Active ), this issue does not address this.
Testing this MR would involve uninstalling modules providing Block Plugins/SDCs, deleting Code component entities (js_component
) that are in-use on Nodes by Component entities. Deleting Component entities directly is outside of scope here. - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Will review this tomorrow 👍 Meanwhile, it'd be great to have @f.mazeikis' question answered — funny enough I was forced to ask the same at #3517941-12: [META] Robust component instance error handling → , independently of this! 😅
- 🇫🇮Finland lauriii Finland
I tried to delete a SDC that was placed on a page (the
experience_builder:two_column
component). So I placed the component on a page, deleted the component from the code base, cleared caches, and reloaded XB.I have no idea how to read this issue because #37 🐛 Cannot delete JS components due to component depending on them Active to me seems to be in a direct conflict with the issue title and #31 🐛 Cannot delete JS components due to component depending on them Active . I'm probably missing some nuance which is why I've completely misinterpreted this issue. 😅
It would be great if we could update the issue summary but besides that, I'm always open to jumping on a quick call to get us on the same page again.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
"components disappearing" ==
block
→ the block plugin disappearing from a modulesdc
→ the SDC disappearing from a modulejs
→ should not be possible thanks to config dependencies
So I placed the component on a page, deleted the component from the code base, cleared caches, and reloaded XB.
Hm, that seems fine then. That's equivalent to the SDC disappearing.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
BTW, this might end up fixing both 💬 ComponentNotFoundException: Unable to find component Active and 📌 Handle update and delete of SingleDirectoryComponent `Component`s, plus missing config dependencies Active too!
- 🇬🇧United Kingdom f.mazeikis Brighton
From description of this I think we need "on the fly" swap Component Source with Fallback if we detect that Component Source is no longer `valid`. I'll take a stab at it.
- 🇬🇧United Kingdom f.mazeikis Brighton
Didn't get very far. I've pushed what I was thinking off, but it's not a complete solution yet. Preview rendering breaks, something to do with HidratedTrees and mismatch between saved inputs and Falllback, it seems. Block and JsComponent source plugins also miss logic in their respective
::valid()
methods. We would need tests for this as well.I was thinking that @lauriii testing revealed, that sometimes Source Plugins can become invalid without triggering any of our Logic, so maybe we should try to catch that at the time of instantiating/accessing Source Plugins and use Fallback source plugin in such situations.
Not even sure if this is of any use - feel free to undo my commit entirely if you think this is wrong approach, @larowlan.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
I think we should defer #40 through #44 to 💬 ComponentNotFoundException: Unable to find component Active
- the scope here is already large enoughThis issue was specifically about dealing with config dependency removals (the original STR were creating a Code Component, then adding it to the library but _not_ being able to delete it because it was *in use*)
I've pushed @f.mazeikis's commits to a branch in 💬 ComponentNotFoundException: Unable to find component Active with all of the commits from here squashed so rebasing will be easier once this is in.
I've then rewound this branch to the commits before @f.mazeikis started addressing #40 onwards.
Added 📌 [PP-1] [Needs design] Implement design treatment for fallback component Active to implement the design changes (once ready) eluded to in #36
Putting this back to needs review in its current state.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Very nice work here, @larowlan and @f.mazeikis!
This is essentially a sibling to 🌱 [META] Robust component instance error handling Active — but taking care of a different scenario: not broken logic inside a component, nor invalid inputs passed into a component instance, but a component disappearing from a source and XB about it. (By contrast, 💬 ComponentNotFoundException: Unable to find component Active is about a component disappearing from a source without XB getting informed about it.)
Been sick, so didn't get to do in #38 what I said I'd do 🙈
I see that @larowlan opened a follow-up for conveying through the UI which component instances are actually fallbacks (thanks @mglaman for asking critical questions!): 📌 [PP-1] [Needs design] Implement design treatment for fallback component Active — linking.
🐛 Only fixes the canonical route; editing in XB still broken 😅
On a fresh install, I can still reproduce exactly the failure that @f.mazeikis reported on #35, which means that despite the test coverage of this MR proving it works, it only does so when viewing the
Node
orPage
at its canonical page; it still crashes when editing it through XB.This crash appears to be happening in the client's
ComponentOverlay
and/orSlotOverlay
.@f.mazeikis proposed to do that in a FE follow-up, but that doesn't yet exist?
🤔 Deep review: 3 concerns
I still have three remaining concerns:
- The first is tying back to #20. The current MR does solve it for the
sdc
ComponentSource
(👍 — technically addresses #20), but does so in a way that is SDC-specific. What about other\Drupal\experience_builder\ComponentSource\ComponentSourceWithSlotsInterface
component source plugins in the future? 😅
The way it's currently implemented will require significant duplication (and likely inconsistency) across component sources.I think it's possible to solve generically: why not move
slot_definitions
out oftype: experience_builder.component_source_settings.(sdc|fallback)
and into a newfallback_metadata.slot_definitions
undertype: experience_builder.component.*
itself? That could then contain all the "best-effort fallback" metadata. - The second is about how the fallback rendering is implemented — for future maintainability and cohesion with #3470422, I think that ideally this would be part of
\Drupal\experience_builder\Element\RenderSafeComponentContainer
and the way that is used byComponentTreeHydrated::renderify()
. IF there's a reason not to do that, then I think at minimum we need docs explaining where the boundaries lie.Because this MR is de facto introducing a new kind of robustness: the robustness of ensuring that child trees of components with slots that were properly uninstalled do not result in their contained subtrees disappearing on content authors, to avoid perceived data loss. By contrast, #3470422 was about ensuring invalid inputs and/or broken logic in components not resulting in crashes.
- Currently, component instances from the
sdc
andjs
component sources can have their underlying components (SDC plugins orJavaScriptComponent
config entities) uninstalled and they'll then automatically switch to thefallback
plugin. They'll continue to render partially (i.e. subtrees in slots will be visible, nothing else will be, nor could be).But AFAICT (although I cannot test this due to the bug reported by @f.mazeikis in #35), editing the component tree will lose the stored explicit inputs for the component instance, because:
\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\Fallback::requiresExplicitInput()
returnsFALSE
\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\Fallback::clientModelToInput()
returns[]
- … et cetera
… which means that the
Now perform an action that causes the component to recover from the fallback.
test coverage at the end ofComponentSourceTestBase::testFallback()
is essentially an illusion: it only works because the test assumes nothing has happened to the component tree while theFallback
source was active.
Sorry for being a party pooper 😔
- The first is tying back to #20. The current MR does solve it for the
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
If we're to proceed with a
fallback
source, I'd expect it to be explicitly documented indocs/components.md
— both which sources are eligible, but also what can be expected of the fallback in terms of:- rendering component instances relying on it
- data loss impact on the component instance's props & slots if edits happen once it's using the
fallback
source - etc.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
BTW, updated the title here to contrast it more clearly with 💬 ComponentNotFoundException: Unable to find component Active 's title & scope.
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
#35 (the front end editing issue) is 🐛 Component/Slot overlay is brittle if HTML comments are missing Active - I've refactored how we render the fallback component to make sure the Twig visitor outputs the comments the FE needs. I've also added a test for it. So that fixes the issues we were seeing but highlights that this is particularly rigid w.r.t. how component slots are rendered. We can't know that _every_ source plugin will print the slots by name in twig (ie
{{ some_slot_name }}
in order for the twig node visitor to wrap that with the comments. So that follow up is more about making the FE more robust rather than fixing a new issue added here.#48.1 I've made this adjustment. Was pretty clean/simple in the end.
I think that ideally this would be part of \Drupal\experience_builder\Element\RenderSafeComponentContainer
We are already getting wrapped in one of those for free - thanks to how
::renderify
works - this is just another component. The changes I had to make to resolve #35 also make it further evident that keeping the two separate are probably best. If we added generic slot printing fallback to theRenderSafeComponentContainer
it would have to mimic the same stuff we're doing here with explicitly printing slots by name, but also in try-catch because that component cannot fail to render. I think it is worth exploring that in a new issue - I've opened 📌 [PP-1] Explore adding support for fallback rendering of slots to RenderSafeComponentContainer Postponed to see if the changes I've made toFallback::renderComponent
and::setSlots
could move to a generic render element. I am proposing doing it in a followup because the scope of this MR is already large. If you feel strongly about it I can close that and do it here.#48.3In theory we can also copy over fallback metadata on prop definitions to the fallback plugin but that assumes we are only dealing with SDC/Code components. What do we do for blocks where the form isn't based off the generated UX base class? I think we should get some input from @laurii here - what is the intended behavior. I don't think we can continue to show the same component inputs form (because how we handle SDC vs Blocks isn't compatible) - we could probably just store the values in hidden inputs so at least the values are retained. But, is it safe to keep the values around in case the scenario that caused the component to be remove is reversed? What happens if the deleted JS component is added back but with different props? I think we should confirm the intended behavior before jumping to an implementation. As a result assigning to @laurii
- 🇫🇮Finland lauriii Finland
i.e. subtrees in slots will be visible, nothing else will be, nor could be
Per #36 🐛 Cannot delete JS components due to component depending on them Active , subtrees should not be visible in the preview or in the live site when the parent component is missing. Maybe you're describing that they are visible in the layers?
I don't think we can continue to show the same component inputs form (because how we handle SDC vs Blocks isn't compatible) - we could probably just store the values in hidden inputs so at least the values are retained.
Would it be possible to show the values in disabled fields? This way it would be possible to copy and paste the content elsewhere. I understand this may not be rendered exactly like the real component form would be but that seems fine since this is a fallback which is not really intended for authoring, but just to prevent you from losing data.
But, is it safe to keep the values around in case the scenario that caused the component to be remove is reversed? What happens if the deleted JS component is added back but with different props?
Wouldn't this fall under the scenario where props have been changed (i.e. 🌱 Plan to allow editing props and slots for exposed code components Active )? I think in the absence of that, it would be fine if we cannot render the component until the shape is in a valid state, i.e. no missing required props. When content with that component is being edited, it would have to be brought to validity.
This is not all that different from how things work today in Drupal. You can run into this without even doing anything too crazy because if you add a required field to an existing content type with content, it makes all of the content invalid. We have no safe guards against that today.
We may need a sibling issue to 📌 [SPIKE] Prove that it's possible to apply block settings update paths to stored XB component trees Active to document how one could delete all instances of a component when you really want to get rid of all of the content.
- 🇬🇧United Kingdom f.mazeikis Brighton
Would it be possible to show the values in disabled fields?
Without the Component Source Plugin, we lose the metadata about the props/block settings. We would need to rely on data stored in XB field on a node and do best our attempt go generate input fields matching value, expression and source type.
This is certainly possible, but it feels like somewhat a separate deep dive that warrants it's own issue.With that being said, I've tried testing Wim's described scenario of data loss:
- Enable
xb_test_sdc
module - Place couple of components on a node -
Heading
andXB test SDC with props and slots
in laytout - Edit heading of
XB test SDC with props and slots
- Publish the changes
field_xb_demo_inpus
store the following:
{"6c280bf1-cc58-4c34-af73-7ea36d6dc1eb": {"heading": {"value": "There goes my test", "expression": "ℹ︎string␟value", "sourceType": "static:field_item:string"}}, "8cb6fa57-08df-4508-b439-cc88d9301999": {"text": {"value": "A heading element", "expression": "ℹ︎string␟value", "sourceType": "static:field_item:string"}, "style": {"value": "primary", "expression": "ℹ︎list_string␟value", "sourceType": "static:field_item:list_string", "sourceTypeSettings": {"storage": {"allowed_values": [{"label": "primary", "value": "primary"}, {"label": "secondary", "value": "secondary"}]}}}, "element": {"value": "h1", "expression": "ℹ︎list_string␟value", "sourceType": "static:field_item:list_string", "sourceTypeSettings": {"storage": {"allowed_values": [{"label": "div", "value": "div"}, {"label": "h1", "value": "h1"}, {"label": "h2", "value": "h2"}, {"label": "h3", "value": "h3"}, {"label": "h4", "value": "h4"}, {"label": "h5", "value": "h5"}, {"label": "h6", "value": "h6"}]}}}}}
- Disable
xb_test_sdc
module and clear cache - Edit the node in question - update
Heading
component - Publish the changes
field_xb_demo_inpus
value is updated to the following:
{"8cb6fa57-08df-4508-b439-cc88d9301999": {"text": {"value": "A heading test", "expression": "ℹ︎string␟value", "sourceType": "static:field_item:string"}, "style": {"value": "primary", "expression": "ℹ︎list_string␟value", "sourceType": "static:field_item:list_string", "sourceTypeSettings": {"storage": {"allowed_values": [{"label": "primary", "value": "primary"}, {"label": "secondary", "value": "secondary"}]}}}, "element": {"value": "h1", "expression": "ℹ︎list_string␟value", "sourceType": "static:field_item:list_string", "sourceTypeSettings": {"storage": {"allowed_values": [{"label": "div", "value": "div"}, {"label": "h1", "value": "h1"}, {"label": "h2", "value": "h2"}, {"label": "h3", "value": "h3"}, {"label": "h4", "value": "h4"}, {"label": "h5", "value": "h5"}, {"label": "h6", "value": "h6"}]}}}}}
Notice how"6c280bf1-cc58-4c34-af73-7ea36d6dc1eb": {"heading": {"value": "There goes my test", "expression": "ℹ︎string␟value", "sourceType": "static:field_item:string"}}
is removed from the beginning of JSON blob.- Enable
xb_test_sdc
module - Attempt opening XB editor for node in testing
- Observe the following exception when trying to view the node:
Drupal\experience_builder\MissingComponentInputsException: No props sources stored for 6c280bf1-cc58-4c34-af73-7ea36d6dc1eb. Caused by either incorrect logic or `inputs` being out of sync with `tree`. in Drupal\experience_builder\Plugin\DataType\ComponentInputs->getValues() (line 174 of /Users/felix.mazeikis/work/pbx-poc/web/modules/contrib/experience_builder/src/Plugin/DataType/ComponentInputs.php).
- Attempting to open same node in XB Editor results in a crash that prevents XB UI from fully loading, storing same kind of exception in log reports:
Drupal\experience_builder\MissingComponentInputsException: No props sources stored for 6c280bf1-cc58-4c34-af73-7ea36d6dc1eb. Caused by either incorrect logic or `inputs` being out of sync with `tree`. in Drupal\experience_builder\Plugin\DataType\ComponentInputs->getValues() (line 174 of /Users/felix.mazeikis/work/pbx-poc/web/modules/contrib/experience_builder/src/Plugin/DataType/ComponentInputs.php).
I was about to write a suggestion that we should move "data loss and recovery" into a separate issue, but after managing to brick my XB/Drupal so easily I am no longer sure it's a good idea. Although one could argue that this is not the fault of this MR, but rather that
Drupal\experience_builder\Plugin\DataType\ComponentInputs
should handle such scenario gracefully. - Enable
- 🇫🇮Finland lauriii Finland
Without the Component Source Plugin, we lose the metadata about the props/block settings. We would need to rely on data stored in XB field on a node and do best our attempt go generate input fields matching value, expression and source type.
This is certainly possible, but it feels like somewhat a separate deep dive that warrants it's own issue.I'm totally fine if we want to move this to a follow-up. Tagging just so that it doesn't get forgotten!
- Merge request !1029Subset of "Don't prevent component deletion" MR → (Closed) created by Unnamed author
- 🇬🇧United Kingdom f.mazeikis Brighton
During todays XB team scrum there was agreement that we should try to split the part of this issue MR that can be merged. Changes related to permissions and audit can be merged separately from the rest of the Fallback Source Plugin mechanism related work.
I've tried to do that in 3519168-subset-mr. - 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
I have a solution
here's the component edit form when in fallback state
And here's the recovered state
Will add some tests
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
#60 works for published content because we do client to server transformations during the entity conversion. This means any client-side representations of the model have been removed and we're back to the raw server side version.
But it doesn't work if the data is in the autosave store - opened 📌 [PP-1] Autosave data should store converted server-side representation of model Postponed for that because the scope here is already big enough and that is a big change on its own. Added a skipped test for this case and a passing test for the published case. In the auto save case, we're working with client data that is source plugin specific and needs access to the prop definitions. If we do the client to server transformation before writing to auto save, we don't need the prop field definitions around in order to re-do it.Also added 📌 [PP-1] Improve the UX of the fallback component input form Postponed to improve the initial version of the inputs form
Removing the follow up tag
- 🇫🇮Finland lauriii Finland
#60 🐛 Cannot delete JS components due to component depending on them Active is a great workaround to this problem 👏 Definitely remove some urgency from 📌 [PP-1] Improve the UX of the fallback component input form Postponed .
Could we update the text to: "Component has been deleted. Copy values to new component." to be a bit more concise?
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Could we update the text to: "Component has been deleted. Copy values to new component." to be a bit more concise?
Done 👌
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
@larowlan in #52: very nice work! 👏🤩 Glad to see #48.1 was easy, #48.2 has a stronger reason than I realized to be the way it is (thanks for the follow-up #3524052) and #48.3 was solved subsequently 👍
@lauriii in #54: The fallback rendering actually was rendering the subtrees on both the live site and in the preview. That's what the
Fallback
source was literally doing.You can run into this without even doing anything too crazy because if you add a required field to an existing content type with content, it makes all of the content invalid. We have no safe guards against that today.
This is not a fair comparison IMHO. If an SDC/code component adds a new required prop, the component will refuse/fail to render if it is not populated. Content entities in Drupal that don't have a required field just won't render that field, and subsequent edits will require a value to be specified.
Note: supporting new required props on SDCs/code components is actually the easiest problem to solve. Explanation at #3509115-6: Plan to allow editing props and slots for exposed code components → .document how one could delete all instances of a component when you really want to get rid of all of the content.
So, you're proposing a new issue for identifying and surfacing dangling/dead component subtrees? If so: +1, and no work should happen on it until after 📌 [PP-1] Consider not storing the ComponentTreeStructure data type as a JSON blob Postponed + 📌 [PP-1] Spike: Explore storing a hash lookup of component inputs Postponed are done, because they would significantly simplify the logic for finding+listing those dead subtrees, and for bulk-deleting them.
Tagging for follow-up.
@larowlan in #61 Woah, 📌 [PP-1] Autosave data should store converted server-side representation of model Postponed would be a massive change indeed.
Re-reviewing in detail. Hopeful to merge 🤓🤞
- 🇫🇮Finland lauriii Finland
The fallback rendering actually was rendering the subtrees on both the live site and in the preview. That's what the Fallback source was literally doing.
Is this still the behavior? If it is, we need at least a follow-up to revisit that.
This is not a fair comparison IMHO. If an SDC/code component adds a new required prop, the component will refuse/fail to render if it is not populated. Content entities in Drupal that don't have a required field just won't render that field, and subsequent edits will require a value to be specified.
The point was that core is not protecting the data from becoming invalid; instead it deals with it on the runtime. This is probably something we will have to do as well when it comes to changing props.
FWIW, you will run into that exact same problem if you use SDCs for rendering the content. Because of this, using required isn't common for components. For example, UI Suite themes are not using required fields at all.
So, you're proposing a new issue for identifying and surfacing dangling/dead component subtrees?
Yep, +1 for a follow-up on that. And +1 for postponing that until we have made decisions around what the data model is going to be.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
wim leers → credited penyaskito → .
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
This MR elevated the importance of 📌 Constraint slot names allowed by XB in its component tree Active .
@penyaskito seems to have struggled to understand the same bits of the MR as me — good reassurance — so I got his +1s for some of the comment/docs additions 😊🙏
The subtler/trickier bits of the
Fallback
plugin made me discover a bug in theblock
component source: 📌 `BlockComponent::validateComponentInput()` allows garbage to pile up Active .Epic work here, everyone — especially @larowlan & @f.mazeikis!
I think the essence of this issue is best described by
docs/components.md#3.4 Fallback
for architecture and end-user impact- the
ComponentInterface::setSource()
docblock for details wrt when "changing the source" is appropriate
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Cross-posted with @lauriii's #66.
You're right, @lauriii, that behavior was changed 👍 But the docs still said that was the behavior until a few seconds ago. And @penyaskito also got confused by the code — so docs in the relevant code have been clarified too 👍
Yep, +1 for a follow-up on that. And +1 for postponing that until we have made decisions around what the data model is going to be.
Done: ✨ [later phase] Provide API for finding and UI for surfacing dangling/dead component subtrees — aka garbage clean-up Postponed .
-
wim leers →
committed 0d0fa193 on 0.x authored by
larowlan →
Issue #3519168 by larowlan, wim leers, f.mazeikis, longwave, lauriii,...
-
wim leers →
committed 0d0fa193 on 0.x authored by
larowlan →
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Next up:
Automatically closed - issue fixed for 2 weeks with no activity.