- Issue created by @wim leers
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Config schema changes necessary for XB's
JavaScriptComponent
config entities attached to help get this going 👍 - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Fixing markup.
And crediting @pdureau, for our collaboration at DrupalCon Atlanta to ensure XB and UI Patterns 2 are aligned 😊
- First commit to issue fork.
- Merge request !898#3516602 SDC `enum` props should have human-readable labels: use `meta:enum` → (Merged) created by penyaskito
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Exciting to see ✨ Enum vales do not have translatable labels Active be ready for review! Now let's get this going 😁 (Because XB can't wait for core to ship this in a release.)
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
This works and has good test coverage.
- We need a follow-up for when the core issue lands.
- We might want a follow-up to change the Code Components UI for having 2 fields and store option lists as "value => Human-friendly label" instead of having only the value as of now.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
Re-reading IS I think Wim expected to implement the Code Components here too? 🤔🤔
- 🇫🇮Finland lauriii Finland
+1 for the follow-ups mentioned in #12 📌 Leap ahead of #3493070 in core: SDC `enum` props should have human-readable labels: use `meta:enum` Active .
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
It took me a while to figure out why we need any change at all for JS Component.
So documenting it step by step.Right now, the site builder will generate their prop, and select "List: string".
They see a single textfield, named "Value", with placeholder "Enter a text value", where they input their values one by one, and select the default one.That generates:
js_component.enumcodecomponent.yml [...] props: color: title: Color type: string examples: - green enum: - blue - green - red - Orange - 'Another weird color'
One we enable the component, that transforms to:
experience_builder.component.js.enumcodecomponent.yml [...] allowed_values: - value: blue label: blue - value: green label: green - value: red label: red - value: Orange label: Orange - value: 'Another weird color' label: 'Another weird color'
So if they input a friendly label, that's what they get. For translation, we need to translate that config entity.
There's no way we can do this right without having some value - label pair on the client, or document how their values will be generated (potentially like prop names already are). In that case we might indicate in the UI that we expect labels, not values, and ideally print the value so they can copypaste that into the code editor.If we do that in the client, they will post the pairs (or the value can be easily calculated from the label, as prop names do). For simplicity, we use the same format than SDC (see props in js_component above).
And when we have that, it's the client who would send the enum and the meta:enum (optionally we might want a x-translation-context, or generate one server side, but that's definitely for another follow-up), and we will have the same info than a "meta:enum" complete component (or an easy way to generate it server-side), which will generate the right config entity allowed_values pairs for e.g. translation.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
I think this is ready if we split the code components part, which I moved to 📌 JsComponents `enum` props should have human-readable labels: use `meta:enum` Active
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
We'll work on JsComponents here.
- 🇪🇸Spain isholgueras
I wanted to add a new code component with 2 props, one with enums and another one with enums and meta:enums to have a yml file with this as an example.
We had tested it in
XbConfigEntityHttpApiTest
but I think having a code component in a yml is useful for testing and for new adopters to see how is done.I've also fixed issues with HEAD.
Steps to test, in Summary, is also updated.
- Assigned to isholgueras
- Status changed to Needs work
about 1 month ago 1:47pm 2 June 2025 - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Partial review, but I'm pretty sure I spotted some significant simplification potential? 😇
- First commit to issue fork.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
✨ Enum vales do not have translatable labels Active landed in time for 11.2.0
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
#28: 🎉🥳
Next up: make XB leap ahead of core by landing this MR … ⚠️ but because XB will not be able to require 11.2 until AFTER beta1, we need to be careful about how we approach it.
- First commit to issue fork.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Merged in upstream, let's get this to passing tests so we can land it 🙏
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
All tests passing 🎉
Something that doesn't have e2e tests is the code editor, but we need to fix it to at least send the same values in enum as meta:enum.
Bálint volunteered to write this.@balintbrews For now I'd expect to send the same added values as labels. The only thing to take into account is replacing dots with underscores. Something like:
const getMetaEnumValue = (x: string) => x.replace('.', '_'); const enumValues = [ '3.14', 'b', 'c', ]; const metaEnums = Object.fromEntries(new Map(enumValues.map(value => [getMetaEnumValue(value), value]))) console.log(metaEnums); //{ // "3_14": "3.14", // "b": "b", // "c": "c" //}
- 🇫🇮Finland lauriii Finland
Any SDC that has enum without the necessary meta:enum will no longer be available to XB users, and will now appear in the list of disabled XB components at /admin/appearance/component/status, with an explanation of why.
I'm not entirely convinced that we should not allow SDCs without meta:enum to be used in XB because it is possible to achieve an acceptable UX without providing meta:enum, albeit not in all scenarios. For example, for margin-top, you could choose to provide options '4px', '6px', and '8px'. In this case the same value could apply both as the human readable and machine readable value.
We could still allow translating the enum options but keep the machine readable names consistent across translations or we could simply prevent translating these enums.
I don't think this needs to block this issue from being committed. It seems that we could loosen this requirement in future if this would require a non-trivial amount of work to change.
- First commit to issue fork.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
I need to self-review this yet, but feels close. Bálint changes look good to me, thanks!
- 🇫🇷France pdureau Paris
I'm not entirely convinced that we should not allow SDCs without meta:enum to be used in XB because it is possible to achieve an acceptable UX without providing meta:enum, albeit not in all scenarios. For example, for margin-top, you could choose to provide options '4px', '6px', and '8px'. In this case the same value could apply both as the human readable and machine readable value.
Hi Lauriii,
According to the 🐛 Don't raise exception when an enum value is missing from meta:enum Active , all SDC prop with an
enum
has also a completemeta:enum
. We made themeta:enum
optional at the YAML declaration level, but theparseSchemaInfo()
method is aligning the values:// Ensure all enum values are also in meta:enum. $enum = array_combine($prop_schema['enum'], $prop_schema['enum']); $prop_schema['meta:enum'] = array_replace($enum, $prop_schema['meta:enum'] ?? []);
Source: https://git.drupalcode.org/project/drupal/-/commit/166350f2acc649d60e4da...
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
This is ready for further reviews.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
After raising a single (but very important because affecting
Component
versions and update paths for component instances) concern, then thinking I was wrong and reverting, then actually realizing I might've been right, it took me a few hours of digging deep into how theoptions
module's field/widget infrastructure works, to find a better solution that overcomes all concerns and has the blessing of @penyaskito! (Just paired with him and demonstrated it.)Let me illustrate it using XB's
heading
SDC'sComponent
config entity's versions — start at the bottom of this example, because top = newest, bottom = oldest:uuid: 6864c52b-71e4-4342-a825-0ce0f58b9533 langcode: en status: true dependencies: module: - options active_version: 9616e3c4ab9b4fce versioned_properties: active: 👈 👈👈 This represents the approach I refactored it to. No more labels, but also no more enum values. ⚠️ This is fine, because ComponentSourceBase::generateVersionHash() uses the normalized prop shapes to generate a deterministic hash, so changes in `enum` cause a new version, changes in `meta:enum` do not 👍 settings: prop_field_definitions: element: field_type: list_string field_storage_settings: allowed_values_function: experience_builder_load_allowed_values_for_component_prop 👈 👈👈 No more labels! field_instance_settings: { } field_widget: options_select default_value: - value: h1 expression: ℹ︎list_string␟value style: field_type: list_string field_storage_settings: allowed_values_function: experience_builder_load_allowed_values_for_component_prop 👈 👈👈 No more labels! field_instance_settings: { } field_widget: options_select default_value: - value: primary expression: ℹ︎list_string␟value text: field_type: string field_storage_settings: { } field_instance_settings: { } field_widget: string_textfield default_value: - value: 'A heading element' expression: ℹ︎string␟value fallback_metadata: slot_definitions: { } ebbad79a7ac7d1fa: 👈 👈👈 This represents the state in the MR I started reviewing, after I broke it 😅 settings: prop_field_definitions: element: field_type: string field_storage_settings: { } field_instance_settings: { } field_widget: string_textfield default_value: - value: h1 expression: ℹ︎string␟value style: field_type: string field_storage_settings: { } field_instance_settings: { } field_widget: string_textfield default_value: - value: primary expression: ℹ︎string␟value text: field_type: string field_storage_settings: { } field_instance_settings: { } field_widget: string_textfield default_value: - value: 'A heading element' expression: ℹ︎string␟value fallback_metadata: slot_definitions: { } 94d7e3cb448df7c9: 👈 👈👈 This represents the state of the MR I started reviewing. settings: prop_field_definitions: element: field_type: list_string field_storage_settings: allowed_values: 👈 👈👈 Note the labels for the enum values are exactly what you'd expect! - value: div label: Container - value: h1 label: Header 1 - value: h2 label: Header 2 - value: h3 label: Header 3 - value: h4 label: Header 4 - value: h5 label: Header 5 - value: h6 label: Header 6 field_instance_settings: { } field_widget: options_select default_value: - value: h1 expression: ℹ︎list_string␟value style: field_type: list_string field_storage_settings: allowed_values: - value: primary label: Primary - value: secondary label: Secondary field_instance_settings: { } field_widget: options_select default_value: - value: primary expression: ℹ︎list_string␟value text: field_type: string field_storage_settings: { } field_instance_settings: { } field_widget: string_textfield default_value: - value: 'A heading element' expression: ℹ︎string␟value fallback_metadata: slot_definitions: { } 1b4f8df7c94d7e3c: 👈 👈👈 This represents the state in HEAD. settings: prop_field_definitions: element: field_type: list_string field_storage_settings: allowed_values: 👈 👈👈 Note the labels for the enum values are … just the enum values. This is the terrible UX we want to fix. - value: div label: div - value: h1 label: h1 - value: h2 label: h2 - value: h3 label: h3 - value: h4 label: h4 - value: h5 label: h5 - value: h6 label: h6 field_instance_settings: { } field_widget: options_select default_value: - value: h1 expression: ℹ︎list_string␟value style: field_type: list_string field_storage_settings: allowed_values: - value: primary label: primary - value: secondary label: secondary field_instance_settings: { } field_widget: options_select default_value: - value: primary expression: ℹ︎list_string␟value text: field_type: string field_storage_settings: { } field_instance_settings: { } field_widget: string_textfield default_value: - value: 'A heading element' expression: ℹ︎string␟value fallback_metadata: slot_definitions: { } label: Heading id: sdc.experience_builder.heading provider: experience_builder source: sdc source_local_id: 'experience_builder:heading' category: Atom/Text
Next: make the MR pass again, by updating all
component_version
s all over the MR, because the differentsettings
in theComponent
config entities that contain >=1enum
-shaped prop cause a different deterministic version hash 😅 - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Green except e2e tests, hoping that @penyaskito can fix those. 😇
Epic work here! 👏
Still needs follow-up for updating the code component editor UI: https://git.drupalcode.org/project/experience_builder/-/merge_requests/8...
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
Didn't get to find why yet, but the enums aren't loading the default value/ set value correctly.
e.g.
- add a One Column SDC
- Set width to Narrow
- Select another component to navigate away
- Select the One Column component
- See width is not set to Narrow
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
What I've found is that this might be that we need some changes in the client UI that I didn't spot yet.
A symptom:
1. Add a heading component (has 2 enums)
2. Add a druplicon component
3. Edit the heading style + element props (enums)
4. Click on the druplicon. The form fails to load.
5. Back to heading, the style + elements have the defaults instead of our changes. - 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Thanks, that's helpful. I suggest you switch to something else for a bit, it sounds like this has been a frustrating ride :/
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
I tested this and with this MR the values aren't set for any prop, not only enum, even when the SDC has no enums.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Paired with @penyaskito on this. We got closer.
- Original state to start editing a page/article without anything in auto-save, the
/xb/api/v0/api/layout/node/1
response contains this after placing a new Heading SDC:
-
Then, upon changing the default value for the
text
prop, the client incorrectly sends this
Note how the original prop value remains present (left) and the value I actually entered is sent with the wrong key (right).
This is what's causing things to not work. This appears to be happening in
buildPreparedModel()
, which is what generates the value forform_xb_props
. - Original state to start editing a page/article without anything in auto-save, the
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
The last js component failures are because 🐛 Don't raise exception when an enum value is missing from meta:enum Active avoids any way to provide meta:enums, overriding them even when set.
This is a problem when using
\Drupal\experience_builder\Plugin\ExperienceBuilder\ComponentSource\JsComponent::buildEphemeralSdcPluginInstance
for validating js components as sdc components. - First commit to issue fork.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
Updated after 📌 Remove "List: number" as an available shape in the code component editor Active landed.
- 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺
Back to green. Added the followup needed in IS.
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Thanks, @penyaskito! 🙏
https://git.drupalcode.org/project/experience_builder/-/merge_requests/8... → well done!
Just one final question/thing that needs to be updated: https://git.drupalcode.org/project/experience_builder/-/merge_requests/8...
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
Finally. 🥹
- Create
@todo
s pointing to a yet-to-be-created follow-up issue that drop XB's logic in favor of core'sComponentMetadata::getEnumOptions()
, as well as any other things we could drop from XB once XB requires a core version containing #3493070.
This was added in #3 but is obsolete, because core didn't end up adding any such infrastructure 😅
- Create
-
wim leers →
committed a1948186 on 0.x authored by
penyaskito →
Issue #3516602 by penyaskito, isholgueras, wim leers, balintbrews,...
-
wim leers →
committed a1948186 on 0.x authored by
penyaskito →