Problem/Motivation

Really similar to #874000: Automatically remove module's nodes upon module uninstallation, we want to automatically remove the content entities of the module upon the its uninstallation, but for entity types.
Currently we already have some Contrib modules that have their own workaround (see e.g. #2609782: Trouble deleting and removing Paragraphs - can't uninstall comment #10, ...), and we want to avoid having them individually but provide this thing in Core.

Proposed resolution

This feature provides a "prepare uninstall" form, similar to a "confirm uninstallation" form, displaying the amount of content entities that need to be removed before uninstalling a module, that will be accessible by a link provided on the Uninstall page for each entity type a module has as admin/modules/uninstall/entity/{entity_type_id}. After the content data has/-ve been removed, the form is redirected to the Uninstall page.

Uninstall page

Prepare uninstall page (e.g. for node)

Confirmation

CommentFileSizeAuthor
#152 Screen Shot 2016-07-27 at 09.45.56.png76.54 KBalexpott
#152 2688945-152.patch19.48 KBalexpott
#152 143-152-interdiff.txt849 bytesalexpott
#146 batch_content_deletion.png51.13 KBxjm
#146 module_uninstall_config_deletion.png69.84 KBxjm
#146 vocab_deletion.png53.37 KBxjm
#146 node_deletion.png28.17 KBxjm
#143 2688945-143.patch19.59 KBalexpott
#143 140-143-interdiff.txt8.08 KBalexpott
#140 interdiff.txt824 bytesamateescu
#140 2688945-140.patch15.99 KBamateescu
#138 2688945-136.patch15.9 KBalexpott
#138 135-136-interdiff.txt1.18 KBalexpott
#135 132-135-interdiff.txt5.41 KBalexpott
#135 2688945-135.patch15.89 KBalexpott
#132 interdiff.txt3.59 KBamateescu
#132 2688945-test-only-for-taxonomy-uninstall.patch16.18 KBamateescu
#132 2688945-132.patch16.4 KBamateescu
#116 2688945-116.patch14.34 KBalexpott
#116 113-116-interdiff.txt1.48 KBalexpott
#113 interdiff.txt1.67 KBamateescu
#113 2688945-113.patch14.13 KBamateescu
#112 interdiff.txt2.48 KBamateescu
#112 2688945-112.patch14.13 KBamateescu
#110 interdiff-110.txt3.19 KBamateescu
#110 2688945-110.patch14.01 KBamateescu
#103 delete-all-content-items.png24.6 KBamateescu
#103 interdiff-103.txt5.87 KBamateescu
#103 2688945-103.patch13.73 KBamateescu
#98 delete-content-uninstall.png23.5 KBifrik
#98 delete-content.png18.28 KBifrik
#90 confirm-before-delete.jpeg55.16 KByoroy
#82 bulk-delete.jpeg24.17 KByoroy
#76 interdiff.txt1.12 KBamateescu
#76 2688945-76.patch12.05 KBamateescu
#73 interdiff.txt7.57 KBamateescu
#73 2688945-73.patch12.04 KBamateescu
#64 2688945-62-64.drupal.remove-content-entities.interdiff.txt2.06 KBjoachim
#64 2688945-64.drupal.remove-content-entities.patch10.74 KBjoachim
#62 remove_module_content_entities_upon_uninstallation-2688945-62.patch10.74 KBtduong
#62 interdiff-2688945-61-62.txt1.35 KBtduong
#61 Screen Shot 2016-07-04 at 12.14.33.png68.99 KBtduong
#61 Screen Shot 2016-07-04 at 12.11.17.png59.45 KBtduong
#61 Screen Shot 2016-07-04 at 12.15.51.png77.84 KBtduong
#61 remove_module_content_entities_upon_uninstallation-2688945-61.patch10.73 KBtduong
#61 interdiff-2688945-59-61.txt4.13 KBtduong
#59 interdiff.txt5.92 KBtimmillwood
#59 allow_to_remove-2688945-59.patch10.43 KBtimmillwood
#57 interdiff.txt3.14 KBtimmillwood
#57 allow_to_remove-2688945-57.patch3.14 KBtimmillwood
#53 allow_to_remove-2688945-53.patch10.27 KBtimmillwood
#53 interdiff.txt802 bytestimmillwood
#51 interdiff.txt894 bytestimmillwood
#51 2688945-49.drupal.remove-content-entities.patch10.24 KBtimmillwood
#49 2688945-49-delete-uninstall.png38.74 KBjoachim
#49 2688945-40-49.drupal.remove-content-entities.interdiff.txt4.83 KBjoachim
#49 2688945-49.drupal.remove-content-entities.patch10.24 KBjoachim
#40 interdiff.txt1.08 KBtimmillwood
#40 allow_to_remove-2688945-40.patch9.88 KBtimmillwood
#38 interdiff.txt2.59 KBtimmillwood
#38 allow_to_remove-2688945-38.patch9.83 KBtimmillwood
#37 remove_module_content_entities_upon_uninstallation-2688945-37.patch9.92 KBtduong
#36 remove_module_content_entities_upon_uninstallation-2688945-36.patch9.92 KBtduong
#36 interdiff-2688945-34-36.txt1.19 KBtduong
#34 remove_module_content_entities_upon_uninstallation-2688945-34.patch9.12 KBtduong
#34 interdiff-2688945-32-34.txt2.46 KBtduong
#32 ridirected.png124.56 KBtduong
#32 remove_module_content_entities_upon_uninstallation-2688945-32.patch9.3 KBtduong
#32 interdiff-2688945-30-32.txt4.56 KBtduong
#30 remove_module_content_entities_upon_uninstallation-2688945-30.patch8.95 KBtduong
#30 interdiff-2688945-28-30.txt7.31 KBtduong
#28 1_uninstall_before.png130.03 KBtduong
#28 remove_module_content_entities_upon_uninstallation-2688945-28.patch8.68 KBtduong
#28 interdiff-2688945-25-28.txt2.07 KBtduong
#25 remove_module_content_entities_upon_uninstallation-2688945-25.patch8.5 KBtduong
#25 interdiff-2688945-22-25.txt2.66 KBtduong
#22 5_uninstall_test.png75.67 KBtduong
#22 4_uninstall_after.png124.31 KBtduong
#22 3_prepare_uninstall_finish.png80.57 KBtduong
#22 2_prepare_uninstall_begin.png72.53 KBtduong
#22 1_uninstall_before.png130.94 KBtduong
#22 remove_module_content_entities_upon_uninstallation-2688945-22.patch8.42 KBtduong
#22 interdiff-2688945-19-22.txt4.83 KBtduong
#19 remove_module_content_entities_upon_uninstallation-2688945-19.patch6.78 KBtduong
#16 uninstall node.png117.17 KBtduong
#16 prepare uninstall node finished.png65.43 KBtduong
#16 prepare uninstall node.png64.86 KBtduong
#16 remove_module_content_entities_upon_uninstallation-2688945-16.patch6.78 KBtduong
#16 remove_module_content_entities_upon_uninstallation-2688945-16-test_only.patch2.29 KBtduong
#16 interdiff-2688945-14-16.txt3.91 KBtduong
#14 count after.png77.82 KBtduong
#14 count before.png72.96 KBtduong
#14 remove_module_content_entities_upon_uninstallation-2688945-14.patch5.51 KBtduong
#14 interdiff-2688945-11-14.txt1.27 KBtduong
#11 prepare uninstall finished.png73.13 KBtduong
#11 prepare uninstall progress bar.png55.19 KBtduong
#11 prepare uninstall page.png67.57 KBtduong
#11 remove_module_content_entities_upon_uninstallation-2688945-11.patch4.9 KBtduong
#7 remove_module_content_entities_upon_uninstallation-2688945-7.patch4.34 KBtduong

Comments

tduong created an issue. See original summary.

tduong’s picture

Issue summary: View changes
tduong’s picture

Issue summary: View changes
tduong’s picture

Assigned: Unassigned » tduong
berdir’s picture

Title: Automatically remove module's entity types upon module uninstallation » Automatically remove module's content entities prior to module uninstallation
tduong’s picture

Status: Active » Needs review
StatusFileSize
new4.34 KB

Started with the form but I cannot make it work properly (it does not get the entity_type argument from routing). I've also tried so many things that now I'm confused... Will work more on this tomorrow!

cilefen’s picture

Version: 8.0.x-dev » 8.2.x-dev
+++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
@@ -0,0 +1,89 @@
+      '#title' => $this->t('Prepare uninstall'),
+      '#description' => $this->t('Clicking on this button, all module content entities data will be removed.'),
+    );

