diff --git a/composer.json b/composer.json
index 6c97470805a9f510515b34904fef1177d817ae36..97007233277cd3e14e8060bd726e706f47b4fdb0 100644
--- a/composer.json
+++ b/composer.json
@@ -112,7 +112,7 @@
         "drupal/ctools": "3.4",
         "drupal/devel": "2.0",
         "drupal/draggableviews": "1.0",
-        "drupal/dropzonejs": "2.3",
+        "drupal/dropzonejs": "2.4",
         "drupal/editor_advanced_link": "1.8",
         "drupal/embed": "1.4",
         "drupal/entity": "1.0-beta1",
@@ -132,13 +132,13 @@
         "drupal/honeypot": "1.30",
         "drupal/image_popup": "1.1",
         "drupal/inline_entity_form": "1.0-rc8",
-        "drupal/libraries": "3.0.0-alpha6",
+        "drupal/libraries": "3.0-beta1",
         "drupal/link_attributes": "1.11",
         "drupal/linkit": "5.0-beta12",
         "drupal/magnific_popup": "1.3",
         "drupal/mathjax": "2.7",
         "drupal/media_entity_browser": "2.0-alpha3",
-        "drupal/media_entity_twitter": "2.4",
+        "drupal/media_entity_twitter": "2.6",
         "drupal/menu_block": "1.6",
         "drupal/menu_block_title": "1.1",
         "drupal/menu_breadcrumb": "1.14",
@@ -151,7 +151,7 @@
         "drupal/mobile_device_detection": "3.2",
         "drupal/module_filter": "3.1",
         "drupal/multiple_fields_remove_button": "^1.0@alpha",
-        "drupal/pantheon_advanced_page_cache": "1.1",
+        "drupal/pantheon_advanced_page_cache": "1.2",
         "drupal/paragraphs": "1.12",
         "drupal/pathauto": "1.8",
         "drupal/realname": "1.0.0-rc2",
@@ -183,7 +183,7 @@
         "drupal/views_ajax_history": "1.5",
         "drupal/views_autocomplete_filters": "1.3",
         "drupal/views_bootstrap": "3.1",
-        "drupal/views_bulk_operations": "3.9",
+        "drupal/views_bulk_operations": "3.10",
         "drupal/views_fieldsets": "3.3",
         "drupal/views_infinite_scroll": "1.7",
         "drupal/views_slideshow": "4.4",
