Overview

SDCs can have default images. See for example tests/modules/xb_test_sdc/components/image-optional-with-example.

We need equal functionality for code components (JavaScriptComponent config entities).

To achieve this, we'll need to bring in part of the PoC at https://git.drupalcode.org/project/experience_builder/-/commit/8ecc46f91... from >1 year ago.

Proposed resolution

  1. ✅ Make it possible to specify the filename of the default image just like is the case for the above SDC:
    --- a/tests/modules/xb_test_code_components/config/install/experience_builder.js_component.xb_test_code_components_vanilla_image.yml
    +++ b/tests/modules/xb_test_code_components/config/install/experience_builder.js_component.xb_test_code_components_vanilla_image.yml
    @@ -12,7 +18,7 @@ props:
         type: object
         examples:
           -
    -        src: 'https://placehold.co/1200x900@2x.png'
    +        src: cosmo.jpg
             width: 1200
             height: 900
    
  2. ✅ Make it possible for that filename to be tied to a File entity by specifying a content dependency:
    --- a/tests/modules/xb_test_code_components/config/install/experience_builder.js_component.xb_test_code_components_vanilla_image.yml
    +++ b/tests/modules/xb_test_code_components/config/install/experience_builder.js_component.xb_test_code_components_vanilla_image.yml
    @@ -1,7 +1,13 @@
     uuid: 3066d9d2-75f8-444d-a733-644698b43ad4
     langcode: en
     status: true
    -dependencies: {  }
    +dependencies:
    +  content:
    +    file:file:<UUID>
     machineName: xb_test_code_components_vanilla_image
     name: Vanilla Image
     block_override: null
    
  3. ✅ The above is then the updated YAML representation of this config entity while stored in the Drupal DB.
  4. ✅ Add DefaultRelativeUrlPropSource support. Which requires updating JsComponent::rewriteExampleUrl() to resolve cosmo.jpg to something like /sites/defaults/files/js_component/defaults/cosmo_1.jpg (assuming this is the second component pointing to cosmo.jpg: the File entity's mechanisms will have detected that this file already existed, so it might resolve to a slightly different filename, but the examples entry in the definition will still work!). Otherwise the default image won't render in actual instances of this code component.
  5. ✅ During export, ensure that the content dependency (file:file:<UUID>) is carried along with the config entity, to allow it to be reconstructed (File::create(…)->save()) on another site, and have that code component work as if magic! That's where the PoC comes in.
    --- a/tests/modules/xb_test_code_components/config/install/experience_builder.js_component.xb_test_code_components_vanilla_image.yml
    +++ b/tests/modules/xb_test_code_components/config/install/experience_builder.js_component.xb_test_code_components_vanilla_image.yml
    @@ -1,7 +1,13 @@
     uuid: 3066d9d2-75f8-444d-a733-644698b43ad4
     langcode: en
     status: true
    -dependencies: {  }
    +dependencies:
    +  content:
    +    file:file:<UUID>
    +# @see https://git.drupalcode.org/project/experience_builder/-/commit/8ecc46f9141b0e563605b33ebdae7baf1d7730fc
    +encoded_entities:
    +  encoded_files:
    +    …shrug…
     machineName: xb_test_code_components_vanilla_image
     name: Vanilla Image
     block_override: null
    

User interface changes

None, this is about back-end support only; not even including internal HTTP API support.

Issue fork canvas-3532574

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:

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

f.mazeikis created an issue. See original summary.

wim leers’s picture

Category: Task » Feature request
Issue tags: -Configuration schema, -validation, -missing config dependencies

I wrote this issue summary together with @f.mazeikis 🤓

larowlan’s picture

larowlan credited mstrelan.

larowlan’s picture

@mstrelan pointed out we have the 8.4 polyfill in 11.2 but not in 11.1

f.mazeikis’s picture

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

Pushed all the work so far, including working tests. @larowlan had some feedback, I think I've addressed most of it, but happy to get back to it if there's more.

Moving into ready for review.

wim leers’s picture

#6: That should be fine, because XB bumped its requirement to 11.2 in #3492722: Update XB to require Drupal 11.2? That's what's in 0.5.0-alpha1, so <0.5 is for Drupal <11.2, >=0.5 is for Drupal >=11.2


That was pretty fast! Reviewing… 🤓

lauriii’s picture

We can work around this in beta by uploading images to media library and manually referencing them in component code. This is obviously not great and doesn't allow components to be moved from environment to another so we definitely still need this. Just trying to avoid rushing this before the beta.

mstrelan’s picture

Re polyfill:
Regardless of core version no reason XB couldn't add it as a dep, just give it a loose constraint so it doesn't conflict with core.

wim leers’s picture

Assigned: wim leers » f.mazeikis
Status: Needs review » Needs work

Looking promising!

  1. This needs to have preliminary internal HTTP API support. "preliminary", because it might be imperfect, and that's fine. But we need to have the FE folks unblocked to build the entire feature; we can then still refine it later 👍
  2. That MUST come with updated test coverage in \Drupal\Tests\experience_builder\Functional\XbConfigEntityHttpApiTest::testJavaScriptComponent()
  3. Some missing test coverage to ensure that saved config entities in config entity storage do not actually contain these base64 blobs
f.mazeikis’s picture

Status: Needs work » Needs review

Addressed everything on MR and in #11.

larowlan’s picture

Status: Needs review » Needs work

Great work @f.mazeikis - did another review and added some comments/observations

wim leers’s picture

Title: `JavaScriptComponent` config entities must support default images: `File` content entity dependency, base64-encoded upon export » `JavaScriptComponent` config entities must support default images, videos, etc.: `File` content entity dependency, base64-encoded upon export
f.mazeikis’s picture

I've addressed most of the feedback, replied with reasoning for the rest. This might not be complete, but a second pass review and further feedback on Comment on lines +802 to +804 would be beneficial.

f.mazeikis’s picture

Status: Needs work » Needs review
wim leers’s picture

Assigned: f.mazeikis » Unassigned

I'll review tomorrow — it's possible @larowlan will beat me to it, so not yet self-assigning.

wim leers’s picture

Component: Theme builder » Config management
Issue tags: -Needs tests
Related issues: +#3538711: [PP-1] Add support for example images for Code Components' image props

Thanks for the excellent docs additions 👏, that made it 10x easier to review this! 🥳

(Still in the process of reviewing.)

Created #3538711: [PP-1] Add support for example images for Code Components' image props for the actual feature that this is intended to unblock.

wim leers’s picture

Finished reviewing the MR. Epic work! 🤩 Confirmed that it meets all 5 goals outlined in the issue summary! 👍


My commits/self-addressed:

Remaining feedback:

Thanks, @larowlan for creating #3537728: [PP-1] Consider adding ramsey/uuid for hash-based UUID (v5) generation for default files — linked to it 👍

wim leers’s picture

Asked @larowlan to double-check my security concerns, and per https://git.drupalcode.org/project/experience_builder/-/merge_requests/1... seems like he's +1 😅

effulgentsia’s picture

Project: Experience Builder » Drupal Canvas
Version: 0.x-dev » 1.0.0-alpha1
Issue tags: -stable blocker +RC blocker
wim leers’s picture

Title: `JavaScriptComponent` config entities must support default images, videos, etc.: `File` content entity dependency, base64-encoded upon export » `ContentTemplate` config entities must support exporting images in `StaticPropSource`s that reference media items: `File` content entity dependency, base64-encoded upon export

Discussed with @f.mazeikis, @lauriii and @effulgentsia.

The bigger impact is actually for ContentTemplates being fully exportable and importable (without the need for content syncing!), not code component default images.

f.mazeikis changed the visibility of the branch 3532574-javascriptcomponent-config-entities to hidden.

f.mazeikis changed the visibility of the branch 3532574-javascriptcomponent-config-entities to hidden.

nagwani’s picture

Issue tags: -RC blocker
f.mazeikis’s picture

Issue tags: +RC blocker

Had a call with @lauriii to clarify some things and here's the summary of the conversation:

There needs to be a simple way to export Content Template config, including all of its dependencies (config and images). Current plan is to have CLI commands for this, but eventually we will need UI for this as well. Export doesn't have to be a single .yml file, we just need the commands handling export/impor/upload/download to be easy and convenient to use.

Commands for exports and imports need to support two scenarios:

  1. User wants to export a single "Content Type" - complete dependency tree and images should be exported, but no unrelated config or files. Export should include content type config, its dependencies, content template and its dependencies and any images used on Content Template canvas.
  2. User wants to export the full Drupal configuration. We should still provide a way for users to handle Content Template images. This could be done via embedding images in exported .yml files or by using Default Content Export in core.

We need to decide if export/import and upload/download should be separate sets of commands. We also need to decide if we want to modify standard config export/import process to handle images (similar to how it was done in PoC) or if we want a separate command/flag to allow for "full config export with file/media dependencies".

When exporting a content template that uses Media Entity as an image, after importing on the destination site the expectation is this:

  • If an identical Media entity exists (Using identical uuid? Using identical Media entity UUID + identical File UUID?), we ensure the content template uses that (we might need to update target_id in component_tree.inputs)
  • If such a Media entity doesn't exist, we should create a new Media entity using exported image file and metadata and ensure Content Template uses it (we might need to update target_id in component_tree.inputs)

When we will pick up "Code Components" export functionality, same logic applies - "if CLI commands are easy to use for export/import/download/upload, then it's ok to have multiple fires per single Code Component export". According to @laurii, it should "just work". Whether it's a single file or multiple files in separate directories is implementation detail.

nagwani’s picture

Issue tags: -RC blocker
wim leers’s picture

Version: 1.0.0-alpha1 » 1.x-dev
Assigned: f.mazeikis » lauriii
Priority: Critical » Major
Status: Needs work » Needs review
Issue tags: +Needs product manager review
StatusFileSize
new679.41 KB

Discussed this in detail with @f.mazeikis. We tried to figure out if there would be a reasonable way to rely as much as possible on 11.3's new content exporting functionality (already in use by Drupal's Recipes ecosystem!).

We think we see a way forward. It'd require:

  1. Allowing for different kinds of providers, to ALLOW but NOT REQUIRE content dependencies (e.g. Acquia Source would likely prefer to rely only on config import/export and rely on media assets in Acquia DAM).
  2. Which then in turn requires transforming these URLs upon import to locally-resolvable URLs.
  3. (But keep the specified image/video/… URLs conforming to the JSON Schema constraints, by leveraging https://en.wikipedia.org/wiki/Well-known_URI)

👇

Exported

So, applied to a concrete Canvas code component for both the "pure Drupal core" scenario and a "Acquia Source/DAM" scenario, an exported code component would look like this:

  1. Contrib (blue rectangles): content dependencies + a "well known" URI that specifies "default content" as the provider
  2. Acquia Source/DAM (purple rectangles): NO dependencies a single module dependency: acquia_dam + a "well known" URI that specifies "Acquia DAM" as the provider

Imported

Upon importing the code component, these URIs would need to be: 1) validated (that they are accessible, resolve, etc.), 2) after passing validation, transformed to concrete, actual image/video/… URLs

WDYT, @lauriii?

wim leers’s picture

Forgot one thing: for Acquia Source/DAM, it would say:

dependencies:
  module:
    - acquia_dam