From 020702d358bb87e95599e8c3d4f8ebfbcaee158c Mon Sep 17 00:00:00 2001
From: Michael Lee <lee.5151@osu.edu>
Date: Wed, 25 May 2022 12:42:31 -0400
Subject: [PATCH]  Upgrading drupal/field_group (3.1.0 => 3.2.0)

---
 composer.json                                 |   2 +-
 composer.lock                                 |  16 +--
 vendor/composer/installed.json                |  16 +--
 vendor/composer/installed.php                 |  10 +-
 ...up.field_group_formatter_plugin.schema.yml |  14 +-
 .../field_group_migrate.info.yml              |   6 +-
 .../d6_field_group_entity_form_display.yml    |   4 +-
 .../d6_field_group_entity_view_display.yml    |   3 +-
 .../migrations/d7_field_group.yml             |   4 +-
 .../Plugin/migrate/D7FieldGroupDeriver.php    |  77 +++++++++++
 .../FieldGroupEntityFormDisplay.php           |  20 ++-
 .../FieldGroupEntityViewDisplay.php           |  20 ++-
 .../migrate/destination/d7/FieldGroup.php     |  18 ++-
 .../Plugin/migrate/source/d7/FieldGroup.php   |  18 ++-
 .../Migrate/d7/MigrateFieldGroupTest.php      |   2 -
 web/modules/field_group/field_group.info.yml  |   6 +-
 web/modules/field_group/field_group.install   |   2 +-
 .../field_group/field_group.libraries.yml     |   8 --
 web/modules/field_group/field_group.module    |  85 ++++++++++--
 .../formatters/tabs/horizontal-tabs.js        | 124 +++++++++---------
 web/modules/field_group/includes/field_ui.inc |  12 +-
 .../src/FieldGroupFormatterBase.php           |  12 ++
 .../src/Form/FieldGroupDeleteForm.php         |  19 ++-
 .../FieldGroupFormatter/AccordionItem.php     |   3 +
 .../FieldGroupFormatter/Details.php           |   1 +
 .../FieldGroupFormatter/Fieldset.php          |   3 +
 .../FieldGroupFormatter/HtmlElement.php       |   3 +
 .../field_group/FieldGroupFormatter/Tabs.php  |  15 ++-
 .../templates/horizontal-tabs.html.twig       |   5 +-
 .../field_group_test.info.yml                 |   6 +-
 .../src/Functional/ManageDisplayTest.php      |  22 ++--
 31 files changed, 384 insertions(+), 172 deletions(-)
 create mode 100644 web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/D7FieldGroupDeriver.php

diff --git a/composer.json b/composer.json
index e23a58291f..9dc9ccd5fb 100644
--- a/composer.json
+++ b/composer.json
@@ -119,7 +119,7 @@
         "drupal/entity_reference_revisions": "1.9",
         "drupal/exif_orientation": "^1.1",
         "drupal/externalauth": "1.3",
-        "drupal/field_group": "3.1",
+        "drupal/field_group": "3.2",
         "drupal/field_permissions": "1.1",
         "drupal/file_browser": "1.3",
         "drupal/focal_point": "1.5",
diff --git a/composer.lock b/composer.lock
index e7dc111015..c52882fc4c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "0db64872456ea6dcec72cfaea15b3fdf",
+    "content-hash": "a7fe7d7e2f7971440c4615126cd51e4f",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -4284,17 +4284,17 @@
         },
         {
             "name": "drupal/field_group",
-            "version": "3.1.0",
+            "version": "3.2.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_group.git",
-                "reference": "8.x-3.1"
+                "reference": "8.x-3.2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.1.zip",
-                "reference": "8.x-3.1",
-                "shasum": "8a719eaea594f0ba874172831cb28da93c66b77a"
+                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.2.zip",
+                "reference": "8.x-3.2",
+                "shasum": "2020bbfe40f6ba43bc733ae7c8761632572433a0"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9"
@@ -4305,8 +4305,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.1",
-                    "datestamp": "1591772567",
+                    "version": "8.x-3.2",
+                    "datestamp": "1628513585",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 83a97a7e71..0aac769e0e 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -4421,18 +4421,18 @@
         },
         {
             "name": "drupal/field_group",
-            "version": "3.1.0",
-            "version_normalized": "3.1.0.0",
+            "version": "3.2.0",
+            "version_normalized": "3.2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_group.git",
-                "reference": "8.x-3.1"
+                "reference": "8.x-3.2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.1.zip",
-                "reference": "8.x-3.1",
-                "shasum": "8a719eaea594f0ba874172831cb28da93c66b77a"
+                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.2.zip",
+                "reference": "8.x-3.2",
+                "shasum": "2020bbfe40f6ba43bc733ae7c8761632572433a0"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9"
@@ -4443,8 +4443,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.1",
-                    "datestamp": "1591772567",
+                    "version": "8.x-3.2",
+                    "datestamp": "1628513585",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index afded3349f..d538b32ad0 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -5,7 +5,7 @@
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
-        'reference' => 'ac0e30f29859b960ce5fce6752376c2d329ff838',
+        'reference' => '8efca4e84f761c4555f30d66931381a148db7860',
         'name' => 'osu-asc-webservices/d8-upstream',
         'dev' => true,
     ),
