From 3f29fd91435a2c1b6ca53e1f7fbfa02902d78e7e Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 3 Feb 2015 10:05:06 +0000
Subject: [PATCH] Issue #2165989 by Xano, pcambra, damiankloip, dawehner: Add a
 Views field handler for multiple entity operations

---
 .../ContentTranslationOperationsTest.php      |  66 ++++++
 .../config/install/views.view.content.yml     |  72 ++++---
 core/modules/node/src/Tests/NodeAdminTest.php |   1 +
 .../install/views.view.user_admin_people.yml  |  70 +------
 .../config/schema/views.data_types.schema.yml |   3 +
 core/modules/views/src/EntityViewsData.php    |   8 +
 .../Plugin/views/field/EntityOperations.php   | 124 +++++++++++
 .../Handler/FieldEntityOperationsTest.php     |  58 ++++++
 .../views/field/EntityOperationsUnitTest.php  | 170 +++++++++++++++
 .../views.view.test_entity_operations.yml     | 193 ++++++++++++++++++
 10 files changed, 677 insertions(+), 88 deletions(-)
 create mode 100644 core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php
 create mode 100644 core/modules/views/src/Plugin/views/field/EntityOperations.php
 create mode 100644 core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
 create mode 100644 core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
 create mode 100644 core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_operations.yml

diff --git a/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php
new file mode 100644
index 000000000000..2fce045cfdc8
--- /dev/null
+++ b/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\content_translation\Tests\ContentTranslationOperationsTest.
+ */
+
+namespace Drupal\content_translation\Tests;
+
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\node\Tests\NodeTestBase;
+
+/**
+ * Tests the content translation operations available in the content listing.
+ *
+ * @group content_translation
+ */
+class ContentTranslationOperationsTest extends NodeTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['language', 'content_translation', 'node', 'views'];
+
+  protected function setUp() {
+    parent::setUp();
+
+    // Enable additional languages.
+    $langcodes = ['es', 'ast'];
+    foreach ($langcodes as $langcode) {
+      ConfigurableLanguage::createFromLangcode($langcode)->save();
+    }
+
+    // Enable translation for the current entity type and ensure the change is
+    // picked up.
+    \Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE);
+    drupal_static_reset();
+    \Drupal::entityManager()->clearCachedDefinitions();
+    \Drupal::service('router.builder')->rebuild();
+    \Drupal::service('entity.definition_update_manager')->applyUpdates();
+
+    $this->base_user_1 = $this->drupalCreateUser(['access content overview']);
+    $this->base_user_2 = $this->drupalCreateUser(['access content overview', 'create content translations', 'update content translations', 'delete content translations']);
+  }
+
+  /**
+   * Test that the operation "Translate" is displayed in the content listing.
+   */
+  function testOperationTranslateLink() {
+    $node = $this->drupalCreateNode(['type' => 'article', 'langcode' => 'es']);
+    // Verify no translation operation links are displayed for users without
+    // permission.
+    $this->drupalLogin($this->base_user_1);
+    $this->drupalGet('admin/content');
+    $this->assertNoLinkByHref('node/' . $node->id() . '/translations');
+    $this->drupalLogout();
+    // Verify there's a translation operation link for users with enough
+    // permissions.
+    $this->drupalLogin($this->base_user_2);
+    $this->drupalGet('admin/content');
+    $this->assertLinkByHref('node/' . $node->id() . '/translations');
+  }
+
+}
diff --git a/core/modules/node/config/install/views.view.content.yml b/core/modules/node/config/install/views.view.content.yml
index 2a44101f8dc3..7fd418ac8883 100644
--- a/core/modules/node/config/install/views.view.content.yml
+++ b/core/modules/node/config/install/views.view.content.yml
@@ -249,34 +249,56 @@ display:
           plugin_id: date
           entity_type: node
           entity_field: changed
-        edit_node:
-          id: edit_node
+        operations:
+          id: operations
           table: node
-          field: edit_node
-          label: ''
-          exclude: true
-          text: Edit
-          plugin_id: node_link_edit
-          entity_type: node
-        delete_node:
-          id: delete_node
-          table: node
-          field: delete_node
-          label: ''
-          exclude: true
-          text: Delete
-          plugin_id: node_link_delete
-          entity_type: node
-        dropbutton:
-          id: dropbutton
-          table: views
-          field: dropbutton
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
           label: Operations
-          fields:
-            edit_node: edit_node
-            delete_node: delete_node
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
           destination: true
-          plugin_id: dropbutton
+          plugin_id: entity_operations
       filters:
         status_extra:
           id: status_extra
