Issue:
Changing machine name, duplicating a Page to a Block silently removes the Page.
Steps to reproduce:
1) Create a Page on any view or create new one;
2) Select "Machine name" and "Apply";
3) Select "Duplicate as Block";
You can see that the Block has the same machine name now;
4) Save.
Expected: 1 Page and 1 Block.
Result: 1 Block only.

No notifications about deleting the page or having two identical machine names are displayed.

I have not tested on 8.5 versions, but I assume nothing has changed about this.

CommentFileSizeAuthor
#15 2915175-15.patch2.03 KBAnonymous (not verified)
#7 2915175-7.patch4.3 KBAnonymous (not verified)
#7 2915175-7-two-changes-test-only.patch2.99 KBAnonymous (not verified)
#7 2915175-7-duplicate-test-only.patch2.33 KBAnonymous (not verified)
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Phonoman created an issue. See original summary.

Phonoman’s picture

Issue summary: View changes
Phonoman’s picture

Priority: Normal » Major
swentel’s picture

Sounds a bit like #2897576: Resaving a view display results in deletion of view display - although not entirely the same

Phonoman’s picture

Component: views.module » views_ui.module

Changing to views_ui.module since the issue happens when working with UI.

Phonoman’s picture

Title: Duplicating Page (changed machine name) to Block and saving removes Page » Duplicating the Page to Block and saving destroys the Page
Version: 8.3.7 » 8.4.2
Issue summary: View changes

This still currently occurs.

Anonymous’s picture

@Phonoman, good catch and steps to reproduce!

I added a patch that fixes the duplication problem (just unset new_id key).

But looks like we need more attention to this problem. Example, if we change two display id on same new id, we also have this problem:

id1 -> id3
id2 -> id3
# Save and lost one display

.
I tried to fix this problem on the UI level, but maybe we need to do it on more lower level. But I do not know exactly where: views/View::set, views/View::preSave, view_ui/ViewEditForm, ...?

Review of change on the UI level:

+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -1873,8 +1873,13 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) {
-            if ($id != $this->view->current_display && ($form_state->getValue('display_id') == $id || (isset($display->new_id) && $form_state->getValue('display_id') == $display->new_id))) {
-              $form_state->setError($form['display_id'], $this->t('Display id should be unique.'));
+            if ($id !== $this->view->current_display) {
+              if ($form_state->getValue('display_id') === $id ||
+                (isset($display->new_id) && $form_state->getValue('display_id') === $display->new_id) ||
+                (isset($display->display['new_id']) && $form_state->getValue('display_id') === $display->display['new_id'])
+              ) {
+                $form_state->setError($form['display_id'], $this->t('Display id should be unique.'));
+              }

Here, only one more check $display->display['new_id'] is added, by analogy with check $display->new_id, but the condition was very long, so it is divided into several if and lines, for better readability.

Anonymous’s picture

Status: Active » Needs review
Anonymous’s picture

Version: 8.4.2 » 8.5.x-dev

I have not tested on 8.5 versions, but I assume nothing has changed about this

This is true.

The last submitted patch, 7: 2915175-7-two-changes-test-only.patch, failed testing. View results

The last submitted patch, 7: 2915175-7-duplicate-test-only.patch, failed testing. View results

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Anonymous’s picture

#7:

But I do not know exactly where: views/View::set, views/View::preSave(), view_ui/ViewEditForm::save(), ...?

Even if we need control at this lower level, then perhaps we can do it in a separate issue?

Currently, patch #7 fixes the problem at the UI level. Since the steps described in IS lead to the loss of all the data from the display (and the display, of course), it is possible to change status on Critical?

Lendude’s picture

Title: Duplicating the Page to Block and saving destroys the Page » Duplicating a Page to Block after changing the display id and then saving the view destroys the Page

Nice find, nice tests, but I agree with @vaplas: not too sure about the fix.

Also, we seem to be fixing 2 bugs in one issue at the moment. If we can get one fix that fixes both cases I'm fine with doing it in one issue, but currently it's two fixes for two problems in one issue.

+++ b/core/modules/views/src/Entity/View.php
@@ -245,6 +245,7 @@ public function duplicateDisplayAsType($old_display_id, $new_display_type) {
+    unset($display_duplicate['new_id']);

+++ b/core/modules/views_ui/tests/src/Functional/DisplayCRUDTest.php
@@ -143,6 +143,27 @@ public function testDuplicateDisplay() {
+    // Duplicate display when changed id.
+    $view_id = $view->id();
+    $this->drupalPostForm("admin/structure/views/nojs/display/$view_id/page_2/display_id", ['display_id' => 'page_new'], 'Apply');
+    $this->drupalPostForm(NULL, [], 'Duplicate as Block');
+    $this->drupalPostForm(NULL, [], t('Save'));
+    $view = Views::getView($view_id);
+    $view->initDisplay();
+    $this->assertNotNull($view->displayHandlers->get('page_new'), 'The original display is saved with a changed id');
+    $this->assertNotNull($view->displayHandlers->get('block_2'), 'The duplicate display is saved with new id');

I think this should be a fix by itself. I think that is RTBC with just a nit fixed for the comment. And even if we come up with a generic way of preventing duplicate display names, just cleaning up the data when cloning makes sense anyway.

The other fix:

+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -1873,8 +1873,13 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) {
+            if ($id !== $this->view->current_display) {
+              if ($form_state->getValue('display_id') === $id ||
+                (isset($display->new_id) && $form_state->getValue('display_id') === $display->new_id) ||
+                (isset($display->display['new_id']) && $form_state->getValue('display_id') === $display->display['new_id'])
+              ) {

This seems very fragile. And I agree with @vaplas that it would be better to fix that whole logic at a different level then the UI. Some way we can just say 'We never allow duplicate display machine names when saving a view'. @vaplas suggestion of views/View::preSave sounds like a good place to start.

nitpicking some comments:

  1. +++ b/core/modules/views_ui/tests/src/Functional/DisplayCRUDTest.php
    @@ -143,6 +143,27 @@ public function testDuplicateDisplay() {
    +    // Duplicate display when changed id.
    

    Test duplicating a display after changing the machine name.

  2. +++ b/core/modules/views_ui/tests/src/Functional/DisplayCRUDTest.php
    @@ -143,6 +143,27 @@ public function testDuplicateDisplay() {
    +    // Prevent set display id, if other display also set same new id.
    

    Test setting the same machine name for two different displays before saving.

Anonymous’s picture

@Lendude, thanks for review and a wise remark about two problems in one issue. Now I see that this is true! Open separated issue by #14: #2944859: Never allow duplicate display machine names when saving a view (clean up IS too).

Here is the first half of the patch #7 + #14.1 comment fix:

-    // Duplicate display when changed id.
+    // Test duplicating a display after changing the machine name.
Lendude’s picture

Priority: Major » Critical
Status: Needs review » Reviewed & tested by the community

@vaplas thanks for that! This looks good.

Bumping this to critical since it leads to data loss through normal use of the UI.

Since it's not a common scenario, it might just be major, but it's not like it takes a weird setup to get into this state.

  • catch committed 3d6a12a on 8.6.x
    Issue #2915175 by vaplas, Phonoman, Lendude: Duplicating a Page to Block...
catch’s picture

Version: 8.6.x-dev » 8.5.x-dev
Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.6.x and cherry-picked to 8.5.x. Thanks!

  • catch committed 9a1d267 on 8.5.x
    Issue #2915175 by vaplas, Phonoman, Lendude: Duplicating a Page to Block...

Status: Fixed » Closed (fixed)

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