@@ -950,12 +950,12 @@
             ),
         ),
         'drupal/field_group' => array(
-            'pretty_version' => '3.1.0',
-            'version' => '3.1.0.0',
+            'pretty_version' => '3.2.0',
+            'version' => '3.2.0.0',
             'type' => 'drupal-module',
             'install_path' => __DIR__ . '/../../web/modules/field_group',
             'aliases' => array(),
-            'reference' => '8.x-3.1',
+            'reference' => '8.x-3.2',
             'dev_requirement' => false,
         ),
         'drupal/field_layout' => array(
@@ -2101,7 +2101,7 @@
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
-            'reference' => 'ac0e30f29859b960ce5fce6752376c2d329ff838',
+            'reference' => '8efca4e84f761c4555f30d66931381a148db7860',
             'dev_requirement' => false,
         ),
         'pantheon-systems/quicksilver-pushback' => array(
diff --git a/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml b/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml
index 01154220db..b24ecddb43 100644
--- a/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml
+++ b/web/modules/field_group/config/schema/field_group.field_group_formatter_plugin.schema.yml
@@ -14,7 +14,7 @@ field_group.field_group_formatter_plugin.accordion_item:
       type: string
       label: 'Formatting of the item'
     description:
-      type: label
+      type: text
       label: 'Description of the item'
     required_fields:
       type: boolean
@@ -47,7 +47,7 @@ field_group.field_group_formatter_plugin.fieldset:
   label: 'Mapping for the fieldset formatter settings'
   mapping:
     description:
-      type: label
+      type: text
       label: 'Description of the item'
     required_fields:
       type: boolean
@@ -90,7 +90,7 @@ field_group.field_group_formatter_plugin.tab:
       type: string
       label: 'default state for the tab'
     description:
-      type: label
+      type: text
       label: 'Description of the tab'
     required_fields:
       type: boolean
@@ -104,7 +104,7 @@ field_group.field_group_formatter_plugin.tabs:
       type: string
       label: 'default state for the tabs'
     description:
-      type: label
+      type: text
       label: 'description of the tabs'
     required_fields:
       type: boolean
@@ -112,6 +112,9 @@ field_group.field_group_formatter_plugin.tabs:
     direction:
       type: string
       label: 'Direction of the tabs'
+    width_breakpoint:
+      type: integer
+      label: 'Disable Tabs widget if the window width is equal or smaller'
 
 field_group.field_group_formatter_plugin.base:
   type: mapping
@@ -123,6 +126,9 @@ field_group.field_group_formatter_plugin.base:
     classes:
       type: string
       label:  'Classes of the fieldgroup'
+    show_empty_fields:
+      type: boolean
+      label: 'Show Empty Fields'
     id:
       type: string
       label: 'Html id of the fieldgroup'
diff --git a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
index de95c532dd..b0a31916f3 100644
--- a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
+++ b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
@@ -6,7 +6,7 @@ core_version_requirement: ^8.8 || ^9
 dependencies:
   - field_group:field_group
 
-# Information added by Drupal.org packaging script on 2020-06-10
-version: '8.x-3.1'
+# Information added by Drupal.org packaging script on 2021-08-09
+version: '8.x-3.2'
 project: 'field_group'
-datestamp: 1591772570
+datestamp: 1628513588
diff --git a/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml
index 01edd68bfa..d62c27bda2 100644
--- a/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml
+++ b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_form_display.yml
@@ -9,6 +9,7 @@ dependencies:
 id: d6_field_group_entity_form_display
 migration_tags:
   - 'Drupal 6'
+  - Configuration
 label: 'Field groups'
 source:
   plugin: d6_field_group
@@ -35,7 +36,4 @@ process:
 destination:
   plugin: field_group_entity_form_display
 template: d6_field_instance_widget_settings
-migration_dependencies:
-  required:
-    - d6_field_instance
 migration_group: null
diff --git a/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml
index 92adcc169a..1d6f5eb3a4 100644
--- a/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml
+++ b/web/modules/field_group/contrib/field_group_migrate/migrations/d6_field_group_entity_view_display.yml
@@ -9,6 +9,7 @@ dependencies:
 id: d6_field_group_entity_view_display
 migration_tags:
   - 'Drupal 6'
+  - Configuration
 label: 'Field groups'
 source:
   plugin: d6_field_group
@@ -35,5 +36,5 @@ destination:
 template: d6_field_instance_widget_settings
 migration_dependencies:
   required:
-    - d6_field_instance
+    - d6_view_modes
 migration_group: null
diff --git a/web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml b/web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml
index bf80db7068..f558ffa3ac 100644
--- a/web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml
+++ b/web/modules/field_group/contrib/field_group_migrate/migrations/d7_field_group.yml
@@ -2,8 +2,10 @@ id: d7_field_group
 label: Field groups
 migration_tags:
   - Drupal 7
+  - Configuration
 source:
   plugin: d7_field_group
+deriver: Drupal\field_group_migrate\Plugin\migrate\D7FieldGroupDeriver
 process:
   entity_type: entity_type
   bundle: bundle
@@ -25,4 +27,4 @@ destination:
   plugin: d7_field_group
 migration_dependencies:
   required:
-    - d7_field_formatter_settings
+    - d7_view_modes
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/D7FieldGroupDeriver.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/D7FieldGroupDeriver.php
new file mode 100644
index 0000000000..07951c5e41
--- /dev/null
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/D7FieldGroupDeriver.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\field_group_migrate\Plugin\migrate;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Database\DatabaseExceptionWrapper;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\migrate\Exception\RequirementsException;
+use Drupal\migrate\Plugin\MigrationDeriverTrait;
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Derives Drupal 7 field group migrations per entity type and bundle.
+ */
+class D7FieldGroupDeriver extends DeriverBase {
+
+  use MigrationDeriverTrait;
+  use StringTranslationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $field_group_source = static::getSourcePlugin('d7_field_group');
+
+    try {
+      $field_group_source->checkRequirements();
+    }
+    catch (RequirementsException $e) {
+      // The requirements of the "d7_field_group" source plugin can fail if:
+      // - The source database is not configured or it isn't a Drupal 7 DB.
+      // - The Field Group module is not enabled on the source Drupal instance.
+      return $this->derivatives;
+    }
+
+    assert($field_group_source instanceof DrupalSqlBase);
+
+    try {
+      foreach ($field_group_source as $field_group_row) {
+        assert($field_group_row instanceof Row);
+        [
+          'entity_type' => $entity_type,
+          'bundle' => $bundle,
+        ] = $field_group_row->getSource();
+
+        $derivative_id = implode(PluginBase::DERIVATIVE_SEPARATOR, [
+          $entity_type,
+          $bundle,
+        ]);
+
+        if (!empty($this->derivatives[$derivative_id])) {
+          continue;
+        }
+        $derivative_definition = $base_plugin_definition;
+        $derivative_definition['source']['entity_type'] = $entity_type;
+        $derivative_definition['source']['bundle'] = $bundle;
+        $derivative_definition['label'] = $this->t('@label of @entity_type (bundle: @bundle)', [
+          '@label' => $derivative_definition['label'],
+          '@entity_type' => $entity_type,
+          '@bundle' => $bundle,
+        ]);
+        $this->derivatives[$derivative_id] = $derivative_definition;
+      }
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      // Once we begin iterating the source plugin it is possible that the
+      // source tables will not exist. This can happen when the
+      // MigrationPluginManager gathers up the migration definitions but we do
+      // not actually have a Drupal 7 source database.
+    }
+
+    return $this->derivatives;
+  }
+
+}
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php
index 860f91ad36..e0ca4b53b2 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityFormDisplay.php
@@ -25,18 +25,16 @@ public function import(Row $row, array $old_destination_id_values = []) {
       $values[$id] = $row->getDestinationProperty($id);
     }
     $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values[static::MODE_NAME]);