diff --git a/core/modules/node/src/Tests/NodeAdminTest.php b/core/modules/node/src/Tests/NodeAdminTest.php
index 616538c774d0..44b77ff54754 100644
--- a/core/modules/node/src/Tests/NodeAdminTest.php
+++ b/core/modules/node/src/Tests/NodeAdminTest.php
@@ -171,4 +171,5 @@ function testContentAdminPages() {
       $this->assertLinkByHref('node/' . $node->id() . '/delete');
     }
   }
+
 }
diff --git a/core/modules/user/config/install/views.view.user_admin_people.yml b/core/modules/user/config/install/views.view.user_admin_people.yml
index ff62509461c6..a62860eea04f 100644
--- a/core/modules/user/config/install/views.view.user_admin_people.yml
+++ b/core/modules/user/config/install/views.view.user_admin_people.yml
@@ -458,61 +458,10 @@ display:
           plugin_id: date
           entity_type: user
           entity_field: access
-        edit_node:
-          id: edit_node
+        operations:
+          id: operations
           table: users
-          field: edit_node
-          relationship: none
-          group_type: group
-          admin_label: ''
-          label: 'Link to edit user'
-          exclude: true
-          alter:
-            alter_text: false
-            text: ''
-            make_link: false
-            path: ''
-            absolute: false
-            external: false
-            replace_spaces: false
-            path_case: none
-            trim_whitespace: false
-            alt: ''
-            rel: ''
-            link_class: ''
-            prefix: ''
-            suffix: ''
-            target: ''
-            nl2br: false
-            max_length: ''
-            word_boundary: true
-            ellipsis: true
-            more_link: false
-            more_link_text: ''
-            more_link_path: ''
-            strip_tags: false
-            trim: false
-            preserve_tags: ''
-            html: false
-          element_type: ''
-          element_class: ''
-          element_label_type: ''
-          element_label_class: ''
-          element_label_colon: true
-          element_wrapper_type: ''
-          element_wrapper_class: ''
-          element_default_classes: true
-          empty: ''
-          hide_empty: false
-          empty_zero: false
-          hide_alter_empty: true
-          text: Edit
-          plugin_id: user_link_edit
-          entity_type: user
-        dropbutton:
-          id: dropbutton
-          table: views
-          field: dropbutton
+          field: operations
           relationship: none
           group_type: group
           admin_label: ''
@@ -557,16 +506,9 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
-          fields:
-            edit_node: edit_node
-            user_bulk_form: '0'
-            name: '0'
-            status: '0'
-            roles_target_id: '0'
-            created: '0'
-            access: '0'
           destination: true
-          plugin_id: dropbutton
+          entity_type: user
+          plugin_id: entity_operations
         mail:
           id: mail
           table: users_field_data
@@ -875,6 +817,7 @@ display:
           1: AND
       field_langcode: '***LANGUAGE_language_content***'
       field_langcode_add_to_query: null
+      display_extenders: {  }
   page_1:
     display_plugin: page
     id: page_1
@@ -900,3 +843,4 @@ display:
         show_admin_links: false
       field_langcode: '***LANGUAGE_language_content***'
       field_langcode_add_to_query: null
+      display_extenders: {  }
diff --git a/core/modules/views/config/schema/views.data_types.schema.yml b/core/modules/views/config/schema/views.data_types.schema.yml
index 7cf0cad1a992..76ffb14ca8bd 100644
--- a/core/modules/views/config/schema/views.data_types.schema.yml
+++ b/core/modules/views/config/schema/views.data_types.schema.yml
@@ -581,6 +581,9 @@ views_field:
     hide_alter_empty:
       type: boolean
       label: 'Hide rewriting if empty'
+    destination:
+      type: boolean
+      label: 'Append a destination query string to operation links.'
     plugin_id:
       type: string
       label: 'Plugin ID'
diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php
index cb3042279719..0efd1640fcb5 100644
--- a/core/modules/views/src/EntityViewsData.php
+++ b/core/modules/views/src/EntityViewsData.php
@@ -148,6 +148,14 @@ public function getViewsData() {
       }
     }
 