This sentence does not make sense. Also, we really need a confirmation form for this.

Status: Needs review » Needs work
berdir’s picture

That form *is* the confirmation form, we don't need another.

tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new4.9 KB
new67.57 KB
new55.19 KB
new73.13 KB

Now it works, but only as standalone form, so you have to go to admin/modules/uninstall/entity/{entity_type_id} to test it. At the moment you cannot go to the install/uninstall page because of an exception: Symfony\Component\Routing\Exception\MissingMandatoryParametersException.

What is in plan is that this form will be accessible by a link provided on the unintall page for each entity type a module has, but we need to decide more in details how to do it.

Next task: count how many content entities there are for the entity type we want to delete and show them on this prepare uninstall form.

tduong’s picture

No interdiff because it is bigger than the patch :P

Status: Needs review » Needs work
tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new1.27 KB
new5.51 KB
new72.96 KB
new77.82 KB

Added content entity counter.

Status: Needs review » Needs work
tduong’s picture

  • improved counter check as if we use another langcode it might not work properly
  • dropped prepare_uninstall from links.tasks
  • added test coverage

I've noticed that in the UI ("fresh drupal instance") the node module has also taxonomy and history requirements, and you cannot uninstall node until you don't uninstall the other two first, but in the test there is no such thing (see screenshots to get what I mean). Do I miss some obvious informations?

Status: Needs review » Needs work
tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new6.78 KB

Rerolled. I've just noticed that all my previous patches were made against 8.0.x branch. Now I'll set testbot to run on that branch instead of 8.2.x and see if there are still problems.

Locally I've switched to the 8.2.x ranch and tried to run the test but I got a warning and a fatal error, here is the output:

PHP Warning:  require(/usr/local/var/www/d8.dev/www/vendor/autoload.php): failed to open stream: No such file or directory in /usr/local/var/www/d8.dev/www/autoload.php on line 14
PHP Stack trace:
PHP   1. {main}() /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:0
PHP   2. require_once() /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:20

Warning: require(/usr/local/var/www/d8.dev/www/vendor/autoload.php): failed to open stream: No such file or directory in /usr/local/var/www/d8.dev/www/autoload.php on line 14

Call Stack:
    0.0023     475512   1. {main}() /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:0
    0.0024     476648   2. require_once('/usr/local/var/www/d8.dev/www/autoload.php') /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:20

PHP Fatal error:  require(): Failed opening required '/usr/local/var/www/d8.dev/www/vendor/autoload.php' (include_path='.:') in /usr/local/var/www/d8.dev/www/autoload.php on line 14
PHP Stack trace:
PHP   1. {main}() /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:0
PHP   2. require_once() /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:20

Fatal error: require(): Failed opening required '/usr/local/var/www/d8.dev/www/vendor/autoload.php' (include_path='.:') in /usr/local/var/www/d8.dev/www/autoload.php on line 14

Call Stack:
    0.0023     475512   1. {main}() /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:0
    0.0024     476648   2. require_once('/usr/local/var/www/d8.dev/www/autoload.php') /usr/local/var/www/d8.dev/www/core/scripts/run-tests.sh:20

Does anyone knows what can I do now ?

tduong’s picture

Version: 8.2.x-dev » 8.0.x-dev

Hmm, ok I'm dumb...

andypost’s picture

Version: 8.0.x-dev » 8.2.x-dev

This is right version to run tests
@tduong about #19 see https://www.drupal.org/node/2648064

tduong’s picture

Ok, changed branch, added a link in the uninstall module descriptions to its "Prepare uninstall" page, extended the test and uploaded new screenshots.

As my current code I cannot get all entity type ids right (e.g. 'views' instead of 'view'). Any suggestion ?

And there is still the odd thing for the test: after removing the content data, uninstall Node checkbox should still be disabled and it should be required at least by Taxonomy and History (as blank drupal installation), but in the test it is ready to be uninstalled without any further dependencies. Do you know what is wrong here ?