-    if (!$entity->isNew()) {
-      $settings = $row->getDestinationProperty('field_group');
-      $settings += [
-        'region' => 'content',
-        'parent_name' => '',
-      ];
-      $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings);
-      if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) {
-        $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('id'));
-      }
-      $entity->save();
+    $settings = $row->getDestinationProperty('field_group');
+    $settings += [
+      'region' => 'content',
+      'parent_name' => '',
+    ];
+    $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings);
+    if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) {
+      $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('id'));
     }
+    $entity->save();
     return array_values($values);
   }
 
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php
index 3277e934c3..4853d7f435 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/FieldGroupEntityViewDisplay.php
@@ -27,18 +27,16 @@ public function import(Row $row, array $old_destination_id_values = []) {
 
     foreach ($row->getSourceProperty('view_modes') as $view_mode => $settings) {
       $entity = $this->getEntity($values['entity_type'], $values['bundle'], $view_mode);
-      if (!$entity->isNew()) {
-        $settings += [
-          'region' => 'content',
-          'parent_name' => '',
-        ];
-        $settings = array_merge($row->getDestinationProperty('field_group'), $settings);
-        $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings);
-        if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) {
-          $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('id'));
-        }
-        $entity->save();
+      $settings += [
+        'region' => 'content',
+        'parent_name' => '',
+      ];
+      $settings = array_merge($row->getDestinationProperty('field_group'), $settings);
+      $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('id'), $settings);
+      if (isset($settings['format_type']) && ($settings['format_type'] == 'no_style' || $settings['format_type'] == 'hidden')) {
+        $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('id'));
       }
+      $entity->save();
     }
 
     return array_values($values);
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php
index 64b6c4cd17..35266ae223 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/destination/d7/FieldGroup.php
@@ -27,17 +27,15 @@ public function import(Row $row, array $old_destination_id_values = []) {
     }
 
     $entity = $this->getEntity($values['entity_type'], $values['bundle'], $values['mode'], $values['type']);
-    if (!$entity->isNew()) {
-      $settings = $row->getDestinationProperty('settings');
-      $settings += [
-        'region' => 'content',
-      ];
-      $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('group_name'), $settings);
-      if (isset($settings['format_type']) && ($settings['format_type'] == 'hidden')) {
-        $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('group_name'));
-      }
-      $entity->save();
+    $settings = $row->getDestinationProperty('settings');
+    $settings += [
+      'region' => 'content',
+    ];
+    $entity->setThirdPartySetting('field_group', $row->getDestinationProperty('group_name'), $settings);
+    if (isset($settings['format_type']) && ($settings['format_type'] == 'hidden')) {
+      $entity->unsetThirdPartySetting('field_group', $row->getDestinationProperty('group_name'));
     }
+    $entity->save();
 
     return array_values($values);
   }
