Leap ahead of #3493070 in core: SDC `enum` props should have human-readable labels: use `meta:enum`

Created on 1 April 2025, 3 months ago

Overview

Enum vales do not have (translatable) labels.

We need human-readable equivalents, and those equivalents must be translatable (using Drupal's interface translation mechanism).

โš ๏ธ This should not be XB-specific.

โš ๏ธ Out-of-scope here: translatability. Nothing in XB is translatable yet today. This will add the necessary infrastructure to make it feasible later ๐Ÿ‘

Proposed resolution

  1. Fix this in core first: implement #3493070-10: SDC `enum` props should have translatable labels: use `meta:enum` โ†’ .
  2. Then, port that core MR to XB, with the following changes:
    1. XB should perform the equivalent of these in \Drupal\experience_builder\ComponentMetadataRequirementsChecker:
      1. INFRA: Update \Drupal\Core\Theme\Component\ComponentMetadata::parseSchemaInfo() to trigger a deprecation error when an enum is encountered without a corresponding meta:enum
      2. INFRA: Update \Drupal\Core\Theme\Component\ComponentMetadata::parseSchemaInfo() to trigger a \LogicException when a meta:enum is encountered whose keys do not match (i.e. are a subset or superset) the values listed in the corresponding enum.

      โ€ฆ but rather than deprecating or a logic exception, it will simply become a hard requirement for XB.

    2. XB must support this not only for SDCs, but also for its "in-browser code components" (aka JavaScriptComponent config entities), which use the same metadata structure as SDCs.
    3. Modify \Drupal\Tests\experience_builder\Functional\XbConfigEntityHttpApiTest::testJavaScriptComponent() to also create a enum prop. This should first fail validation (422 response), then upon adding the matching meta:enum, it should pass validation.

      This is XB's equivalent for

      1. TEST: kernel test asserting that a meta:enum not matching the enum triggers a \LogicException
    4. XB must change the logic in \Drupal\experience_builder\JsonSchemaInterpreter\SdcPropJsonSchemaType::toDataTypeShapeRequirements() to do the equivalent of
      1. INFRA: add a getEnumOptions(string $prop): array<string, TranslatableMarkup> method to \Drupal\Core\Theme\Component\ComponentMetadata inspired by ui_patterns' \Drupal\ui_patterns\EnumTrait::getEnumOptions(). (The thing that ui_patterns does not yet do is pass it through Drupal's t().)

      That means changing e.g.

            SdcPropJsonSchemaType::STRING => match (TRUE) {
              array_key_exists('enum', $schema) => new DataTypeShapeRequirement('Choice', [
                'choices' => $schema['enum'],
              ], NULL),
      

      to actually use the meta:enum values.

      (Note that here, they must NOT be translated โ€” translation must happen at runtime โ€” this corresponds to a FieldConfig config entity aka configuration.)

    5. Now update ui/tests/e2e/prop-types.cy.js to prove that the labels for the enum indeed appear in the UI, by updating the it('Enum (select) - string', () => { test case.

      This is XB's equivalent for

      1. TEST: kernel test asserting that 2 identical type: string, enum: [โ€ฆ] props can have different translations for the same enum values. For example: a '' enum value results in Same window for the target prop and in None for a rel prop.
        โ†’ verifies it works end-to-end, and supports translation contexts

User interface changes

  • 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/structure/component/status, with an explanation of why.
  • Any SDC (or code component) that does have both enum and a matching meta:enum will now see those labels in the component inputs form on the right-hand side.
๐Ÿ“Œ Task
Status

Active

Version

0.0

Component

Component sources

Created by

๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

Live updates comments and jobs are added and updated live.
  • Usability

    Makes Drupal easier to use. Preferred over UX, D7UX, etc.

Sign in to follow issues

Merge Requests

Comments & Activities

  • 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 ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • ๐Ÿ‡ง๐Ÿ‡ช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.
  • Pipeline finished with Failed
    2 months ago
    Total: 1766s
    #473001
  • ๐Ÿ‡ง๐Ÿ‡ช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.)

  • Pipeline finished with Failed
    2 months ago
    Total: 1870s
    #474743
  • Pipeline finished with Failed
    2 months ago
    Total: 1708s
    #475855
  • Pipeline finished with Failed
    about 2 months ago
    #488904
  • Pipeline finished with Failed
    about 2 months ago
    #489079
  • Pipeline finished with Failed
    about 2 months ago
    #489095
  • Pipeline finished with Failed
    about 2 months ago
    Total: 612s
    #489351
  • Pipeline finished with Failed
    about 2 months ago
    #491105
  • Pipeline finished with Running
    about 2 months ago
    #491232
  • Pipeline finished with Failed
    about 2 months ago
    Total: 630s
    #491333
  • Pipeline finished with Failed
    about 2 months ago
    Total: 523s
    #491387
  • Pipeline finished with Failed
    about 2 months ago
    Total: 602s
    #491424
  • Pipeline finished with Failed
    about 2 months ago
    Total: 643s
    #491462
  • Pipeline finished with Failed
    about 2 months ago
    Total: 3222s
    #492201
  • Pipeline finished with Failed
    about 2 months ago
    Total: 721s
    #492327
  • Pipeline finished with Success
    about 2 months ago
    Total: 672s
    #492379
  • ๐Ÿ‡ช๐Ÿ‡ธ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? ๐Ÿค”๐Ÿค”

  • Pipeline finished with Success
    about 2 months ago
    Total: 761s
    #492591
  • ๐Ÿ‡ช๐Ÿ‡ธ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.

  • Pipeline finished with Success
    about 1 month ago
    Total: 676s
    #495214
  • Pipeline finished with Failed
    about 1 month ago
    Total: 679s
    #495325
  • Pipeline finished with Success
    about 1 month ago
    Total: 742s
    #496358
  • ๐Ÿ‡ช๐Ÿ‡ธSpain penyaskito Seville ๐Ÿ’ƒ, Spain ๐Ÿ‡ช๐Ÿ‡ธ, UTC+2 ๐Ÿ‡ช๐Ÿ‡บ
  • Pipeline finished with Success
    about 1 month ago
    Total: 663s
    #501056
  • ๐Ÿ‡ช๐Ÿ‡ธ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.

  • ๐Ÿ‡ช๐Ÿ‡ธSpain isholgueras

    It needs to fix a complex conflict.

  • Pipeline finished with Failed
    25 days ago
    #510340
  • Assigned to isholgueras
  • Status changed to Needs work 23 days ago
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Partial review, but I'm pretty sure I spotted some significant simplification potential? ๐Ÿ˜‡

  • First commit to issue fork.
  • Pipeline finished with Failed
    22 days ago
    Total: 437s
    #513258
  • ๐Ÿ‡ช๐Ÿ‡ธ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.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    This needs to make meta:enum mandatory for XB. ๐Ÿ™ See the rationale.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • ๐Ÿ‡ช๐Ÿ‡ธSpain penyaskito Seville ๐Ÿ’ƒ, Spain ๐Ÿ‡ช๐Ÿ‡ธ, UTC+2 ๐Ÿ‡ช๐Ÿ‡บ
  • Pipeline finished with Failed
    14 days ago
    Total: 864s
    #519004
  • Pipeline finished with Failed
    14 days ago
    Total: 767s
    #519010
  • Pipeline finished with Failed
    14 days ago
    Total: 1474s
    #519018
  • Pipeline finished with Failed
    14 days ago
    Total: 2238s
    #519113
  • Pipeline finished with Failed
    14 days ago
    Total: 825s
    #519186
  • Pipeline finished with Failed
    14 days ago
    Total: 686s
    #519202
  • Pipeline finished with Failed
    14 days ago
    Total: 612s
    #519257
  • Pipeline finished with Failed
    14 days ago
    Total: 821s
    #519275
  • First commit to issue fork.
  • Pipeline finished with Failed
    14 days ago
    Total: 675s
    #519368
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    Merged in upstream, let's get this to passing tests so we can land it ๐Ÿ™

  • ๐Ÿ‡ช๐Ÿ‡ธSpain isholgueras
  • ๐Ÿ‡ช๐Ÿ‡ธSpain isholgueras

    Conflicts with 0.x fixed

  • Pipeline finished with Failed
    7 days ago
    #524380
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    @isholgueras is now (hopefully) AFK :)

  • Pipeline finished with Failed
    7 days ago
    Total: 680s
    #524648
  • Pipeline finished with Failed
    7 days ago
    Total: 613s
    #524661
  • Pipeline finished with Failed
    7 days ago
    #524687
  • Pipeline finished with Failed
    7 days ago
    #524703
  • Pipeline finished with Failed
    6 days ago
    Total: 569s
    #525348
  • Pipeline finished with Failed
    6 days ago
    Total: 1023s
    #525423
  • Pipeline finished with Failed
    6 days ago
    Total: 871s
    #525462
  • Pipeline finished with Failed
    6 days ago
    Total: 1450s
    #525555
  • Pipeline finished with Failed
    6 days ago
    Total: 1011s
    #525734
  • Pipeline finished with Failed
    6 days ago
    Total: 1035s
    #525737
  • Pipeline finished with Failed
    6 days ago
    Total: 1450s
    #525749
  • Pipeline finished with Failed
    6 days ago
    Total: 654s
    #525771
  • Pipeline finished with Failed
    6 days ago
    Total: 890s
    #525773
  • Pipeline finished with Failed
    6 days ago
    Total: 1427s
    #526233
  • ๐Ÿ‡ช๐Ÿ‡ธ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"
    //} 
    
  • Pipeline finished with Success
    5 days ago
    Total: 1782s
    #526330
  • ๐Ÿ‡ซ๐Ÿ‡ฎ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.
  • ๐Ÿ‡ณ๐Ÿ‡ฑNetherlands balintbrews Amsterdam, NL
  • Pipeline finished with Failed
    1 day ago
    Total: 1156s
    #529659
  • Pipeline finished with Failed
    1 day ago
    Total: 1048s
    #529662
  • ๐Ÿ‡ช๐Ÿ‡ธ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 complete meta:enum. We made the meta:enum optional at the YAML declaration level, but the parseSchemaInfo() 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...

Production build 0.71.5 2024