Status: Needs review » Needs work
berdir’s picture

  1. +++ b/core/modules/system/src/Form/ModulesUninstallForm.php
    @@ -136,6 +138,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
           if (isset($validation_reasons[$module_key])) {
    +        $link = Link::fromTextAndUrl(t('here'), Url::fromRoute('system.prepare_modules_entity_uninstall', ['entity_type_id' => $module_key]));
    +        $validation_reasons[$module_key][] = $this->t('To delete these content data go <a>' . $link->toString() . '</a>');
    

    entity type and module is no the same thing. You can't add this here, you have to add it in ContentUninstallValidator

  2. +++ b/core/modules/system/src/Tests/Module/PrepareUninstallTest.php
    @@ -0,0 +1,72 @@
    +
    +use Drupal\search_api\Tests\WebTestBase;
    +
    

    that's why the test doesn't work.

tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new2.66 KB
new8.5 KB

He-hem... D*mn it... You are right!

Status: Needs review » Needs work
berdir’s picture

+++ b/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php
@@ -41,6 +43,9 @@ public function validate($module) {
+        $link = Link::fromTextAndUrl(t('here'), Url::fromRoute('system.prepare_modules_entity_uninstall', ['entity_type_id' => $entity_type->id()]));
+        $reasons[] = $this->t('To delete these content data go <a>' . $link->toString() . '</a>');
       }

that's not how links work :) We might also want to make this part of the same reason string, not two separate ones.

tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new2.07 KB
new8.68 KB
new130.03 KB

Done.

Learnt something new. For those who wonder why with the previous code there were 2 problems:

  1. it had two tags, "mine" (which was invalid) and the one from the string...
  2. ... which had the whole link as placeholder that makes much harder to translate such strings

Status: Needs review » Needs work
tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new7.31 KB
new8.95 KB

Forgot to fix the link thing also in the "Prepare uninstall" page. Also improved the test by checking for the modules description instead of their names, re-enabled the check for taxonomy and history (since node is supposed to be required by them, thus it could not be uninstall as long as they are still alive, but both local test and testbot do something strange...)

I've investigated a bit for the failing unit test and it seems like there is still something wrong with the link in ContentUninstallValidator when toString() is called and it ends to core/lib/Drupal/Core/Routing/RouteProvider.php on line 214 where fetchAllKeyed() is called on a non-object variable.
Cannot figure out how to fix it. Any suggestions ?

Status: Needs review » Needs work
tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new4.56 KB
new9.3 KB
new124.56 KB

Discussed with @Berdir and it makes more sense to redirect back to the "Uninstall" page right after the data has been removed.

The reason why taxonomy and history don't appear during test it's because I didn't enable them, but when installing Drupal it does it by default. Dropped checks for these modules from the test.

Now locally my test fails checking that we are redirected back to the uninstall page and I think it's because batch needs time to run for the test, so it needs to sleep a bit, but probably I'm not doing that right.

Status: Needs review » Needs work
tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new2.46 KB
new9.12 KB

Reroll and removed that unnecessary sleep() thing. Still no idea why the expected and actual path are not matching during tests... manually works fine!

Status: Needs review » Needs work
tduong’s picture

Status: Needs work » Needs review
StatusFileSize
new1.19 KB
new9.92 KB

Discussed with @Berdir and found the bug: need to set the domain for the redirect response. and about the failing kernel test the register() method .. does nothing but failing our test :D

tduong’s picture

Title: Automatically remove module's content entities prior to module uninstallation » Allow to remove module's content entities prior to module uninstallation
Issue summary: View changes
StatusFileSize
new9.92 KB

Another reroll, updated IS and put some screenshots as well.

timmillwood’s picture

StatusFileSize
new9.83 KB
new2.59 KB

I quite like this solution, just updated some of the wording.

Status: Needs review » Needs work

The last submitted patch, 38: allow_to_remove-2688945-38.patch, failed testing.

timmillwood’s picture

StatusFileSize
new9.88 KB
new1.08 KB

Forgot to update the test.

timmillwood’s picture

Status: Needs work » Needs review
tduong’s picture

This change looks odd for other content entities, e.g.:
comment --> "Remove Comment entities" "There are 2 Comment entities to remove!",
shortcut --> "Remove Shortcut link entities" "There are 2 Shortcut link entities to remove!", ...
In the title there is already written that that delete form is related to which content entity, so I think it is clear enough and it is enough to know the amount of content entities to delete (not Content, from 'node' entity type).

timmillwood’s picture

I think from a UX point of view it's better to be explicit.

timmillwood’s picture

Issue tags: +Needs usability review
berdir’s picture

The main problem with mentioning the type in messages like that is getting case and plural forms correctly. Which is practically impossible.

joachim’s picture

Status: Needs review » Needs work

This is a really big improvement!

Just some UI things to tweak:

> There are 2 Content entities to remove!

I don't think exclamation mark is needed. We don't use those anywhere else in UI strings.

Though what we should have is the standard warning that 'This action cannot be undone.' And maybe that should go with some further help text, such as we have when you delete a field? Eg, 'This will delete all Foo entities from the site, and will allow the Foobar module to be uninstalled. This action cannot be undone.'

The button could also maybe be changed to say 'Delete all Foo entities'.

Lastly, there's no need for a fieldset that consists of the whole form.

joachim’s picture

Looking at this some more, this should be following the same UI pattern as other deletion forms.

I'm having a look at making this use ConfirmFormBase or ConfirmFormInterface, but getting a bit stuck with getting the entity type ID into the form...

joachim’s picture

Assigned: tduong » joachim

I'm working on this at the moment.

joachim’s picture

Assigned: joachim » Unassigned
Status: Needs work » Needs review
StatusFileSize
new10.24 KB
new4.83 KB
new38.74 KB

Updated patch:

- changed form class to inherit from ConfirmFormBase, so we get:
-- standard title with the confirmation question
-- cancel button
- changed confirm button to use the entity type label for additional clarity
- fixed entity type ID rather than label used in one of the batch labels
- fixed whitespace at the end

I'm not massively keen on this in buildForm():

    $this->entityTypeId = $entity_type_id;

but the only way to avoid it that I see is adding a form builder, which seems like overkill.

EDIT: drat, this will possibly break the test due to the button label change :( And I'm out of coding time for this weekend. Sorry!

Status: Needs review » Needs work

The last submitted patch, 49: 2688945-49.drupal.remove-content-entities.patch, failed testing.

timmillwood’s picture

Status: Needs work » Needs review
StatusFileSize
new10.24 KB
new894 bytes

Quick update to fix tests.

Although untested due to local environment issues.

Status: Needs review » Needs work

The last submitted patch, 51: 2688945-49.drupal.remove-content-entities.patch, failed testing.

timmillwood’s picture

Status: Needs work » Needs review
StatusFileSize
new802 bytes
new10.27 KB

Ooops

Bojhan’s picture

Generally we do not use the word "entities" in the UI. This is part of our guidelines. Can we in this case not say:

"Delete all Content types"

Unless I am wrong, for core almost all "bundles" are referred to as types in the UI. I would keep that consistent pattern.

I would happily have a philosophical debate over the label, but its a established standard - if one wishes to re-open that discussion we need a separate issue, and avoid negatively impacting the importance of this issue.

joachim’s picture

Status: Needs review » Needs work

> Generally we do not use the word "entities" in the UI

Fair enough.

Though "Delete all Content types" isn't what we're doing here. We're deleting all nodes / comments / menu links / flaggings.

Entity types have plural labels as of 8.1.x, so we can use these:

 *   label_plural = @Translation("content items"),
 *   label_count = @PluralTranslation(
 *     singular = "@count content item",
 *     plural = "@count content items"
 *   ),
Bojhan’s picture

Ahh, good point. Great!

timmillwood’s picture

Status: Needs work » Needs review
StatusFileSize
new3.14 KB
new3.14 KB

Updating with suggestion from #55.

berdir’s picture

Status: Needs review » Needs work

Looks like you uploaded the interdiff twice?

timmillwood’s picture

Status: Needs work » Needs review
StatusFileSize
new10.43 KB
new5.92 KB

ok, this should be correct now.

Status: Needs review » Needs work

The last submitted patch, 59: allow_to_remove-2688945-59.patch, failed testing.

tduong’s picture

Missed to edit some places and screenshots.

tduong’s picture

Missing uppercase.

timmillwood’s picture

Issue summary: View changes
joachim’s picture

+++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
@@ -0,0 +1,146 @@
+    $context['results']['entity_type_plural'] = ucfirst($entity_type->getPluralLabel());
...
+    drupal_set_message(t('@entity_type_plural have been deleted.', [
+      '@entity_type_plural' => $results['entity_type_plural'],
+    ]));

We can't rely on the replacement token being at the start of the sentence in other languages, so ucfirst() is wrong here.

Best way is to reword so the token is not at the start of the sentence.

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs usability review

Looks like we're in a pretty good place.

cilefen’s picture

Title: Allow to remove module's content entities prior to module uninstallation » Allow removing a module's content entities prior to module uninstallation

The grammar police say "allow" cannot be followed immediately by an infinitive, but gerund phrases are acceptable.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 64: 2688945-64.drupal.remove-content-entities.patch, failed testing.

amateescu’s picture

Component: node system » entity system
Status: Needs work » Reviewed & tested by the community

The patch is still green, back to RTBC.

Although.. the current patch does not address un-installing a module via the API (or drush). Is it ok to leave that for a followup?

alexpott’s picture

  1. Nice to see this really close!! Great work everyone
  2. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,146 @@
    +      $this->formatPlural($count,
    +        'There is 1 @entity_type entity to remove.',
    +        'There are @count @entity_type_plural to remove.',
    +        [
    +          '@entity_type' => $entity_type->getSingularLabel(),
    +          '@entity_type_plural' => $entity_type->getPluralLabel(),
    +        ]
    +      )
    +      . ' ' .
    +      $this->t('This action cannot be undone.');
    +  }
    

    Let's not concatenate translations - this causes problems for RTL.

  3. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,146 @@
    +          [__CLASS__, 'deleteContentEntities'], [$entity_type_id],
    ...
    +      'finished' => [__CLASS__, 'moduleBatchFinished'],
    

    Nice - I like keeping all the batch logic in the same place.

  4. Have we considered permissions or are we assuming that whoever has the ability to uninstall modules should be able to delete content?
  5. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,146 @@
    +      'progress_message' => static::t('Deleting @entity_type_plural... Completed @percentage% (@current of @total).', [
    +        '@entity_type_plural' => $entity_type->getPluralLabel(),
    +      ]),
    

    Where is @current, @percentage and @total coming from?

  6. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,146 @@
    +    $entity_type_ids = \Drupal::entityQuery($entity_type_id)->range(0, 100)->execute();
    

    Maybe we should have the 100 as something configurable.

  7. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,146 @@
    +    $context['finished'] = (int) count($entity_type_ids) < 100;
    

    This looks tricky - I think we should set it to finished when the number is 0 or the number has not changed from the last number. If the last number is not 0 then we need to fail and say that we couldn't delete something.

  8. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,146 @@
    +    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
    +    $context['results']['entity_type_plural'] = $entity_type->getPluralLabel();
    

    I would just passed the entity_type_id into the results otherwise we need to this on every batch iteration.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
alexpott’s picture

I definitely think the Drush issue is fine to do in a followup - or even the drush queue.

alexpott’s picture

I think this patch could do with a product manager review.

amateescu’s picture

Status: Needs work » Needs review
StatusFileSize
new12.04 KB
new7.57 KB

Re #69:

2. Fixed.
4. Yes.. I think that's a safe assumption :)
5. They were coming from _batch_process() itself, but I rewrote the progress message part to show a better overview of the real progress.
6. Done, made it configurable in the form, hidden under an 'Advanced options' details element.
7. We can only assume that we were able to delete everything, otherwise an exception would have been thrown and the batch would've stopped anyway.
8. Done.

amateescu’s picture

I definitely think the Drush issue is fine to do in a followup - or even the drush queue.

It's not only Drush, it's our own module API that is not taken into account here, i.e. \Drupal\Core\Extension\ModuleInstallerInterface::uninstall(). Basically, the only reason that #874000: Automatically remove module's nodes upon module uninstallation is still open after so many years :)

However, the workaround for someone who wants to uninstall a module in an update hook or something is that they have to manually remove their content entities with Batch API, pretty much like how we're doing it in this patch.

alexpott’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,169 @@
    +    // Inform the batch engine that we are not finished,
    +    // and provide an estimation of the completion level we reached.
    +    if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    

    One of the problems we have is that there is nothing to stop people creating content whilst this is on-going.

  2. +++ b/core/modules/system/src/Tests/Module/PrepareUninstallTest.php
    @@ -0,0 +1,69 @@
    +    // Delete Node data.
    +    $this->drupalGet('admin/modules/uninstall/entity/node');
    +    $this->assertText(t('There are 4 content items to remove. This action cannot be undone.'));
    +    $this->drupalPostForm(NULL, [], t('Delete all content items'));
    

    Let's set this to do it one at a time then so we're sure that batching is working.

amateescu’s picture

Status: Needs work » Needs review
StatusFileSize
new12.05 KB
new1.12 KB

One of the problems we have is that there is nothing to stop people creating content whilst this is on-going.

True, but that only means that the user will have to go through this 'delete content' step again before uninstalling the module. It's not like we're automatically uninstalling it at the end of the batch process, we're just redirecting back to the module uninstall page.

Let's set this to do it one at a time then so we're sure that batching is working.

Sure thing :)

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