diff --git a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php
index 4825c84594..ac9a3a2689 100644
--- a/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php
+++ b/web/modules/field_group/contrib/field_group_migrate/src/Plugin/migrate/source/d7/FieldGroup.php
@@ -20,7 +20,19 @@ class FieldGroup extends DrupalSqlBase {
    * {@inheritdoc}
    */
   public function query() {
-    return $this->select('field_group', 'f')->fields('f');
+    $query = $this->select('field_group', 'f')->fields('f');
+    $entity_type = $this->configuration['entity_type'] ?? NULL;
+    $bundle = $this->configuration['bundle'] ?? NULL;
+
+    if ($entity_type) {
+      $query->condition('f.entity_type', $entity_type);
+
+      if ($bundle) {
+        $query->condition('f.bundle', $bundle);
+      }
+    }
+
+    return $query;
   }
 
   /**
@@ -69,6 +81,10 @@ public function prepareRow(Row $row) {
         $settings['format_type'] = 'tab';
         break;
 
+      case 'html-element':
+        $settings['format_type'] = 'html_element';
+        break;
+
     }
     $row->setSourceProperty('settings', $settings);
     return parent::prepareRow($row);
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
index e83c38d647..71c20bd0ef 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
@@ -44,8 +44,6 @@ protected function setUp() {
       'd7_taxonomy_vocabulary',
       'd7_view_modes',
       'd7_field',
-      'd7_field_instance',
-      'd7_field_formatter_settings',
       'd7_field_group',
     ]);
   }
diff --git a/web/modules/field_group/field_group.info.yml b/web/modules/field_group/field_group.info.yml
index 0e4b01a222..1b207b580c 100644
--- a/web/modules/field_group/field_group.info.yml
+++ b/web/modules/field_group/field_group.info.yml
@@ -6,7 +6,7 @@ core_version_requirement: ^8.8 || ^9
 dependencies:
   - drupal:field
 
-# Information added by Drupal.org packaging script on 2020-06-10
-version: '8.x-3.1'
+# Information added by Drupal.org packaging script on 2021-08-09
+version: '8.x-3.2'
 project: 'field_group'
-datestamp: 1591772570
+datestamp: 1628513588
diff --git a/web/modules/field_group/field_group.install b/web/modules/field_group/field_group.install
index b247a47a05..2e2dbe1764 100644
--- a/web/modules/field_group/field_group.install
+++ b/web/modules/field_group/field_group.install
@@ -51,7 +51,7 @@ function field_group_update_8302() {
     if (\Drupal::service('extension.list.module')
       ->getName('jquery_ui_accordion')) {
       \Drupal::service('module_installer')
-        ->install(['jquery_ui_accordion'], FALSE);
+        ->install(['jquery_ui_accordion'], TRUE);
       return t('The "jquery_ui_accordion" module has been installed.');
     }
   }
diff --git a/web/modules/field_group/field_group.libraries.yml b/web/modules/field_group/field_group.libraries.yml
index e09631b7ce..f5aed67001 100644
--- a/web/modules/field_group/field_group.libraries.yml
+++ b/web/modules/field_group/field_group.libraries.yml
@@ -1,5 +1,4 @@
 field_ui:
-  version: VERSION
   js:
     js/field_group.field_ui.js: {}
   css:
@@ -12,7 +11,6 @@ field_ui:
     - core/drupalSettings
 
 core:
-  version: VERSION
   js:
     js/field_group.js: {}
   dependencies:
@@ -22,36 +20,30 @@ core:
     - core/drupalSettings
 
 formatter.accordion:
-  version: VERSION
   js:
     formatters/accordion/accordion.js: {}
   dependencies:
     - core/jquery.ui.accordion
 
 formatter.html_element:
-  version: VERSION
   js:
     formatters/html_element/html-element.js: {}
 
 formatter.fieldset:
-  version: VERSION
   js:
     formatters/fieldset/fieldset.js: {}
 
 formatter.details:
-  version: VERSION
   js:
     formatters/details/details.js: {}
 
 formatter.tabs:
-  version: VERSION
   js:
     formatters/tabs/tabs.js: {}
   dependencies:
     - core/modernizr
 
 element.horizontal_tabs:
-  version: VERSION
   js:
     # Load before field_group/core.
     formatters/tabs/horizontal-tabs.js: {weight: -1}
diff --git a/web/modules/field_group/field_group.module b/web/modules/field_group/field_group.module
index 006ae6f6e3..52b0cbd37c 100644
--- a/web/modules/field_group/field_group.module
+++ b/web/modules/field_group/field_group.module
@@ -40,11 +40,11 @@ function field_group_library_info_alter(&$libraries, $extension) {
   // Swap jQuery.ui library if available.
   // See https://www.drupal.org/project/field_group/issues/3109552 for more
   // background on the logic.
-  if (version_compare(\Drupal::VERSION, 9) > 0 && $extension == 'field_group') {
+  if ($extension == 'field_group') {
     if (\Drupal::moduleHandler()->moduleExists('jquery_ui_accordion')) {
       $libraries['formatter.accordion']['dependencies'] = ['jquery_ui_accordion/accordion'];
     }
-    else {
+    elseif (version_compare(\Drupal::VERSION, 9) > 0 ) {
       $libraries['formatter.accordion']['js'] = [];
       $libraries['formatter.accordion']['dependencies'] = [];
     }
@@ -76,6 +76,10 @@ function field_group_theme_registry_alter(&$theme_registry) {
     $theme_registry['eck_entity']['preprocess functions'][] = 'field_group_build_entity_groups';
   }
 
+  // External entities use the external_entity as theme function.
+  if (isset($theme_registry['external_entity'])) {
+    $theme_registry['external_entity']['preprocess functions'][] = 'field_group_build_entity_groups';
+  }
 }
 
 /**
@@ -278,6 +282,31 @@ function field_group_inline_entity_form_entity_form_alter(&$entity_form, FormSta
   FormatterHelper::formProcess($entity_form, $form_state);
 }
 
+/**
+ * Implements hook_form_media_library_add_form_upload_alter().
+ */
+function field_group_form_media_library_add_form_upload_alter(&$form, FormStateInterface $form_state) {
+
+  // Attach the fieldgroups to the media entity form in Media Library widget.
+  $storage = $form_state->getStorage();
+  if (!empty($storage['media'])) {
+    foreach ($storage['media'] as $delta => $media) {
+      $context = [
+        'entity_type' => $storage['media'][$delta]->getEntityTypeId(),
+        'bundle' => $storage['media'][$delta]->bundle(),
+        'entity' => $storage['media'][$delta],
+        'context' => 'form',
+        'display_context' => 'form',
+        'mode' => 'media_library',
+      ];
+
+      field_group_attach_groups($form['media'][$delta]['fields'], $context);
+      $form['media'][$delta]['fields']['#process'][] = [FormatterHelper::class, 'formProcess'];
+    }
+  }
+
+}
+
 /**
  * Implements hook_form_layout_builder_update_block_alter().
  */
@@ -341,6 +370,30 @@ function field_group_entity_view_alter(&$build, EntityInterface $entity, EntityD
   }
 }
 