+    $data[$base_table]['operations'] = array(
+      'field' => array(
+        'title' => $this->t('Operations links'),
+        'help' => $this->t('Provides links to perform entity operations.'),
+        'id' => 'entity_operations',
+      ),
+    );
+
     // Setup relations to the revisions/property data.
     if ($data_table) {
       $data[$data_table]['table']['join'][$base_table] = [
diff --git a/core/modules/views/src/Plugin/views/field/EntityOperations.php b/core/modules/views/src/Plugin/views/field/EntityOperations.php
new file mode 100644
index 000000000000..a3b10483da08
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Plugin\views\field\EntityOperations.
+ */
+
+namespace Drupal\views\Plugin\views\field;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\views\ResultRow;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Renders all operations links for an entity.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("entity_operations")
+ */
+class EntityOperations extends FieldPluginBase {
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * Constructor.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param array $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *    The entity manager.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $entity_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.manager')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function usesGroupBy() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defineOptions() {
+    $options = parent::defineOptions();
+
+    $options['destination'] = array(
+      'default' => TRUE,
+    );
+
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $form['destination'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Include destination'),
+      '#description' => $this->t('Include a <code>destination</code> parameter in the link to return the user to the original view upon completing the link action.'),
+      '#default_value' => $this->options['destination'],
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $values) {
+    $entity = $this->getEntity($values);
+    $operations = $this->entityManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
+    if ($this->options['destination']) {
+      foreach ($operations as &$operation) {
+        if (!isset($operation['options']['query'])) {
+          $operation['options']['query'] = array();
+        }
+        $operation['options']['query'] += drupal_get_destination();
+      }
+    }
+    $build = array(
+      '#type' => 'operations',
+      '#links' => $operations,
+    );
+
+    return $build;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    // There is nothing to ensure or add for this handler, so we purposefully do
+    //   nothing here and do not call parent::query() either.
+  }
+
+}
diff --git a/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php b/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
new file mode 100644
index 000000000000..38a54b54c894
--- /dev/null
+++ b/core/modules/views/src/Tests/Handler/FieldEntityOperationsTest.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Definition of \Drupal\views\Tests\Handler\FieldEntityOperationsTest.
+ */
+
+namespace Drupal\views\Tests\Handler;
+
+use Drupal\views\Tests\ViewUnitTestBase;
+use Drupal\views\Views;
+
+/**
+ * Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
+ *
+ * @group views
+ */
+class FieldEntityOperationsTest extends HandlerTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_entity_operations');
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node');
+
+  /**
+   * Tests entity operations field.
+   */
+  public function testEntityOperations() {
+    // Create some test nodes.
+    $nodes = array();
+    for ($i = 0; $i < 5; $i++) {
+      $nodes[] = $this->drupalCreateNode();
+    }
+
+    $admin_user = $this->drupalCreateUser(array('access administration pages', 'bypass node access'));
+    $this->drupalLogin($admin_user);
+    $this->drupalGet('test-entity-operations');
+
+    /* @var $node \Drupal\node\NodeInterface */
+    foreach ($nodes as $node) {
+      $operations = \Drupal::entityManager()->getListBuilder('node')->getOperations($node);
+      foreach ($operations as $operation) {
+        $result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', array(':path' => $operation['url']->getInternalPath(), ':title' => $operation['title']));
+        $this->assertEqual(count($result), 1, t('Found node @operation link.', array('@operation' => $operation['title'])));
+      }
+    }
+  }
+
+}
diff --git a/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
new file mode 100644
index 000000000000..751471040c04
--- /dev/null
+++ b/core/modules/views/src/Tests/Plugin/views/field/EntityOperationsUnitTest.php
@@ -0,0 +1,170 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\Plugin\views\field\EntityOperationsUnitTest.
+ */
+
+namespace Drupal\views\Tests\Plugin\views\field {
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\field\EntityOperations;
+use Drupal\views\ResultRow;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\EntityOperations
+ * @group Views
+ */
+class EntityOperationsUnitTest extends UnitTestCase {
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  /**
+   * The plugin under test.
+   *
+   * @var \Drupal\views\Plugin\views\field\EntityOperations
+   */
+  protected $plugin;
+
+  /**
+   * {@inheritdoc}
+   *
+   * @covers ::__construct
+   */
+  public function setUp() {
+    $this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
+
+    $configuration = array();
+    $plugin_id = $this->randomMachineName();
+    $plugin_definition = array(
+      'title' => $this->randomMachineName(),
+    );
+    $this->plugin = new EntityOperations($configuration, $plugin_id, $plugin_definition, $this->entityManager);
+    $view = $this->getMockBuilder('\Drupal\views\ViewExecutable')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $display = $this->getMockBuilder('\Drupal\views\Plugin\views\display\DisplayPluginBase')
+      ->disableOriginalConstructor()
+      ->getMockForAbstractClass();
+    $view->display_handler = $display;
+    $this->plugin->init($view, $display);
+  }
+
+  /**
+   * @covers ::usesGroupBy
+   */
+  public function testUsesGroupBy() {
+    $this->assertFalse($this->plugin->usesGroupBy());
+  }
+
+  /**
+   * @covers ::defineOptions
+   */
+  public function testDefineOptions() {
+    $options = $this->plugin->defineOptions();
+    $this->assertInternalType('array', $options);
+    $this->assertArrayHasKey('destination', $options);
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRenderWithDestination() {
+    $entity_type_id = $this->randomMachineName();
+    $entity = $this->getMockBuilder('\Drupal\user\Entity\Role')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->any())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue($entity_type_id));
+
+    $operations = array(
+      'foo' => array(
+        'title' => $this->randomMachineName(),
+      ),
+    );
+    $list_builder = $this->getMock('\Drupal\Core\Entity\EntityListBuilderInterface');
+    $list_builder->expects($this->once())
+      ->method('getOperations')
+      ->with($entity)
+      ->will($this->returnValue($operations));
+
+    $this->entityManager->expects($this->once())
+      ->method('getListBuilder')
+      ->with($entity_type_id)
+      ->will($this->returnValue($list_builder));
+
+    $this->plugin->options['destination'] = TRUE;
+
+    $result = new ResultRow();
+    $result->_entity = $entity;
+
+    $expected_build = array(
+      '#type' => 'operations',
+      '#links' => $operations
+    );
+    $expected_build['#links']['foo']['options']['query'] = drupal_get_destination();
+    $build = $this->plugin->render($result);
+    $this->assertSame($expected_build, $build);
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRenderWithoutDestination() {
+    $entity_type_id = $this->randomMachineName();
+    $entity = $this->getMockBuilder('\Drupal\user\Entity\Role')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity->expects($this->any())
+      ->method('getEntityTypeId')
+      ->will($this->returnValue($entity_type_id));
+
+    $operations = array(
+      'foo' => array(
+        'title' => $this->randomMachineName(),
+      ),
+    );
+    $list_builder = $this->getMock('\Drupal\Core\Entity\EntityListBuilderInterface');
+    $list_builder->expects($this->once())
+      ->method('getOperations')
+      ->with($entity)
+      ->will($this->returnValue($operations));
+
+    $this->entityManager->expects($this->once())
+      ->method('getListBuilder')
+      ->with($entity_type_id)
+      ->will($this->returnValue($list_builder));
+
+    $this->plugin->options['destination'] = FALSE;
+
+    $result = new ResultRow();
+    $result->_entity = $entity;
+
+    $expected_build = array(
+      '#type' => 'operations',
+      '#links' => $operations
+    );
+    $build = $this->plugin->render($result);
+    $this->assertSame($expected_build, $build);
+  }
+}
+
+}
+
+namespace {
+
+if (!function_exists('drupal_get_destination')) {
+  function drupal_get_destination() {
+    return array(
+      'destination' => 'foobar',
+    );
+  }
+}
+
+}
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_operations.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_operations.yml
new file mode 100644
index 000000000000..205e8ce64fbb
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_entity_operations.yml
@@ -0,0 +1,193 @@
+langcode: und
+status: true
+dependencies:
+  module:
+    - node
+    - user
+id: test_entity_operations
+label: test_entity_operations
+module: views
+description: ''
+tag: ''
+base_table: node
+base_field: nid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: null
+    display_options:
+      access:
+        type: perm
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+        options:
+          items_per_page: 10
+      style:
+        type: default
+      row:
+        type: fields
+      fields:
+        nid:
+          id: nid
+          table: node
+          field: nid
+          plugin_id: node
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Nid
+          exclude: true
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          link_to_node: false
+          entity_type: node
+          entity_field: nid
+        title:
+          id: title
+          table: node_field_data
+          field: title
+          plugin_id: node
+          label: ''
+          alter:
+            alter_text: false
+            make_link: false
+            absolute: false
+            trim: false
+            word_boundary: false
+            ellipsis: false
+            strip_tags: false
+            html: false
+          hide_empty: false
+          empty_zero: false
+          link_to_node: true
+          entity_type: node
+          entity_field: title
+        operations:
+          id: operations
+          table: node
+          field: operations
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Operations
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: ''
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          destination: true
+          plugin_id: entity_operations
+      filters:
+        status:
+          value: true
+          table: node_field_data
+          field: status
+          id: status
+          plugin_id: boolean
+          expose:
+            operator: '0'
+          group: 1
+          entity_type: node
+          entity_field: status
+      sorts:
+        created:
+          id: created
+          table: node_field_data
+          field: created
+          order: DESC
+          plugin_id: date
+          entity_type: node
+          entity_field: created
+      title: test_entity_operations
+      field_langcode: '***LANGUAGE_language_content***'
+      field_langcode_add_to_query: null
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: null
+    display_options:
+      path: test-entity-operations
+      field_langcode: '***LANGUAGE_language_content***'
+      field_langcode_add_to_query: null
-- 
GitLab