#76 looks good to me.

I agree that if content is created during the delete process then they will just have to run the process again. One would assume that users will only do this process on a dev version of the site too.

joachim’s picture

> I agree that if content is created during the delete process then they will just have to run the process again. One would assume that users will only do this process on a dev version of the site too.

The alternative is to run an ordered query for 100 entities in each batch run, and instead of setting the max at the start of the batch, set finished if the query returns fewer than 100. It means your batch UI can't show progress (or we can show approximate progress that might jump at the end).

I used this approach on a site with a batch that processed all entities of a certain type, while users were potentially adding more.

webchick’s picture

Will try and review this today during UX meeting. For now, adding the tags.

At a glance of the screen shots, though, it doesn't look like we're doing nearly enough here to inform people about what sort of destruction is about to happen. For example:

- Notice about 2 content items about to be deleted is not styled in any way (e.g. red error), so it's super easy to just click past it, leading to unwanted data loss.
- Rather than simply saying "2 content items" it probably should display a (truncated if necessary) list of node titles, which would more clearly communicate what is being deleted.

Will ping the UX team to see if they have other feedback.

berdir’s picture

@webchick: Note that the only way to get to this page is from the uninstall page when it tells you why a module can't be uninstalled. So a site builder shouldn't accidently end up there. But sure, adding a red message that this will delete data and that there is really no undo won't hurt ;)

