Overview

Code components, once they're added to components, i.e. become exposed, lock props and slots. This was implemented in #3500081: Editing components sourced as code components.

In #3509115: [META] Plan to allow editing props and slots for in-use code components we're working to relax that for cases we know we can support

Proposed resolution

Support removing a slot from a code component

User interface changes

Issue fork canvas-3557272

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.

larowlan’s picture

Assigned: Unassigned » larowlan

larowlan’s picture

Title: Support removing a slot from a code component » BE: Support removing a slot from a code component
Component: Page builder » Internal HTTP API
Assigned: larowlan » Unassigned
Status: Active » Needs review
larowlan’s picture

Assigned: Unassigned » lauriii

@lauriii can you clarify how this should work with respect to children inside the slot that is removed.

Should they become a sibling of the parent from where the slot was removed or should they also be removed?

effulgentsia’s picture

Assigned: lauriii » Unassigned

@lauriii and I discussed this at one point, so I can answer for him.

The children of a deleted slot should be removed when the host entity (Page, Content Template, etc.) is edited (i.e., what's in auto-save storage is updated). Until then, the children should remain in the server-side data but not get rendered or returned in HTTP API responses.

If someone adds back a slot with the same name before the above happens, then the children should be back in action as though the slot never got deleted.

We may want a follow-up to figure out if there are any conditions under which orphaned children are problematic and what to do for those cases.

larowlan’s picture

Assigned: Unassigned » larowlan
larowlan’s picture

Assigned: larowlan » Unassigned

Confirmed that's what we're doing in the current branch - the children are lost when we do server side conversion upon post.

penyaskito’s picture

Status: Needs review » Needs work

Just a Nit.

larowlan’s picture

Status: Needs work » Needs review

Replied in the MR

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

wim leers’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

MR looks great! No remarks.

However, shouldn't we explicitly test

Confirmed that's what we're doing in the current branch - the children are lost when we do server side conversion upon post.

?

That's something that could be considered data loss, so I think it's worth testing explicitly.

Furthermore, I think we definitely need tests for

If someone adds back a slot with the same name before the above happens, then the children should be back in action as though the slot never got deleted.

mglaman’s picture

Assigned: Unassigned » mglaman
mglaman’s picture

#12: is that for here or another issue in the main issue? this just relaxes validations. or are the tests just for documenting behavior at this point while we work between issues

effulgentsia’s picture

I think it makes sense to add the tests for #12 to this MR. The MR in the parent issue was already merged and added the testCodeComponentCanRemoveASlot() function, but I think here we should expand that test coverage for how that impacts existing data to verify our hypothesis that the existing behavior in 1.x is what we want it to be and stop it from regressing once we enable Code Component authors to actually remove slots.

mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests

Expanded testCodeComponentCanRemoveASlot

wim leers’s picture

Assigned: Unassigned » penyaskito
Status: Needs review » Reviewed & tested by the community

@effulgentsia++

I'll let @penyaskito review this test in detail.

penyaskito’s picture

Test looks good, as in we want to allow the slot coming back.

But what if I upgrade that component instance to a new version? Should the stale data disappear at any point? aka, do we need a follow-up as in #3524401: `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` allows garbage to pile up for slots?
If not, IMHO we should explicitly document this in `docs/components.md` or an ADR.

wim leers’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue rescope

#18++ — very good point!

We discussed this at some point, I believe specifically in the context of exposed slots, where this would be an even bigger problem. (Grep for "exposed slot" on the meta: #3520449: [META] Production-ready data storage.)

I believe the answer is "yes, data in a no-longer-existing slot should be dropped upon the next save".

In fact this problem is far worse than the props equivalent #3524401: `GeneratedFieldExplicitInputUxComponentSourceBase::validateComponentInput()` allows garbage to pile up, because it can contain an entire component tree that is potentially very complex! So the amount of data that we would be forever keeping around if we didn't delete it could be huge. And there wouldn't be any way to see it!

Proposal:

  1. Only save component subtrees if the containing slot actually exists in containing slot's component instance's component version.
  2. Expand Canvas' auditing UI to gain a "data in deleted slots" tab.
  3. Make that tab first list which components have deleted slots: iterate over all versions of each Component config entity, and create the union of all past versions' slot_definitions, if this is a superset of the active version's slot, then it's necessary to perform an auditing DB query across all (config & content) component trees.
  4. That DB query would need to do something like WHERE slot IN (deleted_slot_one, deleted_slot_two) and then make sure that the parent component instance that that slot is for, is in fact a slot of that particular Component config entity (because the same slot name might be used by multiple components, so have to make sure that it's in fact an actually deleted component slot).

(Alternative for 2+3: add a "Audit deleted slot data" action to the existing /admin/appearance/component UI, and convey somehow for each component whether it has >=1 deleted slots.)

This should happen either here, or in a critical follow-up.

mglaman’s picture

Only save component subtrees if the containing slot actually exists in containing slot's component instance's component version

Makes sense. So in \Drupal\canvas\Controller\ClientServerConversionTrait::clientModelToInput we'd drop data for invalid slots. So that once a component drops a slot, the component tree is cleaned up the next time the tree using the component is loaded in the editor.

Expand Canvas' auditing UI to gain a "data in deleted slots" tab.

Can this (bullet 2/3/4) be spun out to a non-critical follow up?

mglaman’s picture

Actually, I think this is already covered:

Only save component subtrees if the containing slot actually exists in containing slot's component instance's component version

In `expectedOriginalClientModel` there is `CHILD_COMPONENT_INSTANCE_ID` in the `description` slot. The test asserts that the slot is empty in the client representation with the new version:

    $expectedClientModelFunction = fn(string $version) => [
      'layout' => [
        [
          'uuid' => self::COMPONENT_INSTANCE_UUID,
          'nodeType' => 'component',
          'type' => \sprintf('%s@%s', self::COMPONENT_ID, $version),
          'slots' => [],
          'name' => NULL,
        ],
      ],

And that it is restored if the original layout is used. So I think this isn't NW and just needs an audit UI follow up.

mglaman’s picture

Status: Needs work » Reviewed & tested by the community

RTBC. #18 was answered in #6

The children of a deleted slot should be removed when the host entity (Page, Content Template, etc.) is edited (i.e., what's in auto-save storage is updated). Until then, the children should remain in the server-side data but not get rendered or returned in HTTP API responses.

lauriii’s picture

Issue tags: -Needs issue rescope

Can this (bullet 2/3/4) be spun out to a non-critical follow up?

These can be moved to a follow-up. This would make a great task for a contributor to work on!

wim leers’s picture

Assigned: penyaskito » Unassigned
Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs followup

#23++

RE: #19: I was asked to review #3568906, and in doing so, ~30 mins ago I ended up independently writing #3568906-2: Handle upgrading and rendering not yet upgraded component instances of components with newly removed props or slots, which ties into #19.1.

Approved with context. Auto-merge queued. Keeping issue open to ensure follow-up is created. Thanks all! Shoot, spotted a bug in the test coverage that prevents my approving 😔

mglaman’s picture

Assigned: Unassigned » mglaman
mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Needs review

I think I addressed the test feedback.

wim leers’s picture

Assigned: Unassigned » mglaman
Status: Needs review » Needs work

Approved MR, but MR no longer applies 😇

Let's get this in!

mglaman’s picture

Yeah, I was in rebase hell on Friday and waited on fighting that until I got your eyes. Fixing soon!

mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Reviewed & tested by the community

Fixed the MR, waiting for CI then preparing to merge

  • mglaman committed 6d6c16a8 on 1.x authored by larowlan
    feat: #3557272 BE: Support removing a slot from a code component
    
    By:...
mglaman’s picture

Status: Reviewed & tested by the community » Patch (to be ported)

Setting status due to follow up needed

mglaman’s picture

Status: Patch (to be ported) » Fixed
Issue tags: -Needs followup

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

wim leers’s picture

Status: Fixed » Closed (fixed)

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