Legend
- β Done.
- π’ Confident it will not require backwards compatibility breaks.
- π‘ Medium confidence; more work needed to achieve necessary confidence.
- π΄ Low confidence; requires a lot more work
Overview
XB's data model (ComponentTreeItem) was originally prototyped with:
- only SDCs
- β
dynamic data fetched from the host entity, the right value(s) extracted using
(Reference)Field(Object)PropExpressionand assigned to the right component instance into the component tree:DynamicPropSources - β
static data stored in independent field item objects:
StaticPropSources (which also must extract the right value(s), and does so using(Reference)FieldType(Object)PropExpression) - β
symmetric + asymmetric translation support (symmetric:
treeis locked,inputsare per-translation; assymmetric: both are translatable, meaning different component trees for each translation)
Those foundations remained largely the same, but since then we gained:
- β
multiple component types, thanks to
ComponentSourceplugins β everything must scale to unknown future component types - β
additional prop sources, such as
DefaultRelativeUrlPropSourceβ everything must scale to unknown future prop sources - β auto-saving of component trees
Finally, we know there's both known technical debt, and more features that we'll eventually need to support:
- β debt: full dependency support, throughout all of the above, to allow for reliable updates
- π’ debt: the explicit input schema must be able to evolve, and each
ComponentSourcemay have different needs for that. For example: block plugins may change their settings (and their config schema), SDCs may gain new optional inputs, JS components may gain new required inputs β #3501708: Prove that it *will* be possible to apply block settings update paths (assuming #3521221 in core) to stored XB component trees in config/content + #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row here β but #3524751: [later phase] Component Source plugins: generalized support for schema changes of explicit inputs later. - β
debt: we went with a JSON-heavy initial implementation (the
inputsandtreeprops both store a JSON struture), but we may want to reconsider this β solved in #3468272: Store the ComponentTreeStructure field property one row per component instance, with additional refinements possible post-release for more field types than just XB - β
feature: content entities' XB component trees must be able to populate the exposed slots provided by the corresponding
ContentTemplate(β #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities) - π’ feature: asymmetric translation will need some explicit inputs to be locked, because some explicit inputs may be considered to be not translatable β for example an image input of some component
- π’ debt: currently, XB fields can only exist on XB's own
Pagecontent entity type (base field definition) and on thearticlebundle ofNodeentities (configurable field) β expanding that is out of scope here and is in scope for #3498525: [META] Allow Canvas to be used on any content entity type (bundle), as long as it has certain entity type characteristics. This poses no additional risks for XB's data storage, because this already covers the gamut of possible kinds of XB fields on content entities. - π’ feature: full read/write support of XB trees in JSON:API (#3521002: [META] Maintainable client-side data model + internal HTTP API's #3499632: Remove `ClientServerConversionTrait` (CβS) and `ComponentTreeItemList::getClientSideRepresentation()` (SβC) in favor of (de)normalizers), including the ability to filter (β #3523844: Spike: Explore adding configuration options to the tree item formatter to support alternate use-cases).
- π’ feature: ability to store variants of component trees for use cases like personalization (i.e. different component subtree for Belgians & Brits vs everyone else β #3525564: [META] Experience Builder Personalization), responsive design (i.e. breakpoint-specific overrides), and arbitrary future use cases (β #3525746-6: Update the React client preview view)
Beta blockers (July 2025)
Beta blockers (tag: beta blocker) MUST happen before #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites.
β οΈ As part of this, we're aiming to ideally close #3477428: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values and #3440578: [PP-2] JSON-based data storage proposal for component-based page building, but both of those cover many aspects. They're being tackled piece-by-piece by the beta-blocking issues below, as originally proposed by @larowlan at #3477428-44: [PP-1] Refactor (or decide not to) the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values.
(Numbered lists must happen one after the other, bulleted lists can happen in parallel.)
- β Dependencies/usage beta blockers
- Precise dependency information for every XB component tree: every config entity with a component tree AND every revision of an XB field instance in content entities, because that allows strong guarantees, and is essential for explicit input schema evolvability
-
- β #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation
- β #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying
- β #3460230: Component entity config dependencies are incomplete: missing ComponentSourceInterface::calculateSettingsDependencies() to compute deps for field storage + instance settings + widget
- β #3544604: Calculating dependencies of `ReferenceField(Type)PropExpression` is missing intermediate dependencies
- β Field type storage (content entities) schema beta blockers
-
Given lessons in the ecosystem over the past decade, plus what we know about functionality we still intend to add to XB, organize the data storage to avoid future backwards compatibility breaks, and allow data storage for new features to be easily added later.
-
- β
Ensuring multi-value (
type: array) explicit inputs (e.g. list of integers for sparkline component, list of images for image gallery component, etc.) can be supported later: #3467870: Support `{type: array, β¦}` prop shapes - β 1 row/revision with 2 enormous JSON blobs β 1 row/component instance/revision with a single tiny JSON blob: #3468272: Store the ComponentTreeStructure field property one row per component instance
- β
content templates: XB field on content entities should be able to store >1 component tree: one per exposed slot in the governing
ContentTemplate, if any #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities - β
New
namefield property for additional functionality: #3460958: Data storage support for allowing Content Creator to name component instances for the specific context - β
versioned
Components + associated storable prop shapes (field types + settings) (blocker for #3524751: [later phase] Component Source plugins: generalized support for schema changes of explicit inputs): #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row - β
bike shedfinalize the field type's field property names: #3528167: Rename `version` field property to `component_version` - β ensure this architecture allows for efficient updating of existing component trees when explicit input schemas (block settings, SDC props β¦) change: #3501708: Prove that it *will* be possible to apply block settings update paths (assuming #3521221 in core) to stored XB component trees in config/content
- β #3528528: `ComponentInputs::getPropSources()` needs to take `GeneratedFieldExplicitInputUxComponentSourceBase::rawInputValueToPropSourceArray()` into account
- β #3528499: Revisit storage of dependencies in separate table now we have separate deltas per component + remove plugin dependencies + make component version usages auditable
- β #3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround
- β
Ensuring multi-value (
- β Configuration storage schema beta blockers
-
- β #3502982: Rename ComponentSource settings' `plugin_id` to `local_source_id` or similar to not bias towards source plugins that don't use plugins under the hood
- β #3521137: XB's storing JSON blobs should not be visible in exported config nor to test authors
- β ensure the versions are deterministic hashes: #3528159: Ensure deterministic version hashes for ComponentSource-specific settings, thanks to config schema-powered normalization
- β ensure the deterministic hashes capture all crucial aspects: #3528362: Deterministic Component version hash should depend not only on source-specific settings, but also slots + explicit input schema
- β #3526127: Ensure deterministic config export order of config-defined component trees
- β Validation beta blockers
-
- β #3473289: XB Component config entity's `status` may only be `true` if it meets all of XB's requirements
- β #3526818: Tighten validation of `parent_uuid` and `slot` on XB fields to match the strictness of config
- β #3519891: Constrain slot names allowed by XB in Components (and in its component tree)
- Field type storage (content entities) schema stable blockers
- Configuration storage schema stable blockers
-
- β #3533458: Change CodeComponentDataProvider::getRequiredXbDataLibraries() to base its logic on information provided by the front-end rather than on naive string/regex matching
- β #3538537: Update path tests should also run against non-SQLite DBs
- β #3548165: Components in `ContentTemplate`s and `PageRegion`s are not always rendered in correct order
- #3538273: Use AST to identify resources fetched by CodeComponents so they can be preloaded/prefetched
- #3460232: [PP-1] Support XB config entities with component trees that reference File/Media, use target_uuid and embed β aka: self-contained content entity dependencies
- #3526706: Stop assuming default Field Widget settings sufficeΒ βΒ add Field Widget settings support to `experience_builder.generated_field_explicit_input_ux: prop_field_definitions`
- #3503272: JavaScriptComponent config entities should have mutable machineNames Assigned to: balintbrews
- #3464042: Add ComponentAuditabilityTest
- Validation stable blockers
-
- β #3471026: Harden UUID validation in ComponentTreeStructureConstraintValidator
- β #3525759: SdcPropKeysConstraintValidator::validate() should complain about extraneous keys too, not just missing keys
- β #3526721: Require Drupal 11.1.8 and remove `type: field.value.language` work-around
- β #3526707: Tighten validation of `experience_builder.generated_field_explicit_input_ux: prop_field_definitions.[%key].default_value`
- β #3538503: Disallow component trees with `component_version: active`
- β #3526716: Tighten validation of `experience_builder.generated_field_explicit_input_ux: prop_field_definitions.[%key].expression`
- β #3538487: Don't allow passing uncollapsed inputs if using default expression
- Security stable blockers
-
- β #3546996: Component instances populated by linked `DynamicPropSource`s, but inaccessible entity/field: fall back to `NULL` for these values, triggering fallback rendering
- β #3554184: Bubble cacheability of resolved props values and access results + `PropSourceBase::evaluate()` does not return cacheability at all
- Other stable blockers
Stable blockers (October 2025)
Stable blockers (tag: stable blocker) do not block #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites, but would be nice-to-have at that point in time. They MUST happen before #3517885: Milestone 1.0.0: Production Sites.
Post-stable priorities (after October 2025)
Post-stable priorities (tag: post-stable priority) do not block any release, and are things we'd like to see happen, but are intentionally NOT happening any time soon. We're highly confident that these will be net additions without the need for backwards compatibility breaks.
- Field type storage (content entities) schema full feature scope blockers
- #3524406: [later phase] [Needs design] [PP-1] Provide API for finding and UI for surfacing dangling/dead component subtrees β aka garbage clean-up Assigned to: lauriii
- #3498525: [META] Allow Canvas to be used on any content entity type (bundle), as long as it has certain entity type characteristics
- #3526189: Spike: explore merits of one Canvas field per exposed slot in content templates
- #3528458: Component instances in exposed `ContentTemplate` slots must use the exposed slot's machine name
- To be categorized:
- π’#3518272: Support all entity types with configurable displays for content templates β note that the stable-blocking subset already landed β see #3518272-7: Support all entity types with configurable displays for content templates for details.
- #3526703: Adopt `AtLeastOneOf` validation constraint for cardinality validation
- #3523844: Spike: Explore adding configuration options to the tree item formatter to support alternate use-cases Assigned to: larowlan
- #3522953: [later phase] Make Component `audit` operation performant/scalable
- #3530051: Update `ComponentAudit::getConfigEntityDependenciesUsingComponent()` to support component versions
- #3532712: Audit use of ::loadUnchanged and any routes that might need to load the latest revision
- clean-up:
- #3530097: [later phase] [PP-1] Prune unused `Component` config entity versions
- #3495625: Remove ComponentTreeItemList::ROOT_UUID from hydration and client-to-server conversion
- #3518696: [2.x] [11.3-only] Remove `BetterConfigExistsContraint` and move back to `ConfigExistsContraint`
- #3481188: [later phase] Gracefully handle deleted regions in PageTemplate config entities"
- asymmetric translation explicit input locking: across al component instances and/or per component instance
- Add a
untranslatable_inputsfield property, to allow a content author to lock an explicit input of a single component instance β e.g. a particular image component instance may have contain an image that should be the same across all translations (maybe it is a photo of the CEO), but another image component instance may have an image that should be translatable (e.g. locale-specific names for the same product: "Lotus" speculoos cookies in Belgium, "Biscoff" in the US)
diff --git a/config/schema/experience_builder.schema.yml b/config/schema/experience_builder.schema.yml index 900a0b96e..ea54e8b34 100644 --- a/config/schema/experience_builder.schema.yml +++ b/config/schema/experience_builder.schema.yml @@ -264,6 +264,10 @@ experience_builder.component_tree_node: inputs: type: ignore label: 'Input values for each component in the component tree' + translatable: true + untranslatable_inputs: + type: ignore + label: 'Untranslatable input values for each component in the component tree' # Based on core/assets/schemas/v1/metadata-full.schema.json#$defs.slotDefinition # @todo Tighten & add validation in https://www.drupal.org/project/experience_builder/issues/3519891 diff --git a/src/Plugin/Field/FieldType/ComponentTreeItem.php b/src/Plugin/Field/FieldType/ComponentTreeItem.php index 6fc12e593..c9a95873b 100644 --- a/src/Plugin/Field/FieldType/ComponentTreeItem.php +++ b/src/Plugin/Field/FieldType/ComponentTreeItem.php @@ -96,6 +96,10 @@ use Symfony\Component\Validator\ConstraintViolationList; 'component_id', ], ], + 'untranslatable_inputs' => [ + 'label' => new TranslatableMarkup('Untranslatable component input values'), + 'translatable' => FALSE, + ], ], )] class ComponentTreeItem extends FieldItemBase { @@ -257,7 +261,16 @@ class ComponentTreeItem extends FieldItemBase { 'not null' => TRUE, ], 'inputs' => [ - 'description' => 'The input for this component instance in the component tree.', + 'description' => 'The inputs for this component instance in the component tree.', + 'type' => 'json', + 'pgsql_type' => 'jsonb', + 'mysql_type' => 'json', + // @todo Change back to 'json' once https://www.drupal.org/i/3487533 is resolved. + 'sqlite_type' => 'text', + 'not null' => FALSE, + ], + 'untranslatable_inputs' => [ + 'description' => 'The untranslatable inputs for this component instance in the component tree.', 'type' => 'json', 'pgsql_type' => 'jsonb', 'mysql_type' => 'json', @@ -333,6 +346,10 @@ class ComponentTreeItem extends FieldItemBase { ->setLabel(new TranslatableMarkup('Input values for each component in the component tree')) ->setRequired(TRUE); + $properties['untranslatable_inputs'] = DataDefinition::create('component_inputs') + ->setLabel(new TranslatableMarkup('Input values for each component in the component tree')) + ->setRequired(FALSE); + return $properties; } - Related, add a new
asymmetrically_translated_explicit_inputssetting totype: experience_builder.component_source_settings.*to allow site builders to lock an explicit input of ALL instances of a component:
diff --git a/config/schema/experience_builder.schema.yml b/config/schema/experience_builder.schema.yml index 19722e2bc..bafe44264 100644 --- a/config/schema/experience_builder.schema.yml +++ b/config/schema/experience_builder.schema.yml @@ -266,6 +266,12 @@ experience_builder.component_source_settings.*: type: string label: 'The intra-source ID of this component in this source' constraints: {} + asymmetrically_translated_explicit_inputs: + type: sequence + label: 'The list of explicit inputs of this component that should only be stored in the default translation' + sequence: + # @todo Validate: must match a concrete explicit input + type: string
- Add a
- storage efficiency β see #13 through #15 on #3523842 for the most current overview (mid-May 2025). This is about deduplication of blobs of the per-component instance JSON blobs that contain the explicit inputs for that component instance. Doing both of these is best, but doing either one will diminish the impact of the other.
- core: #3469082: Add way to "intern" large field item values to reduce database size by 10x to 100x for sites with many entity revisions and/or languages
- core: #2770417: Revision garbage collection and/or compression
- XB β probably we won't do this after 1 or both of the above land: #3523842: Spike: Explore storing a hash lookup of the ComponentInputs field property: one hash per component instance
- #3463996: [META] When the field type, storage/instance settings, widget, expression or requiredness for an SDC/code component prop changes, the Content Creator must be able to upgrade Assigned to: penyaskito
- #3524345: Avoid deleting `PageRegion`s & `Pattern`s when uninstalling field type-providing module: implement `::onDependencyRemoval()` , replace with default StaticPropSource
Issue fork experience_builder-3520449
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
Comment #2
wim leersComment #3
wim leersComment #4
wim leersProposed to @longwave to close #3468269: #3468269-23: `ComponentTreeStructure` data type: simplify the stored structure.
Comment #5
wim leersComment #6
wim leersComment #7
wim leersMoved a significant chunk out of here and into #3520484: [META] Production-ready ComponentSource plugins.
Comment #8
wim leersComment #9
catchThere is a @todo in ComponentTreeItem linking to #3487533: Cannot modify a table which uses JSON type so I think that probably needs to be included here?
Comment #10
catchOpened #3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround.
Comment #11
wim leersComment #12
wim leersComment #13
wim leersComment #14
larowlanAdditional things I think we need for a 1.0
* plugabble/flexible ComponentTreeLoader so that LB/PG can provide a translation layer for legacy data
* it would be good if default values were stored as an array instead of JSON for the sake of git diff on exported config - same reasons as #2871354: Improve "allowed_html" to provide a better config diff - the current json is going to be very painful for content template git conflicts
Comment #15
catchI think the last point is being tackled in #3521137: XB's storing JSON blobs should not be visible in exported config nor to test authors.
Comment #16
penyaskitoCreated
The third one might be a data integrity issue.
Comment #17
longwaveI don't think anything with automated sequential integers is going to work because we have to handle partial deployments of config between sites. Let's say you export a Section from your site that uses a component that is on version 2 of the schema. The SDCs and component config entities might already exist on the destination site, but if it was installed later than the site it was exported from, the same component might only be on version 1 of its schema.
Comment #18
wim leers#3467870: Support `{type: array, β¦}` prop shapes is in.
Comment #19
penyaskitoπ#3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation landed!
Comment #20
wim leersAdded #3521137: XB's storing JSON blobs should not be visible in exported config nor to test authors per @larowlan's #14.
Comment #21
wim leers#3521137: XB's storing JSON blobs should not be visible in exported config nor to test authors is in π₯³
Comment #22
larowlanAdded a link to #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row to item 2.1. Wim and I basically came up with the same thing independently - nice!
Comment #23
wim leersWRT dependency/usage tracking: #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation landed, and so did its follow-up #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying. This cleaned up the technical debt around
FieldTypeUninstallValidatorand hence enabled me to close 3 stable blockers, see #3457504-56 for details.This unblocked:
Only remaining: #3460230: Component entity config dependencies are incomplete: missing ComponentSourceInterface::calculateSettingsDependencies() to compute deps for field storage + instance settings + widget. That is a stable blocker too, but won't require data storage changes. So: I'm assigning that subset of this meta a π’.
Comment #24
wim leersExplain relation to #3498525: [META] Allow Canvas to be used on any content entity type (bundle), as long as it has certain entity type characteristics in the issue summary.
Comment #25
wim leersAdded @larowlan's #3468272: Store the ComponentTreeStructure field property one row per component instance and #3523842: Spike: Explore storing a hash lookup of the ComponentInputs field property: one hash per component instance.
Comment #26
wim leersAdded #3523846: [PP-1] Spike: Explore storing component inputs in separate columns (aka field union).
Comment #27
wim leersRemoved
because that doesn't affect the data storage.
Comment #28
wim leersDescoped #3523846 per @catch in #3523846-7: [PP-1] Spike: Explore storing component inputs in separate columns (aka field union). We may revisit that after #3468272: Store the ComponentTreeStructure field property one row per component instance. π
Comment #29
wim leersAdded #3460958: Data storage support for allowing Content Creator to name component instances for the specific context
Clarified #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row
Comment #30
wim leersLanded #3460230: Component entity config dependencies are incomplete: missing ComponentSourceInterface::calculateSettingsDependencies() to compute deps for field storage + instance settings + widget.
Now going to overhaul this meta issue to clarify what's for beta vs stable β¦
Comment #31
wim leers#3468272: Store the ComponentTreeStructure field property one row per component instance landed!
Next up: #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row.
Good news! The current issue summary's
is getting to that point of clarity thanks to @larowlan, @effulgentsia, @catch and I actively having started to push these forward in the past few weeks.
So: time for an overhaul of the issue summary!
Updated the issue summary to more clearly distinguish between:
β¦ and within each of those, the areas within "data storage" they target. For beta, that's:
Comment #32
wim leersPosted "FYI, captured in the data storage meta" comments on:
Comment #33
wim leersPer @lauriii: add more features we'll eventually need to support.
And: update the status indicators for all of them.
Comment #34
wim leersClarify JSON:API support, bump to π’ . Linked (not added!) #3499632: Remove `ClientServerConversionTrait` (CβS) and `ComponentTreeItemList::getClientSideRepresentation()` (SβC) in favor of (de)normalizers even though it actually belongs under #3521002: [META] Maintainable client-side data model + internal HTTP API, because it's how we'll add JSON:API support. This is π’ because after #3468272, the implementation path for it became crystal clear.
Comment #35
wim leersAdded #3526127: Ensure deterministic config export order of config-defined component trees.
That doesn't mean I can remove though β that's still true.
Comment #36
wim leersBumped from π΄ to π‘ based on
#3525746-6: Update the React client preview view, and based on @penyaskito having proven in #3525565: Personalization ComponentSource PoC that the single new
ComponentSourceapproach works. That means zero data storage changes are needed!Tempted to mark π’, but would prefer to be cautious instead of overly confident. Will only mark as such once more of it is working.
Comment #37
wim leersTriaged the issue queue component, as well as the
@todos in XB's config schema.Added many newly created issuesΒ β all of them
stable blockers unless marked otherwise:Comment #38
wim leersHaving reviewed #3519352 and written #3519352-55: Content templates, part 3b: store exposed slot subtrees on individual entities (specifically the part), I'm bumping from π‘ to π’.
Comment #39
wim leersPer #37, I triaged all config management issues this morning.
Didn't find anything.
So I can move to π₯³ Note that #3526127-5: Ensure deterministic config export order of config-defined component trees might become a beta blocker.
did not have an indicator yet β the sole issue there is well on its way, so marked it π’.
Comment #40
wim leers#32 failed to update from π’ to β for the cited reasons.
Comment #41
wim leersThe
untranslatable_inputssample diff for post-stable was incomplete.Comment #42
wim leersAdded #3526814: Default content exports of component trees are invalid and hence are not correct after importing to stable blockers and #3526818: Tighten validation of `parent_uuid` and `slot` on XB fields to match the strictness of config to beta blockers β thanks @justafish!
Comment #43
wim leers#3526818: Tighten validation of `parent_uuid` and `slot` on XB fields to match the strictness of config landed.
Comment #44
wim leersLanded beta blocker #3519352: Content templates, part 3b: store exposed slot subtrees on individual entities! π₯³
Added #3526189: Spike: explore merits of one Canvas field per exposed slot in content templates as stable blocker.
Comment #45
wim leers#3460958: Data storage support for allowing Content Creator to name component instances for the specific context landed!
Comment #46
wim leers#3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row landed!
But two beta-blocking bits were descoped from it:
Comment #47
wim leersBumping from π‘ to π’ given #46.
Also bumping from π‘ to π’ after discussing with @effulgentsia (he agreed), because A) we've discussed it in depth over the past ~2 weeks, B) @penyaskito has a working PoC of this at #3525565: Personalization ComponentSource PoC, which he'll be updating tomorrow (since a few blockers have landed for him).
That means everything now is either π’ or β !
Comment #48
wim leersThe two new beta blockers that spun out from #3523841 last night have already landed: #3528167: Rename `version` field property to `component_version` + #3528159: Ensure deterministic version hashes for ComponentSource-specific settings, thanks to config schema-powered normalization β thanks to @larowlan!
Added #3528284: Add e2e tests that prove we can edit an old version of a component as a stable blocker (again: thanks Lee).
Finally: swapping the overall/catch-all #3525564: [META] Experience Builder Personalization for the more tightly scoped #3525728: Personalization ComponentSource plugin: test of fundamental functionality + working tech demo as proof for full confidence in this future feature:
Comment #49
wim leersAdded #3528362: Deterministic Component version hash should depend not only on source-specific settings, but also slots + explicit input schema as a beta blocker.
Comment #50
wim leers#3519891: Constrain slot names allowed by XB in Components (and in its component tree) landed.
Per discussion with @larowlan, moved #3526127: Ensure deterministic config export order of config-defined component trees from stable to beta blocking.
Comment #51
catch#3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation and #3521202: Store XB field type's "deps_*" columns in separate table to allow efficient querying were done before #3468272: Store the ComponentTreeStructure field property one row per component instance and #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions β less data to store per XB field row.
I think this means that a lot of (maybe all?) the data that was denormalized into a special database table can now be retrieved by querying the field tables (in combination with component config entity dependencies). Is there a still-open issue where this is being discussed? I wasn't able to find one.
Comment #52
wim leersAdded #3528458: Component instances in exposed `ContentTemplate` slots must use the exposed slot's machine name as stable blocker.
Comment #54
larowlanAdded #3528499: Revisit storage of dependencies in separate table now we have separate deltas per component + remove plugin dependencies + make component version usages auditable for #51 @catch
Comment #55
wim leers#3528362: Deterministic Component version hash should depend not only on source-specific settings, but also slots + explicit input schema and #3526127: Ensure deterministic config export order of config-defined component trees landed, bringing remaining back down to zero!
In , #3501708: Prove that it *will* be possible to apply block settings update paths (assuming #3521221 in core) to stored XB component trees in config/content landed, and per #3520923-18: [PP-1] Use `json` schema type for SQLite and remove `text` workaround, moved #3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround to the bottom of that section.
Next (and IMHO last) most important issue: #3528499: Revisit storage of dependencies in separate table now we have separate deltas per component + remove plugin dependencies + make component version usages auditable.
Comment #56
wim leersLanded the stable-not-beta-blocking #3525759: SdcPropKeysConstraintValidator::validate() should complain about extraneous keys too, not just missing keys since @larowlan commented on it: #3525759-9: SdcPropKeysConstraintValidator::validate() should complain about extraneous keys too, not just missing keys.
Re-checked the list of open issues tagged and found one not listed here: #3528528: `ComponentInputs::getPropSources()` needs to take `GeneratedFieldExplicitInputUxComponentSourceBase::rawInputValueToPropSourceArray()` into account.
Added #3528723: Component::onDependencyRemoval() should be an uninstall validator if the dependency being removed is a module or theme as a stable blocker.
(FYI: for beta blockers, the bulk of the attention is going to #3528499: Revisit storage of dependencies in separate table now we have separate deltas per component + remove plugin dependencies + make component version usages auditable.)
Comment #57
wim leers#3528528: `ComponentInputs::getPropSources()` needs to take `GeneratedFieldExplicitInputUxComponentSourceBase::rawInputValueToPropSourceArray()` into account is in, and the core blocker for #3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround landed upstream! π₯³
Comment #58
wim leersLanded #3528723: Component::onDependencyRemoval() should be an uninstall validator if the dependency being removed is a module or theme (not here) which ended up (unexpectedly for me) blocking #3528499: Revisit storage of dependencies in separate table now we have separate deltas per component + remove plugin dependencies + make component version usages auditable.
That means the sole remaining data storage beta blocker is #3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround, but the upstream core issue is in (#3487533: Cannot modify a table which uses JSON type), so now itβs a trivial update on our end once a Drupal core release ships β which should be trivial to do in the coming ~1.5 month.
New stable blockers:
New post-stable priority:
Comment #61
wim leersAs described at #3520923-29: [PP-1] Use `json` schema type for SQLite and remove `text` workaround, that can't happen until
11.2.0is tagged. It's a trivial MR to land though :)So: THE BETA PARTS ARE DONE! π₯³π₯³π₯³ Special thanks to:
Comment #62
wim leersSignaling this is "done for now", i.e. for #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites but NOT for #3517885: Milestone 1.0.0: Production Sites, by marking this .
Comment #63
wim leersRetroactively adding things that actually did happen for beta, but before this meta issue existed or was sufficiently groomed.
Comment #64
larowlanIdeally it would be good to do a spike on a BC loading layer for Paragraphs/Layout builder to triple check we've got a clean run at that in the future with the current data model
Comment #65
wim leersThat would be lovely indeed. But I don't think that's a hard blocker for beta. Let's first make sure we actually achieve #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites, and then let's do this. I don't see how expressing anything that can be built in Layout Builder/Paragraphs/β¦ (see #3454519: [META] Support component types other than SDC, block, and code components) could not be expressed in XB, because XB has more freedom/is much less prescriptive?
Also β¦ didn't we discuss (and in fact you proposed it! π) to only convert existing data into the client-side data model, so you can load an existing component-tree-esque thing (Layout Builder, Paragraphs, whatever) into XB and then choose to publish or not?
IOW: require human judgment, because anything automated is unlikely to A) be perfect (pixel perfect match), B) forgiving (a human could judge that actually, it makes sense to use some other component because it is better or simpler or $reason).
An automated batch migration is likely to result in problems, whereas this allows for a nice gradual migration: they can both live side-by-side until every relevant entity has been switched over to XB.
Comment #66
larowlanSorry, I wasn't clear, I'm not proposing any change to the discussed approach, just validating that the approach is viable. Will focus on #3515932: Milestone 1.0.0-beta1: Enable creation of non-throwaway sites
Comment #67
larowlanAdded #3532712: Audit use of ::loadUnchanged and any routes that might need to load the latest revision which we need for sites running content moderation
Comment #68
larowlanComment #69
wim leers#3520923: [PP-1] Use `json` schema type for SQLite and remove `text` workaround landed as part of #3492722: Update XB to require Drupal 11.2 π₯³
Discussed #3532712 with @larowlan, it's not beta-blocking β see #3532712-10: Audit use of ::loadUnchanged and any routes that might need to load the latest revision.
Comment #70
wim leersLanded: #3528723: Component::onDependencyRemoval() should be an uninstall validator if the dependency being removed is a module or theme, #3526721: Require Drupal 11.1.8 and remove `type: field.value.language` work-around.
New: #3537783: ComponentTreeItem must override `::mainPropertyName()` because it has no `value` field property (and also landed π).
Comment #71
wim leersValidation stable blocker #3526707: Tighten validation of `experience_builder.generated_field_explicit_input_ux: prop_field_definitions.[%key].default_value` is in! And a new one was found: #3538487: Don't allow passing uncollapsed inputs if using default expression, #3538503: Disallow component trees with `component_version: active` β the latter of which already landed too.
Comment #72
wim leersAdded #3533458: Change CodeComponentDataProvider::getRequiredXbDataLibraries() to base its logic on information provided by the front-end rather than on naive string/regex matching (fixed!), #3538273: Use AST to identify resources fetched by CodeComponents so they can be preloaded/prefetched and #3538537: Update path tests should also run against non-SQLite DBs.
Comment #73
wim leers#3526716: Tighten validation of `experience_builder.generated_field_explicit_input_ux: prop_field_definitions.[%key].expression` landed.
Comment #74
wim leersADR updated and now IMHO ready to be merged. Hoping to get +1s from @effulgentsia, @lauriii, @larowlan and @catch.
Comment #75
larowlanADR looks good to me, thanks for taking the time to collate that
Comment #76
wim leers#3538487: Don't allow passing uncollapsed inputs if using default expression and #3538537: Update path tests should also run against non-SQLite DBs landed. π₯³
Thanks for confirming the ADR looks good to you, @larowlan β I'd like a +1 from at least @lauriii still, given he's the one who asked for the consequences to be more complete, and to also list negative consequences.
Comment #77
lauriiiThe changes look good and it gives a sense that we thought of both the pros and cons of these decisions π
Comment #78
wim leersLanded the stable-blocking subset of #3518272: Support all entity types with configurable displays for content templates already, hence moved the remainder to post-stable.
Comment #79
catchThanks for the updates. ADRs are still pretty new to me so I'm not sure what the format/verbosity is supposed to be like overall, but this all looks correct now! The one thing I wondered about is if it needs more details about the trade-offs between flexible storage for inputs vs them not being queryable, but if that's more detail than intended seems fine to leave it implied.
Comment #81
wim leersYep, it's supposed to be prescriptive of high-level architecture, not implementation details. Some of that is subjective. But historically, we've been very bad at actually finishing (i.e. merging/publishing) ADRs, so @lauriii has urged us (rightfully so IMHO!) to err on the side of high-level. IOW: the details are for concrete implementation issues and detailed docs, the architectural choices and their rationales are for ADRs.
Very glad to have your blessing, so: merged! ππ₯³
Comment #82
wim leersLanded last week: #3528284: Add e2e tests that prove we can edit an old version of a component.
We've met our beta goals, so un-RTBC'ing, to convey that now we're working towards stable blockers. However, the target scope of 1.0 has been reduced, which in turn reduces the number of stable blockers. @lauriii is going to document that scope at #3517885-3: Milestone 1.0.0: Production Sites.
This is a first pass at updating the issue summary.
Comment #84
wim leers#3544604: Calculating dependencies of `ReferenceField(Type)PropExpression` is missing intermediate dependencies was discovered by @penyaskito and fixed by him and I. It's something we missed in #3457504: XB field type: calculate all dependencies, store them, surface in new Component "Audit" operation.
Comment #85
wim leersData integrity-impacting bug spotted: #3548165: Components in `ContentTemplate`s and `PageRegion`s are not always rendered in correct order β and fixed π
Comment #86
wim leersTwo new stable blockers surfaced, both relating to security: #3546996: Component instances populated by linked `DynamicPropSource`s, but inaccessible entity/field: fall back to `NULL` for these values, triggering fallback rendering (already done >1 month ago), and #3554184: Bubble cacheability of resolved props values and access results + `PropSourceBase::evaluate()` does not return cacheability at all (currently in progress).
Comment #87
wim leers#3554184: Bubble cacheability of resolved props values and access results + `PropSourceBase::evaluate()` does not return cacheability at all landed yesterday!