Bojhan’s picture

Issue tags: +Needs screenshots
yoroy’s picture

Issue tags: -Needs usability review
StatusFileSize
new24.17 KB

Discussed this during UX meeting in Slack:

In general: not explicit enough about what is going to happen. We need to slow down this quite a bit (introduce more friction) so that people become really aware that there is no undo here.

1. For example: have people literally type in the word "Delete" in a text field before they can continue.
2. Showing a list of what's going to be deleted would also help estimate the impact. "3 Flagging entities" is quite abstract, can we show a list of titles instead? Similar to the confirm screen that follows bulk-deleting from the content listing:

3. Lets not make the primary button blue here, maybe we should introduce a big scary red button here.
4. Do we want to remind people to create a backup of their database first? That's the only undo option there is right?

yoroy’s picture

Status: Reviewed & tested by the community » Needs work

So yeah, needs work :)

timmillwood’s picture

@yoroy - The patch extends ConfirmFormBase, and therefore follows all the design patterns of other confirmation forms. Should we apply your points from #82 to all confirmation forms?

gábor hojtsy’s picture

@timmillwood: Well, the conclusion of the discussion was that most confirm forms don't have the potential to delete 5k nodes that you worked on for 4 years "accidentally". That this form can do such damage as to undo the majority of a site, so it needs to be treated as such.

webchick’s picture

Whatever the content admin page is doing to its confirm form, though, is a pattern that already exists in core, so however it's doing that, yes, we want to establish the same "OMG ARE YOU REALLY REALLY SURE?" pattern in both places.

gábor hojtsy’s picture

The content admin page allows you to act on 50 nodes at most (by default). This form allows to act on all the content on the site, be it 50, 5000, 50000 or whatever. There is a clear level of difference in damage made. Not sure I would want to type in "Delete" each time I want to bulk-delete 2 nodes, but if I am about to delete four years of work, I would welcome the extra caution.

timmillwood’s picture

ok, how about, based on #82:
1) This confirm form
2) All confirm forms
3) All confirm forms
4) This confirm form

webchick’s picture

Btw, lest you think we're just being overly paranoid here, this same type of deal is literally how jQuery lost its entire plugins repository a few years ago, thanks to a major "oops" with VBO. :P https://blog.jquery.com/2011/12/08/what-is-happening-to-the-jquery-plugi...

#88: I think so, except I'd say 3) is probably this form only. Gábor is correct that this is pretty special, at least in terms of what ships with core.

yoroy’s picture

StatusFileSize
new55.16 KB

Iterated over a design for this with @Bojhan, @gabor and @webchick:

  1. Lets *not* do the type-something-to-confirm-deletion thing
  2. List the first 10 titles of the entities about to be deleted
  3. Mention the number of remaining items also about to be deleted. Show the actual number in bold
  4. Add "Make a backup of your database if you want to be able to restore these items.
  5. Make "Cancel" the default button, "Delete" a secondary red link
gábor hojtsy’s picture

And by red Delete link I think what is meant is it should still be a submit button but look like a link. Otherwise page preloaders and other nifty client side tools would delete all your content :D

webchick’s picture

Cool, if that's the spec, my concerns are addressed!

berdir’s picture

Fine with me, just a note on the titles/labels. Not everything really has a label that can be shown there. Flaggings for example don't have a label, so the output there will be pretty weird.

I suppose we can skip the list if we detect that no labels are returned.

timmillwood’s picture

@Berdir makes a good point, I am here for ContentModerationState entities, which don't have labels. I guess we could compute one if that would be a good UX+.

joachim’s picture

Reversing the position of the action button and the delete seems like a really bad idea to me. People often go for UI elements based on their position without fully reading them. It s the reason OS X dialog boxes always have the confirm button at the bottom right, for instance.

joachim’s picture

Also, I think the name of the entity type needs to be in there somewhere. Titles can be ambiguous, and some entities won't have meaningful labels (eg I have no idea what flagging entities show for their titles). So either page title or the total count should include the entity type label in the sentence.

gábor hojtsy’s picture

@joachim: the point of reversing the buttons was because people don't usually read them and this form can do massive irreversible damage to your site.