diff --git a/composer.lock b/composer.lock
index 3cfc95e1442f4d01d0d312a43b43aba26138161d..3f5bcca64b133e977bdca278117bcf288ceda350 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": "483958ad644d5bd3351af88c32212e2b",
+    "content-hash": "cf9dbe7bb1771287f68ffec2f43f12ce",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -4069,17 +4069,17 @@
         },
         {
             "name": "drupal/dropzonejs",
-            "version": "2.3.0",
+            "version": "2.4.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/dropzonejs.git",
-                "reference": "8.x-2.3"
+                "reference": "8.x-2.4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.3.zip",
-                "reference": "8.x-2.3",
-                "shasum": "c145f2560ed31de32ea8938b0c0378765f70e36a"
+                "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.4.zip",
+                "reference": "8.x-2.4",
+                "shasum": "182e41163753bac785ad56d7d157cbe50706d706"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9"
@@ -4093,8 +4093,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-2.3",
-                    "datestamp": "1600311980",
+                    "version": "8.x-2.4",
+                    "datestamp": "1610726518",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -5476,17 +5476,17 @@
         },
         {
             "name": "drupal/libraries",
-            "version": "3.0.0-alpha6",
+            "version": "3.0.0-beta1",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/libraries.git",
-                "reference": "8.x-3.0-alpha6"
+                "reference": "8.x-3.0-beta1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-alpha6.zip",
-                "reference": "8.x-3.0-alpha6",
-                "shasum": "d2aaf7f0968a1864457a7741b7e38ab11ef83e2c"
+                "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-beta1.zip",
+                "reference": "8.x-3.0-beta1",
+                "shasum": "7843870c52251cc5290e1cdca94524f71edbf016"
             },
             "require": {
                 "drupal/core": "^8 || ^9"
@@ -5494,17 +5494,17 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.0-alpha6",
-                    "datestamp": "1608099124",
+                    "version": "8.x-3.0-beta1",
+                    "datestamp": "1609758293",
                     "security-coverage": {
                         "status": "not-covered",
-                        "message": "Alpha releases are not covered by Drupal security advisories."
+                        "message": "Beta releases are not covered by Drupal security advisories."
                     }
                 }
             },
             "notification-url": "https://packages.drupal.org/8/downloads",
             "license": [
-                "GPL-2.0+"
+                "GPL-2.0-or-later"
             ],
             "authors": [
                 {
@@ -5515,6 +5515,10 @@
                     "name": "joseph.olstad",
                     "homepage": "https://www.drupal.org/user/1321830"
                 },
+                {
+                    "name": "podarok",
+                    "homepage": "https://www.drupal.org/user/116002"
+                },
                 {
                     "name": "rjacobs",
                     "homepage": "https://www.drupal.org/user/422459"
@@ -5819,17 +5823,17 @@
         },
         {
             "name": "drupal/media_entity_twitter",
-            "version": "2.4.0",
+            "version": "2.6.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/media_entity_twitter.git",
-                "reference": "8.x-2.4"
+                "reference": "8.x-2.6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.4.zip",
-                "reference": "8.x-2.4",
-                "shasum": "11bca09cc6dd678dc7585d16d66167a09c6e42fb"
+                "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.6.zip",
+                "reference": "8.x-2.6",
+                "shasum": "777062eb55314da47ee3878db6d10d022e91bed6"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9",
@@ -5837,12 +5841,9 @@
             },
             "type": "drupal-module",
             "extra": {
-                "branch-alias": {
-                    "dev-2.x": "2.x-dev"
-                },
                 "drupal": {
-                    "version": "8.x-2.4",
-                    "datestamp": "1585646747",
+                    "version": "8.x-2.6",
+                    "datestamp": "1610375564",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -6576,17 +6577,17 @@
         },
         {
             "name": "drupal/pantheon_advanced_page_cache",
-            "version": "1.1.0",
+            "version": "1.2.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/pantheon_advanced_page_cache.git",
-                "reference": "8.x-1.1"
+                "reference": "8.x-1.2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.1.zip",
-                "reference": "8.x-1.1",
-                "shasum": "faef7abc7814c47dc0ba5cdb2c5a01f7386627ce"
+                "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.2.zip",
+                "reference": "8.x-1.2",
+                "shasum": "265f738df7e0d094f43b4f7a5b31ac3c5d799316"
             },
             "require": {
                 "drupal/core": "^8 || ^9"
@@ -6599,8 +6600,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.1",
-                    "datestamp": "1589904160",
+                    "version": "8.x-1.2",
+                    "datestamp": "1611003910",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -8473,17 +8474,17 @@
         },
         {
             "name": "drupal/views_bulk_operations",
-            "version": "3.9.0",
+            "version": "3.10.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/views_bulk_operations.git",
-                "reference": "8.x-3.9"
+                "reference": "8.x-3.10"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.9.zip",
-                "reference": "8.x-3.9",
-                "shasum": "d7f6e50c31d21ff32f21e8f4aaedb52f6dee2da8"
+                "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.10.zip",
+                "reference": "8.x-3.10",
+                "shasum": "e346c2a72fc9a1ae8af418e6a02076f52c0fcc7b"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9"
@@ -8497,8 +8498,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.9",
-                    "datestamp": "1597319021",
+                    "version": "8.x-3.10",
+                    "datestamp": "1608795018",
                     "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 e0aade52f2bc82bf9887eaf6622d5bef176e2262..f42a9ad2d804fd18186a8fe5567ba185e91b3695 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -4191,18 +4191,18 @@
     },
     {
         "name": "drupal/dropzonejs",
-        "version": "2.3.0",
-        "version_normalized": "2.3.0.0",
+        "version": "2.4.0",
+        "version_normalized": "2.4.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/dropzonejs.git",
-            "reference": "8.x-2.3"
+            "reference": "8.x-2.4"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.3.zip",
-            "reference": "8.x-2.3",
-            "shasum": "c145f2560ed31de32ea8938b0c0378765f70e36a"
+            "url": "https://ftp.drupal.org/files/projects/dropzonejs-8.x-2.4.zip",
+            "reference": "8.x-2.4",
+            "shasum": "182e41163753bac785ad56d7d157cbe50706d706"
         },
         "require": {
             "drupal/core": "^8.8 || ^9"
@@ -4216,8 +4216,8 @@
         "type": "drupal-module",
         "extra": {
             "drupal": {
-                "version": "8.x-2.3",
-                "datestamp": "1600311980",
+                "version": "8.x-2.4",
+                "datestamp": "1610726518",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
@@ -5640,18 +5640,18 @@
     },
     {
         "name": "drupal/libraries",
-        "version": "3.0.0-alpha6",
-        "version_normalized": "3.0.0.0-alpha6",
+        "version": "3.0.0-beta1",
+        "version_normalized": "3.0.0.0-beta1",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/libraries.git",
-            "reference": "8.x-3.0-alpha6"
+            "reference": "8.x-3.0-beta1"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-alpha6.zip",
-            "reference": "8.x-3.0-alpha6",
-            "shasum": "d2aaf7f0968a1864457a7741b7e38ab11ef83e2c"
+            "url": "https://ftp.drupal.org/files/projects/libraries-8.x-3.0-beta1.zip",
+            "reference": "8.x-3.0-beta1",
+            "shasum": "7843870c52251cc5290e1cdca94524f71edbf016"
         },
         "require": {
             "drupal/core": "^8 || ^9"
@@ -5659,18 +5659,18 @@
         "type": "drupal-module",
         "extra": {
             "drupal": {
-                "version": "8.x-3.0-alpha6",
-                "datestamp": "1608099124",
+                "version": "8.x-3.0-beta1",
+                "datestamp": "1609758293",
                 "security-coverage": {
                     "status": "not-covered",
-                    "message": "Alpha releases are not covered by Drupal security advisories."
+                    "message": "Beta releases are not covered by Drupal security advisories."
                 }
             }
         },
         "installation-source": "dist",
         "notification-url": "https://packages.drupal.org/8/downloads",
         "license": [
-            "GPL-2.0+"
+            "GPL-2.0-or-later"
         ],
         "authors": [
             {
@@ -5681,6 +5681,10 @@
                 "name": "joseph.olstad",
                 "homepage": "https://www.drupal.org/user/1321830"
             },
+            {
+                "name": "podarok",
+                "homepage": "https://www.drupal.org/user/116002"
+            },
             {
                 "name": "rjacobs",
                 "homepage": "https://www.drupal.org/user/422459"
@@ -5995,18 +5999,18 @@
     },
     {
         "name": "drupal/media_entity_twitter",
-        "version": "2.4.0",
-        "version_normalized": "2.4.0.0",
+        "version": "2.6.0",
+        "version_normalized": "2.6.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/media_entity_twitter.git",
-            "reference": "8.x-2.4"
+            "reference": "8.x-2.6"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.4.zip",
-            "reference": "8.x-2.4",
-            "shasum": "11bca09cc6dd678dc7585d16d66167a09c6e42fb"
+            "url": "https://ftp.drupal.org/files/projects/media_entity_twitter-8.x-2.6.zip",
+            "reference": "8.x-2.6",
+            "shasum": "777062eb55314da47ee3878db6d10d022e91bed6"
         },
         "require": {
             "drupal/core": "^8.8 || ^9",
@@ -6014,12 +6018,9 @@
         },
         "type": "drupal-module",
         "extra": {
-            "branch-alias": {
-                "dev-2.x": "2.x-dev"
-            },
             "drupal": {
-                "version": "8.x-2.4",
-                "datestamp": "1585646747",
+                "version": "8.x-2.6",
+                "datestamp": "1610375564",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
@@ -6778,18 +6779,18 @@
     },
     {
         "name": "drupal/pantheon_advanced_page_cache",
-        "version": "1.1.0",
-        "version_normalized": "1.1.0.0",
+        "version": "1.2.0",
+        "version_normalized": "1.2.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/pantheon_advanced_page_cache.git",
-            "reference": "8.x-1.1"
+            "reference": "8.x-1.2"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.1.zip",
-            "reference": "8.x-1.1",
-            "shasum": "faef7abc7814c47dc0ba5cdb2c5a01f7386627ce"
+            "url": "https://ftp.drupal.org/files/projects/pantheon_advanced_page_cache-8.x-1.2.zip",
+            "reference": "8.x-1.2",
+            "shasum": "265f738df7e0d094f43b4f7a5b31ac3c5d799316"
         },
         "require": {
             "drupal/core": "^8 || ^9"
@@ -6802,8 +6803,8 @@
         "type": "drupal-module",
         "extra": {
             "drupal": {
-                "version": "8.x-1.1",
-                "datestamp": "1589904160",
+                "version": "8.x-1.2",
+                "datestamp": "1611003910",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
@@ -8738,18 +8739,18 @@
     },
     {
         "name": "drupal/views_bulk_operations",
-        "version": "3.9.0",
-        "version_normalized": "3.9.0.0",
+        "version": "3.10.0",
+        "version_normalized": "3.10.0.0",
         "source": {
             "type": "git",
             "url": "https://git.drupalcode.org/project/views_bulk_operations.git",
-            "reference": "8.x-3.9"
+            "reference": "8.x-3.10"
         },
         "dist": {
             "type": "zip",
-            "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.9.zip",
-            "reference": "8.x-3.9",
-            "shasum": "d7f6e50c31d21ff32f21e8f4aaedb52f6dee2da8"
+            "url": "https://ftp.drupal.org/files/projects/views_bulk_operations-8.x-3.10.zip",
+            "reference": "8.x-3.10",
+            "shasum": "e346c2a72fc9a1ae8af418e6a02076f52c0fcc7b"
         },
         "require": {
             "drupal/core": "^8.8 || ^9"
@@ -8763,8 +8764,8 @@
         "type": "drupal-module",
         "extra": {
             "drupal": {
-                "version": "8.x-3.9",
-                "datestamp": "1597319021",
+                "version": "8.x-3.10",
+                "datestamp": "1608795018",
                 "security-coverage": {
                     "status": "covered",
                     "message": "Covered by Drupal's security advisory policy"
diff --git a/web/modules/dropzonejs/composer.libraries.json b/web/modules/dropzonejs/composer.libraries.json
index 7f82b5e1d07fe76f04edf51669b7ad80c2092646..dc4b1cd2c281d9c8d90804fff8545c311b6a52af 100644
--- a/web/modules/dropzonejs/composer.libraries.json
+++ b/web/modules/dropzonejs/composer.libraries.json
@@ -4,16 +4,16 @@
             "type": "package",
             "package": {
                 "name": "enyo/dropzone",
-                "version": "5.7.1",
+                "version": "5.7.2",
                 "type": "drupal-library",
                 "dist": {
-                    "url": "https://github.com/enyo/dropzone/archive/v5.7.1.zip",
+                    "url": "https://github.com/enyo/dropzone/archive/v5.7.2.zip",
                     "type": "zip"
                 }
             }
         }
     },
     "require": {
-        "enyo/dropzone": "5.7.1"
+        "enyo/dropzone": "5.7.2"
     }
 }
diff --git a/web/modules/dropzonejs/dropzonejs.info.yml b/web/modules/dropzonejs/dropzonejs.info.yml
index 25f528f95958870969901534b81b748629ccb2ba..a8205d9f4e367a0e28c7d76e64f6d368c0b77240 100644
--- a/web/modules/dropzonejs/dropzonejs.info.yml
+++ b/web/modules/dropzonejs/dropzonejs.info.yml
@@ -1,12 +1,12 @@
 name: dropzonejs
 type: module
-description: DropzoneJS
+description: The Drupal integration for DropzoneJS.
 core_version_requirement: ^8.8 || ^9
 package: Media
 dependencies:
   - drupal:file
 
-# Information added by Drupal.org packaging script on 2020-09-17
-version: '8.x-2.3'
+# Information added by Drupal.org packaging script on 2021-01-15
+version: '8.x-2.4'
 project: 'dropzonejs'
-datestamp: 1600310563
+datestamp: 1610726520
diff --git a/web/modules/dropzonejs/dropzonejs.libraries.yml b/web/modules/dropzonejs/dropzonejs.libraries.yml
index a73667e399a17ec92fbdff0b183c9a62605f75e5..1a4fe857b5f427477947cbaf5adc11bffcf91cd5 100644
--- a/web/modules/dropzonejs/dropzonejs.libraries.yml
+++ b/web/modules/dropzonejs/dropzonejs.libraries.yml
@@ -1,16 +1,16 @@
 dropzonejs:
   title: 'Dropzonejs'
   website: http://www.dropzonejs.com
-  version: 4.0.1
+  version: 5.7.2
   license:
     name: MIT
     url: https://github.com/enyo/dropzone/blob/master/LICENSE
     gpl-compatible: true
   js:
-    /libraries/dropzone/dist/min/dropzone.min.js: {}
+    /libraries/dropzone/dist/min/dropzone.min.js: { minified: true }
   css:
     component:
-      /libraries/dropzone/dist/min/dropzone.min.css: {}
+      /libraries/dropzone/dist/min/dropzone.min.css: { minified: true }
 widget:
   version: VERSION
   css:
diff --git a/web/modules/dropzonejs/js/dropzone.integration.js b/web/modules/dropzonejs/js/dropzone.integration.js
index 14b1bd0ed2231b3035c20be339ccbbfe325ce4dd..b30d11e7965e8c08c48f4b1f7dd4f2e46d11b454 100644
--- a/web/modules/dropzonejs/js/dropzone.integration.js
+++ b/web/modules/dropzonejs/js/dropzone.integration.js
@@ -25,7 +25,24 @@
         // Initiate dropzonejs.
         var config = {
           url: input.attr('data-upload-path'),
-          addRemoveLinks: false
+          addRemoveLinks: false,
+          dictDefaultMessage: Drupal.t('Drop files here to upload'),
+          dictFallbackMessage: Drupal.t('Your browser does not support drag\'n\'drop file uploads.'),
+          dictFallbackText: Drupal.t('Please use the fallback form below to upload your files like in the olden days.'),
+          dictFileTooBig: Drupal.t('File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.'),
+          dictInvalidFileType: Drupal.t('You can\'t upload files of this type.'),
+          dictResponseError: Drupal.t('Server responded with {{statusCode}} code.'),
+          dictCancelUpload: Drupal.t('Cancel upload'),
+          dictCancelUploadConfirmation: Drupal.t('Are you sure you want to cancel this upload?'),
+          dictRemoveFile: Drupal.t('Remove file'),
+          dictMaxFilesExceeded: Drupal.t('You can not upload any more files.'),
+          dictFileSizeUnits: {
+            tb: Drupal.t('TB'),
+            gb: Drupal.t('GB'),
+            mb: Drupal.t('MB'),
+            kb: Drupal.t('KB'),
+            b: Drupal.t('b')
+          },
         };
         var instanceConfig = drupalSettings.dropzonejs.instances[selector.attr('id')];
 
diff --git a/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml b/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml
index f803a34dc837b6a60c49a51c2b6564f45cb383f7..cd039f2fd2222f5576f75c8da42032d83d4beaf5 100644
--- a/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml
+++ b/web/modules/dropzonejs/modules/eb_widget/dropzonejs_eb_widget.info.yml
@@ -1,6 +1,6 @@
 name: DropzoneJS entity browser widget
 type: module
-description: DropzoneJS Entity browser widget
+description: 'DropzoneJS Entity browser widget.'
 core_version_requirement: ^8.8 || ^9
 package: Media
 dependencies:
@@ -9,7 +9,7 @@ dependencies:
   - entity_browser:entity_browser
 
 
-# Information added by Drupal.org packaging script on 2020-09-17
-version: '8.x-2.3'
+# Information added by Drupal.org packaging script on 2021-01-15
+version: '8.x-2.4'
 project: 'dropzonejs'
-datestamp: 1600310563
+datestamp: 1610726520
diff --git a/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml b/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml
index ebe917b3029bc8c804dc8d219341b8f0720179c6..7a0c3dcd426b4caa4b9954fbcfce482c576ccdbd 100644
--- a/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml
+++ b/web/modules/dropzonejs/tests/modules/dropzonejs_test/dropzonejs_test.info.yml
@@ -9,7 +9,7 @@ dependencies:
  - dropzonejs:dropzonejs
  - dropzonejs:dropzonejs_eb_widget
 
-# Information added by Drupal.org packaging script on 2020-09-17
-version: '8.x-2.3'
+# Information added by Drupal.org packaging script on 2021-01-15
+version: '8.x-2.4'
 project: 'dropzonejs'
-datestamp: 1600310563
+datestamp: 1610726520
diff --git a/web/modules/libraries/composer.json b/web/modules/libraries/composer.json
index 4af11e12e838280670e4095241afeef46d2d91ca..a1807ddcb828def716b9d521e42efa6068a01c10 100644
--- a/web/modules/libraries/composer.json
+++ b/web/modules/libraries/composer.json
@@ -10,5 +10,5 @@
     "irc": "irc://irc.freenode.org/drupal-contribute",
     "source": "http://cgit.drupalcode.org/libraries"
   },
-  "license": "GPL-2.0+"
+  "license": "GPL-2.0-or-later"
 }
diff --git a/web/modules/libraries/libraries.info.yml b/web/modules/libraries/libraries.info.yml
index 68ea958a3ffe6b11eabfa45db73c68f393b68355..d0d9423667ae2d95f8d09473e39447ab09f78d35 100644
--- a/web/modules/libraries/libraries.info.yml
+++ b/web/modules/libraries/libraries.info.yml
@@ -4,7 +4,7 @@ description: Allows version-dependent and shared usage of external libraries.
 core: 8.x
 core_version_requirement: ^8 || ^9
 
-# Information added by Drupal.org packaging script on 2020-12-16
-version: '8.x-3.0-alpha6'
+# Information added by Drupal.org packaging script on 2021-01-04
+version: '8.x-3.0-beta1'
 project: 'libraries'
-datestamp: 1608099126
+datestamp: 1609758296
diff --git a/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php b/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php
index 7ab3eeb7e4ce73dd3b3bbef97f2571ab13b214e0..e307846c3ee138e019c5584db7a52525f70e2093 100644
--- a/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php
+++ b/web/modules/libraries/src/ExternalLibrary/Exception/InvalidLibraryDependencyException.php
@@ -12,8 +12,10 @@
  */
 class InvalidLibraryDependencyException extends \UnexpectedValueException implements LibraryAccessorInterface {
 
-  use LibraryAccessorTrait;
-  use DependencyAccessorTrait;
+  use LibraryAccessorTrait, DependencyAccessorTrait {
+    LibraryAccessorTrait::getLibrary insteadof DependencyAccessorTrait;
+    DependencyAccessorTrait::getLibrary as libraryAccessor;
+  }
 
   /**
    * Constructs a library exception.
diff --git a/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php b/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php
index 3f08e4ba4c1f2d346aa6158f6594e56ea3034cba..3cb75290295e8a9e03e89374b4512d983cad7d17 100644
--- a/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php
+++ b/web/modules/libraries/src/ExternalLibrary/Local/LocalLibraryTrait.php
@@ -92,8 +92,8 @@ public function setLocalPath($path) {
     $this->installed = TRUE;
     $this->localPath = (string) $path;
 
-    assert('$this->localPath !== ""');
-    assert('$this->localPath[0] !== "/"');
+    assert($this->localPath !== "");
+    assert($this->localPath[0] !== "/");
   }
 
 }
diff --git a/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php b/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php
index 348be0c247c8aec40cbba68e28c132437b9c0938..27325050212d7c39d3f2c467d6eb02e072c09650 100644
--- a/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php
+++ b/web/modules/libraries/src/Plugin/libraries/Locator/UriLocator.php
@@ -73,7 +73,7 @@ public static function create(ContainerInterface $container, array $configuratio
   public function locate(LocalLibraryInterface $library) {
     /** @var \Drupal\Core\StreamWrapper\LocalStream $stream_wrapper */
     $stream_wrapper = $this->streamWrapperManager->getViaUri($this->uri);
-    assert('$stream_wrapper instanceof \Drupal\Core\StreamWrapper\LocalStream');
+    assert($stream_wrapper instanceof \Drupal\Core\StreamWrapper\LocalStream);
     // Calling LocalStream::getDirectoryPath() explicitly avoids the realpath()
     // usage in LocalStream::getLocalPath(), which breaks if Libraries API is
     // symbolically linked into the Drupal installation.
diff --git a/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php b/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php
index ce0b276b17eb58aa46789392ae6eb6fb92e1c866..a92f27daa09b55166d1d8d7f7fe26dc1329ec6e8 100644
--- a/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php
+++ b/web/modules/libraries/src/Plugin/libraries/Type/AssetLibraryType.php
@@ -24,7 +24,7 @@ public function getLibraryClass() {
    * {@inheritdoc}
    */
   public function getAttachableAssetLibraries(LibraryInterface $library, LibraryManagerInterface $library_manager) {
-    assert('$library instanceof \Drupal\libraries\ExternalLibrary\Asset\AssetLibraryInterface');
+    assert($library instanceof \Drupal\libraries\ExternalLibrary\Asset\AssetLibraryInterface);
     /** @var \Drupal\libraries\ExternalLibrary\Asset\AssetLibraryInterface $library */
     return [$library->getId() => $library->getAttachableAssetLibrary($library_manager)];
   }
diff --git a/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php b/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php
index 31ec6a62c6c41aace30735496788f4f85118900d..f73887e917f22e21bbf8609b7e3f5bc1dc95b06a 100644
--- a/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php
+++ b/web/modules/libraries/src/Plugin/libraries/Type/MultipleAssetLibraryType.php
@@ -25,7 +25,7 @@ public function getLibraryClass() {
    * {@inheritdoc}
    */
   public function getAttachableAssetLibraries(LibraryInterface $external_library, LibraryManagerInterface $library_manager) {
-    assert('$external_library instanceof \Drupal\libraries\ExternalLibrary\Asset\MultipleAssetLibraryInterface');
+    assert($external_library instanceof \Drupal\libraries\ExternalLibrary\Asset\MultipleAssetLibraryInterface);
     /** @var \Drupal\libraries\ExternalLibrary\Asset\MultipleAssetLibraryInterface $external_library */
     $attachable_libraries = [];
     foreach ($external_library->getAttachableAssetLibraries($library_manager) as $component_name => $attachable_library) {
diff --git a/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php b/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php
index 7cf0764ec0c75d3cd9cc2d0384c15f395c2811cd..eff3146ae7eeaf814c6c18bdc0fd8f58ca933f12 100644
--- a/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php
+++ b/web/modules/libraries/src/StreamWrapper/LibraryDefinitionsStream.php
@@ -3,6 +3,7 @@
 namespace Drupal\libraries\StreamWrapper;
 
 use Drupal\Core\StreamWrapper\LocalStream;
+use Drupal\Core\Config\ConfigFactory;
 
 /**
  * Provides a stream wrapper for library definitions.
@@ -33,7 +34,7 @@ class LibraryDefinitionsStream extends LocalStream {
   use PrivateStreamTrait;
 
   /**
-   * The config factory
+   * The config factory.
    *
    * @var \Drupal\Core\Config\ConfigFactoryInterface
    */
@@ -44,8 +45,8 @@ class LibraryDefinitionsStream extends LocalStream {
    *
    * @todo Dependency injection.
    */
-  public function __construct() {
-    $this->configFactory = \Drupal::configFactory();
+  public function __construct(ConfigFactory $config_factory) {
+    $this->configFactory = $config_factory;
   }
 
   /**
diff --git a/web/modules/libraries/src/Tests/LibrariesWebTest.php b/web/modules/libraries/src/Tests/LibrariesWebTest.php
index 2c9254c45323010c0145c28f58785d39e4e46f81..f0a0da04f75ff6c0d6b32d43e12ef3f20ba301b7 100644
--- a/web/modules/libraries/src/Tests/LibrariesWebTest.php
+++ b/web/modules/libraries/src/Tests/LibrariesWebTest.php
@@ -54,7 +54,7 @@ protected function setUp() {
   function testLibrariesDetectDependencies() {
     $library = array(
       'name' => 'Example',
-      'dependencies' => array('example_missing'),
+      'dependencies' => array('Example missing'),
     );
     libraries_detect_dependencies($library);
     $this->assertEqual($library['error'], 'missing dependency', 'libraries_detect_dependencies() detects missing dependency');
diff --git a/web/modules/libraries/tests/example/example_info_file.libraries.info.yml b/web/modules/libraries/tests/example/example_info_file.libraries.info.yml
index d0ffc711a33096f3b68c6c0e2de3bf1186e9be38..90d4246681245efa5a1480d2f2d6160b5d65836c 100644
--- a/web/modules/libraries/tests/example/example_info_file.libraries.info.yml
+++ b/web/modules/libraries/tests/example/example_info_file.libraries.info.yml
@@ -1,7 +1,7 @@
 # This is an example info file of a library used for testing purposes.
 name: Example info file
 
-# Information added by Drupal.org packaging script on 2020-12-16
-version: '8.x-3.0-alpha6'
+# Information added by Drupal.org packaging script on 2021-01-04
+version: '8.x-3.0-beta1'
 project: 'libraries'
-datestamp: 1608099126
+datestamp: 1609758296
diff --git a/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml b/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml
index f2bb897e8a092fcafba1d595314f8f8a9a62c0c5..6a9118db1042dfa891a3d1b8eae8af80cbd762ca 100644
--- a/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml
+++ b/web/modules/libraries/tests/modules/libraries_test/libraries_test.info.yml
@@ -3,13 +3,13 @@ type: module
 description: Tests library detection and loading.
 core: 8.x
 dependencies:
-  - libraries
+  - libraries:libraries
 hidden: TRUE
 library_dependencies:
   - test_asset_library
   - test_asset_multiple_library
 
-# Information added by Drupal.org packaging script on 2020-12-16
-version: '8.x-3.0-alpha6'
+# Information added by Drupal.org packaging script on 2021-01-04
+version: '8.x-3.0-beta1'
 project: 'libraries'
-datestamp: 1608099126
+datestamp: 1609758296
diff --git a/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php b/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php
index 14bf74e4f6ecfbbd5e1a7a693c4a88349af084be..0b049bfdab1a0c1c61cfa3f5469dfba05469012d 100644
--- a/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php
+++ b/web/modules/libraries/tests/src/Functional/ExternalLibrary/Definition/DefinitionDiscoveryFactoryTest.php
@@ -108,11 +108,11 @@ public function testDiscovery() {
     /** @var \Drupal\libraries\ExternalLibrary\Definition\DefinitionDiscoveryInterface $discovery */
     $discovery = $this->container->get($discovery_service_id);
     $definition_file = "$definitions_directory/$library_id.json";
-    $this->assertFalse(file_exists($definition_file));
+    $this->assertFileNotExists($definition_file);
     $this->assertTrue($discovery->hasDefinition($library_id));
-    $this->assertFalse(file_exists($definition_file));
+    $this->assertFileNotExists($definition_file);
     $this->assertEquals($discovery->getDefinition($library_id), $expected_definition);
-    $this->assertTrue(file_exists($definition_file));
+    $this->assertFileExists($definition_file);
   }
 
 }
diff --git a/web/modules/media_entity_twitter/media_entity_twitter.info.yml b/web/modules/media_entity_twitter/media_entity_twitter.info.yml
index 0c97051226a80c0915b0e89329ddaabbba4d34a7..03aa469d411658a8a1911666a43a8c437fde586f 100644
--- a/web/modules/media_entity_twitter/media_entity_twitter.info.yml
+++ b/web/modules/media_entity_twitter/media_entity_twitter.info.yml
@@ -6,7 +6,7 @@ core_version_requirement: ^8.8 || ^9
 dependencies:
   - drupal:media
 
-# Information added by Drupal.org packaging script on 2020-03-31
-version: '8.x-2.4'
+# Information added by Drupal.org packaging script on 2021-01-11
+version: '8.x-2.6'
 project: 'media_entity_twitter'
-datestamp: 1585646749
+datestamp: 1610375567
diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraint.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraint.php
deleted file mode 100644
index 28aca9571f63f2a894a0035fbc440952fe3a371e..0000000000000000000000000000000000000000
--- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraint.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * Checks if a value is a valid Tweet embed code/URL.
- *
- * @Constraint(
- *   id = "TweetEmbedCode",
- *   label = @Translation("Tweet embed code", context = "Validation"),
- *   type = { "link", "string", "string_long" }
- * )
- */
-class TweetEmbedCodeConstraint extends Constraint {
-
-  /**
-   * The default violation message.
-   *
-   * @var string
-   */
-  public $message = 'Not valid Tweet URL/embed code.';
-
-}
diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraintValidator.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraintValidator.php
deleted file mode 100644
index 699a819416639accfb0f82221d05e101bb512620..0000000000000000000000000000000000000000
--- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetEmbedCodeConstraintValidator.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint;
-
-use Drupal\media_entity_twitter\Plugin\media\Source\Twitter;
-use Drupal\Core\Field\FieldItemList;
-use Drupal\Core\Field\FieldItemInterface;
-use Symfony\Component\Validator\Constraint;
-use Symfony\Component\Validator\ConstraintValidator;
-
-/**
- * Validates the TweetEmbedCode constraint.
- */
-class TweetEmbedCodeConstraintValidator extends ConstraintValidator {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validate($value, Constraint $constraint) {
-    $data = '';
-    if (is_string($value)) {
-      $data = $value;
-    }
-    elseif ($value instanceof FieldItemList) {
-      $fieldtype = $value->getFieldDefinition()->getType();
-      $field_value = $value->getValue();
-      if ($fieldtype == 'link') {
-        $data = empty($field_value[0]['uri']) ? "" : $field_value[0]['uri'];
-      }
-      else {
-        $data = empty($field_value[0]['value']) ? "" : $field_value[0]['value'];
-      }
-    }
-    elseif ($value instanceof FieldItemInterface) {
-      $class = get_class($value);
-      $property = $class::mainPropertyName();
-      if ($property) {
-        $data = $value->{$property};
-      }
-    }
-    if ($data) {
-      $matches = [];
-      foreach (Twitter::$validationRegexp as $pattern => $key) {
-        if (preg_match($pattern, $data, $item_matches)) {
-          $matches[] = $item_matches;
-        }
-      }
-      if (empty($matches)) {
-        $this->context->addViolation($constraint->message);
-      }
-    }
-  }
-
-}
diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraint.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraint.php
deleted file mode 100644
index 2a16846a9d461d013d885d228336fbbce7b161eb..0000000000000000000000000000000000000000
--- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraint.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-
-namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * Checks if a Tweet is publicly visible.
- *
- * @Constraint(
- *   id = "TweetVisible",
- *   label = @Translation("Tweet publicly visible", context = "Validation"),
- *   type = { "entity", "entity_reference", "string", "string_long" }
- * )
- */
-class TweetVisibleConstraint extends Constraint {
-
-  /**
-   * The default violation message.
-   *
-   * @var string
-   */
-  public $message = 'Referenced tweet is not publicly visible.';
-
-}
diff --git a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraintValidator.php b/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraintValidator.php
deleted file mode 100644
index 81967dab07e16aee442b0743cb16c62a3d90904d..0000000000000000000000000000000000000000
--- a/web/modules/media_entity_twitter/src/Plugin/Validation/Constraint/TweetVisibleConstraintValidator.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-namespace Drupal\media_entity_twitter\Plugin\Validation\Constraint;
-
-use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\media_entity_twitter\Plugin\media\Source\Twitter;
-use Drupal\Core\Field\FieldItemInterface;
-use GuzzleHttp\Client;
-use GuzzleHttp\Exception\ClientException;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\Validator\Constraint;
-use Symfony\Component\Validator\ConstraintValidator;
-
-/**
- * Validates the TweetVisible constraint.
- */
-class TweetVisibleConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
-
-  /**
-   * The HTTP client to fetch the feed data with.
-   *
-   * @var \GuzzleHttp\Client
-   */
-  protected $httpClient;
-
-  /**
-   * Constructs a new TweetVisibleConstraintValidator.
-   *
-   * @param \GuzzleHttp\Client $http_client
-   *   The http client service.
-   */
-  public function __construct(Client $http_client) {
-    $this->httpClient = $http_client;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static($container->get('http_client'));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validate($value, Constraint $constraint) {
-    $data = '';
-    if (is_string($value)) {
-      $data = $value;
-    }
-    elseif ($value instanceof FieldItemListInterface) {
-      $fieldtype = $value->getFieldDefinition()->getType();
-      $field_value = $value->getValue();
-      if ($fieldtype == 'link') {
-        $data = empty($field_value[0]['uri']) ? "" : $field_value[0]['uri'];
-      }
-      else {
-        $data = empty($field_value[0]['value']) ? "" : $field_value[0]['value'];
-      }
-    }
-    elseif ($value instanceof FieldItemInterface) {
-      $class = get_class($value);
-      $property = $class::mainPropertyName();
-      if ($property) {
-        $data = $value->{$property};
-      }
-    }
-    foreach (Twitter::$validationRegexp as $pattern => $key) {
-      if (preg_match($pattern, $data, $item_matches)) {
-        $matches[] = $item_matches;
-      }
-    }
-
-    if (empty($matches[0][0])) {
-      // If there are no matches the URL is not correct, so stop validation.
-      return;
-    }
-
-    // Fetch content from the given url.
-    try {
-      $response = $this->httpClient->get($matches[0][0], ['allow_redirects' => FALSE]);
-    }
-    catch (ClientException $e) {
-      $this->context->addViolation($constraint->message);
-      return;
-    }
-
-    if ($response->getStatusCode() == 302 && ($location = $response->getHeader('location'))) {
-      $effective_url_parts = parse_url($location[0]);
-      if (!empty($effective_url_parts) && isset($effective_url_parts['query']) && $effective_url_parts['query'] == 'protected_redirect=true') {
-        $this->context->addViolation($constraint->message);
-      }
-    }
-  }
-
-}
diff --git a/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php b/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php
index 72018dfee2a72d58c9117bedeb96ce3b35bbb6b6..22abcfeac576bbcb96582ec7aac2cc10777af7d0 100644
--- a/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php
+++ b/web/modules/media_entity_twitter/src/Plugin/media/Source/Twitter.php
@@ -14,6 +14,7 @@
 use Drupal\media\MediaInterface;
 use Drupal\media\MediaSourceBase;
 use Drupal\media\MediaTypeInterface;
+use Drupal\media\Plugin\media\Source\OEmbedInterface;
 use Drupal\media_entity_twitter\TweetFetcherInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
@@ -33,7 +34,7 @@
  *   }
  * )
  */
-class Twitter extends MediaSourceBase implements MediaSourceFieldConstraintsInterface {
+class Twitter extends MediaSourceBase implements MediaSourceFieldConstraintsInterface, OEmbedInterface {
 
   /**
    * The renderer.
@@ -114,6 +115,8 @@ public static function create(ContainerInterface $container, array $configuratio
    *   The tweet fetcher.
    * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
    *   The logger channel.
+   * @param \Drupal\Core\File\FileSystemInterface $file_system
+   *   The file system.
    */
   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, ConfigFactoryInterface $config_factory, RendererInterface $renderer, TweetFetcherInterface $tweet_fetcher, LoggerChannelInterface $logger, FileSystemInterface $file_system) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
@@ -210,7 +213,6 @@ public function getMetadata(MediaInterface $media, $attribute_name) {
         ];
         $svg = $this->renderer->renderRoot($thumbnail);
 
-
         return $this->fileSystem->saveData($svg, $thumbnail_uri, FileSystemInterface::EXISTS_ERROR) ?: parent::getMetadata($media, $attribute_name);
     }
 
@@ -379,8 +381,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
    */
   public function getSourceFieldConstraints() {
     return [
-      'TweetEmbedCode' => [],
-      'TweetVisible' => [],
+      'oembed_resource' => [],
     ];
   }
 
@@ -448,7 +449,7 @@ protected function matchRegexp(MediaInterface $media) {
     $matches = [];
 
     $source_field = $this->getSourceFieldDefinition($media->bundle->entity)->getName();
-    if ($media->hasField($source_field)) {
+    if ($media->hasField($source_field) && !$media->get($source_field)->isEmpty()) {
       $property_name = $media->get($source_field)->first()->mainPropertyName();
       foreach (static::$validationRegexp as $pattern => $key) {
         if (preg_match($pattern, $media->get($source_field)->{$property_name}, $matches)) {
@@ -480,4 +481,11 @@ protected function fetchTweet($id) {
     return $this->tweetFetcher->fetchTweet($id);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getProviders() {
+    return ['Twitter'];
+  }
+
 }
diff --git a/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php b/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php
index 2df19dca8c51235ca5050b61838105d4c0496f4d..e928db8dcd55591de5d214e7c47b3655cb7efadb 100644
--- a/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php
+++ b/web/modules/media_entity_twitter/tests/src/Functional/TweetEmbedFormatterTest.php
@@ -67,14 +67,14 @@ public function testManageEmbedFormatter() {
     ];
     $this->drupalPostForm(NULL, $edit_conf, t('Save and continue'));
     $this->assertSession()
-        ->responseContains('These settings apply to the <em class="placeholder">' . $edit_conf['label'] . '</em> field everywhere it is used.');
+      ->responseContains('These settings apply to the <em class="placeholder">' . $edit_conf['label'] . '</em> field everywhere it is used.');
     $edit = [
       'cardinality' => 'number',
       'cardinality_number' => '1',
     ];
     $this->drupalPostForm(NULL, $edit, t('Save field settings'));
     $this->assertSession()
-        ->responseContains('Updated field <em class="placeholder">' . $edit_conf['label'] . '</em> field settings.');
+      ->responseContains('Updated field <em class="placeholder">' . $edit_conf['label'] . '</em> field settings.');
 
     // Set the new string_long field type as required.
     $edit = [
@@ -82,7 +82,7 @@ public function testManageEmbedFormatter() {
     ];
     $this->drupalPostForm(NULL, $edit, t('Save settings'));
     $this->assertSession()
-        ->responseContains('Saved <em class="placeholder">' . $edit_conf['label'] . '</em> configuration.');
+      ->responseContains('Saved <em class="placeholder">' . $edit_conf['label'] . '</em> configuration.');
 
     // Assert that the new field types configurations have been successfully
     // saved.
@@ -139,7 +139,7 @@ public function testManageEmbedFormatter() {
     // Assert that the link url formatter exists on this page.
     $this->assertSession()->pageTextContains('Tweet URL');
     $this->assertSession()
-        ->responseContains('<a href="https://twitter.com/RamzyStinson/statuses/670650348319576064">', 'Link in embedded Tweet found.');
+      ->responseContains('<a href="https://twitter.com/RamzyStinson/statuses/670650348319576064">', 'Link in embedded Tweet found.');
 
     // Assert that the string_long code formatter exists on this page.
     $this->assertSession()->pageTextContains('Embed code');
diff --git a/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php b/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php
index 4c43d24c816980b5e9db62234a46c6837ff1075d..1c0d4b66831f17782f7962aece3b3a99cd2672df 100644
--- a/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php
+++ b/web/modules/media_entity_twitter/tests/src/Kernel/ThumbnailTest.php
@@ -107,7 +107,7 @@ protected function setUp() {
       ->get('media_entity_twitter.settings')
       ->get('local_images');
 
-    \Drupal::service('file_system')->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY| FileSystemInterface::MODIFY_PERMISSIONS);
+    \Drupal::service('file_system')->prepareDirectory($dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
   }
 
   /**
diff --git a/web/modules/media_entity_twitter/tests/src/Unit/ConstraintsTest.php b/web/modules/media_entity_twitter/tests/src/Unit/ConstraintsTest.php
deleted file mode 100644
index 69e4a1bb0f641ec187b72a584615b4c626625720..0000000000000000000000000000000000000000
--- a/web/modules/media_entity_twitter/tests/src/Unit/ConstraintsTest.php
+++ /dev/null
@@ -1,198 +0,0 @@
-<?php
-
-namespace Drupal\Tests\media_entity_twitter\Unit;
-
-use Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem;
-use Drupal\Core\TypedData\ComplexDataDefinitionInterface;
-use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraint;
-use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraintValidator;
-use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraint;
-use Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraintValidator;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * Tests media_entity_twitter constraints.
- *
- * @group media_entity
- */
-class ConstraintsTest extends UnitTestCase {
-
-  /**
-   * Creates a string_long FieldItemInterface wrapper around a value.
-   *
-   * @param string $value
-   *   The wrapped value.
-   *
-   * @return \Drupal\Core\Field\FieldItemInterface
-   *   Mocked string field item.
-   */
-  protected function getMockFieldItem($value) {
-    $definition = $this->prophesize(ComplexDataDefinitionInterface::class);
-    $definition->getPropertyDefinitions()->willReturn([]);
-
-    $item = new StringLongItem($definition->reveal());
-    $item->set('value', $value);
-
-    return $item;
-  }
-
-  /**
-   * Tests TweetEmbedCode constraint.
-   *
-   * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraintValidator
-   * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetEmbedCodeConstraint
-   *
-   * @dataProvider embedCodeProvider
-   */
-  public function testTweetEmbedCodeConstraint($embed_code, $expected_violation_count) {
-    // Check message in constraint.
-    $constraint = new TweetEmbedCodeConstraint();
-    $this->assertEquals('Not valid Tweet URL/embed code.', $constraint->message, 'Correct constraint message found.');
-
-    $execution_context = $this->getMockBuilder('\Drupal\Core\TypedData\Validation\ExecutionContext')
-      ->disableOriginalConstructor()
-      ->getMock();
-
-    if ($expected_violation_count) {
-      $execution_context->expects($this->exactly($expected_violation_count))
-        ->method('addViolation')
-        ->with($constraint->message);
-    }
-    else {
-      $execution_context->expects($this->exactly($expected_violation_count))
-        ->method('addViolation');
-    }
-
-    $validator = new TweetEmbedCodeConstraintValidator();
-    $validator->initialize($execution_context);
-
-    $validator->validate($this->getMockFieldItem($embed_code), $constraint);
-  }
-
-  /**
-   * Provides test data for testTweetEmbedCodeConstraint().
-   */
-  public function embedCodeProvider() {
-    return [
-      'valid tweet URL' => ['https://twitter.com/drupal8changes/status/649167396230578176', 0],
-      'valid tweet embed code' => ['<blockquote class="twitter-tweet" lang="en"><p lang="en" dir="ltr">EntityChangedInterface now also defines the function setChangedTime <a href="http://t.co/1Q58UcR8OY">http://t.co/1Q58UcR8OY</a></p>&mdash; Drupal 8 Changes (@drupal8changes) <a href="https://twitter.com/drupal8changes/status/649167396230578176">September 30, 2015</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>', 0],
-      'invalid URL' => ['https://drupal.org/project/media_entity_twitter', 1],
-      'invalid text' => ['I want my Tweet!', 1],
-      'invalid tweet URL' => ['https://twitter.com/drupal8changes/statustypo/649167396230578176', 1],
-      'invalid tweet ID' => ['https://twitter.com/drupal8changes/status/aa64916739bb6230578176', 1],
-    ];
-  }
-
-  /**
-   * Tests TweetVisible constraint.
-   *
-   * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraintValidator
-   * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraint
-   *
-   * @dataProvider visibleProvider
-   */
-  public function testTweetVisibleConstraint($embed_code, $mocked_response, $violations) {
-    // Check message in constraint.
-    $constraint = new TweetVisibleConstraint();
-    $this->assertEquals('Referenced tweet is not publicly visible.', $constraint->message, 'Correct constraint message found.');
-
-    $http_client = $this->createMock('\GuzzleHttp\Client');
-    $http_client->expects($this->once())
-      ->method('__call')
-      ->with('get', [$embed_code, ['allow_redirects' => FALSE]])
-      ->willReturn($mocked_response);
-
-    // Make sure no violations are raised for visible tweet.
-    $execution_context = $this->getMockBuilder('\Drupal\Core\TypedData\Validation\ExecutionContext')
-      ->disableOriginalConstructor()
-      ->getMock();
-
-    if ($violations) {
-      $execution_context->expects($this->once())
-        ->method('addViolation')
-        ->with($constraint->message);
-    }
-    else {
-      $execution_context->expects($this->exactly($violations))
-        ->method('addViolation');
-    }
-
-    $validator = new TweetVisibleConstraintValidator($http_client);
-    $validator->initialize($execution_context);
-
-    $validator->validate($this->getMockFieldItem($embed_code), $constraint);
-  }
-
-  /**
-   * Provides test data for testTweetVisibleConstraint().
-   */
-  public function visibleProvider() {
-    $visible_response = $this->createMock('\GuzzleHttp\Psr7\Response');
-    $visible_response->expects($this->any())
-      ->method('getStatusCode')
-      ->will($this->returnValue(200));
-
-    $invisible_response = $this->createMock('\GuzzleHttp\Psr7\Response');
-    $invisible_response->expects($this->once())
-      ->method('getStatusCode')
-      ->will($this->returnValue(302));
-    $invisible_response->expects($this->once())
-      ->method('getHeader')
-      ->with('location')
-      ->will($this->returnValue(['https://twitter.com/drupal8changes?protected_redirect=true']));
-
-    return [
-      'valid URL' => [
-        'https://twitter.com/drupal8changes/status/649167396230578176',
-        $visible_response,
-        0,
-      ],
-      'invalid URL' => [
-        'https://twitter.com/drupal8changes/status/649637310024273920',
-        $invisible_response,
-        1,
-      ],
-    ];
-  }
-
-  /**
-   * Tests whether the TweetVisible constraint is robust against bad URLs.
-   *
-   * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraintValidator
-   * @covers \Drupal\media_entity_twitter\Plugin\Validation\Constraint\TweetVisibleConstraint
-   *
-   * @dataProvider badUrlsProvider
-   */
-  public function testBadUrlsOnVisibleConstraint($embed_code) {
-
-    $http_client = $this->createMock('\GuzzleHttp\Client');
-    $http_client->expects($this->never())
-      ->method('__call')
-      ->with('get', [$embed_code, ['allow_redirects' => FALSE]]);
-
-    $execution_context = $this->getMockBuilder('\Drupal\Core\TypedData\Validation\ExecutionContext')
-      ->disableOriginalConstructor()
-      ->getMock();
-
-    $validator = new TweetVisibleConstraintValidator($http_client);
-    $validator->initialize($execution_context);
-
-    $constraint = new TweetVisibleConstraint();
-    $validator->validate($this->getMockFieldItem($embed_code), $constraint);
-  }
-
-  /**
-   * Provides test data for testBadUrlsOnVisibleConstraint().
-   */
-  public function badUrlsProvider() {
-
-    return [
-      ['https://google.com'],
-      ['https://twitter.com/drupal/ssstatus/725771037837762561'],
-      ['https://twitter.com/drupal/status'],
-      ['https://twitter.com/drupal/status/foo'],
-    ];
-
-  }
-
-}
diff --git a/web/modules/pantheon_advanced_page_cache/.circleci/config.yml b/web/modules/pantheon_advanced_page_cache/.circleci/config.yml
index 6c7397c29dc8c236f75ec89c06a6a5fa16671e3c..f07920472edeca64a79537a68e7057221d01fcfa 100644
--- a/web/modules/pantheon_advanced_page_cache/.circleci/config.yml
+++ b/web/modules/pantheon_advanced_page_cache/.circleci/config.yml
@@ -1,80 +1,72 @@
 version: 2
 # https://circleci.com/docs/configuration#machine
 jobs:
-    # @todo, separate build and test phases.
     build:
         docker:
-            # @todo, update container
-            - image: quay.io/pantheon-public/build-tools-ci:1.x
-        working_directory: ~/pantheon_advanced_page_cache
+            - image: quay.io/pantheon-public/build-tools-ci:6.x
         environment:
-            BASH_ENV: ~/.bashrc
-            TZ: "/usr/share/zoneinfo/America/Los_Angeles"
             TERMINUS_SITE: d9-papc2
         steps:
+            - run:
+                name: login-pantheon
+                command: terminus auth:login -n --machine-token="$TERMINUS_TOKEN"
+            # Start making a multidev right away in the background so that
+            # this slow step is done as soon as possible.
+            - run:
+                name: make-multidev
+                command: |
+                    terminus env:create $TERMINUS_SITE.dev ${CIRCLE_BUILD_NUM} || echo "mystery errors were being thrown by env:create so I am adding this OR (https://circleci.com/gh/pantheon-systems/pantheon_advanced_page_cache/610)"
+                    touch multidev-made.txt
+                background: true
             - checkout
-            - restore_cache:
-                key: dependency-cache-{{ checksum "composer.lock" }}
             - run:
                 name: Composer install
                 command: |
                   composer install
-                  drush help
-            - save_cache:
-                key: dependency-cache-{{ checksum "composer.lock" }}
-                paths:
-                  - ~/.composer/cache
+            - run:
+                name: Git Config
+                command: |
+                  git config --global user.email "$GitEmail"
+                  git config --global user.name "Circle CI"
+            - run:
+                # this configuration prevents a prompt from stopping git pushes.
+                name: ssh config
+                command: |
+                  touch $HOME/.ssh/config
+                  echo "StrictHostKeyChecking no" >> "$HOME/.ssh/config"
             - run:
                 name: PHP Code Sniff
                 command: composer codesniff
             - run:
                 name: Unit Tests for Behat helper
                 command: composer phpunit
+#             - run:
+#                 # @todo, update core update mechanism for D9
+#                 name: apply upstream updates in dev
+#                 command: terminus connection:set $TERMINUS_SITE.dev git && terminus upstream:updates:apply $TERMINUS_SITE && terminus connection:set $TERMINUS_SITE.dev sftp
+
             - run:
-                name: login-pantheon
-                command: terminus auth:login -n --machine-token="$TERMINUS_TOKEN"
-            - run:
-                name: delete old sites
-                command: terminus env:list --field=id $TERMINUS_SITE | grep -v '[a-z]' | grep -Eo '[0-9]{1,9}' | sort --numeric-sort --reverse | sed 1,7d | xargs -n1 -I ENV terminus env:delete --yes $TERMINUS_SITE.ENV
+                name: Add modules to site
+                command: ./.circleci/scripts/setup-drupal-repo.sh
+
             - run:
-                name: ssh
+                name: Wait for multidev creation to be completed before doing site install.
                 command: |
-                  touch $HOME/.ssh/config
-                  echo "StrictHostKeyChecking no" >> "$HOME/.ssh/config"
-            - run:
-                # @todo, update core update mechanism for D9
-                name: apply upstream updates in dev
-                command: terminus connection:set $TERMINUS_SITE.dev git && terminus upstream:updates:apply $TERMINUS_SITE && terminus connection:set $TERMINUS_SITE.dev sftp
-            - run:
-                name: make-multidev
-                command: terminus env:create $TERMINUS_SITE.dev ${CIRCLE_BUILD_NUM} || echo "mystery errors were being thrown by env:create so I am adding this OR (https://circleci.com/gh/pantheon-systems/pantheon_advanced_page_cache/610)"
+                    while [ ! -f multidev-made.txt ]
+                    do
+                      sleep 2
+                    done
+                    exit 0
+
             - run:
                 name: site install
                 command: |
                   terminus connection:set ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} sftp
-                  terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- site-install -y
+                  terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- site-install -y --quiet
                   terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- cset system.performance cache.page.max_age 600 -y
 
             - run:
-                name: Permissions
-                command: |
-                  # composer will write to the default directory 
-                  $(terminus connection:info ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} --field=sftp_command) <<EOF
-                  chmod 755 code/web/sites/default
-                  exit
-                  EOF
-
-            - run:
-                name: Composer require papc
-                command: |
-                  terminus composer ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- config repositories.papc vcs git@github.com:pantheon-systems/pantheon_advanced_page_cache.git
-                  terminus composer ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- require drupal/pantheon_advanced_page_cache:dev-${CIRCLE_BRANCH}#${CIRCLE_SHA1}
-            - run:
-                name: composer require drupal/views_custom_cache_tag
-                command: |
-                  terminus composer ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- require drupal/views_custom_cache_tag
-            - run:
-                name: en -y views_custom_cache_tag_demo pantheon_advanced_page_cache
+                name: Enable modules
                 command: |
                   terminus drush ${TERMINUS_SITE}.${CIRCLE_BUILD_NUM} -- en -y views_custom_cache_tag_demo pantheon_advanced_page_cache
             - run:
diff --git a/web/modules/pantheon_advanced_page_cache/.circleci/scripts/setup-drupal-repo.sh b/web/modules/pantheon_advanced_page_cache/.circleci/scripts/setup-drupal-repo.sh
new file mode 100755
index 0000000000000000000000000000000000000000..90c19b121f1115cbbf45a1ee231da0571a61991c
--- /dev/null
+++ b/web/modules/pantheon_advanced_page_cache/.circleci/scripts/setup-drupal-repo.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+set -e
+export TERMINUS_ENV=$CIRCLE_BUILD_NUM
+
+# Bring the code down to Circle so that modules can be added via composer.
+git clone $(terminus connection:info ${TERMINUS_SITE}.dev --field=git_url) --branch $TERMINUS_ENV drupal-site
+cd drupal-site
+
+
+composer -- config repositories.papc vcs git@github.com:pantheon-systems/pantheon_advanced_page_cache.git
+# Composer require the given commit of this module
+composer -- require drupal/views_custom_cache_tag "drupal/pantheon_advanced_page_cache:dev-${CIRCLE_BRANCH}#${CIRCLE_SHA1}"
+
+# Don't commit a submodule
+rm -rf web/modules/contrib/pantheon_advanced_page_cache/.git/
+
+# Make a git commit
+git add .
+git commit -m 'Result of build step'
+git push --set-upstream origin $TERMINUS_ENV
diff --git a/web/modules/pantheon_advanced_page_cache/README.md b/web/modules/pantheon_advanced_page_cache/README.md
index c2df80fb940f8dcac12a49d2f902393cafdb4bb3..1ce74e3a31b6e27428da433fa2af39bf719bd5a2 100644
--- a/web/modules/pantheon_advanced_page_cache/README.md
+++ b/web/modules/pantheon_advanced_page_cache/README.md
@@ -22,6 +22,16 @@ A direct way of inspecting headers is with `curl -I`. This command will make a r
 
 `curl -IH "Pantheon-Debug:1" https://dev-cache-tags-demo.pantheonsite.io/ | grep -i Surrogate-Key-Raw`
 
+## Changing Listing Tags
+
+Prior to the 1.2 release, this module would change the cache tags used on default listings.
+This changing of was done to make cache hits more likely but resulted in [confusing cache clearing behavior](https://www.drupal.org/project/pantheon_advanced_page_cache/issues/2944229).
+Sites that installed this module prior to 1.2 should uninstall and reinstall or run this command to update their settings.
+
+```
+terminus drush [MACHINE-NAME-OF-SITE].[ENV-NAME] -- config:set pantheon_advanced_page_cache.settings --input-format=yaml   "override_list_tags" "false"
+```
+
 ## Limit on header size
 
 Pantheon's nginx configuration limits total header size to 32k.
diff --git a/web/modules/pantheon_advanced_page_cache/config/install/pantheon_advanced_page_cache.settings.yml b/web/modules/pantheon_advanced_page_cache/config/install/pantheon_advanced_page_cache.settings.yml
new file mode 100644
index 0000000000000000000000000000000000000000..68e445b930b12c56166b299b974fa192c73dc06d
--- /dev/null
+++ b/web/modules/pantheon_advanced_page_cache/config/install/pantheon_advanced_page_cache.settings.yml
@@ -0,0 +1 @@
+override_list_tags: false
\ No newline at end of file
diff --git a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml
index e8ad3870f2a5ffb6d34dddc934a0fe394bf6faf7..d276de1fd4fe86046011182e13bc7cd8b3924330 100644
--- a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml
+++ b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.info.yml
@@ -4,7 +4,7 @@ package: Performance and scalability
 type: module
 core_version_requirement: ^8 || ^9
 
-# Information added by Drupal.org packaging script on 2020-05-19
-version: '8.x-1.1'
+# Information added by Drupal.org packaging script on 2021-01-18
+version: '8.x-1.2'
 project: 'pantheon_advanced_page_cache'
-datestamp: 1589904163
+datestamp: 1611003913
diff --git a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.install b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.install
new file mode 100644
index 0000000000000000000000000000000000000000..eb7f642d692930808fab30e1b2fb219bb51c1e81
--- /dev/null
+++ b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.install
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Update functions for the Pantheon Advanced Page Cache module.
+ */
+
+/**
+ * Set override_list_tags to TRUE for backwards compatibility. We recommend manually changing to FALSE for more consistent clearing. See README
+ */
+function pantheon_advanced_page_cache_update_8001() {
+  \Drupal::configFactory()->getEditable('pantheon_advanced_page_cache.settings')->set('override_list_tags', TRUE)->save();
+}
diff --git a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml
index 6b0326c92438e22c15ea8422800aa2d3b4ea4c38..266c2398dd7956335888e638626d018b6a4eb357 100644
--- a/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml
+++ b/web/modules/pantheon_advanced_page_cache/pantheon_advanced_page_cache.services.yml
@@ -8,6 +8,6 @@ services:
       - { name: cache_tags_invalidator }
   pantheon_advanced_page_cache.cacheable_response_subscriber:
     class: Drupal\pantheon_advanced_page_cache\EventSubscriber\CacheableResponseSubscriber
-    arguments: ['@logger.channel.pantheon_advanced_page_cache']
+    arguments: ['@logger.channel.pantheon_advanced_page_cache', '@config.factory']
     tags:
       - { name: event_subscriber }
diff --git a/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php b/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php
index 905b5356ce962651602aaca05db64c4572e0b88e..b9a72a9bc6031cc43e3569880bd24803f5d3f581 100644
--- a/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php
+++ b/web/modules/pantheon_advanced_page_cache/src/EventSubscriber/CacheableResponseSubscriber.php
@@ -8,6 +8,7 @@
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Psr\Log\LoggerInterface;
 use Drupal\Core\Logger\RfcLogLevel;
+use Drupal\Core\Config\ConfigFactoryInterface;
 
 /**
  * Adds Surrogate-Key header to cacheable master responses.
@@ -21,14 +22,44 @@ class CacheableResponseSubscriber implements EventSubscriberInterface {
    */
   protected $logger;
 
+  /**
+   * Configuration Factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
   /**
    * Constructs a new DefaultExceptionHtmlSubscriber.
    *
    * @param \Psr\Log\LoggerInterface $logger
    *   The logger service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   Configuration for this module.
    */
-  public function __construct(LoggerInterface $logger) {
+  public function __construct(LoggerInterface $logger, ConfigFactoryInterface $config_factory = NULL) {
+    if (!$config_factory instanceof ConfigFactoryInterface) {
+      @trigger_error('Not passing the config factory service as the second parameter to ' . __METHOD__ . ' is deprecated in pantheon_advanced_page_cache:8.x-1.2 and will throw a type error in pantheon_advanced_page_cache:8.x-2.0. Pass an instance of \\Drupal\\Core\\Config\\ConfigFactoryInterface. See https://www.drupal.org/node/2944229', E_USER_DEPRECATED);
+      $config_factory = \Drupal::service('config.factory');
+    }
     $this->logger = $logger;
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * Returns whether entity_list tags should be overridden.
+   *
+   * Overriding these tags was the initial behavior of the 1.0 version of this
+   * module. That is no longer recommended.
+   */
+  public function getOverrideListTagsSetting() {
+    $config = $this->configFactory->get('pantheon_advanced_page_cache.settings');
+    // Only return FALSE if this config value is really set to false.
+    // A null value should return TRUE for backwards compatibility.
+    if ($config->get('override_list_tags') === FALSE) {
+      return FALSE;
+    }
+    return TRUE;
   }
 
   /**
@@ -49,8 +80,10 @@ public function onRespond(FilterResponseEvent $event) {
 
       // Rename all _list cache tags to _emit_list to avoid clearing list cache
       // tags by default.
-      foreach ($tags as $key => $tag) {
-        $tags[$key] = str_replace('_list', '_emit_list', $tag);
+      if ($this->getOverrideListTagsSetting()) {
+        foreach ($tags as $key => $tag) {
+          $tags[$key] = str_replace('_list', '_emit_list', $tag);
+        }
       }
 
       $tags_string = implode(' ', $tags);
diff --git a/web/modules/pantheon_advanced_page_cache/tests/behat/features/override_list_tag.feature b/web/modules/pantheon_advanced_page_cache/tests/behat/features/override_list_tag.feature
new file mode 100644
index 0000000000000000000000000000000000000000..a4ecbd1c4fe10d8f2a72a025da0651ac715f941c
--- /dev/null
+++ b/web/modules/pantheon_advanced_page_cache/tests/behat/features/override_list_tag.feature
@@ -0,0 +1,21 @@
+Feature: Listing tags
+In order to control caching of lists
+As an administrator
+I want to toggle the setting for overriding cache tags
+
+  @api
+  Scenario: Core behavior
+    Given there are some "article" nodes
+    And "/" is caching
+    When a generate a "article" node
+    Then "/" has been purged
+    And "/" is caching
+
+  @api @current
+  Scenario: Old override
+    Given there are some "article" nodes
+    When I run drush "config:set pantheon_advanced_page_cache.settings --input-format=yaml   override_list_tags true"
+    And "/" is caching
+    When a generate a "article" node
+    And "/" has not been purged
+
diff --git a/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml b/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml
index 89b371af46c5be905f52d26c1678f42829b06a1a..cfff2567679d75ee7b494c5e129edfb0a5e76a8c 100644
--- a/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml
+++ b/web/modules/pantheon_advanced_page_cache/tests/modules/pantheon_advanced_page_cache_test/pantheon_advanced_page_cache_test.info.yml
@@ -4,7 +4,7 @@ package: Testing
 type: module
 core_version_requirement: ^8 || ^9
 
-# Information added by Drupal.org packaging script on 2020-05-19
-version: '8.x-1.1'
+# Information added by Drupal.org packaging script on 2021-01-18
+version: '8.x-1.2'
 project: 'pantheon_advanced_page_cache'
-datestamp: 1589904163
+datestamp: 1611003913
diff --git a/web/modules/views_bulk_operations/js/frontUi.js b/web/modules/views_bulk_operations/js/frontUi.js
index 97bef561112012e4926c74117c4e73bd5f617ef4..82013da155ed4deef854abd508b30ae0153846f8 100644
--- a/web/modules/views_bulk_operations/js/frontUi.js
+++ b/web/modules/views_bulk_operations/js/frontUi.js
@@ -38,14 +38,14 @@
           if (event.which === 13) {
             event.preventDefault();
             event.stopPropagation();
-            selectionObject.update(this.checked, index, $(this).val());
+            selectionObject.update(!this.checked, index, $(this).val());
             $(this).trigger('click');
           }
           if (event.which === 32) {
-            selectionObject.update(this.checked, index, $(this).val());
+            selectionObject.update(!this.checked, index, $(this).val());
           }
         });
-        $element.on('mousedown', function (event) {
+        $element.on('click', function (event) {
           // Act only on left button click.
           if (event.which === 1) {
             selectionObject.update(this.checked, index, $(this).val());
@@ -70,8 +70,8 @@
 
         var list = {}, op = '';
         if (index === 'selection_method_change') {
-          var op = state ? 'method_include' : 'method_exclude';
-          if (!state) {
+          var op = state ? 'method_exclude' : 'method_include';
+          if (state) {
             list = this.list[index];
           }
         }
@@ -82,7 +82,7 @@
           else {
             list = this.list[index];
           }
-          op = state ? 'remove' : 'add';
+          op = state ? 'add' : 'remove';
         }
 
         var $placeholder = this.$placeholder;
@@ -167,6 +167,10 @@
           this.checked = value;
         });
 
+        // Clear the selection information if exists.
+        $vboForm.find('.vbo-info-list-wrapper').each(function () {
+          $(this).html('');
+        });
       });
 
       if ($multiSelectElement.length) {
diff --git a/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml b/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml
index cbe4230c851dbbe3d0837f8658310751ef1ee623..3b5675c624840a62212724f42cff8e6be452c8b1 100644
--- a/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml
+++ b/web/modules/views_bulk_operations/modules/actions_permissions/actions_permissions.info.yml
@@ -6,7 +6,7 @@ core_version_requirement: ^8 || ^9
 dependencies:
   - drupal:views_bulk_operations
 
-# Information added by Drupal.org packaging script on 2020-08-13
-version: '8.x-3.9'
+# Information added by Drupal.org packaging script on 2020-12-24
+version: '8.x-3.10'
 project: 'views_bulk_operations'
-datestamp: 1597319023
+datestamp: 1608795021
diff --git a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php
index 6d9e813d7d14af30026c318010150fdc9765466b..3c7b9d23cc080f6a9f0160eeb8b01256e4863171 100644
--- a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php
+++ b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/src/Plugin/Action/ViewsBulkOperationExampleAction.php
@@ -83,7 +83,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
    * Submit handler for the action configuration form.
    *
    * If not implemented, the cleaned form values will be
-   * passed direclty to the action $configuration parameter.
+   * passed directly to the action $configuration parameter.
    *
    * @param array $form
    *   Form array.
diff --git a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml
index f221f4c2ca8ff269643bd574d0424bb770885b3c..2d2965100fc775258329b7ff2eae5911bf5a18de 100644
--- a/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml
+++ b/web/modules/views_bulk_operations/modules/views_bulk_operations_example/views_bulk_operations_example.info.yml
@@ -6,7 +6,7 @@ core_version_requirement: ^8 || ^9
 dependencies:
   - drupal:views_bulk_operations
 
-# Information added by Drupal.org packaging script on 2020-08-13
-version: '8.x-3.9'
+# Information added by Drupal.org packaging script on 2020-12-24
+version: '8.x-3.10'
 project: 'views_bulk_operations'
-datestamp: 1597319023
+datestamp: 1608795021
diff --git a/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php b/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php
index b03c244932e6b983a7a239d2f0a4f3163bc0f318..643ccdce938d0e85a69ad76d625d3b81173c8d2a 100644
--- a/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php
+++ b/web/modules/views_bulk_operations/src/Commands/ViewsBulkOperationsCommands.php
@@ -76,7 +76,7 @@ public function __construct(
    * @option display-id
    *   ID of the display to use.
    * @option args
-   *   View arguments (slash is a delimeter).
+   *   View arguments (slash is a delimiter).
    * @option exposed
    *   Exposed filters (query string format).
    * @option batch-size
diff --git a/web/modules/views_bulk_operations/src/Form/ConfigureAction.php b/web/modules/views_bulk_operations/src/Form/ConfigureAction.php
index e4bce65029384a033a64e118a9b95c46131a8747..a5d4972b2f3def700dd5b6dd98de650413e445d7 100644
--- a/web/modules/views_bulk_operations/src/Form/ConfigureAction.php
+++ b/web/modules/views_bulk_operations/src/Form/ConfigureAction.php
@@ -92,7 +92,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $view_id
     $form['list'] = $this->getListRenderable($form_data);
 
     // :D Make sure the submit button is at the bottom of the form
-    // and is editale from the action buildConfigurationForm method.
+    // and is editable from the action buildConfigurationForm method.
     $form['actions']['#weight'] = 666;
     $form['actions']['submit'] = [
       '#type' => 'submit',
diff --git a/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php b/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php
index 9d83f90c122992c8d68dda3d6420daf48b8e4dab..5fe4260896908a5cfb0f4c21daac2267df09ae2a 100644
--- a/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php
+++ b/web/modules/views_bulk_operations/src/Form/ViewsBulkOperationsFormTrait.php
@@ -108,6 +108,8 @@ protected function getListRenderable(array $form_data) {
       $renderable['#title'] = $this->t('Selected @count entities:', ['@count' => $form_data['selected_count']]);
     }
 
+    $renderable['#wrapper_attributes'] = ['class' => ['vbo-info-list-wrapper']];
+
     return $renderable;
   }
 
diff --git a/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php b/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php
index 9243b259c3419df15e67a649d1e4626545d8fa8a..0c1c08cef0afcc2a1730834c2b26acd9cfc6c10a 100644
--- a/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php
+++ b/web/modules/views_bulk_operations/src/Plugin/Action/EntityDeleteAction.php
@@ -3,6 +3,7 @@
 namespace Drupal\views_bulk_operations\Plugin\Action;
 
 use Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionBase;
+use Drupal\Core\Entity\TranslatableInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -10,7 +11,7 @@
  *
  * @Action(
  *   id = "views_bulk_operations_delete_entity",
- *   label = @Translation("Delete selected entities"),
+ *   label = @Translation("Delete selected entities / translations"),
  *   type = "",
  *   confirm = TRUE,
  * )
@@ -21,8 +22,16 @@ class EntityDeleteAction extends ViewsBulkOperationsActionBase {
    * {@inheritdoc}
    */
   public function execute($entity = NULL) {
-    $entity->delete();
-    return $this->t('Delete entities');
+    if ($entity instanceof TranslatableInterface && !$entity->isDefaultTranslation()) {
+      $untranslated_entity = $entity->getUntranslated();
+      $untranslated_entity->removeTranslation($entity->language()->getId());
+      $untranslated_entity->save();
+      return $this->t('Delete translations');
+    }
+    else {
+      $entity->delete();
+      return $this->t('Delete entities');
+    }
   }
 
   /**
diff --git a/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php b/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php
index 8579de308f6f74c5a8a24262c8899417c25cb771..1f1f00d7bd68f8b880d478ee7c366727e6ae79c0 100644
--- a/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php
+++ b/web/modules/views_bulk_operations/src/Plugin/views/field/ViewsBulkOperationsBulkForm.php
@@ -202,8 +202,11 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
    * This function must be called a bit later, when the view
    * query has been built. Also, no point doing this on the view
    * admin page.
+   *
+   * @param array $bulk_form_keys
+   *   The calculated bulk form keys.
    */
-  protected function updateTempstoreData() {
+  protected function updateTempstoreData(array $bulk_form_keys = NULL) {
     // Initialize tempstore object and get data if available.
     $this->tempStoreData = $this->getTempstoreData($this->view->id(), $this->view->current_display);
 
@@ -216,6 +219,11 @@ protected function updateTempstoreData() {
       'exposed_input' => $this->view->getExposedInput(),
     ];
 
+    // Add bulk form keys when the form is displayed.
+    if (isset($bulk_form_keys)) {
+      $variable['bulk_form_keys'] = $bulk_form_keys;
+    }
+
     // A fix to account for empty initial exposed input vs the default values
     // difference.
     if (empty($variable['exposed_input'])) {
@@ -580,8 +588,29 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
     $action_options = $this->getBulkOptions();
     if (!empty($this->view->result) && !empty($action_options)) {
 
-      // Update tempstore data.
-      $this->updateTempstoreData();
+      // Calculate bulk form keys for all rows.
+      $bulk_form_keys = [];
+      $base_field = $this->view->storage->get('base_field');
+      foreach ($this->view->result as $row_index => $row) {
+        $entity = $this->getEntity($row);
+        $bulk_form_keys[$row_index] = self::calculateEntityBulkFormKey(
+          $entity,
+          $row->{$base_field}
+        );
+      }
+
+      // Update and fetch tempstore data to be available from this point
+      // as it's needed for proper functioning of further logic.
+      // Update tempstore data with bulk form keys only when the form is
+      // displayed, but not when the form is being built before submission
+      // (data is subject to change - new entities added or deleted after
+      // the form display). TODO: consider using $form_state->set() instead.
+      if (empty($form_state->getUserInput())) {
+        $this->updateTempstoreData($bulk_form_keys);
+      }
+      else {
+        $this->updateTempstoreData();
+      }
 
       $form[$this->options['id']]['#tree'] = TRUE;
 
@@ -595,14 +624,8 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
 
       // Render checkboxes for all rows.
       $page_selected = [];
-      $base_field = $this->view->storage->get('base_field');
       foreach ($this->view->result as $row_index => $row) {
-        $entity = $this->getEntity($row);
-        $bulk_form_key = self::calculateEntityBulkFormKey(
-          $entity,
-          $row->{$base_field}
-        );
-
+        $bulk_form_key = $bulk_form_keys[$row_index];
         $checked = isset($this->tempStoreData['list'][$bulk_form_key]);
         if (!empty($this->tempStoreData['exclude_mode'])) {
           $checked = !$checked;
@@ -618,6 +641,15 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
           '#default_value' => $checked,
           '#return_value' => $bulk_form_key,
         ];
+
+        // We should use #value instead of #default_value to always apply
+        // the plugin's own saved checkbox state (data being changed after form
+        // submission results in wrong values applied by the FAPI),
+        // however - automated tests fail if it's done this way.
+        // We have to apply values conditionally for tests to pass.
+        if (isset($element['#value']) && $element['#value'] != $checked) {
+          $element['#value'] = $checked;
+        }
       }
 
       // Ensure a consistent container for filters/operations
@@ -847,26 +879,22 @@ public function viewsFormSubmit(array &$form, FormStateInterface $form_state) {
       }
 
       // Update list data with the current page selection.
-      if ($form_state->getValue('select_all')) {
-        foreach ($form_state->getValue($this->options['id']) as $row_index => $bulkFormKey) {
-          if ($bulkFormKey) {
-            unset($this->tempStoreData['list'][$bulkFormKey]);
-          }
-          else {
-            $row_bulk_form_key = $form[$this->options['id']][$row_index]['#return_value'];
-            $this->tempStoreData['list'][$row_bulk_form_key] = $this->getListItem($row_bulk_form_key);
-          }
-        }
+      $selected_keys = [];
+      $input = $form_state->getUserInput();
+      foreach ($input[$this->options['id']] as $row_index => $bulk_form_key) {
+        $selected_keys[$bulk_form_key] = $bulk_form_key;
       }
-      else {
-        foreach ($form_state->getValue($this->options['id']) as $row_index => $bulkFormKey) {
-          if ($bulkFormKey) {
-            $this->tempStoreData['list'][$bulkFormKey] = $this->getListItem($bulkFormKey);
-          }
-          else {
-            $row_bulk_form_key = $form[$this->options['id']][$row_index]['#return_value'];
-            unset($this->tempStoreData['list'][$row_bulk_form_key]);
-          }
+      $select_all = $form_state->getValue('select_all');
+
+      foreach ($this->tempStoreData['bulk_form_keys'] as $bulk_form_key) {
+        if (
+          (isset($selected_keys[$bulk_form_key]) && !$select_all) ||
+          (!isset($selected_keys[$bulk_form_key]) && $select_all)
+        ) {
+          $this->tempStoreData['list'][$bulk_form_key] = $this->getListItem($bulk_form_key);
+        }
+        else {
+          unset($this->tempStoreData['list'][$bulk_form_key]);
         }
       }
 
@@ -971,6 +999,18 @@ public function viewsFormValidate(&$form, FormStateInterface $form_state) {
         $actionObject->validateConfigurationForm($form['header'][$this->options['id']]['configuration'], $form_state);
       }
     }
+
+    // Update bulk form key list if the form has errors, as data might have
+    // changed before validation took place.
+    if ($form_state->getErrors()) {
+      $bulk_form_keys = [];
+      foreach ($form[$this->options['id']] as $row_index => $element) {
+        if (is_numeric($row_index) && isset($element['#return_value'])) {
+          $bulk_form_keys[$row_index] = $element['#return_value'];
+        }
+      }
+      $this->updateTempstoreData($bulk_form_keys);
+    }
   }
 
   /**
diff --git a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php
index 40af081bb9af06ef4ca7d1137af36110e22ddcc6..00db7e5153e28cc0165d5dd0fa85ec6bb5783566 100644
--- a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php
+++ b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionManager.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Symfony\Component\EventDispatcher\Event;
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
 
@@ -26,6 +27,13 @@ class ViewsBulkOperationsActionManager extends ActionManager {
    */
   protected $eventDispatcher;
 
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
   /**
    * Additional parameters passed to alter event.
    *
@@ -45,15 +53,21 @@ class ViewsBulkOperationsActionManager extends ActionManager {
    *   The module handler to invoke the alter hook with.
    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
    *   The event dispatcher service.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   *   Entity type manager.
    */
   public function __construct(
     \Traversable $namespaces,
     CacheBackendInterface $cacheBackend,
     ModuleHandlerInterface $moduleHandler,
-    EventDispatcherInterface $eventDispatcher
+    EventDispatcherInterface $eventDispatcher,
+    EntityTypeManagerInterface $entityTypeManager
   ) {
     parent::__construct($namespaces, $cacheBackend, $moduleHandler);
+
     $this->eventDispatcher = $eventDispatcher;
+    $this->entityTypeManager = $entityTypeManager;
+
     $this->setCacheBackend($cacheBackend, 'views_bulk_operations_action_info');
   }
 
@@ -63,18 +77,28 @@ public function __construct(
   protected function findDefinitions() {
     $definitions = $this->getDiscovery()->getDefinitions();
 
-    // Incompatible actions.
-    $incompatible = [
-      // Deprecated anyway, to be deleted eventually.
-      'node_delete_action',
-      // Those are up to date.
-      'entity:delete_action:node',
-      'user_cancel_user_action',
-    ];
-
+    $entity_type_definitions = $this->entityTypeManager->getDefinitions();
     foreach ($definitions as $plugin_id => &$definition) {
       $this->processDefinition($definition, $plugin_id);
-      if (empty($definition) || in_array($definition['id'], $incompatible)) {
+
+      // We only allow actions of existing entity type and empty
+      // type meaning it's applicable to all entity types.
+      if (
+        empty($definition) ||
+        (
+          !empty($definition['type']) &&
+          !isset($entity_type_definitions[$definition['type']])
+        )
+      ) {
+        unset($definitions[$plugin_id]);
+      }
+
+      // Filter definitions that are incompatible due to applied core
+      // configuration form workaround (using confirm_form_route for config
+      // forms and using action execute() method for purposes other than
+      // actual action execution). Luckily, core also has useful actions
+      // without the workaround, like node_assign_owner_action.
+      if (!in_array('Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionInterface', class_implements($definition['class'])) && (!empty($definition['confirm_form_route_name']))) {
         unset($definitions[$plugin_id]);
       }
     }
diff --git a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php
index 801f647e15b78ed6fd747e8abc89510ee482d2c6..c40294a84a2bb3793607f56732ed42b5a775cdbb 100644
--- a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php
+++ b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsActionProcessor.php
@@ -127,7 +127,7 @@ public function initialize(array $view_data, $view = NULL) {
       $this->queue = [];
     }
 
-    $this->excludeMode = $view_data['exclude_mode'];
+    $this->excludeMode = !empty($view_data['exclude_mode']);
 
     if (isset($view_data['action_id'])) {
       if (!isset($view_data['configuration'])) {
@@ -210,7 +210,7 @@ public function getPageList($page) {
       $this->view->setExposedInput(['_views_bulk_operations_override' => TRUE]);
     }
 
-    // In some cases we may encounter nondeterministic bahaviour in
+    // In some cases we may encounter nondeterministic behaviour in
     // db queries with sorts allowing different order of results.
     // To fix this we're removing all sorts and setting one sorting
     // rule by the view base id field.
@@ -303,7 +303,7 @@ public function populateQueue(array $data, array &$context = []) {
       $batch_list = $list;
     }
 
-    $this->view->setItemsPerPage(0);
+    $this->view->setItemsPerPage($batch_size);
     $this->view->setCurrentPage(0);
     $this->view->setOffset(0);
     $this->view->initHandlers();
diff --git a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php
index d72ae49e0eddec0be7e605e254418708d527c015..a3466f4b340387cc65ca05074d98751e6b06cee2 100644
--- a/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php
+++ b/web/modules/views_bulk_operations/src/Service/ViewsBulkOperationsViewData.php
@@ -38,7 +38,7 @@ class ViewsBulkOperationsViewData implements ViewsBulkOperationsViewDataInterfac
   protected $view;
 
   /**
-   * The realtionship ID.
+   * The relationship ID.
    *
    * @var string
    */
diff --git a/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php b/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php
index b809ebf464d75f89ed63eaf8c7f0a08537bf0601..97356a16fa3cac36b3a57cfb060fb4e2ef666d6f 100644
--- a/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php
+++ b/web/modules/views_bulk_operations/src/ViewsBulkOperationsBatch.php
@@ -77,7 +77,7 @@ public static function getList(array $data, array &$context) {
    * Save generated list to user tempstore.
    *
    * @param bool $success
-   *   Was the process successfull?
+   *   Was the process successful?
    * @param array $results
    *   Batch process results array.
    * @param array $operations
@@ -145,7 +145,7 @@ public static function operation(array $data, array &$context) {
    * Batch finished callback.
    *
    * @param bool $success
-   *   Was the process successfull?
+   *   Was the process successful?
    * @param array $results
    *   Batch process results array.
    * @param array $operations
diff --git a/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php b/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php
index b008520b345e89065ee653f413b89622a363b430..3c700d685a5ff52159e1102c423f8da2b755ff0f 100644
--- a/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php
+++ b/web/modules/views_bulk_operations/tests/src/Functional/ViewsBulkOperationsBulkFormTest.php
@@ -56,47 +56,6 @@ protected function setUp() {
 
   }
 
-  /**
-   * Helper function to test a batch process.
-   *
-   * After checking if we're on a Batch API page,
-   * the iterations are executed, the finished page is opened
-   * and browser redirects to the final destination.
-   *
-   * NOTE: As of Drupal 8.4, functional test
-   * automatically redirects user through all Batch API pages,
-   * so this function is not longer needed.
-   */
-  protected function assertBatchProcess() {
-    // Get the current batch ID.
-    $current_url = $this->getUrl();
-    $q = substr($current_url, strrpos($current_url, '/') + 1);
-    $this->assertEquals('batch?', substr($q, 0, 6), 'We are on a Batch API page.');
-
-    preg_match('#id=([0-9]+)#', $q, $matches);
-    $batch_id = $matches[1];
-
-    // Proceed with the operations.
-    // Assumption: all operations will be completed within a single request.
-    // TODO: modify code to include an option when the assumption is false.
-    do {
-      $this->drupalGet('batch', [
-        'query' => [
-          'id' => $batch_id,
-          'op' => 'do_nojs',
-        ],
-      ]);
-    } while (FALSE);
-
-    // Get the finished page.
-    $this->drupalGet('batch', [
-      'query' => [
-        'id' => $batch_id,
-        'op' => 'finished',
-      ],
-    ]);
-  }
-
   /**
    * Tests the VBO bulk form with simple test action.
    */
diff --git a/web/modules/views_bulk_operations/tests/src/FunctionalJavascript/ViewsBulkOperationsBulkFormTest.php b/web/modules/views_bulk_operations/tests/src/FunctionalJavascript/ViewsBulkOperationsBulkFormTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7263470640aa5648322ffbd247c2d5d95206d348
--- /dev/null
+++ b/web/modules/views_bulk_operations/tests/src/FunctionalJavascript/ViewsBulkOperationsBulkFormTest.php
@@ -0,0 +1,143 @@
+<?php
+
+namespace Drupal\Tests\views_bulk_operations\FunctionalJavaScript;
+
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\views_bulk_operations\Form\ViewsBulkOperationsFormTrait;
+
+/**
+ * @coversDefaultClass \Drupal\views_bulk_operations\Plugin\views\field\ViewsBulkOperationsBulkForm
+ * @group views_bulk_operations
+ */
+class ViewsBulkOperationsBulkFormTest extends WebDriverTestBase {
+
+  use ViewsBulkOperationsFormTrait;
+
+  const TEST_NODE_COUNT = 15;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stable';
+
+
+  /**
+   * The assert session.
+   *
+   * @var \Drupal\Tests\WebAssert
+   */
+  protected $assertSession;
+
+  /**
+   * The page element.
+   *
+   * @var \Behat\Mink\Element\DocumentElement
+   */
+  protected $page;
+
+
+  /**
+   * The selected indexes of rows.
+   *
+   * @var array
+   */
+  protected $selectedIndexes = [];
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'node',
+    'views',
+    'views_bulk_operations',
+    'views_bulk_operations_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create some nodes for testing.
+    $this->drupalCreateContentType(['type' => 'page']);
+    for ($i = 1; $i <= self::TEST_NODE_COUNT; $i++) {
+      $this->drupalCreateNode([
+        'type' => 'page',
+        'title' => 'Title ' . $i,
+      ]);
+    }
+    $admin_user = $this->drupalCreateUser(
+      [
+        'edit any page content',
+        'create page content',
+        'delete any page content',
+      ]);
+    $this->drupalLogin($admin_user);
+
+    $this->assertSession = $this->assertSession();
+    $this->page = $this->getSession()->getPage();
+
+    $this->drupalGet('/views-bulk-operations-test');
+
+    // Make sure a checkbox appears on all rows and the button exists.
+    for ($i = 0; $i < 4; $i++) {
+      $this->assertSession->fieldExists('edit-views-bulk-operations-bulk-form-' . $i);
+    }
+    $this->assertSession->buttonExists('Simple test action');
+
+    $this->selectedIndexes = [0, 1, 3];
+
+    foreach ($this->selectedIndexes as $selected_index) {
+      $this->page->checkField('edit-views-bulk-operations-bulk-form-' . $selected_index);
+    }
+
+  }
+
+  /**
+   * Tests the VBO bulk form without dynamic insertion.
+   */
+  public function testViewsBulkOperationsWithOutDynamicInsertion() {
+
+    $this->page->pressButton('Simple test action');
+
+    foreach ($this->selectedIndexes as $index) {
+      $this->assertSession->pageTextContains(sprintf('Test action (preconfig: Test setting, label: Title %s)', self::TEST_NODE_COUNT - $index));
+    }
+    $this->assertSession->pageTextContains(sprintf('Action processing results: Test (%s)', count($this->selectedIndexes)));
+
+  }
+
+  /**
+   * Tests the VBO bulk form with dynamic insertion.
+   *
+   * Nodes inserted right after selecting targeted row(s) of the view.
+   */
+  public function testViewsBulkOperationsWithDynamicInsertion() {
+
+    // Insert nodes.
+    $nodes = [];
+    for ($i = 100; $i < 100 + self::TEST_NODE_COUNT; $i++) {
+      $nodes[] = $this->drupalCreateNode([
+        'type' => 'page',
+        'title' => 'Title ' . $i,
+      ]);
+    }
+
+    $this->page->pressButton('Simple test action');
+
+    foreach ($this->selectedIndexes as $index) {
+      $this->assertSession->pageTextContains(sprintf('Test action (preconfig: Test setting, label: Title %s)', self::TEST_NODE_COUNT - $index));
+    }
+    $this->assertSession->pageTextContains(sprintf('Action processing results: Test (%s)', count($this->selectedIndexes)));
+
+    // Remove nodes inserted in the middle.
+    foreach ($nodes as $node) {
+      $node->delete();
+    }
+
+  }
+
+}
diff --git a/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php b/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php
index 6c80cedd5d5f7bb0a46ce9d9215f3c005873d3f6..032e3a45cc72c81adcda62fc8d57a4682d906922 100644
--- a/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php
+++ b/web/modules/views_bulk_operations/tests/src/Kernel/ViewsBulkOperationsKernelTestBase.php
@@ -262,7 +262,7 @@ protected function executeAction(array $vbo_data) {
       $vbo_data['action_label'] = (string) $action_definition['label'];
     }
 
-    // Account for eclude mode.
+    // Account for exclude mode.
     if ($vbo_data['exclude_mode']) {
       $vbo_data['exclude_list'] = $vbo_data['list'];
       $vbo_data['list'] = [];
diff --git a/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml b/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml
index d38540259e69437dd3496847f8d19f16546fd188..1d3513193f973e4882c9f1e188fbe7a971d8172b 100644
--- a/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml
+++ b/web/modules/views_bulk_operations/tests/views_bulk_operations_test/views_bulk_operations_test.info.yml
@@ -7,7 +7,7 @@ dependencies:
   - drupal:views_bulk_operations
   - drupal:node
 
-# Information added by Drupal.org packaging script on 2020-08-13
-version: '8.x-3.9'
+# Information added by Drupal.org packaging script on 2020-12-24
+version: '8.x-3.10'
 project: 'views_bulk_operations'
-datestamp: 1597319023
+datestamp: 1608795021
diff --git a/web/modules/views_bulk_operations/views_bulk_operations.drush.inc b/web/modules/views_bulk_operations/views_bulk_operations.drush.inc
index 4593d13f58f4cf606e594752219be1e9e158d597..8ac8bd17600bca0fbf10920e1312110187a7043d 100644
--- a/web/modules/views_bulk_operations/views_bulk_operations.drush.inc
+++ b/web/modules/views_bulk_operations/views_bulk_operations.drush.inc
@@ -22,7 +22,7 @@ function views_bulk_operations_drush_command() {
       ],
       'options' => [
         'display-id' => 'ID of the display to use (default: default)',
-        'args' => 'View arguments (slash is a delimeter, default: none)',
+        'args' => 'View arguments (slash is a delimiter, default: none)',
         'exposed' => 'Exposed filters (query string format)',
         'batch-size' => 'Processing batch size (default: 100)',
         'config' => 'Action configuration (query string format)',
@@ -77,7 +77,7 @@ function _views_bulk_operations_timer($debug = TRUE, $id = NULL) {
 }
 
 /**
- * The vbo-exec command executtion function.
+ * The vbo-exec command execution function.
  *
  * @param string $view_id
  *   The ID of the view to use.
diff --git a/web/modules/views_bulk_operations/views_bulk_operations.info.yml b/web/modules/views_bulk_operations/views_bulk_operations.info.yml
index 0c013455895cbb137b3edb4186600f914730ef73..9539dbe95dbe7a65e514e269b8d624345a6303cf 100644
--- a/web/modules/views_bulk_operations/views_bulk_operations.info.yml
+++ b/web/modules/views_bulk_operations/views_bulk_operations.info.yml
@@ -6,7 +6,7 @@ core_version_requirement: ^8.8 || ^9
 dependencies:
   - drupal:views
 
-# Information added by Drupal.org packaging script on 2020-08-13
-version: '8.x-3.9'
+# Information added by Drupal.org packaging script on 2020-12-24
+version: '8.x-3.10'
 project: 'views_bulk_operations'
-datestamp: 1597319023
+datestamp: 1608795021
diff --git a/web/modules/views_bulk_operations/views_bulk_operations.services.yml b/web/modules/views_bulk_operations/views_bulk_operations.services.yml
index ef64d9e476501b7c1a8bcd8589255fb65f2d2858..3937a3d0273cd1e5e8aa1014d5d22abe86fa31ff 100644
--- a/web/modules/views_bulk_operations/views_bulk_operations.services.yml
+++ b/web/modules/views_bulk_operations/views_bulk_operations.services.yml
@@ -7,7 +7,7 @@ services:
     arguments: ['@views_bulk_operations.data', '@plugin.manager.views_bulk_operations_action', '@current_user', '@module_handler']
   plugin.manager.views_bulk_operations_action:
     class: Drupal\views_bulk_operations\Service\ViewsBulkOperationsActionManager
-    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher']
+    arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@event_dispatcher', '@entity_type.manager']
   views_bulk_operations.access:
     class: Drupal\views_bulk_operations\Access\ViewsBulkOperationsAccess
     arguments: ['@tempstore.private']