+/**
+ * Implements hook_conditional_fields().
+ */
+function field_group_conditional_fields($entity_type, $bundle_name) {
+  $fields = [];
+  $groups = field_group_info_groups($entity_type, $bundle_name, 'form', 'default');
+  foreach ($groups as $name => $group) {
+    $fields[$name] = $group->label;
+  }
+  return $fields;
+}
+
+/**
+ * Implements hook_conditional_fields_children().
+ */
+function field_group_conditional_fields_children($entity_type, $bundle_name) {
+  $groups = [];
+  $group_info = field_group_info_groups($entity_type, $bundle_name, 'form', 'default');
+  foreach ($group_info as $name => $info) {
+    $groups[$name] = $info->children;
+  }
+  return $groups;
+}
+
 /**
  * Pre render callback for rendering groups.
  *
@@ -498,8 +551,10 @@ function field_group_attach_groups(&$element, $context) {
   // Create a lookup array.
   $group_children = [];
   foreach ($element['#fieldgroups'] as $group_name => $group) {
-    foreach ($group->children as $child) {
-      $group_children[$child] = $group_name;
+    if (!empty($group->children)) {
+      foreach ($group->children as $child) {
+        $group_children[$child] = $group_name;
+      }
     }
   }
   $element['#group_children'] = $group_children;
@@ -528,7 +583,7 @@ function field_group_build_entity_groups(array &$vars, $context = 'view') {
     $element = &$vars['content'];
   }
   else {
-    if ($context === 'eck_entity') {
+    if ($context === 'eck_entity' || $context === 'external_entity') {
       $element = &$vars['entity'];
     }
     else {
@@ -628,7 +683,7 @@ function field_group_fields_nest(&$element, &$vars = NULL, $context = NULL) {
       $key = field_group_get_content_element_key($context);
       if (!isset($element['#fieldgroups'][$child_name]) && isset($vars[$key][$child_name])) {
 
-        // ECK marks his defaut properties as printed, while it is not printed yet.
+        // ECK marks his default properties as printed, while it is not printed yet.
         if ($context === 'eck_entity' && !empty($vars[$key][$child_name]['#printed'])) {
           $vars[$key][$child_name]['#printed'] = FALSE;
         }
@@ -720,7 +775,7 @@ function field_group_field_layout_fields_nest(array &$element, &$vars = NULL, $c
     $key = field_group_get_content_element_key($context);
     if (!isset($element['#fieldgroups'][$child_name]) && isset($vars[$key]['_field_layout'][$region][$child_name])) {
 
-      // ECK marks his defaut properties as printed, while it is not printed yet.
+      // ECK marks his default properties as printed, while it is not printed yet.
       if ($context === 'eck_entity' && !empty($vars[$key]['_field_layout'][$region][$child_name]['#printed'])) {
         $vars[$key]['_field_layout'][$region][$child_name]['#printed'] = FALSE;
       }
@@ -759,7 +814,7 @@ function field_group_pre_render(& $element, $group, & $rendering_object) {
 
   // Only run the pre_render function if the group has elements.
   // $group->group_name.
-  if ($element == []) {
+  if ($element == [] && empty($group->format_settings['show_empty_fields'])) {
     return;
   }
 
@@ -1003,6 +1058,11 @@ function field_group_remove_empty_form_groups(&$element, $groups, $entity_type)
         $group_name = str_replace($name_prefix, '', $element[$childname]['#group']);
         $empty_groups_indication[$group_name] = FALSE;
       }
+
+      $show_empty_fields = isset($element[$childname]['#show_empty_fields']) && $element[$childname]['#show_empty_fields'];
+      if ($show_empty_fields) {
+        $empty_groups_indication[$childname] = FALSE;
+      }
     }
   }
 
@@ -1033,10 +1093,15 @@ function field_group_remove_empty_display_groups(& $element, $groups) {
 
     // Descend if the child is a group.
     if (in_array($name, $groups)) {
-      $empty_child = field_group_remove_empty_display_groups($element[$name], $groups);
-      if (!$empty_child) {
+      if (isset($element[$name]['#show_empty_fields']) && $element[$name]['#show_empty_fields']) {
         $empty_group = FALSE;
       }
+      else {
+        $empty_child = field_group_remove_empty_display_groups($element[$name], $groups);
+        if (!$empty_child) {
+          $empty_group = FALSE;
+        }
+      }
     }
     // Child is a field or a renderable array and the element is not empty.
     elseif (!empty($element[$name])) {
diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.js b/web/modules/field_group/formatters/tabs/horizontal-tabs.js
index 865da55329..4ed238d795 100644
--- a/web/modules/field_group/formatters/tabs/horizontal-tabs.js
+++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.js
@@ -26,72 +26,76 @@
         return;
       }
 
-      $(context).find('[data-horizontal-tabs-panes]').once('horizontal-tabs').each(function () {
-
-        var $this = $(this).addClass('horizontal-tabs-panes');
-        var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
-        var tab_focus;
-
-        // Check if there are some details that can be converted to horizontal-tabs
-        var $details = $this.find('> details');
-        if ($details.length === 0) {
-          return;
-        }
-
-        // If collapse.js did not do his work yet, call it directly.
-        if (!$($details[0]).hasClass('.collapse-processed')) {
-          Drupal.behaviors.collapse.attach(context);
-        }
-
-        // Create the tab column.
-        var tab_list = $('<ul class="horizontal-tabs-list"></ul>');
-        $(this).wrap('<div class="horizontal-tabs clearfix"></div>').before(tab_list);
-
-        // Transform each details into a tab.
-        $details.each(function (i) {
-          var $this = $(this);
-          var summaryElement = $this.find('> summary .details-title');
-
-          if (!summaryElement.length) {
-            summaryElement = $this.find('> summary');
+      $(context).find('[data-horizontal-tabs]').once('horizontal-tabs').each(function() {
+        var horizontal_tabs_clearfix = this;
+        $(this).find('> [data-horizontal-tabs-panes]').each(function () {
+          var $this = $(this).addClass('horizontal-tabs-panes');
+          var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
+          var tab_focus;
+
+          // Check if there are some details that can be converted to horizontal-tabs
+          var $details = $this.find('> details');
+          if ($details.length === 0) {
+            return;
           }
 
-          var summaryText = summaryElement.clone().children().remove().end().text().trim() || summaryElement.find('> span:first-child').text().trim();
-          var horizontal_tab = new Drupal.horizontalTab({
-            title: summaryText,
-            details: $this
-          });
-          horizontal_tab.item.addClass('horizontal-tab-button-' + i);
-          tab_list.append(horizontal_tab.item);
-          $this
-            .removeClass('collapsed')
-            // prop() can't be used on browsers not supporting details element,
-            // the style won't apply to them if prop() is used.
-            .attr('open', true)
-            .addClass('horizontal-tabs-pane')
-            .data('horizontalTab', horizontal_tab);
-          if (this.id === focusID) {
-            tab_focus = $this;
+          // If collapse.js did not do his work yet, call it directly.
+          if (!$($details[0]).hasClass('.collapse-processed')) {
+            Drupal.behaviors.collapse.attach(context);
           }
-        });
-
-        $(tab_list).find('> li:first').addClass('first');
-        $(tab_list).find('> li:last').addClass('last');
+          // Find the tab column.
+          var tab_list = $(horizontal_tabs_clearfix).find('> [data-horizontal-tabs-list]');
+          tab_list.removeClass('visually-hidden')
+
+          // Transform each details into a tab.
+          $details.each(function (i) {
+            var $this = $(this);
+            var summaryElement = $this.find('> summary');
+            var detailsTitle = summaryElement.first().find('.details-title')
+            if (detailsTitle.length) {
+              var summaryText = detailsTitle.find('> span:last-child').text().trim();
+            }
+            else {
+              var summaryText = summaryElement.clone().children().remove().end().text().trim() || summaryElement.find('> span:first-child').text().trim();
+            }
+
+            var horizontal_tab = new Drupal.horizontalTab({
+              title: summaryText,
+              details: $this
+            });
+            horizontal_tab.item.addClass('horizontal-tab-button-' + i);
+            horizontal_tab.item.attr('data-horizontalTabButton', i);
+            tab_list.append(horizontal_tab.item);
+            $this
+              .removeClass('collapsed')
+              // prop() can't be used on browsers not supporting details element,
+              // the style won't apply to them if prop() is used.
+              .attr('open', true)
+              .addClass('horizontal-tabs-pane')
+              .data('horizontalTab', horizontal_tab);
+            if (this.id === focusID) {
+              tab_focus = $this;
+            }
+          });
 
-        if (!tab_focus) {
-          // If the current URL has a fragment and one of the tabs contains an
-          // element that matches the URL fragment, activate that tab.
-          var hash = window.location.hash.replace(/[=%;,\/]/g, '');
-          if (hash !== '#' && $(this).find(hash).length) {
-            tab_focus = $(this).find(hash).closest('.horizontal-tabs-pane');
+          $(tab_list).find('> li:first').addClass('first');
+          $(tab_list).find('> li:last').addClass('last');
+
+          if (!tab_focus) {
+            // If the current URL has a fragment and one of the tabs contains an
+            // element that matches the URL fragment, activate that tab.
+            var hash = window.location.hash.replace(/[=%;,\/]/g, '');
+            if (hash !== '#' && $(hash, this).length) {
+              tab_focus = $(hash, this).closest('.horizontal-tabs-pane');
+            }
+            else {
+              tab_focus = $this.find('> .horizontal-tabs-pane:first');
+            }
           }
-          else {
-            tab_focus = $this.find('> .horizontal-tabs-pane:first');
+          if (tab_focus.length) {
+            tab_focus.data('horizontalTab').focus();
           }
-        }
-        if (tab_focus.length) {
-          tab_focus.data('horizontalTab').focus();
-        }
+        });
       });
     }
   };
diff --git a/web/modules/field_group/includes/field_ui.inc b/web/modules/field_group/includes/field_ui.inc
index 5c53ff1a74..8aefeb677e 100644
--- a/web/modules/field_group/includes/field_ui.inc
+++ b/web/modules/field_group/includes/field_ui.inc
@@ -41,11 +41,13 @@ function field_group_field_ui_form_params($form, EntityDisplayBase $display) {
   // Gather parenting data.
   $params->parents = [];
   foreach ($params->groups as $name => $group) {
-    foreach ($group->children as $child) {
-      // Field UI js sometimes can trigger an endless loop. Check if the parent
-      // of this field is not a child.
-      if ($child !== $group->parent_name) {
-        $params->parents[$child] = $name;
+    if (!empty($group->children)) {
+      foreach ($group->children as $child) {
+        // Field UI js sometimes can trigger an endless loop. Check if the parent
+        // of this field is not a child.
+        if ($child !== $group->parent_name) {
+          $params->parents[$child] = $name;
+        }
       }
     }
   }
diff --git a/web/modules/field_group/src/FieldGroupFormatterBase.php b/web/modules/field_group/src/FieldGroupFormatterBase.php
index b3297a637a..0c56d8e395 100644
--- a/web/modules/field_group/src/FieldGroupFormatterBase.php
+++ b/web/modules/field_group/src/FieldGroupFormatterBase.php
@@ -95,6 +95,13 @@ public function settingsForm() {
       '#weight' => -5,
     ];
 
+    $form['show_empty_fields'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Display element also when empty'),
+      '#description' => $this->t('Display this field group even if the contained fields are currently empty.'),
+      '#default_value' => $this->getSetting('show_empty_fields'),
+    ];
+
     $form['id'] = [
       '#title' => $this->t('ID'),
       '#type' => 'textfield',
@@ -126,6 +133,10 @@ public function settingsSummary() {
       $summary[] = $this->pluginDefinition['label'] . ': ' . $this->getSetting('formatter');
     }
 
+    if ($this->getSetting('show_empty_fields')) {
+      $summary[] = $this->t('Show Empty Fields');
+    }
+
     if ($this->getSetting('id')) {
       $summary[] = $this->t('Id: @id', ['@id' => $this->getSetting('id')]);
     }
@@ -180,6 +191,7 @@ public function preRender(&$element, $rendering_object) {
     $element['#group_name'] = $this->group->group_name;
     $element['#entity_type'] = $this->group->entity_type;
     $element['#bundle'] = $this->group->bundle;
+    $element['#show_empty_fields'] = $this->getSetting('show_empty_fields');
   }
 
   /**
diff --git a/web/modules/field_group/src/Form/FieldGroupDeleteForm.php b/web/modules/field_group/src/Form/FieldGroupDeleteForm.php
index 6814525f96..b4556d553d 100644
--- a/web/modules/field_group/src/Form/FieldGroupDeleteForm.php
+++ b/web/modules/field_group/src/Form/FieldGroupDeleteForm.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\field_group\FieldgroupUi;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -27,14 +28,24 @@ class FieldGroupDeleteForm extends ConfirmFormBase {
    */
   protected $messenger;
 