ifrik’s picture

StatusFileSize
new18.28 KB
new23.5 KB

First of all: this is a great addition because it stops otherwise unnecessary searching round through the admin interface to find out where whatever comes from, and leads the user straight to the next task at hand.

Second: We don't actually have a separate style for situations in which the default option is to delete something. We got the default action as a blue button, a grey cancel button, and a red link for something destructive - but if the destructive action is the option you came to this page for then it's a blue button.
Since that is the same all over core, it probably doesn't make sense to discuss this here as an isolated event.

Third: In other cases when a user deletes not one item but several, they see a list of these items. So getting a list if you hit the "Remove content items" is the expected behaviour. In fact, I would expect a confirmation page that looks very similar to the one I get when I decide to delete the same items in a different way. (See screenshots.)

In this case it is even more relevant to see such a list, because what we delete here can go across a several entity types - labelled as something that is barely visible in the admin UI.
For example uninstalling the Node module, requires the user to delete content of the entity type: Content - and then it simply says all content items or remove x content items. Nowhere is the user alerted that this means deleting all pages and articles, or what ever custom entity types there are.

So there certainly needs to be a list of items. For deleting content through a bulk operation on the Content page, the length of the list is restricted by the number of items is shown in the View (50 items by default).
Following that: a list of items on the confirmation page can also contain 50 items. It could then have a line at the bottom of the list that says "and xxx other items."

To make this even safer, I would even propose to show the entity type in the list. That would make it really obvious.

  • * Article: Lorem ipsum
  • * Page: Veggie ipsum
  • * Page: Yet another page
  • * and another 123 content items.

Fourth: The action a user does is to delete something, and that's the word we use all over the place. Labelling the link "Remove" makes it sound like a different action (and possibly a less destructive one). So this should in any case say "Delete ...". Same in the help text on the confirmation page.

And fifth: yet another issue: So far we have one permission to administer modules, and that was fine in D7, when modules could be disabled. But since uninstalling modules is a destructive action now, we should think about making Uninstall modules a different permission. That would also make it less likely that somebody stumbles on the Uninstall page.

joachim’s picture

> Nowhere is the user alerted that this means deleting all pages and articles, or what ever custom entity types there are

That's a good point. Maybe in addition to 'X items' and the list of titles, we should give a summary like:

This will delete 123 content items, including:

- 43 articles
- 12 pages
- 35 issues
[etc]

> @joachim: the point of reversing the buttons was because people don't usually read them and this form can do massive irreversible damage to your site.

That is my point though. People don't read them properly, and someone could click the thing that LOOKS like a cancel button, but isn't.

gábor hojtsy’s picture

@joachim: because of cancel buttons are red links? Or because of the spatial positioning of them? If we want to keep the button orders, colors, etc. because people may click the wrong thing out of habit, then it is hard to dismiss the idea to need to type in something explicitly into a text field.

joachim’s picture

The spatial position. I believe it's documented in usability studies that people often go by position of elements. I certainly notice that behaviour in myself. I can easily imagine coming to this page, reading the warnings, thinking 'oops, that doesn't look good' and then clicking what I automatically think is the cancel button but without reading the text of it. (Of course myself I'd just close the tab...)

I think the delete button in red in the usual position would be much better.

amateescu’s picture

How about keeping the red delete button on the left but disabled, and add a checkbox above it "I'm sure I want to delete all items", which has to be checked in order to enable the delete button?

Edit: at least this makes it a two-click process, so the user is less likely to do both actions by accident.

amateescu’s picture

Status: Needs work » Needs review
StatusFileSize
new13.73 KB
new5.87 KB
new24.6 KB

For now, this patch implements the design that was agreed upon in #90:

Status: Needs review » Needs work

The last submitted patch, 103: 2688945-103.patch, failed testing.

joachim’s picture

Status: Needs work » Needs review

> How about keeping the red delete button on the left but disabled, and add a checkbox above it "I'm sure I want to delete all items", which has to be checked in order to enable the delete button?

Yup, that sounds good to me. Potentially a UI pattern we could abstract out later on.

Bojhan’s picture

I prefer not to change direction again. Both a red button and a checkbox have significant implications, and should warrant further discussion.

Lets move ahead with the direction which was agreed upon. We can easily optimise most of this later on and right now its holding up a big initiative from going in. This is experimental, we can change it after commit.

ifrik’s picture

Can you still change the wording to talk about "Delete" instead of the weaker "Remove"?

gábor hojtsy’s picture

@Bojhan: to be precise the patch changes various existing parts of the stable Drupal core and therefore is not experimental. The functionality it blocks is experimental but not this patch. That does not mean we cannot make changes to it after the patch lands but much less so to the API at least after 8.2 is released.

joachim’s picture

> Both a red button and a checkbox have significant implications, and should warrant further discussion.

Fair enough. I'd be happy to leave those for later.

However, I do think that the reversed buttons is a big UX mistake.

amateescu’s picture

StatusFileSize
new14.01 KB
new3.19 KB

Fixed and improved the tests for the new UI.

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php
    @@ -37,10 +38,14 @@ public function __construct(EntityManagerInterface $entity_manager, TranslationI
    +          '@entity_type_plural' => $entity_type->getPluralLabel(),
    

    Nice a usecase for the plural label

  2. +++ b/core/lib/Drupal/Core/Entity/ContentUninstallValidator.php
    @@ -37,10 +38,14 @@ public function __construct(EntityManagerInterface $entity_manager, TranslationI
    +          ':link' => Url::fromRoute('system.prepare_modules_entity_uninstall', ['entity_type_id' => $entity_type->id()])->toString(),
    

    Maybe I nitpick and say that this is a URL not a link :P

  3. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,231 @@
    +      '#type' => 'number',
    +      '#title' => $this->t('Limit'),
    +      '#description' => $this->t('Select how many items should be deleted at once in a single batch run.'),
    +      '#default_value' => ($count < 100) ? $count : 100,
    +    ];
    

    Am I the only one who things that nobody actually has to care about this number? Deleting an entity throws hooks is much more costly than having x or 10x batch jobs, so I would have just gone with 10 entities or so and call it a day? The batch API deals with starting new processes, when time is gone.

  4. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,231 @@
    +    if (!isset($context['sandbox']['progress'])) {
    +      $context['sandbox']['progress'] = 0;
    +      $context['sandbox']['max'] = \Drupal::entityQuery($entity_type_id)->count()->execute();
    +    }
    

    Do we care about content which is created in the meantime?

  5. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,231 @@
    +    $entity_ids = $storage->getQuery()->range(0, $limit)->execute();
    

    should we sort by some criteria like ID descending or ascending?

  6. +++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
    @@ -0,0 +1,231 @@
    +    if ($entity_types = $storage->loadMultiple($entity_ids)) {
    +      $storage->delete($entity_types);
    +    }
    

    Weird variable name ... can't we just use $entities

  7. +++ b/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
    @@ -37,16 +36,6 @@ protected function setUp() {
       /**
    -   * {@inheritdoc}
    -   */
    -  public function register(ContainerBuilder $container) {
    ...
    -    // Put a fake route bumper on the container to be called during uninstall.
    -    $container
    -      ->register('router.dumper', 'Drupal\Core\Routing\NullMatcherDumper');
    -  }
    

    I love the typo in here

amateescu’s picture

Issue tags: -Needs screenshots
StatusFileSize
new14.13 KB
new2.48 KB

Thanks for reviewing!

Re #111:

  1. Yup! :)
  2. You would be right, fixed.
  3. I don't really care either, but @alexpott wanted it to be configurable :)
  4. Nope, we don't care that much, see #75/#76.
  5. Why not, let's make sure that we delete the oldest first.
  6. Yup. fixed.
  7. ;)
amateescu’s picture

StatusFileSize
new14.13 KB
new1.67 KB

Also fixed a typo and a comment.

The last submitted patch, 112: 2688945-112.patch, failed testing.

alexpott’s picture

Status: Needs review » Needs work

I seem to be able to break things.

  1. Apply patch
  2. Install standard
  3. Install devel_generate
  4. Create 1000 terms (drush generate-terms tags 1000)
  5. Log in as user 1
  6. Go to admin/modules/uninstall/entity/taxonomy_term
  7. And try to remove them

It gets stuck :)

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new1.48 KB
new14.34 KB

