task: #3567225 Make the component tree loader extensible
Refs #3567225
Summary
Removes final from ComponentTreeLoader and widens its two promoted constructor properties to protected, so a contrib module can subclass it and swap the service.
That is the whole change: one file, one hunk.
Why this merge request shrank
It previously carried the full per-node Content Template override feature across 11 files. That has been reverted here, leaving only the extension point, for two reasons.
The extension point is the part with a caller waiting on it. Canvas Override subclasses ComponentTreeLoader in its service provider. Against stock Drupal Canvas 1.10.0 that is a hard PHP fatal:
Fatal error: Class Drupal\canvas_override\Storage\CanvasOverrideComponentTreeLoader
cannot extend final class Drupal\canvas\Storage\ComponentTreeLoaderThe editor never boots: /canvas/api/v0/layout/node/{nid} returns the fatal instead of JSON. Verified on Drupal 11.4.5 with Drupal Canvas 1.10.0. With this one hunk applied, the same request returns HTTP 200 JSON and the editor renders with no console errors.
The five TypeScript files could not work as shipped. canvas.libraries.yml loads the prebuilt ui/dist/assets/index.js, and Drupal Canvas ships that bundle prebuilt, so changing ui/src has no runtime effect until the bundle is rebuilt. Confirmed by inspection: the shipped bundle contains no occurrence of hidePageDataPanel; after a local npm run build it does. Any site consuming this as a Composer patch gets the shipped bundle back on every composer install.
Keeping those files here also meant re-rolling an 11-file patch on every Drupal Canvas release, for changes that were inert.
What was removed
ApiLayoutController, JsonSchemaPropsComponentSourceBase, TypedDataHelper, CanvasConfigUpdater, DrupalSettings.ts, ContextualPanel.tsx, Topbar.tsx, ComponentInstanceForm.tsx, UndoRedo.tsx, layoutModelSlice.ts.
The per-node Content Template override feature still needs its own issue and merge request. Two of the reverted changes are unrelated fixes that deserve separate issues rather than riding along with a feature: the null guard in ComponentInstanceForm.tsx, and layoutModelSlice.ts using the active editor frame context instead of a hardcoded 'template'.
Testing
-
composer run lintandnpm run lintpass. - Install a module that subclasses
ComponentTreeLoaderand swaps the service; confirm no fatal. - Confirm
ComponentTreeLoaderbehaviour is unchanged for Drupal Canvas itself: the class is still concrete, only thefinalmarker and two property visibilities changed.
AI usage disclosure
Per the Drupal AI contribution policy: AI (Claude Code) assisted with identifying the minimal required change, reverting the unrelated files, and verifying the result on a live site. All changes were reviewed and verified by the human contributor (Rajab Natshah), who is responsible for the logic, security, and licensing.