Problem/Motivation

✅ Unblocked by #3452397: Allow specifying default props values when opting an SDC in for XB.
✅ Unblocked on #3452397: Allow specifying default props values when opting an SDC in for XB.
✅ Un-soft-blocked by #3455898-4: Connect client & server, with zero changes to client (UI): rough working endpoints that mimic the UI's mocks, which may be fixed either there by @jessebaker or in a follow-up issue.
✅ Unblocked by #3461499: Support complex SDC prop shapes: introduce (Storable)PropShape to compute field type storage settings.

The UI currently assumes all SDC props have static values (which is why #3455898: Connect client & server, with zero changes to client (UI): rough working endpoints that mimic the UI's mocks's logic is even transforming SDC props populated by DynamicPropSources to static values for the client/UI, because that is what the client currently expects).

The HTTP API should race ahead of the UI, to empower the UI to surface multiple choices to the end user — choices that the FieldForComponentSuggester service can already generate:

This SHOULD also update the Open API spec if #3450308: Create an Open API spec for the current mock HTTP responses landed before this is done.

Steps to reproduce

(See how in the /node/1/edit UI, the component instance with fake UUID dynamic-static-card2df uses a DynamicPropSource for the text SDC prop. Then see how in the UI, that is presented as a static value, i.e. as a StaticPropSource.)

Proposed resolution

  1. Make /xb-component/… return not just {id: …, name: …, metadata: …} for every component, but {id: …, name: …, metadata: …, prop_source_choices: …}
  2. For the purpose of this issue (and sufficient for 0.1.0), this can be hardcoded to FieldForComponentSuggester::suggest($component_id, EntityDataDefinition::create('node', 'article');
  3. The adapters key that ::suggest() returns MUST be removed: out of scope for 0.1.0
  4. The types key MUST be filtered down to the choice allowed by the configuration being added in #3452397: Allow specifying default props values when opting an SDC in for XB. omitted, in favor of the sole choice computed by #3461499: Support complex SDC prop shapes: introduce (Storable)PropShape to compute field type storage settings.
  5. The instances key MUST be passed through as-is.
  6. This must come with explicit Functional test coverage. Look at \Drupal\Tests\experience_builder\Kernel\FieldForComponentSuggesterTest + \Drupal\Tests\experience_builder\Functional\EndToEndDemoIntegrationTest for inspiration.

Remaining tasks

All points above.

User interface changes

None — this is about leaping ahead of the UI, to allow it to offer the user a choice.

API changes

New API/endpoint to talk to.

Data model 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

Wim Leers created an issue. See original summary.

larowlan’s picture

The FE of this is handled in #3452582: Make store API paths/uris configurable via environment variables (and eventually drupalSettings) it shows (in comments) the extension points. I knew we'd need this at some point so took the time to document it there.

wim leers’s picture

Assigned: Unassigned » wim leers
Issue tags: +Needs issue summary update

I need to update this issue — many things have changed since this was created.

wim leers’s picture

Title: [PP-2] HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context » [PP-1] HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context
Assigned: wim leers » Unassigned
Priority: Normal » Critical
Issue summary: View changes
Issue tags: -Needs issue summary update

All originally identified blockers are in. But #3461499: Support complex SDC prop shapes: introduce (Storable)PropShape to compute field type storage settings changes things.

Issue summary fully updated 👍

wim leers’s picture

Title: [PP-1] HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context » HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context
Issue summary: View changes
wim leers’s picture

Status: Postponed » Active
bnjmnm’s picture

Assigned: Unassigned » bnjmnm

bnjmnm’s picture

Assigned: bnjmnm » Unassigned
Status: Active » Needs review
wim leers’s picture

Thank you, @bnjmnm, for getting this going! 🤩🙏

This looks stellar. Zero remarks on the code. Looks like the details I write >2 months ago were sufficient? 🤓

The exact shape of the response is irrelevant at this time — because the very purpose of this issue is to just leap ahead of the UI and at least allow some experimentation to happen on the front end when the necessary designs for this eventually arrive.

But I am surprised the new test does not fail because #3450308: Create an Open API spec for the current mock HTTP responses introduced an OpenAPI spec that covers this route too. In that OpenAPI spec, /xb-components has this schema:

                type: object
                minProperties: 1
                # @see \Drupal\Core\Plugin\Component::$machineName
                patternProperties:
                  '^\\[a-zA-Z0-9_-]:[a-zA-Z0-9_-]$':
                    $ref: '#/components/schemas/Component'

and that $ref does list additionalProperties: false, which this test should be triggering? 🤔

Now, I know that I literally just wrote:

The exact shape of the response is irrelevant at this time […]

… but I'd expect we'd need to update openapi.yml somewhat like this as a very MVP way to capture this in the OpenAPI spec:

diff --git a/openapi.yml b/openapi.yml
index a29efe50..4160b691 100644
--- a/openapi.yml
+++ b/openapi.yml
@@ -180,6 +180,10 @@ components:
                 type: [string, integer, number, boolean, object]
         default_markup:
           type: string
+        # @todo Refine when designs for choosing a PropSource arrive.
+        # @see https://www.drupal.org/project/experience_builder/issues/3455975
+        prop_source_choices:
+          type: object
       additionalProperties: false
     Layout:
       title: layout
wim leers’s picture

Status: Needs review » Needs work

Still missing here: an update to openapi.yml. The fact that this is currently passing tests is indicative of the openapi.yml file not being validated correctly by ApiResponseValidator, because additionalProperties: false in $ref: '#/components/schemas/Component' should result in a validation error 😬

wim leers’s picture

Issue tags: +openapi
wim leers’s picture

Ugh, looks like thephpleague/openapi-psr7-validator does not really support patternProperties, because the only mention of it is in a comment, and the same goes for devizzent/cebe-php-openapi which it relies upon?! 😱🤯

😭

Time to call it a day.

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

tedbow’s picture

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

@Wim Leers see my MR comments. let me know what you think the `x-xb-validation` using the OpenAPI extension naming to check this. If you are good with approach assign it back to me and I will finish it up

wim leers’s picture

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

+1 for this direction. Details on the MR. Glad you've found a way forward! 👏

tedbow’s picture

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

@Wim Leers see my MR comments

tedbow’s picture

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

Actually I still need to look at test failures

tedbow’s picture

Assigned: tedbow » Unassigned

Unassigning myself. I am not sure the Cypress test is failing. I have the tests running locally but I can't figure it out. Thought maybe it was `ApiResponseValidator` but I commented that out and the test is still failing

balintbrews’s picture

#3463307: Implement simplified zoom interface significantly rewrites those end-to-end tests and introduces hardening for the tests to avoid trying to access elements in the iframe before their events are initialized. It's close to being merged, so I recommend that we wait until it lands, and see how the failing tests behave with those changes.

wim leers’s picture

Title: HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context » [PP-1] HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context

Thanks, @balintbrews!

tedbow’s picture

@balintbrews thanks!

wim leers’s picture

wim leers’s picture

wim leers’s picture

Status: Needs work » Postponed
bnjmnm’s picture

Status: Postponed » Needs work
StatusFileSize
new101.63 KB

There's a remaining test failing because it is failing to find an iframe where data-test-xb-content-initialized is TRUE and I discovered why by adding console.log() calls next to where data-test-xb-content-initialized is switched to false and true.

The two final logs - both which change the attribute to FALSE (without the expected switch to TRUE) - only happen in this MR.

I can see how this might happen since the switch to FALSE will occur any time the useEffect is triggered by a change to dispatch, height, handleDragAdd, handleDragEnd, handleDragStart, layout, model, components, but the switch to TRUE only happens when the onload callback is invoked. It seems like there are plenty of opportunities for one of the 8 useEffect dependencies to change and change data-test-xb-content-initialized to FALSE without onload firing to change it to TRUE.

If those extra renders of the iframe are unnecessary, perhaps they should be addressed in this issue. If it is expected and acceptable, then we need a different way to mark something as initialized.

WITH THIS MR OPEN YOU CAN CONFIRM THIS BY... going to the XB UI and look at the iframe html - you'll see the data-test-xb-content-initialized within moments of the UI loading.

bnjmnm’s picture

StatusFileSize
new559.62 KB

Further debugging shows that this MR is not creating any new changes that trigger the iFrame attribute update changes. Instead, it is changing the order that they change, and components is changing after layout and model.

A change to component triggers the useEffect that sets data-test-xb-content-initialized to false, but unlike layout/model it does not result in the iframe loading anything new, so the onload that would set data-test-xb-content-initialized to TRUE is not invoked.

bnjmnm’s picture

Title: [PP-1] HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context » HTTP API: update /xb-component/{component_id} to list possible prop sources for current entity context
Status: Needs work » Needs review

Based on the extensive debugging it looks like this can be addressed by changing a few lines so components (a list of the available components) is no longer a dependency of the iframe-impacting useEffect or the updateData useCallback. Neither of these should need to update if the components list changes.

While it's true that updateData requires components to have initialized for it to properly add a component to the layout, this doesn't need to be enforced as a callback dependency because the UI doesn't offer that option until it is ready anyways.

I think this solution is sound but it would be good to get another FE person to look it over to ensure this isn't going to break something elsewhere.

balintbrews’s picture

Truly great investigation, and I agree with the solution! I love how this ended up being an actual problem — unnecessary rerenders — our test uncovered.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

👏 @bnjmnm! Agreed with @balintbrews 😊

  • Wim Leers committed 0a04bd43 on 0.x authored by bnjmnm
    Issue #3455975 by tedbow, bnjmnm, Wim Leers: HTTP API: update /xb-...
wim leers’s picture

Status: Reviewed & tested by the community » Fixed
tedbow’s picture

Somehow the removal of patternProperties got remove from this MR will open up a follow-up

Status: Fixed » Closed (fixed)

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