This is happen because of deleting parents - see \Drupal\taxonomy\Entity\Term::postDelete()

Here's a simple fix.

amateescu’s picture

That's a very simple fix indeed, @alexpott++

Status: Needs review » Needs work

The last submitted patch, 116: 2688945-116.patch, failed testing.

yoroy’s picture

Is the patch in #116 supposed to work on simplytest? I enable forum, create forum node, then go to uninstall forum, which then still has a disabled checkbox, telling me to delete forum nodes first.

alexpott’s picture

@yoroy well forum does not provide the entity type - the node module does.

berdir’s picture

Yeah, that's a slightly different use case because forum only provides a node type/bundle for nodes.

I think we can relatively easily extend this to support bundles as well, we just need a condition in the entity queries and pass that argument along, but I think we should do a separate issue for that.

alexpott’s picture

Status: Needs work » Needs review
alexpott’s picture

I agree with @Berdir - let's do that in a follow-up.

Status: Needs review » Needs work

The last submitted patch, 116: 2688945-116.patch, failed testing.

timmillwood’s picture

Status: Needs work » Reviewed & tested by the community

This patch looks to be in a good state, and as it's blocking #2725533: Add experimental content_moderation module, lets get it RTBC'd.

joachim’s picture

+++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
@@ -0,0 +1,237 @@
+    $form['actions']['cancel']['#weight'] = -1;

This reordering of the buttons is a really big mistake.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 116: 2688945-116.patch, failed testing.

The last submitted patch, 116: 2688945-116.patch, failed testing.

timmillwood’s picture

Status: Needs work » Reviewed & tested by the community

Unrelated #fail.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs change record

Before we commit this:

  • I think we should add test coverage (using taxonomy terms) for the bug fixed in #116
  • we should create the followup for #121
  • And we need a change record to tell everyone about this functionality
alexpott’s picture

Issue tags: +8.2.0 release notes
amateescu’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record
StatusFileSize
new16.4 KB
new16.18 KB
new3.59 KB

Here's a test for the bug fixed in #116, also applied to the patch from #113 to prove that it's failing.

Wrote a draft CR for this feature: https://www.drupal.org/node/2772525 and this is the followup requested for #121: #2772511: Support uninstalling modules that provide bundles for content entity types

Status: Needs review » Needs work

The last submitted patch, 132: 2688945-test-only-for-taxonomy-uninstall.patch, failed testing.

alexpott’s picture

Status: Needs work » Reviewed & tested by the community

Nice test.

+++ b/core/modules/system/src/Tests/Module/PrepareUninstallTest.php
@@ -41,12 +49,53 @@ public function setUp() {
+    // disabled.

uninstalled :) can be fixed on commit.

alexpott’s picture

StatusFileSize
new15.89 KB
new5.41 KB

Just re-read #111.3 and realised I caused the additional form element - what I was concerned about was properly testing this whilst batching. The new taxonomy test help resolve this concern. I've removed it and bumped up the number of taxonomy terms created. I've hard-coded the limit to 10.

berdir’s picture

Hm. 10 is a pretty low value IMHO. I guess that's set so low for the term recursive deletion, but even when setting it to 1, there's not really a limit to how many terms it might actually delete?

The problem is that batch overhead is quite high, and when deleting just 10 per batch run, I guess you spend more time on refreshing and bootstraping than actually doing something (batch calls multiple operations but only until 1s is passed).

Just pointing that out, I care way more about actually getting this in than fighting over the limit :)

alexpott’s picture

Am I the only one who things that nobody actually has to care about this number? Deleting an entity throws hooks is much more costly than having x or 10x batch jobs, so I would have just gone with 10 entities or so and call it a day? The batch API deals with starting new processes, when time is gone.

I think if you're doing 1000's of entities we should provide an integration with drush.

alexpott’s picture

StatusFileSize
new1.18 KB
new15.9 KB

Fixing the disables

dawehner’s picture

The problem is that batch overhead is quite high, and when deleting just 10 per batch run, I guess you spend more time on refreshing and bootstraping than actually doing something (batch calls multiple operations but only until 1s is passed).

Well, it still calls operations until you get near the 1s mark, doesn't it? So the overhead of batch operations should be kind of small over what happens on entity deletion ...

amateescu’s picture

StatusFileSize
new15.99 KB
new824 bytes