+  /**
+   * The entity type bundle info service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $entityTypeBundleInfo;
+
   /**
    * FieldGroupDeleteForm constructor.
    *
    * @param \Drupal\Core\Messenger\MessengerInterface $messenger
    *   The messenger.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
+   *   The entity type bundle service.
    */
-  public function __construct(MessengerInterface $messenger) {
+  public function __construct(MessengerInterface $messenger, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
     $this->messenger = $messenger;
+    $this->entityTypeBundleInfo = $entity_type_bundle_info;
   }
 
   /**
@@ -42,7 +53,8 @@ public function __construct(MessengerInterface $messenger) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('messenger')
+      $container->get('messenger'),
+      $container->get('entity_type.bundle.info')
     );
   }
 
@@ -77,7 +89,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $field_gr
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    $bundles = \Drupal::service('entity_type.bundle.info')->getAllBundleInfo();
+
+    $bundles = $this->entityTypeBundleInfo->getAllBundleInfo();
     $bundle_label = $bundles[$this->fieldGroup->entity_type][$this->fieldGroup->bundle]['label'];
 
     field_group_delete_field_group($this->fieldGroup);
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php
index dd8feac371..d163f85e0e 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/AccordionItem.php
@@ -36,6 +36,9 @@ public function process(&$element, $processed_object) {
       '#type' => 'field_group_accordion_item',
       '#effect' => $this->getSetting('effect'),
       '#title' => $this->getLabel(),
+      // Prevent \Drupal\content_translation\ContentTranslationHandler::addTranslatabilityClue()
+      // from adding an incorrect suffix to the field group title.
+      '#multilingual' => TRUE,
     ];
 
     if ($this->getSetting('id')) {
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php
index fdbde635ba..2da178a377 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Details.php
@@ -29,6 +29,7 @@ public function process(&$element, $processed_object) {
       '#type' => 'details',
       '#title' => $this->getLabel(),
       '#open' => $this->getSetting('open'),
+      '#show_empty_fields' => $this->getSetting('show_empty_fields'),
       '#description' => $this->getSetting('description'),
     ];
 
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php
index 327d857b33..bf2e2b7be2 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Fieldset.php
@@ -30,6 +30,9 @@ public function process(&$element, $processed_object) {
       '#title' => $this->getLabel(),
       '#attributes' => [],
       '#description' => $this->getSetting('description'),
+      // Prevent \Drupal\content_translation\ContentTranslationHandler::addTranslatabilityClue()
+      // from adding an incorrect suffix to the field group title.
+      '#multilingual' => TRUE,
     ];
 
     // When a fieldset has a description, an id is required.
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php
index 94015806df..e527817bb9 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/HtmlElement.php
@@ -72,6 +72,9 @@ public function process(&$element, $processed_object) {
     if ($this->getSetting('show_label')) {
       $element['#title_element'] = $this->getSetting('label_element');
       $element['#title'] = $this->getLabel();
+      // Prevent \Drupal\content_translation\ContentTranslationHandler::addTranslatabilityClue()
+      // from adding an incorrect suffix to the field group title.
+      $element['#multilingual'] = TRUE;
       $element['#title_attributes'] = new Attribute();
 
       if (!empty($this->getSetting('label_element_classes'))) {
diff --git a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php
index de6b562b73..56553c4a9c 100644
--- a/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php
+++ b/web/modules/field_group/src/Plugin/field_group/FieldGroupFormatter/Tabs.php
@@ -4,7 +4,6 @@
 
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Form\FormState;
-use Drupal\Core\Render\Element;
 use Drupal\Core\Render\Element\VerticalTabs;
 use Drupal\field_group\Element\HorizontalTabs;
 use Drupal\field_group\FieldGroupFormatterBase;
@@ -54,6 +53,10 @@ public function process(&$element, $processed_object) {
       '#theme_wrappers' => [$this->getSetting('direction') . '_tabs'],
     ];
 
+    // Add auto-disable breakpoint.
+    if ($width_breakpoint = $this->getSetting('width_breakpoint')) {
+      $element['#attached']['drupalSettings']['widthBreakpoint'] = $width_breakpoint;
+    }
   }
 
   /**
@@ -99,6 +102,15 @@ public function settingsForm() {
       '#weight' => 1,
     ];
 
+    $form['width_breakpoint'] = [
+      '#title' => $this->t('Width Breakpoint'),
+      '#description' => $this->t('Auto-disable the Tabs widget if the window width is equal or smaller than this breakpoint.'),
+      '#type' => 'number',
+      '#default_value' => $this->getSetting('width_breakpoint'),
+      '#weight' => 2,
+      '#min' => 0,
+    ];
+
     return $form;
   }
 
@@ -121,6 +133,7 @@ public function settingsSummary() {
   public static function defaultContextSettings($context) {
     return [
       'direction' => 'vertical',
+      'width_breakpoint' => 640,
     ] + parent::defaultContextSettings($context);
   }
 
diff --git a/web/modules/field_group/templates/horizontal-tabs.html.twig b/web/modules/field_group/templates/horizontal-tabs.html.twig
index 9ed2a3a115..5c3da3778b 100644
--- a/web/modules/field_group/templates/horizontal-tabs.html.twig
+++ b/web/modules/field_group/templates/horizontal-tabs.html.twig
@@ -12,4 +12,7 @@
  * @ingroup themeable
  */
 #}
-<div data-horizontal-tabs-panes{{ attributes }}>{{ children }}</div>
+<div data-horizontal-tabs class="horizontal-tabs clearfix">
+  <ul data-horizontal-tabs-list class="horizontal-tabs-list visually-hidden"></ul>
+  <div data-horizontal-tabs-panes{{ attributes }}>{{ children }}</div>
+</div>
diff --git a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
index b5e79b5971..c7f5b784d1 100644
--- a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
+++ b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
@@ -5,7 +5,7 @@ package: 'Fields'
 type: module
 hidden: TRUE
 
-# Information added by Drupal.org packaging script on 2020-06-10
-version: '8.x-3.1'
+# Information added by Drupal.org packaging script on 2021-08-09
+version: '8.x-3.2'
 project: 'field_group'
-datestamp: 1591772570
+datestamp: 1628513588
diff --git a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
index f23f7f62c4..610d3c9414 100644
--- a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
+++ b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
@@ -71,15 +71,17 @@ public function testCreateGroup() {
     ];
 
     $add_form_display = 'admin/structure/types/manage/' . $this->type . '/form-display/add-group';
-    $this->drupalPostForm($add_form_display, $group, 'Save and continue');
+    $this->drupalGet($add_form_display);
+    $this->submitForm($group, 'Save and continue');
     $this->assertSession()->pageTextContains('Machine-readable name field is required.');
 
     // Add required field to form.
     $group['group_name'] = $group_name_input;
 
     // Add new group on the 'Manage form display' page.
-    $this->drupalPostForm($add_form_display, $group, 'Save and continue');
-    $this->drupalPostForm(NULL, [], 'Create group');
+    $this->drupalGet($add_form_display);
+    $this->submitForm($group, 'Save and continue');
+    $this->submitForm([], 'Create group');
 
     $this->assertSession()->responseContains(t('New group %label successfully created.', ['%label' => $group_label]));
 
@@ -91,8 +93,9 @@ public function testCreateGroup() {
     $this->assertEquals('hidden', $this->group->region);
 
     // Add new group on the 'Manage display' page.
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/add-group', $group, 'Save and continue');
-    $this->drupalPostForm(NULL, [], 'Create group');
+    $this->drupalGet('admin/structure/types/manage/' . $this->type . '/display/add-group');
+    $this->submitForm($group, 'Save and continue');
+    $this->submitForm([], 'Create group');
 
     $this->assertSession()->responseContains(t('New group %label successfully created.', ['%label' => $group_label]));
 
@@ -112,7 +115,8 @@ public function testDeleteGroup() {
 
     $group = $this->createGroup('node', $this->type, 'form', 'default', $data);
 
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display/' . $group->group_name . '/delete', [], 'Delete');
+    $this->drupalGet('admin/structure/types/manage/' . $this->type . '/form-display/' . $group->group_name . '/delete');
+    $this->submitForm([], 'Delete');
     $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', ['%label' => $group->label, '%type' => $this->type]));
 
     // Test that group is not in the $groups array.
@@ -129,7 +133,8 @@ public function testDeleteGroup() {
 
     $group = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete', [], t('Delete'));
+    $this->drupalGet('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete');
+    $this->submitForm([], 'Delete');
     $this->assertSession()->responseContains(t('The group %label has been deleted from the %type content type.', ['%label' => $group->label, '%type' => $this->type]));
 
     // Test that group is not in the $groups array.
@@ -153,7 +158,8 @@ public function testNestField() {
     $edit = [
       'fields[body][parent]' => $group->group_name,
     ];
-    $this->drupalPostForm('admin/structure/types/manage/' . $this->type . '/form-display', $edit, 'Save');
+    $this->drupalGet('admin/structure/types/manage/' . $this->type . '/form-display');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->responseContains('Your settings have been saved.');
 
     $group = field_group_load_field_group($group->group_name, 'node', $this->type, 'form', 'default');
-- 
GitLab