Only allow deleting Code Components if there's 0 usages

Created on 13 June 2025, about 1 month ago

Overview

Quoting @catch and I from #3528723-10: Component::onDependencyRemoval() should be an uninstall validator if the dependency being removed is a module or theme :

Reviewed this together with @catch.

The behavior in HEAD is that a code component (JavaScriptComponent) that is in use in e.g. 1 article and 1 page can still be deleted. It requires a little bit of shenanigans though: you have to open a content entity in XB that does not contain an instance of that code component!

If such an instance is present, you do get a nice error message/confirmation dialog:

On all other content entities (i.e. any with an XB component tree but without this particular code component), the deletion will proceed unceremoniously 😅 ⇒ It's far too easy to shoot yourself in the foot right now!

The changes in this MR remove the "shoot yourself in the foot" case for:

  • uninstalling modules providing block plugins
  • uninstalling themes/modules providing SDCs

👍

BUT concerns remain regarding code components — because this MR doesn't change anything (intentionally!) for those.

@catch and I agreed that:

  1. A confirmation dialog like the above should ALWAYS appear
  2. It should inform the user of how many entities/revisions would be impacted
  3. It should inform the user that if they proceed all existing content will look broken.

IOW: allow it only for developers who really know what they're doing, but present the consequences as explicitly as possible.

This strikes the middle ground of desire for reliability+consistency (@catch and I) vs pragmaticness when developing code components (@lauriii's concern).

In the future, if Drupal core gets a "developer mode", we could adjust the behavior based on that — see Add a Production/Development Toggle To Core Needs work .

+

After some more brainstorming with @catch, we think we thought of an alternative approach that actually is better still:

  1. add a soft_deleted: true|false config entity property to JavaScriptComponent, which defaults to false
  2. make the delete operation either:
    1. : actually delete (as is the case today)
    2. : set soft_deleted: true (🆕)
  3. make XB in all its API responses pretend this config entity does not exist
  4. … then just respect all config dependency management as per usual

This approach would mean that the associated Component config entity would still exist, the JS code-on-disk powering it would also still exist, and hence all existing usages of this code component would continue to work exactly as before.

P.S.: yet another alternative approach could be that we make JavaScriptComponent implement VersionedConfigEntityInterface (new since ~2 weeks) to keep the underlying config entity around, and only allow 2 versions: whichever one is the active one, plus a special deleted/trashed version that gets treated everywhere in XB as if it doesn't exist. That way, we would not have to delete

Proposed resolution

Discuss the nuances, but prevent the deleting JavaScriptComponent config entities to comply with config management best practices. We now have usage data, versioned config entity types, etc. — multiple additional pieces of infrastructure that should enable a better UX.

User interface changes

📌 Task
Status

Active

Version

0.0

Component

Theme builder

Created by

🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

Live updates comments and jobs are added and updated live.
  • Usability

    Makes Drupal easier to use. Preferred over UX, D7UX, etc.

Sign in to follow issues

Comments & Activities

  • Issue created by @wim leers
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • Scenario that needs to be addressed with this fix :

    • Create code component named {code01}
    • Create code component named {code02}
    • Import code01 to code02
    • Delete code01 able to delete code01
    • Code02 gives error as below

  • 🇫🇮Finland lauriii Finland

    Could we make the soft delete as an explicit feature? I.e. hiding modules from the UI. I think this would be really useful in the beginning until we can associate which users can use which components. Tagging with needs follow-up for that.

    We could still offer the delete as an option because there are scenarios where it's desired to delete a component and all of its uses altogether. However, there's a difference between content vs components referring to components. I'd say that uses of a component in another component should prevent deleting, but deleting a component used in content should not prevent the deletion (especially because even past revisions would prevent deletion).

    What would be extremely useful is having a list of usages of the component. This is not only useful for the delete use case but also when you want to assess how components are being adopted.

  • 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺

    I tested #7.

    To clarify, this is not an issue when the components are stored (e.g. I publish them, even without "adding to components" aka status=1), only on the transient time when they are in auto-save, not published, not status=1, as we do this validation on config entity dependencies. That part IMHO is Works as designed, as the preview message is informative enough to fix the situation.

    The original purpose of this issue still remains though.

Production build 0.71.5 2024