Overview

In DummyPropsEditForm we're reading the following from the component list data:

  • sourceType
  • sourceTypeSettings
  • expression

However this assumes that every component uses the same expression/source. It does not allow for linked/dynamic values.

And Block-sourced components do not use "prop sources" at all! (See #3491978: Implement saving block settings forms.)

Proposed resolution

  1. Evolve the client-side representation of available components to instantiate from a single catch-all export interface Component to:
    export interface SimpleComponent {
      name: string;
      id: string;
      default_markup: string;
      css: string;
      js_header: string;
      js_footer: string;
      // The source plugin label.
      source: string;
    }
    
    export interface PropSourceComponent extends SimpleComponent {
      // @todo rename this to propSources - https://www.drupal.org/project/experience_builder/issues/3504421
      field_data: FieldData;
      metadata: {
        slots?: {
          [key: string]: {
            title: string;
            [key: string]: any;
          };
        };
        [key: string]: any;
      };
      source: string;
      transforms: TransformConfig;
    }
    
    export type Component = PropSourceComponent | SimpleComponent;
    
  2. Evolve the client-side model for a Component (see above TS) to:
    …snip…
    
    export type PropSource =
      | AdaptedPropSource
      | StaticPropSource
      | DynamicPropSource;
    
    export type ResolvedValues = Record<string, AnyValue>;
    
    export interface ComponentModel {
      name: string;
      // The props that are used to render previews and will be used for client-side
      // preview updates (when they're supported).
      resolved: ResolvedValues;
    }
    
    export type Sources = Record<string, PropSource>;
    
    export interface EvaluatedComponentModel extends ComponentModel {
      // Source props/expressions needed by the server.
      source: Sources;
    }
    

This paves the path for:

  1. #3455629: [PP-1] [META] 7. Content Templates — aka "default layouts" — affects the tree+props data model in the future (which will need DynamicPropSources).
  2. #3500152 — see #3500152-6: Remove InputBehaviorsBlockSettingsForm and consolidate with input components form
  3. … more ComponentSource plugins
  4. closing the overarching #3467954: META: Evolve XB UI's data model to allow non-SDC components' inputs, DynamicPropSource support, etc..

User interface changes

None.

Command icon 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

larowlan created an issue. See original summary.

wim leers’s picture

💯

larowlan’s picture

Assigned: Unassigned » larowlan

wim leers’s picture

Pre-emptive high-level review, prior to a green test run. 🏓

I am worried how this is changing the tightening that #3481720: Tighten validation: only allow StaticPropSource in XB fields + PageTemplate, DynamicPropSource in ContentTypeTemplate brought. AFAICT that's only necessary because #3455629: [PP-1] [META] 7. Content Templates — aka "default layouts" — affects the tree+props data model is not yet done, and we want the UI to leap forward in this way?

Also linked issues that are referenced by @todos in the MR.

larowlan’s picture

Title: Maintain a per-component set of prop expressions/sources » [PP-1] Maintain a per-component set of prop expressions/sources
Status: Active » Postponed (maintainer needs more info)
Related issues: +#3499540: Remove dynamic prop sources from test data
larowlan’s picture

Issue summary: View changes
larowlan’s picture

Status: Postponed (maintainer needs more info) » Postponed
wim leers’s picture

Title: [PP-1] Maintain a per-component set of prop expressions/sources » Maintain a per-component set of prop expressions/sources
Status: Postponed » Needs work

longwave made their first commit to this issue’s fork.

longwave’s picture

The issue with component-operations.cy.js is

      'static-static-card1ab' => [
        'heading' => [
          'sourceType' => 'static:field_item:string',
          'value' => 'hello, world!',
          'expression' => 'ℹ︎string␟value',
        ],
        'cta1href' => [
          'sourceType' => 'static:field_item:uri',
          'value' => 'https://drupal.org',
          'expression' => 'ℹ︎uri␟value',
        ],
      ],

Because we only have these two props set in the stored model, only these two fields actually render in the SDC component form. Not sure where to fix this, putting this down here for today.

larowlan’s picture

Assigned: larowlan » wim leers
Status: Needs work » Needs review

This is green now 🎉

wim leers’s picture

(FYI: I've not lost track of this; @larowlan has just indicated that #3491978: Implement saving block settings forms is more important to land first.)

wim leers’s picture

Assigned: wim leers » Unassigned
Priority: Normal » Major
Status: Needs review » Needs work

I'm very sorry, but #3500994: Remove references to 'props' outside of SDC - use 'inputs' instead seemed both more important and like it could help make this more clear, because it'd ensure this MR would then make this change from a clearer starting point.

So I'm afraid this needs a reroll. But I'm very eager to get this in early next week :)

P.S.: please first check #3500994-15: Remove references to 'props' outside of SDC - use 'inputs' instead + #3500994-18: Remove references to 'props' outside of SDC - use 'inputs' instead — I think this issue is the perfect one to identify what could/should be clearer in docs/shape-matching-into-field-types.md.

wim leers’s picture

Per #3501902-20: Adding the Image component results in a state considered invalid, let's get this going again! And … I see @larowlan already did 😄 🤩

wim leers’s picture

Priority: Major » Critical
Issue tags: +stable blocker
Related issues: +#3501902: Adding the Image component results in a state considered invalid
wim leers’s picture

Component: Page builder » Data model
wim leers’s picture

Issue summary: View changes
Issue tags: +Needs issue summary update

#3499554: Move client-side assumptions about prop form data shape into a series of prop-specific transforms landed, let's get this in next!

@longwave already started pushing this forward today 👍

HardcodedPropsComponentTreeItem was already removed in #3491978: Implement saving block settings forms 😄

wim leers’s picture

Assigned: Unassigned » wim leers
Status: Needs work » Needs review

In #12 (on Jan 17, >2 weeks ago), @larowlan assigned this to me for review. Then we landed a bunch of other issues first.

Time to review this, even though it's not currently passing tests. I don't want @larowlan's work here to go to waste.

wim leers’s picture

Made minor tweaks only, and now this MR is passing all PHP tests, and most of the e2e tests. See attached patch for the full set of changes I made — it's only 7 files changed, 26 insertions(+), 9 deletions(-).

Review

Most important first:

  1. There are a few @todos relating to the handling of default values — AFAICT that's what #3493943: SDC+JS Component Sources: split default values into `resolved` and `source` is for. Please confirm 🙏
  2. I'm concerned about how this makes the hydrated computed field property much more complicated; that was always intended for hydration prior to rendering, not for editing. But #3455898: Connect client & server, with zero changes to client (UI): rough working endpoints that mimic the UI's mocks indeed made the sensible-at-the-time decision to use hydrated to generate the client-side layout + model (for the /api/layout/{entity_type}/{entity} route).
  3. Some naming concerns, because this is the golden opportunity to make the connection between client-side terminology/infra and server-side terminology/infra more coherent. Especially now that #3498889: ComponentSource plugin for code components introduced GeneratedFieldExplicitInputUxComponentSourceBase as a common foundation for "SDC" and "JS" components. Looks like @larowlan already raised similar concerns in his self-review 😄 My observations: https://git.drupalcode.org/project/experience_builder/-/merge_requests/5...
  4. … plus relatively minor things on the MR.
wim leers’s picture

This MR is going through the effort of making sure the client side has both a source and resolved representation. It even updated openapi.yml to convey that it expects /api/layout/{entity_type}/{entity} to return that in its response. But … only openapi.yml examples were updated, not its schema.

Otherwise it would've flagged that the actual responses do not match the prescribed schema! However … for Block-sourced components, the source and resolved key-value pairs should not exist! Fortunately, OpenAPI 3 supports polymorphism for this: https://swagger.io/docs/specification/v3_0/data-models/inheritance-and-p...

Per \SchemaTest::testDiscriminator(), the OpenAPI validation library XB is using does support that 👍

Digging into this made me stumble upon #3494684: Add ::clientModelToInput() to ComponentSourceInterface, the inverse of ::inputToClientModel(), which is very closely related to that. In fact, landing that trivial change should enable this MR to avoid all concerns I raised over at https://git.drupalcode.org/project/experience_builder/-/merge_requests/5... 😇

wim leers’s picture

Finally: the e2e tests are still failing due to

{
                      "status": 500,
                      "data": {
                        "message": "Missing the keys value."
                      }

… which is due to https://git.drupalcode.org/project/experience_builder/-/merge_requests/5...

The client side still needs to merge in that value when assembling the request body to send to ComponentInputsForm.

wim leers’s picture

#3494684: Add ::clientModelToInput() to ComponentSourceInterface, the inverse of ::inputToClientModel() is in, this MR can now take advantage of that, and remove the complex additions to ComponentTreeHydrated.

wim leers’s picture

See https://git.drupalcode.org/project/experience_builder/-/merge_requests/5... for how I implemented #23.

This now feels more tightly scoped and hence more within reach than this morning. I hope @larowlan agrees 😊 I think there's more server-side changes that can be omitted, especially in tests.

larowlan’s picture

So we have an answer to #3491215: Pass model props to ComponentInputsForm via PATCH to avoid limitations with GET due to URL length then - in our failing cypress tests on this issue.

{
                      "status": "PARSING_ERROR",
                      "originalStatus": 414,
                      "data": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>414 Request-URI Too Long</title>\n</head><body>\n<h1>Request-URI Too Long</h1>\n<p>The requested URL's length exceeds the capacity\nlimit for this server.<br />\n</p>\n</body></html>\n",
                      "error": "SyntaxError: Unexpected token '<', \"<!DOCTYPE \"... is not valid JSON"
                    }

So I think this is blocked on #3491215: Pass model props to ComponentInputsForm via PATCH to avoid limitations with GET due to URL length and we need to make form fetching use a POST request.

wim leers’s picture

longwave’s picture

Status: Needs review » Reviewed & tested by the community

I've been over the MR twice and done some manual poking around with it - no additional comments, I think this is ready to land; onwards to the next issue!

  • wim leers committed 65e19288 on 0.x authored by larowlan
    Issue #3493941 by larowlan, wim leers, longwave: Maintain a per-...
wim leers’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Fixed
Issue tags: -Needs issue summary update

Given that @bnjmnm has been expressing his +1 to the direction taken by @larowlan in #3499554: Move client-side assumptions about prop form data shape into a series of prop-specific transforms and #3499550: Support server-side massaging and validating of ComponentInputsForm values, I think it's reasonable for me to merge this without Ben's explicit +1.

Especially considering @larowlan is going to go on PTO after tomorrow, so I'd rather have him finish as much as possible of #3467954: META: Evolve XB UI's data model to allow non-SDC components' inputs, DynamicPropSource support, etc. before then.

This paves the path for:

  1. #3455629: [PP-1] [META] 7. Content Templates — aka "default layouts" — affects the tree+props data model in the future (which will need DynamicPropSources).
  2. #3500152 — see #3500152-6: Remove InputBehaviorsBlockSettingsForm and consolidate with input components form
  3. … more ComponentSource plugins
  4. closing the overarching #3467954: META: Evolve XB UI's data model to allow non-SDC components' inputs, DynamicPropSource support, etc..
wim leers’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.