Overview
Code components, once they're added to components, i.e. become exposed, lock props and slots. This was implemented in #3500081: Editing components sourced as code components.
On a related issue, #3509089: Code component status is not reflected in the code editor, @lauriii raised the following:
the updated status is not reflected in the code editor when the component's code is edited, which is supposed to lock props and slotsThis seems like a pretty drastic consequence. I think we need follow-up issue to find a better way for managing this because it's fairly normal that especially during the initial development of a site that props might change.
Comment by @balintbrews:
[...] it was an easy consensus within the team that we need to ensure that once a component is exposed, which means it can be used for content, we need to ensure data integrity. Props can be updated by moving the component back to internal, where the prerequisite is that it's not used on the page. Maybe we can forego locking props and slots when that prerequisite is met. Happy to discuss in a follow-up.
Comment by @Wim Leers:
Agreed with [comment by @balintbrews]. That requires us knowing whether there's any instances of the code component, as described by @tedbow at #3500043-3: Publishing code components
Proposed resolution
Back-end changes needed
- ✅ adding optional props #3556337: BE: Ensure we support adding a new optional prop to an in-use code component
- ✅ adding required props or making an optional prop required #3556338: BE: Support adding a new required prop with an example to an in-use code component
- 🟢 removing props Mostly works but #3524401: `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` allows garbage to pile up still needs evaluation/resolution
- 🟢 removing a slot #3557272: BE: Support removing a slot from a code component
- 🔴 changing the shape of existing props #3557271: [PP-2] BE: Support changing the data-type of a code component prop (some discussion still pending on data integrity)
- 🟡 upgrading between versions#3463996: [META] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade
No back-end changes needed
- ✅ adding a new slot #3556336: BE: Support adding a new slot to an in-use code component
- ✅ modifying default/examples for slots/props #3557262: Support modifying the default/example value for a code component prop or slot
Combined front-end changes
User interface changes
TBD
Issue fork canvas-3509115
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
balintbrewsComment #4
wim leersCrediting @tedbow for #3500043-3: Publishing code components.
Comment #5
wim leersRelated: #3500074: Usage info for code components with unpublished changes. Because … it'd be 100% safe to change props and slots whenever as long as there are no instances yet. And thanks to #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation, that's now actually possible.
IOW: the conversation here needs to be forked along two paths:
Comment #6
wim leersNote: a new required prop would actually be trivial to support. Because XB requires required props to have an example value!
Especially since #3518336: When a field instance used by a `ContenTemplate` is deleted, or a field-type providing module is uninstalled, replace affected `inputs` with default `StaticPropSource` just added
::getDefaultExplicitInput(), this would be easy to support.Conceptually speaking, the needed changes would be:
ComponentTreeHydratedwould have to change fromto
ValidComponentTreeConstraintValidatorwould need to be updated to relax fromto also do
+ $source->getDefaultExplicitInput()OR
\Drupal\experience_builder\Controller\ClientServerConversionTrait::convertClientToServer()should do+ $source->getDefaultExplicitInput(), which would ensure that any edit to any component tree would automatically add new required props' default values.Comment #7
wim leersImportant for usability of Code Component creators.
Critical for XB's data integrity when we add support for changing props/slots.
Comment #8
wim leersLet's discuss and plan how we could improve this.Initial plan posted! 🏓
Comment #9
wim leers@lauriii, please see the proposed resolution.
Comment #11
lauriiiThe scope of this issue is both props and slots but it looks like the issue summary is only talking about props. Adding the 'Needs issue summary update' tag to expand the proposed solution to include slots.
I think we should allow this to be done. Prop data will be either converted to the new prop type (when possible) or deleted (when conversion is not possible) when component with the changed prop type is loaded.
Comment #12
larowlanComment #13
larowlanAdded child issues and updated the issue summary to reference them
Comment #14
larowlanComment #15
larowlanComment #18
larowlanComment #19
wim leersYou can state that if you want, but that's not a trivial undertaking. Different field types might support the same prop shape, but might store data completely differently.
A number of field types for example use computed properties, and it's only the computed properties that can populate a certain prop shape … the stored data may not even look like it.
And that's just when the prop shape remains the same! You're talking about changing the prop shape, which is an even more difficult transition.
So -1 for including that in the scope here. That's #3463996: [META] [PP-1] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade territory, and would be a significant scope expansion even there.
Huh?! 🤯 How is that not data loss? Can you please elaborate?
EDIT: and the current issue summary still also indicates that we won't support this:
So perhaps I'm just misreading what @lauriii wrote here? 😅
Comment #20
lauriiiI think it's fine to punt that feature to a follow-up issue which we may or may not prioritize depending on feedback. I don't think it's the most critical aspect of this issue. The reason I think we should consider doing that is to avoid data loss like you mention. However, we still should allow changing the prop type by first deleting the prop and then adding a new prop with the same name. It includes a delete action which makes it clear that data loss is involved.
Comment #21
larowlanComment #22
larowlan.
Comment #23
effulgentsia commented.
Comment #24
effulgentsia commented.
Comment #25
effulgentsia commentedOrganizing list of issues in summary into sections.
Comment #26
effulgentsia commented.
Comment #27
larowlanComment #29
larowlan.
Comment #30
larowlan.
Comment #31
penyaskito#3556337: BE: Ensure we support adding a new optional prop to an in-use code component merged.
Comment #32
wim leersThat MR that landed, wow …
\Drupal\Tests\canvas\Kernel\Plugin\Canvas\ComponentSource\JsComponentEvolutionTestis magnificent! Almost 1000 LoC, but that's necessary for maintaining data integrity and ensuring all of this is possible via both PHP an Canvas' internal HTTP API 👏Beautiful work, @larowlan & @penyaskito!
Comment #33
effulgentsia commented#27 reverted (I think unintentionally) my issue summary organization from #26, so I reverted back to the issue summary from #26.
Comment #34
effulgentsia commentedRemoved the last section of the proposed resolution, some of which is outdated, and the rest a repeat of what's above it.
Comment #35
effulgentsia commentedComment #36
effulgentsia commented.
Comment #37
penyaskitoStill not clear if removing a required prop is allowed. By my tests on #3567413: When editing a Canvas entity with a component tree (e.g., page, template, or region), automatically upgrade component instance versions for cases where there's no impact on existing data, it's not completely covered. Maybe we missed an issue here? Or this is deliberately not supported? What should happen then if that happens in an SDC? I might be able to answer my question looking at
\Drupal\Tests\canvas\Kernel\Plugin\Canvas\ComponentSource\ComponentInputsEvolutionTestand\Drupal\Tests\canvas\Kernel\Plugin\Canvas\ComponentSource\JsComponentEvolutionTest, which I didn't yet.Comment #38
lauriiiThis should be allowed. From UX perspective it should be handled the same way as a deletion of an optional prop.
Comment #39
wim leers#3557272: BE: Support removing a slot from a code component landed, now just needs follow-ups created.
Comment #40
wim leersWhat remains to be done here? #3463996: [META] [PP-1] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade seems obsolete, but simultaneously weirdly is still open yet the issue summary marks it with 🟢?
Related: #3524751-10: [later phase] Component Source plugins: generalized support for schema changes of explicit inputs — that is still necessary for e.g. the Block component source.
Comment #41
penyaskitoUpdated IS for #3463996: [META] [PP-1] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade. It's marked with 🟢 because the required changes for this META were done in the sub-issues (aside of changing shapes).
What's left here is 🔴 changing the shape of existing props, which still needs to be discussed., as implies potential data loss.
I'm tempted to mark both METAs as fixed, even if both have still open child issues.
Comment #42
wim leersPer #3463996-45: [META] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade and #3463996-51: [META] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade, changing #3463996 from 🟢 to 🟡. The needle is also moving forward for , see that first comment.