Discussed a bit with @alexpott on IRC and we decided to mark \Drupal\system\Form\PrepareModulesEntityUninstallForm::deleteContentEntities() as @internal in order to make it possible to add additional parameters to it (e.g. $limit or $bundle) in the future without having to worry about BC.

yoroy’s picture

Thanks for creating that followup. Quite likely this design can be improved further still, at least we've made an explicit decision here.

Pity the ui issues surfaced a bit late but i'm happy we accomodated for that bit of work to happen still.

Lets go ahead with this!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
@@ -0,0 +1,223 @@
+          '#markup' => $this->t('And <strong>@count</strong> more @entity_type_plural.', ['@count' => $count - count($labels), '@entity_type_plural' => $entity_type->getPluralLabel()]),

Hmmm this should be a formatPlural... because saying "And 1 more content items" does not make sense.

alexpott’s picture

Status: Needs work » Needs review
StatusFileSize
new8.08 KB
new19.59 KB

Patch attached:

  • Fixes #142
  • Makes the form result in a 404 when passed an entity type that does not exist
  • Removes the submit button and tells the user why when there are no entities to delete
  • Tests the no label key situation
  • Tests all the new changes
amateescu’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/modules/system/src/Form/PrepareModulesEntityUninstallForm.php
@@ -91,6 +92,9 @@ public function getCancelUrl() {
+    if (!$this->entityTypeManager->hasDefinition($this->entityTypeId)) {

Maybe we should also add a check for a non-null $entity_type_id at the beginning of this condition. Or is the routing system handling that for us?

This is pretty minor and can be fixed on commit, the rest of the interdiff looks great :)

xjm’s picture

Maybe we should also add a check for a non-null $entity_type_id at the beginning of this condition. Or is the routing system handling that for us?

This is pretty minor and can be fixed on commit, the rest of the interdiff looks great :)

Well I would not fix anything more than a coding standards or docs fix on commit, personally. :)

xjm’s picture

Issue summary: View changes
StatusFileSize
new28.17 KB
new53.37 KB
new69.84 KB
new51.13 KB

While testing this patch to potentially commit it, I accidentally canceled the form the first time instead of deleting the items, because the Cancel button was where the normal "Yeah do this thing" button would be.

I went back and confirmed that I am not crazy; it is different from every other confirm form, including the one that you might have to visit right before you do this (in my case, uninstalling Taxonomy and History in order to be able to uninstall Node and test the batch deletion).

If I can accidentally cancel my form because the button moved, it's not inconceivable that someone might accidentally click the link when they want to cancel. Less likely, perhaps.

I see this design was discussed earlier on the issue, and @Bojhan suggested going forward with it because it was an experimental module and we can iterate on the best design later. The thing is, this is not an experimental module. This is a change to stable core that lets you delete all your content.

Are we really, really, really sure that basically xjm is just an idiot who needs to pay more attention, and that it is better to have the new design for this one form and no other?

xjm’s picture

I should add that the functionality itself seems to work great, the listing on the confirm form makes it clear what the consequences of the action should be, and the hardcoding at 10 items in the batch job seemed fine based on my testing with large-ish batches (admittedly without 20 other modules firing delete hooks, but nonetheless). I will go ahead and commit it if the usability maintainers say "yes absolutely really". But in the earlier discussion, it did not seem to me that the full consequences of this were clear. Edit: And the first user to test it seems to have gotten it wrong, soooo... :P

twistor’s picture

I'm curious where the missing conversation is regarding:

For example: have people literally type in the word "Delete" in a text field before they can continue.

alexpott’s picture

I agree with @xjm's comment in #146. I think the most relevant example is the uninstall screen where we are listing configuration entities that will be deleted. We have not changed the pattern there - so changing the pattern here seems wrong too. I think we need to remember that the only people who can get to this screen are people who can uninstall modules - which is a very data destructive operation already. Maybe the way forward here is to make this form a usual confirm form and open a followup issue to discuss the design of super-destructive confirm forms like this and the module uninstall form - so we can be consistent.

alexpott’s picture

Bojhan’s picture

Given that this is critical for getting workflow in. I have no objects to removing the change to confirm forms and create a propper followup to solve this. This is a tricky problem and needs a consistent solution.

I am very concerned about all the WI Criticals that get held up though :(

alexpott’s picture

Issue summary: View changes
StatusFileSize
new849 bytes
new19.48 KB
new76.54 KB

Okay removed the special button styling...

alexpott’s picture

alexpott’s picture

Re #144 - visiting admin/modules/uninstall/entity results in the expected 404 - we don't need to check for NULLness. But also...

>>> \Drupal::entityTypeManager()->hasDefinition(NULL)
=> false

So all good imo.

webchick’s picture

I agree we can go ahead with this in the interest of unblocking workflow. I'm confused why #146 is the rationale, though. The accidental click resulted in a non-destructive action, forcing her to go back and read the actual options, which is exactly what it was intending to do.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 152: 2688945-152.patch, failed testing.

alexpott’s picture

Issue summary: View changes
Status: Needs work » Reviewed & tested by the community

For me the rationale is we already have super-destructive operations that precisely a user with the perms necessary to get here and we don;t special case that form either. I do think we should consider the UX pattern for such forms but the arguments that @joachim put forward about spatial reasoning are strong - after all the accidental click documented in #146 could have been intended to cancel but instead deleted everything.

DrupalCI is busy fixing itself.

  • webchick committed 8ac20c7 on 8.2.x
    Issue #2688945 by tduong, amateescu, timmillwood, alexpott, joachim, xjm...
webchick’s picture

Status: Reviewed & tested by the community » Fixed

@twistor: We discussed that alternate pattern briefly in UX meeting the other week, and it was only really supported by Kevin. Bojhan had done some user-testing of it and found it to increase user frustration, and overall feels like a "cover your ass" cheat, rather than an actual design, IMNSHO. :) But something we can explore in the new sub-issue.

Reviewed this upon @alexpott's request, as well as manually tested it. Couldn't find anything to complain about!

Committed and pushed to 8.2.x. Thanks!

alexpott’s picture

  • webchick committed 8ac20c7 on 8.3.x
    Issue #2688945 by tduong, amateescu, timmillwood, alexpott, joachim, xjm...

  • webchick committed 8ac20c7 on 8.3.x
    Issue #2688945 by tduong, amateescu, timmillwood, alexpott, joachim, xjm...

Status: Fixed » Closed (fixed)

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