From 2137eecddf4af0a071380ad22cce42377898b0ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:05:21 +0100 Subject: [PATCH 01/34] Check for good measure again, that a user is able to edit an entity in an admin form issue #1283 --- src/Controller/AdminPages/BaseAdminController.php | 2 ++ src/Form/AdminPages/BaseEntityAdminForm.php | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Controller/AdminPages/BaseAdminController.php b/src/Controller/AdminPages/BaseAdminController.php index 7c109751..c737e291 100644 --- a/src/Controller/AdminPages/BaseAdminController.php +++ b/src/Controller/AdminPages/BaseAdminController.php @@ -195,6 +195,8 @@ abstract class BaseAdminController extends AbstractController $this->commentHelper->setMessage($form['log_comment']->getData()); + //In principle, the form should be disabled, if the edit permission is not granted, but for good measure, we also check it here, before saving changes. + $this->denyAccessUnlessGranted('edit', $entity); $em->persist($entity); $em->flush(); $this->addFlash('success', 'entity.edit_flash'); diff --git a/src/Form/AdminPages/BaseEntityAdminForm.php b/src/Form/AdminPages/BaseEntityAdminForm.php index f4bf37f8..bf005882 100644 --- a/src/Form/AdminPages/BaseEntityAdminForm.php +++ b/src/Form/AdminPages/BaseEntityAdminForm.php @@ -121,6 +121,7 @@ class BaseEntityAdminForm extends AbstractType 'label' => 'entity.edit.alternative_names.label', 'help' => 'entity.edit.alternative_names.help', 'empty_data' => null, + 'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity), 'attr' => [ 'class' => 'tagsinput', 'data-controller' => 'elements--tagsinput', From c5496655785c9f88a88ffc9b87dbd7ec84c62470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:24:29 +0100 Subject: [PATCH 02/34] Fixed flash messages in admin pages --- templates/_turbo_control.html.twig | 20 ++++++++------------ templates/admin/base_admin.html.twig | 5 +---- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/templates/_turbo_control.html.twig b/templates/_turbo_control.html.twig index 281b21f2..a9f78c2e 100644 --- a/templates/_turbo_control.html.twig +++ b/templates/_turbo_control.html.twig @@ -1,23 +1,19 @@ {% block flashes %} {# Insert flashes #} - + {% endblock %} - - {# Insert info about when the sidebar trees were updated last time, so the sidebar_tree_controller can decide if it needs to reload the tree #} diff --git a/templates/admin/base_admin.html.twig b/templates/admin/base_admin.html.twig index e9fc0fb9..f710981d 100644 --- a/templates/admin/base_admin.html.twig +++ b/templates/admin/base_admin.html.twig @@ -195,10 +195,7 @@ {% endif %} - - {# Include turbo control things, so we can still control page title and reloading #} - {% include "_turbo_control.html.twig" %} - {% endblock %} \ No newline at end of file + {% endblock %} From a07170187099433ecbaecbc6830ddb6e0bdb4de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:27:06 +0100 Subject: [PATCH 03/34] Add cache pool clear hint to error pages Related to #1279 --- .../bundles/TwigBundle/Exception/error500.html.twig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/bundles/TwigBundle/Exception/error500.html.twig b/templates/bundles/TwigBundle/Exception/error500.html.twig index 40a418c2..a4e5827b 100644 --- a/templates/bundles/TwigBundle/Exception/error500.html.twig +++ b/templates/bundles/TwigBundle/Exception/error500.html.twig @@ -17,7 +17,7 @@ Can not load frontend assets.

Try following things:

  • Run yarn install and yarn build in Part-DB folder.
  • -
  • Run php bin/console cache:clear
  • +
  • Run php bin/console cache:clear and php bin/console cache:pool:clear --all
{% elseif exception.class == "Doctrine\\DBAL\\Exception\\InvalidFieldNameException" or exception.class == "Doctrine\\DBAL\\Exception\\TableNotFoundException" @@ -26,21 +26,21 @@
  • Check if the DATABASE_URL in .env.local (or docker configure) is correct
  • Run php bin/console doctrine:migrations:migrate to upgrade database schema
  • -
  • Run php bin/console cache:clear
  • +
  • Run php bin/console cache:clear and php bin/console cache:pool:clear --all
{% elseif exception.class == "Doctrine\\DBAL\\Exception\\DriverException" %} Error while executing database query.
This is maybe caused by an old database schema.

Try following things:

  • Check if the DATABASE_URL in .env.local (or docker configure) is correct
  • Run php bin/console doctrine:migrations:migrate to upgrade database schema (if upgrade is available)
  • -
  • Run php bin/console cache:clear
  • +
  • Run php bin/console cache:clear and php bin/console cache:pool:clear --all
  • If this issue persist, create a ticket at GitHub.
{% else %} You could try following things, if this error is unexpected:
  • Check var/log/prod.log (or docker logs when Part-DB is running inside a docker container) for additional informations
  • -
  • Run php bin/console cache:clear to clear cache
  • +
  • Run php bin/console cache:clear and php bin/console cache:pool:clear --all to clear caches
{% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} From df3262a3f73d8e19928478037ef59e8c880b911a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:28:50 +0100 Subject: [PATCH 04/34] Moved cache.settings to cache.system adapter to ensure it is cleared on updating Fixes #1279 --- config/packages/cache.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/packages/cache.yaml b/config/packages/cache.yaml index 846033d6..c1816aa2 100644 --- a/config/packages/cache.yaml +++ b/config/packages/cache.yaml @@ -25,5 +25,5 @@ framework: adapter: cache.app cache.settings: - adapter: cache.app + adapter: cache.system tags: true From f15979ed11d06d7dc21bb44ae021bf299002c07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:33:10 +0100 Subject: [PATCH 05/34] Run cache:pool:clear --all instead of cache:clear in updater to clear really all cache pools, even app ones --- src/Services/System/UpdateExecutor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Services/System/UpdateExecutor.php b/src/Services/System/UpdateExecutor.php index 2fe54173..70aea23f 100644 --- a/src/Services/System/UpdateExecutor.php +++ b/src/Services/System/UpdateExecutor.php @@ -420,7 +420,7 @@ class UpdateExecutor // Step 11: Clear cache $stepStart = microtime(true); $this->runCommand([ - 'php', 'bin/console', 'cache:clear', + 'php', 'bin/console', 'cache:pool:clear', '--all', '--env=prod', '--no-interaction', ], 'Clear cache', 120); @@ -489,7 +489,7 @@ class UpdateExecutor // Clear cache after rollback $this->runCommand([ - 'php', 'bin/console', 'cache:clear', + 'php', 'bin/console', 'cache:pool:clear', '--all', '--env=prod', ], 'Clear cache after rollback', 120); $log('rollback_cache', 'Cleared cache after rollback', true); From af6ddffa1dd996d669251baa368eef60fff6920d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:37:59 +0100 Subject: [PATCH 06/34] Check that user has general access rights to partdb See #1283 --- src/Controller/TypeaheadController.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Controller/TypeaheadController.php b/src/Controller/TypeaheadController.php index 39821f59..b84f3dc0 100644 --- a/src/Controller/TypeaheadController.php +++ b/src/Controller/TypeaheadController.php @@ -71,7 +71,10 @@ class TypeaheadController extends AbstractController #[Route(path: '/builtInResources/search', name: 'typeahead_builtInRessources')] public function builtInResources(Request $request, BuiltinAttachmentsFinder $finder): JsonResponse { - $query = $request->get('query'); + //Ensure that the user can access Part-DB at all + $this->denyAccessUnlessGranted('HAS_ACCESS_PERMISSIONS'); + + $query = $request->query->getString('query'); $array = $finder->find($query); $result = []; From a6299494791a92595c8cf21643e6580b4436ac99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 23:38:32 +0100 Subject: [PATCH 07/34] Bump actions/download-artifact from 7 to 8 (#1278) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker_build.yml | 2 +- .github/workflows/docker_frankenphp.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 1eff846e..194af17d 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -113,7 +113,7 @@ jobs: steps: - name: Download digests - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: path: /tmp/digests pattern: digests-* diff --git a/.github/workflows/docker_frankenphp.yml b/.github/workflows/docker_frankenphp.yml index 8acb5c22..28b82344 100644 --- a/.github/workflows/docker_frankenphp.yml +++ b/.github/workflows/docker_frankenphp.yml @@ -114,7 +114,7 @@ jobs: steps: - name: Download digests - uses: actions/download-artifact@v7 + uses: actions/download-artifact@v8 with: path: /tmp/digests pattern: digests-* From 77ef77961d8b7b1791db8a2c61381eb601ea67d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 23:38:48 +0100 Subject: [PATCH 08/34] Bump actions/upload-artifact from 6 to 7 (#1277) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/assets_artifact_build.yml | 4 ++-- .github/workflows/docker_build.yml | 2 +- .github/workflows/docker_frankenphp.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/assets_artifact_build.yml b/.github/workflows/assets_artifact_build.yml index 3409b7fd..2622ca33 100644 --- a/.github/workflows/assets_artifact_build.yml +++ b/.github/workflows/assets_artifact_build.yml @@ -80,13 +80,13 @@ jobs: run: zip -r /tmp/partdb_assets.zip public/build/ vendor/ - name: Upload assets artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: Only dependencies and built assets path: /tmp/partdb_assets.zip - name: Upload full artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: Full Part-DB including dependencies and built assets path: /tmp/partdb_with_assets.zip diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 194af17d..97c7f0cd 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -98,7 +98,7 @@ jobs: - name: Upload digest if: github.event_name != 'pull_request' - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: digests-${{ matrix.platform-slug }} path: /tmp/digests/* diff --git a/.github/workflows/docker_frankenphp.yml b/.github/workflows/docker_frankenphp.yml index 28b82344..0a1cd515 100644 --- a/.github/workflows/docker_frankenphp.yml +++ b/.github/workflows/docker_frankenphp.yml @@ -99,7 +99,7 @@ jobs: - name: Upload digest if: github.event_name != 'pull_request' - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: digests-${{ matrix.platform-slug }} path: /tmp/digests/* From 30ece644232d828f88254fb19529908bdab7551d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:39:26 +0100 Subject: [PATCH 09/34] Update KiCad symbols and footprints lists (#1282) Co-authored-by: github-actions[bot] --- public/kicad/footprints.txt | 2 +- public/kicad/symbols.txt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/kicad/footprints.txt b/public/kicad/footprints.txt index be6020cb..51f99de5 100644 --- a/public/kicad/footprints.txt +++ b/public/kicad/footprints.txt @@ -1,4 +1,4 @@ -# Generated on Sun Mar 1 11:46:09 UTC 2026 +# Generated on Tue Mar 3 14:26:21 UTC 2026 # This file contains all footprints available in the offical KiCAD library Audio_Module:Reverb_BTDR-1H Audio_Module:Reverb_BTDR-1V diff --git a/public/kicad/symbols.txt b/public/kicad/symbols.txt index 9941ad2c..984e4d66 100644 --- a/public/kicad/symbols.txt +++ b/public/kicad/symbols.txt @@ -1,4 +1,4 @@ -# Generated on Sun Mar 1 11:46:51 UTC 2026 +# Generated on Tue Mar 3 14:27:05 UTC 2026 # This file contains all symbols available in the offical KiCAD library 4xxx:14528 4xxx:14529 @@ -20842,6 +20842,9 @@ Sensor_Pressure:40PC015G Sensor_Pressure:40PC100G Sensor_Pressure:40PC150G Sensor_Pressure:40PC250G +Sensor_Pressure:ABPxxxxxxxxx0 +Sensor_Pressure:ABPxxxxxxxxxA +Sensor_Pressure:ABPxxxxxxxxxS Sensor_Pressure:BMP280 Sensor_Pressure:ILPS28QSW Sensor_Pressure:LPS22DF From a6ee68d75a31809a349074957bf493b58c865bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:54:18 +0100 Subject: [PATCH 10/34] Ensure that user has read permission to part and category to prevent IPN info leakage issue #1283 --- src/Controller/TypeaheadController.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Controller/TypeaheadController.php b/src/Controller/TypeaheadController.php index b84f3dc0..95480329 100644 --- a/src/Controller/TypeaheadController.php +++ b/src/Controller/TypeaheadController.php @@ -208,9 +208,16 @@ class TypeaheadController extends AbstractController /** @var Category|null $category */ $category = $entityManager->getRepository(Category::class)->find($categoryId); + //Ensure the user has access to both the part and the category + $this->denyAccessUnlessGranted('read', $part); + if ($category !== null) { + $this->denyAccessUnlessGranted('read', $category); + } + $clonedPart = clone $part; $clonedPart->setCategory($category); + $partRepository = $entityManager->getRepository(Part::class); $ipnSuggestions = $partRepository->autoCompleteIpn($clonedPart, $description, $this->ipnSuggestSettings->suggestPartDigits); From 1c28efb12ea71ca6c3621779db6cba644e2984fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Wed, 4 Mar 2026 23:58:41 +0100 Subject: [PATCH 11/34] Updated dependencies --- composer.lock | 44 +- yarn.lock | 1385 ++++++++++++++++++++++++------------------------- 2 files changed, 712 insertions(+), 717 deletions(-) diff --git a/composer.lock b/composer.lock index 71af9169..8e010d2b 100644 --- a/composer.lock +++ b/composer.lock @@ -4130,16 +4130,16 @@ }, { "name": "dompdf/dompdf", - "version": "v3.1.4", + "version": "v3.1.5", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "db712c90c5b9868df3600e64e68da62e78a34623" + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623", - "reference": "db712c90c5b9868df3600e64e68da62e78a34623", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", "shasum": "" }, "require": { @@ -4188,9 +4188,9 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v3.1.4" + "source": "https://github.com/dompdf/dompdf/tree/v3.1.5" }, - "time": "2025-10-29T12:43:30+00:00" + "time": "2026-03-03T13:54:37+00:00" }, { "name": "dompdf/php-font-lib", @@ -9502,16 +9502,16 @@ }, { "name": "sabberworm/php-css-parser", - "version": "v9.2.0", + "version": "v9.3.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "59373045e11ad47b5c18fc615feee0219e42f6d3" + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/59373045e11ad47b5c18fc615feee0219e42f6d3", - "reference": "59373045e11ad47b5c18fc615feee0219e42f6d3", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", "shasum": "" }, "require": { @@ -9538,7 +9538,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "9.3.x-dev" + "dev-main": "9.4.x-dev" } }, "autoload": { @@ -9576,9 +9576,9 @@ ], "support": { "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.2.0" + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0" }, - "time": "2026-02-21T17:12:03+00:00" + "time": "2026-03-03T17:31:43+00:00" }, { "name": "sabre/uri", @@ -19148,12 +19148,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "89525190c449738e468ee27e77f9fdc1bc160e08" + "reference": "da19d9c4572f2adae57b28b2111d7fa667cd6dcb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/89525190c449738e468ee27e77f9fdc1bc160e08", - "reference": "89525190c449738e468ee27e77f9fdc1bc160e08", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/da19d9c4572f2adae57b28b2111d7fa667cd6dcb", + "reference": "da19d9c4572f2adae57b28b2111d7fa667cd6dcb", "shasum": "" }, "conflict": { @@ -19282,7 +19282,7 @@ "commerceteam/commerce": ">=0.9.6,<0.9.9", "components/jquery": ">=1.0.3,<3.5", "composer/composer": "<1.10.27|>=2,<2.2.26|>=2.3,<2.9.3", - "concrete5/concrete5": "<9.4.3", + "concrete5/concrete5": "<9.4.8", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", @@ -19296,7 +19296,7 @@ "cosenary/instagram": "<=2.3", "couleurcitron/tarteaucitron-wp": "<0.3", "cpsit/typo3-mailqueue": "<0.4.3|>=0.5,<0.5.1", - "craftcms/cms": "<4.17.0.0-beta1|>=5,<5.9.0.0-beta1", + "craftcms/cms": "<4.17.0.0-beta2|>=5,<5.9.0.0-beta2", "craftcms/commerce": ">=4.0.0.0-RC1-dev,<=4.10|>=5,<=5.5.1", "craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1", "craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21", @@ -19454,7 +19454,7 @@ "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", "froala/wysiwyg-editor": "<=4.3", "frosh/adminer-platform": "<2.2.1", - "froxlor/froxlor": "<=2.2.5", + "froxlor/froxlor": "<=2.3.3", "frozennode/administrator": "<=5.0.12", "fuel/core": "<1.8.1", "funadmin/funadmin": "<=7.1.0.0-RC4", @@ -19504,7 +19504,7 @@ "ibexa/solr": ">=4.5,<4.5.4", "ibexa/user": ">=4,<4.4.3|>=5,<5.0.4", "icecoder/icecoder": "<=8.1", - "idno/known": "<=1.6.2", + "idno/known": "<1.6.4", "ilicmiljan/secure-props": ">=1.2,<1.2.2", "illuminate/auth": "<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", @@ -19554,7 +19554,7 @@ "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3", - "kimai/kimai": "<2.46", + "kimai/kimai": "<=2.50", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", "knplabs/knp-snappy": "<=1.4.2", @@ -20167,7 +20167,7 @@ "type": "tidelift" } ], - "time": "2026-03-01T01:36:02+00:00" + "time": "2026-03-04T22:09:37+00:00" }, { "name": "sebastian/cli-parser", diff --git a/yarn.lock b/yarn.lock index 040f0963..2f8fa801 100644 --- a/yarn.lock +++ b/yarn.lock @@ -837,160 +837,160 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" -"@ckeditor/ckeditor5-adapter-ckfinder@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-adapter-ckfinder/-/ckeditor5-adapter-ckfinder-47.5.0.tgz#76d6d289e7603da1ff209210a53fefbe3e5d114c" - integrity sha512-fOAmkBcSIWrGFDoz7kdb9XE/8yU7MnmzJ5JNbDVGNnpX+IL/1xRwvsnipwJzvJn8i3vo25kbyKLrh7FA8CsFtA== +"@ckeditor/ckeditor5-adapter-ckfinder@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-adapter-ckfinder/-/ckeditor5-adapter-ckfinder-47.6.0.tgz#50bc924ddb4a03e7ad2611af5afc424c910c9948" + integrity sha512-SMGuLMvXlNK9NjKL24zjV1JK3KCQxMoafTFEW5iGiKA63g9GNmhVhpu56dT+9bRpOzDNchnSYW9ljuW04bDr4g== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-upload" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-upload" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-alignment@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-47.5.0.tgz#e808468e40b7abf9b31f3d4ba4711cbc5deb22a3" - integrity sha512-XI+olNUE92MmD4EMbhPhDmk63wt/b+QGNssH0kG/KjNJ/awoQIe+T9r4/k8WzMK7B2j4mdycgI62+ib5rH6XPw== +"@ckeditor/ckeditor5-alignment@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-47.6.0.tgz#97285531923a7d0ef9d24558c3d012b7420af353" + integrity sha512-vfu+Hsza8kW0ehf+7N1hibmWRQpJ84CTPWjM9PNtwb+irvnQ3WjAK8D0fw9dY+ZM7FtPCT9xJGCDCI5MoRZ/fA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-autoformat@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-47.5.0.tgz#c38a3e1a2e18b23e9b74d7ad4fa1c49d7bb3f72c" - integrity sha512-Z9f589prwjroiEJPLRNFqSzaALloOm3oPPUN4jH/YyyRnn1mv+7vI6TEPm7ZLKks3ztBN3yv1hFnrAd9oGqY+g== +"@ckeditor/ckeditor5-autoformat@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-47.6.0.tgz#08ccfa310115a5a392ac9213438db37fb20202dd" + integrity sha512-idBf0RsdKr1sIcaupIqHksx6VPzGtCsKi4ZjAfFl4syVCvx3lPpJselkkvsdpTmw0Rqg4x8zyfMGElSL82SXuA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-heading" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-heading" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-autosave@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-autosave/-/ckeditor5-autosave-47.5.0.tgz#ded3ffef4b96ad7a9576a709b512c165532444d1" - integrity sha512-KKtgL/uJdVLP2srSXG6MbYEZTCjzC2sy3kVcKtkyD6T+q3SA8OWsjH6jCLIPBZkDLNNedNnKnaeUR9+Na4i7Bg== +"@ckeditor/ckeditor5-autosave@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-autosave/-/ckeditor5-autosave-47.6.0.tgz#77e91267abd1eeb7ff31b124d06c7be6a1dc8294" + integrity sha512-bU7E14bu/8paefBMtOT61P5V95fdafaG3OQXdnE5tHD7jrualznuEzek519U5VzL8Gh1Wo4cHyLA2pg1Ljyb/A== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-basic-styles@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-47.5.0.tgz#f14399bfba8503c4d0284cd0a7590c5ee9b7ccf6" - integrity sha512-az6yy2hShx9TO9tk9oUEy4akO6V7CKl6d8R4PjGij+PxYeGbiHXSPRMjLrJkoRqj72okl+5S22YmhEf1KIpoPw== +"@ckeditor/ckeditor5-basic-styles@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-47.6.0.tgz#d0ec52ae4eb17b8e535998a7af9af4cfb56ce117" + integrity sha512-GYYO//eNp13ZGn7Fg7s9eSdaDLt/Hut6efC8gTkakfx2yCZqcjzjV4gBJmvaIul1hw+EzsMjBhYe4lorBAM5oA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-block-quote@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-47.5.0.tgz#fafeff003cd6ac3c10b8c9ed88aba26c8a0a97c0" - integrity sha512-x2T+dn+2CU/r5hmun8AaVwSqNviaod/z483oh0XoexxXDcXE6wLr2FN591INLIdzO4/N2ez3AhcBt0focXYAbg== +"@ckeditor/ckeditor5-block-quote@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-47.6.0.tgz#2181daad92548af74abd139b4e9028a6edf4372f" + integrity sha512-xFydZ2+1tcv5TcqoWPtlDJ0wntujOJfIrXncqDe6wXXe/ByK5/wJu2d88XxLQFCNvn3BjP9VLBQNrKIAlpFM1A== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-bookmark@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-bookmark/-/ckeditor5-bookmark-47.5.0.tgz#c559ead16e24b8b5b07243adbaa16d4271cb2296" - integrity sha512-5EkwJE5BuVTMHjw3VDKscVbMoG4kxD0wDCN2DTnhRo/drPNZ3q2Jw+3SJigpUrFWYUtzhF0s7+Mm6TL94rSBaA== +"@ckeditor/ckeditor5-bookmark@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-bookmark/-/ckeditor5-bookmark-47.6.0.tgz#14b93f34c8c1c13e11ee78ab634f464909a04f56" + integrity sha512-Bkxh46mHCEYM9cOSJjK6NpHtBpSyJWqYVyTrLl24SiixtHUpuXqFKKM7Jo23GjcuPBXVSdG2ax6iwUCzcFuHAg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-link" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-link" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-ckbox@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ckbox/-/ckeditor5-ckbox-47.5.0.tgz#8d1efbd62e8c87509fe8796d64d79139c9d46e47" - integrity sha512-OvTjDZSU+XNNzEmny6X3D90lhGF14DsnS00TcYj7uRqiwOUtnWw0ba0Hw4ulJ9Jrfs2CzG+rz2YokMm5iMgQHw== +"@ckeditor/ckeditor5-ckbox@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ckbox/-/ckeditor5-ckbox-47.6.0.tgz#0a60e5e9e2de5b6e9b7ccc8f5da93d00d66e0ab1" + integrity sha512-IOpJZMc8NLe4ruLfG8jfwC84yEbTqn/0rUyKgdmTf6M5ZofpIMyaqSIU30aULBgmaXwkE/hQTbfjgaJ3UUSo5g== dependencies: - "@ckeditor/ckeditor5-cloud-services" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-image" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-upload" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-cloud-services" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-image" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-upload" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" blurhash "2.0.5" - ckeditor5 "47.5.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-ckfinder@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ckfinder/-/ckeditor5-ckfinder-47.5.0.tgz#a0ba717932942c8bdac9e62d08bc411a87fd4e1c" - integrity sha512-QoyPTGypDiPgehwaaykzfH8ZUzr2qhHKj0BC7pqhAuHZaWzdCl49g2ZTI2PlMZRIrYNWr0io5zxQq/elSOgwcA== +"@ckeditor/ckeditor5-ckfinder@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ckfinder/-/ckeditor5-ckfinder-47.6.0.tgz#f719050a84a0b7c11b8ee968c351b948417fda93" + integrity sha512-hCuFkKx/ph5ntmCSvjO7zIxET/pL/5Q1fYt1joOE9hjaBWFMoRao87GUjJ3O751ZAkioSe90zECP8SXYz8ZlIQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-image" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-image" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-clipboard@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-47.5.0.tgz#aec63eb1d509e8476079cd7d6012611b469dad19" - integrity sha512-LB+KSXasEOL9/3OC2WBPwbLaKd+tDkix+4RVaki9hciQb4XgwQB3q6TWIbKcR1lPjw3Ox8tT/Io11x9AEtOzkg== +"@ckeditor/ckeditor5-clipboard@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-47.6.0.tgz#95c2498e5b3dc688d71184bda176863963449d00" + integrity sha512-ymkOH+O9C+v3vKTaw1iOrlJMti+7Q9ycKdP5bCc9/4ywtR6cRtZ5BnEkbK1S1CSxkijQCdpe+0tNgXI2aniD+A== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-cloud-services@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-cloud-services/-/ckeditor5-cloud-services-47.5.0.tgz#36810ef954fb08e5c0e8cc36c6e8462ce27b0ee1" - integrity sha512-lsvOK5w99+GfwQz9UyXaKEbH70+DEy0+wvO+82lgd5vpOiqMYfHz18b1abi5ICCTMo+m3KZyFFj33NoelRWq6w== +"@ckeditor/ckeditor5-cloud-services@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-cloud-services/-/ckeditor5-cloud-services-47.6.0.tgz#ba89532529c1ea856925b305b963331e72290241" + integrity sha512-8MkrqbfiglNwqkUnfL0uoBZVlHmsqvq6wXiz60fnWTpTiEmxzV95/JeT7toFafvxLO7WSzBjEcZcmc9Z6ChyAw== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-code-block@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-47.5.0.tgz#564ca4e1bbf571e72256a89c726ca5729064cc34" - integrity sha512-DdfmlvIu4nRgX41bUTkGlkL0PGJEIKcL3vVRniLXjgqnNrAsR5kWdbYTOu+qSvlCVzr4Z11nAG49QZIJ/aeAGg== +"@ckeditor/ckeditor5-code-block@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-47.6.0.tgz#6846c66a155807dbfb97f58afc5bac3736583e2a" + integrity sha512-SetV7GnNwUOqyaPHlzXgTuT/TrLLhQ9z3glmfIQ4A9BvV9dvP6Nb9vFeJnDHuhEwBauQS8M0DqdFc+F3qdJwsg== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-core@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-47.5.0.tgz#5919f424fa538437914418cdc4311342ca36cc11" - integrity sha512-4LdO9HIJ/ygN+YC4pty5plmFqlvHmjuQx1zdzzmbL3VSR4MCsaongDX4vVqpUcRVLzxM/1kErP0Da6cpVbkqzw== +"@ckeditor/ckeditor5-core@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-47.6.0.tgz#0df87dc3294b4b91419aa064b414fbc0462827ea" + integrity sha512-kw1zN6Fv5SRiZBSCfJV8yBGmirNC+vnKBOKxiS5I50wRReH90IJnTyh5Fu/vqsmr7UtSR5xvAKhu4xg30MrsRQ== dependencies: - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-watchdog" "47.5.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-watchdog" "47.6.0" es-toolkit "1.39.5" "@ckeditor/ckeditor5-dev-translations@^43.0.1", "@ckeditor/ckeditor5-dev-translations@^43.1.0": @@ -1034,318 +1034,319 @@ terser-webpack-plugin "^4.2.3" through2 "^3.0.1" -"@ckeditor/ckeditor5-easy-image@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-easy-image/-/ckeditor5-easy-image-47.5.0.tgz#c47e54bb58b40649f0986f886faad5a2958f9502" - integrity sha512-e71gKQyA0UnSun4XLXawg5SP+IV2N/jhw8mu4FoFcRxhqV51FAwonldzwfdNgfD9lpX6bhYi3gREPGnuwdVPgA== +"@ckeditor/ckeditor5-easy-image@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-easy-image/-/ckeditor5-easy-image-47.6.0.tgz#7d168f6ccd0adc079435643fb24c6452cf29dca4" + integrity sha512-hOTxDnCU+d3vp0eKeULQxk3rZRkkZ551OM9O1ZE9sEaOjAdndaikqSH9VEwhSKTfmRIWHrMJg1ouxw2aeHvwHw== dependencies: - "@ckeditor/ckeditor5-cloud-services" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-upload" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-cloud-services" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-upload" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-editor-balloon@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-balloon/-/ckeditor5-editor-balloon-47.5.0.tgz#229cfb65c61069a00297fd8857f22333e91876c4" - integrity sha512-UrMEb65RrEmV/v/DvPpGIfFVa8KCoVnONALyDRPQ8zsdp745vKuMi+i2jHGGdhKWz6SYDfzJROQ10dq3FMxuuQ== +"@ckeditor/ckeditor5-editor-balloon@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-balloon/-/ckeditor5-editor-balloon-47.6.0.tgz#4fc068f9981cdb416e825fafb1ebf167b854aee7" + integrity sha512-LsnDsovjVrif7mRbdwFJKmKI5q5xmD2Zi/8+ImsCUm6fOo9Q3nmairDoWhQ0Bm1KH1MFDFYCDzZXuiI42T2F8g== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-editor-classic@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-47.5.0.tgz#2b74e7698a8b8ed0ac432c7bf8ef230ac830fd58" - integrity sha512-OPu3OiaXm03r+mGhzQMdRyMFnJYMT9VPC8+e91e52GVQh/8sR03rwoow2RbNvsznP/+fAVnH4LrIgRR8K5cgUg== +"@ckeditor/ckeditor5-editor-classic@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-47.6.0.tgz#0edcf4a104578164488bac91f3b22ef6e0145650" + integrity sha512-NF+YBnfacILu3+EvsEb5UZvE9llpcO0qfbDdxJUu+t8bHXMhZzo3kOh0Gw3mB3Yil62IVTita0P3AZvzq053zw== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-editor-decoupled@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-decoupled/-/ckeditor5-editor-decoupled-47.5.0.tgz#b6503cea5ed12485ddf606091e113521957b5655" - integrity sha512-bO8+DysIcgdrqo26InvoZ6geyoCBExs/V6c3DPhbG/pUuMXc9F7Zfn/hmKo1iOWL8E+gEJosu7psP/PiYM8RAw== +"@ckeditor/ckeditor5-editor-decoupled@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-decoupled/-/ckeditor5-editor-decoupled-47.6.0.tgz#f87ec232fc5b92fc9f43e0e57d55e1bae75bc95e" + integrity sha512-BgwJZUJEzR06bLf1Qk6Klilaacumk4uMZCAdQCCg4LSMNAk3eaQgccl6SUZqUH9V/NDpogIGcaDbUPWvuxJKjQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-editor-inline@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-inline/-/ckeditor5-editor-inline-47.5.0.tgz#28a083c28b86e6cde1696a3d0fa1b074b4e378a1" - integrity sha512-L+YSTq7Hlt9nmip9xwPBAW1rNQlS8WGIfgXAgOhcdXsUE7r43PA5gjyckvRB0vKASOF5+c6PTDjiLpapNVnv4g== +"@ckeditor/ckeditor5-editor-inline@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-inline/-/ckeditor5-editor-inline-47.6.0.tgz#3d515bab5137fdca3b2ca135b6af0eb56088eaa9" + integrity sha512-89B+SYsuI64mfu/qtIyYarw0qSmripIA33L3FaH6KUJpPBwwIjd5huZg6L5BXE6ZuPMGyRjRq6JapQb0zExWEQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-editor-multi-root@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-multi-root/-/ckeditor5-editor-multi-root-47.5.0.tgz#f5900fc795a2319ba8e9787cf66aae052339be01" - integrity sha512-tpI5VMwT+O3dXktORZ1Z4eCDp9sFEsxxEDDv/mmGz/6s2h+9rjEIfi8KqVnRfEC+uW/H2pu+q6r5y6/S3c+unA== +"@ckeditor/ckeditor5-editor-multi-root@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-multi-root/-/ckeditor5-editor-multi-root-47.6.0.tgz#3c6e07e347c52095206528cc097f1a41938a0834" + integrity sha512-uA5JPlV7QFfMVErqoVdwLJbUoF/u3X3GGg5s+VMeVoVTnn3ZQ8592HVftuT87HIiI8W1NHdlrE/32+3iTnOoVA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-emoji@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-emoji/-/ckeditor5-emoji-47.5.0.tgz#31a2ce0fe2013052d8fbf80d86b3a566036ed73c" - integrity sha512-NVSg4hMpzyq0eVmVugBmY//McJpiyK0/XsXx72qySSh1b4FfKVT1couNB0m1pM5sFm7hXYB33WXyTpB4imyKyA== +"@ckeditor/ckeditor5-emoji@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-emoji/-/ckeditor5-emoji-47.6.0.tgz#36c230ef55aafedb1f777273aab03531165303c2" + integrity sha512-DLoScPQAMKXpe6U3M6Dw2sed0ElQeMgun0B/j//EfBPdtqkY3IDPg/R7SlRxsYuYNf0cEWNZwaNnlL/JI6w+gA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-mention" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-mention" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" fuzzysort "3.1.0" -"@ckeditor/ckeditor5-engine@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-47.5.0.tgz#c9bc555284dd691aea17a3f4a0eb72d88638ed8f" - integrity sha512-4T6MzgjV5C7em5VgaHJ+RuN4gipryTErqtjtmb/RJXvfrEg37CYOpdHurM/VwY8hiD7yGUADB2iJGroLtytzCQ== +"@ckeditor/ckeditor5-engine@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-47.6.0.tgz#98d8d6bec6292668695ba653f1818b63abbfd347" + integrity sha512-HjtlviZZhPDSfHS7aEYUfhVuEWCHCyjCUDd4r4vx9A+02W7G+Gg6I0lqtDqTRL/Bp5rVv3MeRrcaYU21jCFJ3Q== dependencies: - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-utils" "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-enter@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-47.5.0.tgz#5e7221ce635369ae2f6c94e280f12c42b560e4f8" - integrity sha512-knpo3bZwFURor6gnDN2oS2mAA9qoPvMsEjuS3hce5K6pQAKqyUHqGSIQax7dLBW1spaWExvI+OTi/UNtNyPLWA== +"@ckeditor/ckeditor5-enter@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-47.6.0.tgz#187d1a59422e86bd3af2cc9369095bfc4d9d84cd" + integrity sha512-+WlxCGj4J+Q+BFyAWkJZ6q+t4LnDHEstQtYFT5pGj23oUSVeOBzc+7e5FqU4LLtOzYnClN7t98OGPDPOHHhS9w== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" -"@ckeditor/ckeditor5-essentials@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-47.5.0.tgz#4622134a31ade31a1e45d402849e8660b1a41872" - integrity sha512-uEdq/jnWPuN2KL6RufpQW9smnJGnU2f5/a5/QuP+rIfzPmpCmwCjgQto+8/lpCzWvEjUoHUsuIHlIT4TFYUYEQ== +"@ckeditor/ckeditor5-essentials@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-47.6.0.tgz#9d0d8884ddac3e39f20044d845afb3301f2a3af9" + integrity sha512-rI5/FWOcMjGVtWlHisBQCtL88pCZJiB+SwpmpumdALqP99urUqbL8tFprwyv95r7o4sFPMymJYVdHGlUjKb4Dw== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-select-all" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-undo" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-select-all" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-undo" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-find-and-replace@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-47.5.0.tgz#df21b3c6afe49e5aac0e299aa8a73bbf66d9836d" - integrity sha512-30yr8zzztiVxVmYzKgp8snDWh4sJJc1FbS3UM+u9coNGdlxzpuy9SdseNRPOi+tTXsK1OI6/amWJltYmDsAseA== +"@ckeditor/ckeditor5-find-and-replace@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-47.6.0.tgz#cf69a867e896101bea3075964bbd9cc38aa16ead" + integrity sha512-S6E6zgO3T4A5rFC3Idr7DvhD2QEov2yIrWVbkIFTc0Q4fuvuNIxoke59fvc+SYd9BeDvQawP7a3RjMBTgvVRGA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-font@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-font/-/ckeditor5-font-47.5.0.tgz#6c04c37db3c319c8aad73e730040bd21d35b30b4" - integrity sha512-qh9GLJ9+9DsdPXgZg8dH8D5mv/ZZ0mK+Ulwct0rSxIBLruFK5EhjXjngIG8HUv30BGCIpXPawGDTPv2txQ4vlw== +"@ckeditor/ckeditor5-font@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-font/-/ckeditor5-font-47.6.0.tgz#28914be860c57e0fc950c61ab65fb2f3105b28bb" + integrity sha512-MZ9nUVCF+H+uYZeEy2FRlRys4kUFhuFcTJSaVNh6+obC8p9yrdRk9sSIKzH3VfJwmY9RWwEGg5udcyuQ4QT7KQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-fullscreen@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-fullscreen/-/ckeditor5-fullscreen-47.5.0.tgz#130a8ec9624d0a70c3fc67e74a41c6aafa6c168c" - integrity sha512-cdgpNSOKrqKZMslG9hnQQoWRUy+tAVi7r0oGIbDfMezvLnaJDoG7GmYSWbGe1/+l90/TMtxKwYM7cQ6dmqutFA== +"@ckeditor/ckeditor5-fullscreen@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-fullscreen/-/ckeditor5-fullscreen-47.6.0.tgz#3fdaaa584d71f9e4abbde98f1f284c6e27dd8bef" + integrity sha512-M53UtSJ5jLNwt34iqllHeW2zT7HEpZwzSWX/TLn/3Q4d95m9+HAO4vBHDkuX+wd2KTl+8MYcrXYSCNWDqWzU/A== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-editor-classic" "47.5.0" - "@ckeditor/ckeditor5-editor-decoupled" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-editor-classic" "47.6.0" + "@ckeditor/ckeditor5-editor-decoupled" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-heading@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-47.5.0.tgz#56c097ea5f4316e34069fbc2c7c7f54fbdc7993e" - integrity sha512-TEHY+unz+1fnx3554TgoYNGw27Vct7aDm0qw0U5/+PkZIyAxLcElkzRqXu3HhAPy6qs6pqxpPfKWWtREJhKluQ== +"@ckeditor/ckeditor5-heading@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-47.6.0.tgz#86a7727c1c360a4c2c011f28cfc0d2366a306b0a" + integrity sha512-hduHYHzcY3j+K4e2O6A72ksH16I885zWjydwFOCGXnIPUTZAL9ZZLwRuhqDQ6jZ8uNPqiXcuRpZd1tFIXbKXOg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-paragraph" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-paragraph" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-highlight@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-47.5.0.tgz#387550fe2965c4308a6f390fabd78cea4e7e6b3f" - integrity sha512-ajLkP2jA51B+K83g/Ujyuvpe+Wst9iniPBASmMn03pkC3ZNkdDRtCmz1Kkhe0UpYIvhCIKeWHIaH+7BS0DlbAQ== +"@ckeditor/ckeditor5-highlight@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-47.6.0.tgz#408fda9a52e1ec29e1f7521e1833c75b81b02140" + integrity sha512-YXZWN6nIyVBrVvsYXkusruYYenNb84g6GgWilA2PwQxuW6CwTJ7PeAM9KkA3+HQm/hwAme+/I74940FoyOXMnA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-horizontal-line@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-47.5.0.tgz#726bfa24532d4c9f7b579d97cf36f70a61db0291" - integrity sha512-/lPpkiish+KLFCV+oSJ11XldS4MJdOogfKAtWkpdlzLS64/Duw0fxOUTk8lzo3tHAgZgP7Ji9FJM1HtiNehTNw== +"@ckeditor/ckeditor5-horizontal-line@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-47.6.0.tgz#06cafbb62c212c3cd218c04458820b1eca8b91b8" + integrity sha512-m7LZ0wS5GHfmm1rWR1xSs5a8e/CTx79k7ahZdexLmyKmVoI8d/rahsD7oPsaFz6E+lHHhFtz+mmcOURlpI8SCQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-html-embed@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-47.5.0.tgz#10a35f39e4aa249f5e98fae21815fca9a628070f" - integrity sha512-7gDouRaElSoICODnCwmziNxKJnvApur/QPLt374q7gz2l3sCrSM7LuDuCDAXWTQGQGkA1291OrOKQtuXGwY/xQ== +"@ckeditor/ckeditor5-html-embed@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-47.6.0.tgz#364d2e8b290ffc72ac8da1122b1a9fa32bec9cae" + integrity sha512-i8/7VoWcPLuJGkGbDJVQMd63SdTVERDMcah9EqbDFR6uxX+BnhUdPDKiZmcrsIJ93uq6aiK8p3uDmoiEomWp6w== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-html-support@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-47.5.0.tgz#e126a6674ef4bdc05038592d8e54c7d170299918" - integrity sha512-e/OuWdlh6EbE1ZrQDu0/QnMd+V1XdwTmUJkOQrwwZ0x8CSKvKOt+Nb40ac0ShjTE190dMD1tGfOjM0yDpp0neQ== +"@ckeditor/ckeditor5-html-support@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-47.6.0.tgz#73833d4cb9ed7d16bfb1ef434f932cbd20344e1d" + integrity sha512-bGIhD71IUYfdC87LVh3kLDlB6UuMSyBAOPpEsOr/7r8oANhHgUI10BaImZVid03e5Wn5x+S9Jc9v1T38+eRzAQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-heading" "47.5.0" - "@ckeditor/ckeditor5-image" "47.5.0" - "@ckeditor/ckeditor5-list" "47.5.0" - "@ckeditor/ckeditor5-remove-format" "47.5.0" - "@ckeditor/ckeditor5-table" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-heading" "47.6.0" + "@ckeditor/ckeditor5-image" "47.6.0" + "@ckeditor/ckeditor5-list" "47.6.0" + "@ckeditor/ckeditor5-remove-format" "47.6.0" + "@ckeditor/ckeditor5-table" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-icons@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-icons/-/ckeditor5-icons-47.5.0.tgz#9aecb267dc60f366b4281bea16e6811f2f1966fa" - integrity sha512-1LKzMsMrKHOEtLc9rw2C6iV5Wx6YCjd8I4WxFKQnxtW+F7+e4H4+rWU7ILpUxYjubEx0FSUJsyyNB9B98GMUgg== +"@ckeditor/ckeditor5-icons@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-icons/-/ckeditor5-icons-47.6.0.tgz#49b0a1055c73af21e9e5f23cd55cbe3c11978cc3" + integrity sha512-Flu9jiUG7BjVfSdIXnCx4IBshDh4G/Aw6JhnysKstA4RvAOypF7hVkuYw2tqNUdkG7YV9LbYlTlWitFvWEazkw== -"@ckeditor/ckeditor5-image@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-image/-/ckeditor5-image-47.5.0.tgz#8855bb8cd4542c9a59daf974f18fe2d457885833" - integrity sha512-Zm9Qvj5UUC+bKHtQNmPJisTS9Sy1z6UQ6pbH2OxKPcw7ckhozQIeRtZQqoSSKQWq9B9iJ+CPvE3b+7FYkOXkew== +"@ckeditor/ckeditor5-image@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-image/-/ckeditor5-image-47.6.0.tgz#f05e9dcf69df7390fe25f61c1991cc981ab3afe8" + integrity sha512-7X5qtCvqTSc3hJcxe6qTZ2WVIW0Q81z4l4ehIpiNF/vg4FogsSXPyJ5xro2KrNILLIXJzMx20a7BFN2S2HcepQ== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-undo" "47.5.0" - "@ckeditor/ckeditor5-upload" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-undo" "47.6.0" + "@ckeditor/ckeditor5-upload" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-indent@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-47.5.0.tgz#2c439c83d5fa6b40786519d08adab9079e919de9" - integrity sha512-ZioulqHdwXBqirZGwESdkXWiYa1AE+EVbhegMO+a8tNa+SCDIt4do5PsrWxyz+PtW5jGBTKY831TY4NIGTihvQ== +"@ckeditor/ckeditor5-indent@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-47.6.0.tgz#2bec60617bd36e10aede87e34f0d192f8db903d7" + integrity sha512-Rsnw5FHUGRlzyixRtgLeCrK2u3+d1+Bliq8hlQcMWvXB7wfD1GTDSsEU2MxGM7QtGuMbqFa+gO0hfzjEFgRv5g== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-heading" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-list" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-heading" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-list" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-language@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-language/-/ckeditor5-language-47.5.0.tgz#d718d54328b8ea9ca99d6e489b77ddd886b91ed0" - integrity sha512-BSSUxiqXNGEz9knYTgMJF6wpKjCY9NEsFBmfVzsXiIuNpYSXrS281Efl49E1ivjlnsgyEJLvmed6DOa+mkUHpQ== +"@ckeditor/ckeditor5-language@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-language/-/ckeditor5-language-47.6.0.tgz#7f1330e37904fefb0ade9b175280c855ba5220ce" + integrity sha512-nwV0HvQ7xhADG74TdsYZaB3rgiJMlXEqZ1rUQ+Lcl/IcYWCeyL8UaW6CwHzwlod2wTwaZhoIgfEMAk0f50b+qg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-link@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-link/-/ckeditor5-link-47.5.0.tgz#1d62c5a3f010f42c630894d99cf14310b707604a" - integrity sha512-sxsB0dSEsJL1g+GTJ4dTQ33eulS4/mZ2wwU8TgN5EtpPjGR1DcsFM/Hbhpr+nC6pyGfYzjV5GnhgOT/aYGE2lg== +"@ckeditor/ckeditor5-link@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-link/-/ckeditor5-link-47.6.0.tgz#3f990b045582ca90fbc68a95a11ced6baffd621b" + integrity sha512-YEw1y9nMqF3hYbrJ47DbeMGpyZj04uDf89tcYR5Ti27k3P4gqwCjBh/L/q+yiRmDXhfLbne7Zb4sqF6TVDBqog== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-image" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-image" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-list@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-list/-/ckeditor5-list-47.5.0.tgz#07dcf8aab14a054d1885d173aa8ed8cb7f04a021" - integrity sha512-9Yq2Jsgebbdxe6As3jviwFXL4CH38Mb+YUjlO2oEZZEw6fDvwjc83ziBXA/t+6cyBTdLjibbFhGLyPeiy+Y0Lw== +"@ckeditor/ckeditor5-list@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-list/-/ckeditor5-list-47.6.0.tgz#e5b68eaeca34bcfabb0891f15b7a58c6820a9176" + integrity sha512-LyvFrLKZS3DjNX/9J+uRJ/AvwesqD1/+BfeqGF3eP0XWhqJLI4rePosyOl3H91050zWlDuLFINo4lYGL0xDkAw== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-font" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-font" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" + es-toolkit "1.39.5" -"@ckeditor/ckeditor5-markdown-gfm@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-47.5.0.tgz#6dd060188b2397a5b221dce26608f9ef6a04bb70" - integrity sha512-sxttfFji9jTHDKdDklN13w480tI+tLwATIOHO2xTDbsA18tp8opeBFNUUfEeQ8XoZkAxckwv5tFu9Au2XuAdJg== +"@ckeditor/ckeditor5-markdown-gfm@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-47.6.0.tgz#52b1be1b4fde1c6eb42f82999746abde3a751e3d" + integrity sha512-rgL51xVnVsXafj4OwyfjG4roZg6FXHMlcEsZsympauyehdl/IJeE9Jia8fuS7Joef7PJQNpadPr/5IE499e1Xg== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" "@types/hast" "3.0.4" - ckeditor5 "47.5.0" + ckeditor5 "47.6.0" hast-util-from-dom "5.0.1" hast-util-to-html "9.0.5" hast-util-to-mdast "10.1.2" @@ -1361,271 +1362,271 @@ unified "11.0.5" unist-util-visit "5.0.0" -"@ckeditor/ckeditor5-media-embed@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-47.5.0.tgz#0c40872aaad5d68853c5c59bf09c42a784165243" - integrity sha512-aA+MALRNzyeXcfXoEKDJiun0VU5p8llVrXibrXKBK4Kpx53TdBd75+OUe4z8wOcKYN50ntRf7YSGCLB0yqJuLw== +"@ckeditor/ckeditor5-media-embed@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-47.6.0.tgz#4bf7b94cf0522f05108810d8c8d713e5207ddcc5" + integrity sha512-vKlNWEo8ICUzZXzpdo0ZA/rF6nzBglYI7EHRu1LSUAPeSA+gNoh8itXHRlox0wYQ1N5DT5f6Z6ZwxlK1pHQBQg== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-undo" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-undo" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-mention@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-mention/-/ckeditor5-mention-47.5.0.tgz#278c4cb3851b0c74fdd6d4121a0b6e19923a8bfd" - integrity sha512-AhfdHcG6TNRLP/gEJIPdZM792vbjzQUR6lwXy7vFRIfVwDZ+qanEIKsTJue0x1oJYkdxC0hSRx2ZN+4QHwEOFw== +"@ckeditor/ckeditor5-mention@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-mention/-/ckeditor5-mention-47.6.0.tgz#31f14a8089fd94ab8e4ae72064610676ab02c7b6" + integrity sha512-odLiEzED4fTDn5SkM+RS5Rus32ghJp6+hcSWZIHwTTQ0QRJOGab+euKyY/PqNVP0rPI2Mq+Lz5uXRO5mfarahg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-minimap@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-minimap/-/ckeditor5-minimap-47.5.0.tgz#ef05d0f2f9d6cf477b26bec3d820da9c400bf58b" - integrity sha512-GarVZ6e29UY6KWlKZcCQRgEggU1oqep3J6wiXJ0hxrcvYOsDS06Zo326xdcs9zQEC3M/siBO/4WW77gBZdjB0Q== +"@ckeditor/ckeditor5-minimap@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-minimap/-/ckeditor5-minimap-47.6.0.tgz#115dade48515cf7604a90008c6b8ae104c3fb484" + integrity sha512-4hdS2HpkoYsx8cVsMFntN1nsvS0xsA8pHGiJFUMMNqooy77qDMRlAeaprRth+rQqruVNldGAdlnIs7LfqXoJug== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-page-break@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-page-break/-/ckeditor5-page-break-47.5.0.tgz#113c0834e610e833b82c7cf1beba7e931f5f4535" - integrity sha512-e7//l3ls4vVsRXcsX9Lg6r9EBjT5Aq6UfHB5KWpi3bH+S2tqE8CoeQZPKFF7fa6W2V1BVUolkUeN72iiOkCi6w== +"@ckeditor/ckeditor5-page-break@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-page-break/-/ckeditor5-page-break-47.6.0.tgz#b341b2263f155dbf1584db28772d2261776591f9" + integrity sha512-XpWPVmbCtBJD1kOtBqV/LjsVByt94xlhgk9IXXW8QE/XOoNh5Yb2JE3MisHSZ0yM3kXauROM0SWT1FVMYXx2RQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-paragraph@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-47.5.0.tgz#7016e3440e532acf1fb60ac43a0efb50f438abf5" - integrity sha512-dEOJ876f8kvpkNBCOSj9g+2x6Ig9e41k0Gdp3WrkNcX+3QCthNeWa5XJfPDsQqTINldv+L9GBwxgFEMRi0Fq/g== +"@ckeditor/ckeditor5-paragraph@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-47.6.0.tgz#6b9f0e7a00240b6b9a7353dd64c8bee9eed93ea9" + integrity sha512-CxSIn9OLg/7Ol/TpwL+vZxgwwksMvR2ESI2kcSp94R8q3W8du2yoYSdPw0RzQtDuHmdGFs8JuN6xLYEU37oLBw== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" -"@ckeditor/ckeditor5-paste-from-office@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-47.5.0.tgz#5f2ebb0d30ec317dff6d74610f93bf7dfdca3a89" - integrity sha512-xF9TXExWPPVgIEA1gxf+oFNMVSOsbpGgRSNKS23gN5scxLupNGN/G1hj0UGTgHaYczBiOqW44bu82Lgduz7/GQ== +"@ckeditor/ckeditor5-paste-from-office@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-47.6.0.tgz#c3ce43517387356d787f4a777866f5fb1116cb3c" + integrity sha512-lS33vEq8l8MoxJe5aSC3Pem1pt+SAHI/zlf83twmBw/pb0nDjuB3HjkK+Y4Qbe5RQc/4llPJ/PN8VlR5QWyBcg== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-remove-format@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-47.5.0.tgz#530d52bd163a9a46c9643f505ab9da4bac2fca65" - integrity sha512-QTR9ye1iWfnGu7h5a4RONEf2e4y21dC847opNUozO06g51/e7G6iXybEcRtBqs51gpVddKelUbxUV2Zp7tm8iw== +"@ckeditor/ckeditor5-remove-format@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-47.6.0.tgz#5b5a00f7fa9501b2e2da3bc4d7b0e7204c834efb" + integrity sha512-9+ygu79dgcynGYnQ5xkBOOwRS4DseF1gkSG4fsOfgR+53yGaDfmHrHAX4DBOrirpFPVYxBWkrbFPMY+2Wcvo4g== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-restricted-editing@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-restricted-editing/-/ckeditor5-restricted-editing-47.5.0.tgz#6511a83f91bbbed157242252f829aec6023b548b" - integrity sha512-hL6pr3L1xaERwGBNG37AcLwj5XVXqAzYUWKF/pDbT8FnHymA7jn1dbsUHHbmPaqXtk8zu7W9k+aGKXwrkPUFVg== +"@ckeditor/ckeditor5-restricted-editing@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-restricted-editing/-/ckeditor5-restricted-editing-47.6.0.tgz#95d063b835a10a0b0ce8e2f311292aed639817c1" + integrity sha512-vZ0ITt/ozwwUVP57GhqK7Q82yeOd3s3YgjNmNu2EFpd1apR2pYkNTJ2urghUiutVWQwBYum/H1WMwUxdOKC2tw== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-select-all@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-47.5.0.tgz#5fce145bb23e1565aa039cf4604b5ab8e8d75d16" - integrity sha512-g+bLHv5aqgtuGhqLo9FNYS4aSGZztb15myydHXvUBJ7OgY3YlVDILi0xd9WrySPpO+Axi0ATdl9evO42rPYVJg== +"@ckeditor/ckeditor5-select-all@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-47.6.0.tgz#b14def862dba6847f237cfe4c732f799817bc6e5" + integrity sha512-AT6/MSUivNd3x0hYYTb8oVGtAdJ5mNJBCwM8RvjkWmX5RhqGv5xVAHt26w13mH+GNGyhot3aKVrmPgTfY7Zmqg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" -"@ckeditor/ckeditor5-show-blocks@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-show-blocks/-/ckeditor5-show-blocks-47.5.0.tgz#124c93f6e066e9daf0d5883bf05d733909b076cd" - integrity sha512-G902a+fvVv9IMcLm634yaehf7VYwWrSZqRQtD+rpV2wDaHcps5aXCHSPNrk5JdbInheF1d+V3uiySzbkc823IA== +"@ckeditor/ckeditor5-show-blocks@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-show-blocks/-/ckeditor5-show-blocks-47.6.0.tgz#45eeee2b5bb56bc868e204c98613f992efff7560" + integrity sha512-jh9zSrHzjKf8Wqy6Y71+0sjkoCIiLJM13aIseaNuSuxpTU9RvSxciZp2wjpixjsWg3g0iD91QV+XPrVoEkfjgw== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-source-editing@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-47.5.0.tgz#7716a5c492a23cbb745502a8b1047e533e2dab73" - integrity sha512-YmTaRSVkbx441xa9foOz/z+cYqJ385yKC6cW+MACsDVdHj2ruvj1QUDrRpvPc8T0irTSAuhxQhhmCSIEnt61WQ== +"@ckeditor/ckeditor5-source-editing@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-47.6.0.tgz#0e1ea17f435280b957cc442834212e26b5b1499f" + integrity sha512-3GD5xVrvl7ddifeF99pSPmekJhoFZmLizboBBIln6n/ZdHm4wXHCmF9ELvUSPJsxFiHASWtEVEMyHVKk6A3J8g== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-theme-lark" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-theme-lark" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-special-characters@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-47.5.0.tgz#2739d4f930447d2c7388f51324a1a6b562cf52a5" - integrity sha512-Wou/dBJnv3Qiuz7io8YTL5LJGS3JqiGwpw6nLKPxADinZfI8Rr+ZOvw5BL8ifYkPudOwLFKFwMY3/4I7tZQAhA== +"@ckeditor/ckeditor5-special-characters@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-47.6.0.tgz#25c69b01bb9a8ebdaed87cf254a3d885efb65d29" + integrity sha512-QVkL19eOEJshIEBjBHU9XP/DXY2P1xgts7EAC4e+XRvfL/wZLzVdCZZaIC4ELdiZD1wYUGpbL+jiV/twGQxWmg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" -"@ckeditor/ckeditor5-style@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-style/-/ckeditor5-style-47.5.0.tgz#46763990d05acaca5a52b607024379727bcf102b" - integrity sha512-JmXOZQvRoOeNotZyXdColDncBw9GIl6nFbL8lVHZL/BF6wFxRHlJSjy7W/VdYAsHv3GaOKlKWMRg72k+17mgUg== +"@ckeditor/ckeditor5-style@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-style/-/ckeditor5-style-47.6.0.tgz#35055e113ea3a21f59009b5dbe89cd1bef48909a" + integrity sha512-kr2KsSXxwWwkcox85OP8FIIjhoNDhSUURErf/B7kMf28CZcsV8wNv9a0A0gMk0FQDstmtXjUEsRgdHWIzpr/IA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-html-support" "47.5.0" - "@ckeditor/ckeditor5-list" "47.5.0" - "@ckeditor/ckeditor5-table" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-html-support" "47.6.0" + "@ckeditor/ckeditor5-list" "47.6.0" + "@ckeditor/ckeditor5-table" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-table@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-table/-/ckeditor5-table-47.5.0.tgz#b97f6eb3715144229b496b0663f7c7089b8001c0" - integrity sha512-aB4Sn9+DLuDHd5pn5d/QdSGQYzGBLJg2+zlzSddcxSeUS0gj7qtOhtce2ChY899D1pszbdQHXbM/Lnwgy1ZrCQ== +"@ckeditor/ckeditor5-table@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-table/-/ckeditor5-table-47.6.0.tgz#6d9bce4500e96e3e9a4bd3271661239903117864" + integrity sha512-JkyEJpm/WDr9U6eQ0a9wN5MUVAoqP0lk6KPnAGn64TCHAs36raeTgNEIeLbWs+1rYcl3N5IiEG+J3TNzlPpjNA== dependencies: - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-theme-lark@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-theme-lark/-/ckeditor5-theme-lark-47.5.0.tgz#8f34b0fe81cc845290d698f49ce40f938c20b144" - integrity sha512-vmQJyT6UnsmTF9rIWhYWWRGGpDhoxo9vd7aJ+m3b+gJqCLMziGadP6Dz3dezDQpbaW41Fk5CF61QPnMqaHuk7g== +"@ckeditor/ckeditor5-theme-lark@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-theme-lark/-/ckeditor5-theme-lark-47.6.0.tgz#a9f2ffaf65907e0d98552e5fe15818cdd9aab9f9" + integrity sha512-zXZLMcTcR7dSeeybQ5qOnaAk/UicN7BzyRJEFVRKTXpKCloaMFv6YX3xneEpAdH39cY265FhfVSu/Vwvthdr0Q== dependencies: - "@ckeditor/ckeditor5-ui" "47.5.0" + "@ckeditor/ckeditor5-ui" "47.6.0" -"@ckeditor/ckeditor5-typing@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-47.5.0.tgz#6fee4243f88e869a7d561dc1b9b41b8b3429f03f" - integrity sha512-/MoO59Cl/XJ4f79ecc5BHBb0sEnZttMosXpm1wjhwRKE7PyEICt2t+Uqi0zp9txl21O2z+Gmjz716X5InMa/4w== +"@ckeditor/ckeditor5-typing@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-47.6.0.tgz#c676c6e169a819e91389336effc4f0f98868b438" + integrity sha512-7dZylw4YGpxM4yXOO/vT9itMfJlyzkRe1+S3eC34Thh7q4pOOYERQQHuMVi4x+bifMyhR3AgpY8OdJ58R3gLqg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-ui@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-47.5.0.tgz#5efa9d41038e270529a93f8cb465af729fe1465b" - integrity sha512-wn55rqImjQ44CPavijdc9+MGHZZJ9lS9++NEAmt95b45ywd9nAyJ4QcuXDZ6f+xjwfeTuLX7jhBSuz7w8FWcwA== +"@ckeditor/ckeditor5-ui@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-47.6.0.tgz#c75c46a11e700097dad388f90380aa8e02e61ab5" + integrity sha512-bwQyS0APV01GIRzUtp7MLn8lVK60WKRCCs1FNYnpT+oPULgF4XycXwEoARzctfCdhoda3aQulVReC/tZkUeZkw== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-editor-multi-root" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-editor-multi-root" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" "@types/color-convert" "2.0.4" color-convert "3.1.0" color-parse "2.0.2" es-toolkit "1.39.5" vanilla-colorful "0.7.2" -"@ckeditor/ckeditor5-undo@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-47.5.0.tgz#8a9dbbb74b62e17895c832add712fa78bccd27bd" - integrity sha512-StiwvLrAlRqog1BSR8YZ5S6pdUdFB5BCPWPPJEAcMiBfRmG4pSzs+k3LIMgnyVoGwGBUcjdLVayqaESxe89Oeg== +"@ckeditor/ckeditor5-undo@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-47.6.0.tgz#b44336204216702f328cecbe3beeb23cb9f720ff" + integrity sha512-sUXZCd2ZvKEKKZTzAQWaIrJfUO7E22w6+4rnx3i5H9YyUBiJF53r/O4/HJGZxshTskZe2f9nHp5pHSbFSC8UlA== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" -"@ckeditor/ckeditor5-upload@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-47.5.0.tgz#6348083b0b301a64cc9cc49b9f2e8bdb8088aa1d" - integrity sha512-F1DPVYUGsb9P1/35vqPk7E+Y7wlubyb51DDR9irjUCAFyqQzolVQJ2bcsvrUXx+P8LT63sLCzH2do0pwMacGyQ== +"@ckeditor/ckeditor5-upload@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-47.6.0.tgz#d6c186f3c91c7b464e40b9a9c3306dcd48845e86" + integrity sha512-bCjMHRfQWImu/6bmvPbOjdb3Kl+mT52SX3XKp5kmnKPESQhdfrWqVSr8H8+QpJi+0GuSxVEE3GcawPNwK+NqEg== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" -"@ckeditor/ckeditor5-utils@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-47.5.0.tgz#a590672797cf2dcd7f62c70309c1206260894634" - integrity sha512-gkjlbVLjqkmZXo1lacY0kHRi9FTZjfJfL/OkF6WGauh0VLoDAIJHIv73PjqH6Sh7nF0Dx2p78NJ42W0t/KWxug== +"@ckeditor/ckeditor5-utils@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-47.6.0.tgz#ce8f38cdc063a15853cac311ddbcf5de87baffcc" + integrity sha512-+IWW2h6lGjXjLM6qlTHhB8xA7aR500KYQ7FteIn+5Aa5fT0ytyth8+AtmqpVJgXEtIK7GRCuexp1SFAcGntB/g== dependencies: - "@ckeditor/ckeditor5-ui" "47.5.0" + "@ckeditor/ckeditor5-ui" "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-watchdog@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-47.5.0.tgz#1b6ad7b68c2327cc936e38971902256846a20879" - integrity sha512-nmSnCvCvf9ChNS2C5YIdszSMeoGQRvd+CD4cDtLmkmaBqSuV/kePr5nGvqT8lMt5MrMtdqG/KmgE/xxmE4QIHg== +"@ckeditor/ckeditor5-watchdog@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-47.6.0.tgz#0b54d2331affb4536effef93909d343817b95c83" + integrity sha512-0oxx4Gxy5M7V3n4Iy7z6N10MzR/fwrOkFipaiisUbeMb0vHkprI4/i3i/I76iwLGYReSzu7E2Ha6+r9k5dtlfQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-editor-multi-root" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-editor-multi-root" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-widget@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-47.5.0.tgz#a5c71a0f1c0f6284d161553c067576587361060c" - integrity sha512-o8wFSP5Dx2kR6t2XDzpdw1IZoqOrCXdJ51iZvClsUn6zQ+EosZonlmej8oA96ZsRK/nw9GOSt2cM0Snzv3zDtQ== +"@ckeditor/ckeditor5-widget@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-47.6.0.tgz#eaf198832e7defb83c9549786b16829dc093f300" + integrity sha512-/HMwSHiupKVDSEDFgqzfhGEksXN83bM/VTE00e1d4lP4CpNx6HAIopajPHu4dMDFLnIPPqFbtwdTKX9S/ffH3Q== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" es-toolkit "1.39.5" -"@ckeditor/ckeditor5-word-count@47.5.0": - version "47.5.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-47.5.0.tgz#839000c7f28a0b116f47394dc65e7784be1a4eb7" - integrity sha512-zsATU4eI7iFWC+3axpj9JG7Gm6IRzDzjW8fQqYho0xMc3hN71XxgIbPZR7jLpwNo29WirCsNxAfqi4Q2Ws8c6w== +"@ckeditor/ckeditor5-word-count@47.6.0": + version "47.6.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-47.6.0.tgz#2b367dbba743b34d26b65f92cbfa6413d8ff9388" + integrity sha512-XDZSCXWsbbGzG4Cimbl9ArS3mKD7IllvQGYOHZgry80iqvI+V488G7baAlNV+adgdAdeCeaI0VZjdJSrQ8brUQ== dependencies: - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - ckeditor5 "47.5.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + ckeditor5 "47.6.0" es-toolkit "1.39.5" "@csstools/selector-resolve-nested@^3.1.0": @@ -2051,11 +2052,6 @@ webpack-manifest-plugin "^5.0.1" yargs-parser "^21.0.0" -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - "@types/color-convert@2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.4.tgz#843398ae71e951dc5415d202dfd5e43108823eeb" @@ -2793,9 +2789,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001759: - version "1.0.30001775" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz#9572266e3f7f77efee5deac1efeb4795879d1b7f" - integrity sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A== + version "1.0.30001776" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz#3c64d006348a2e92037aa4302345129806a42d24" + integrity sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw== ccount@^2.0.0: version "2.0.1" @@ -2872,72 +2868,72 @@ ci-info@^4.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.4.0.tgz#7d54eff9f54b45b62401c26032696eb59c8bd18c" integrity sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg== -ckeditor5@47.5.0, ckeditor5@^47.0.0: - version "47.5.0" - resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-47.5.0.tgz#f40b2eef70fe768f9e23438bc6d32ac7362199b2" - integrity sha512-Ow4eLxOxXoaIeuugBh4fCidLuu3zICInWO6ugB0+nZRGn9dfz9ENfdk6UlShyV2B0C5Ocu2n6Fm6I5hlByC/qA== +ckeditor5@47.6.0, ckeditor5@^47.0.0: + version "47.6.0" + resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-47.6.0.tgz#f9391aaebb435bdb1b9b8ecc3e8b38ebbdee94a4" + integrity sha512-OynbpuohqK5XV+d5itPRMnXrFjbrTcJQp8xwFbeZzvD58aeoxVSLnM8hX2V6o3wM6OvkBdSGuKq+XhjKcRfM9g== dependencies: - "@ckeditor/ckeditor5-adapter-ckfinder" "47.5.0" - "@ckeditor/ckeditor5-alignment" "47.5.0" - "@ckeditor/ckeditor5-autoformat" "47.5.0" - "@ckeditor/ckeditor5-autosave" "47.5.0" - "@ckeditor/ckeditor5-basic-styles" "47.5.0" - "@ckeditor/ckeditor5-block-quote" "47.5.0" - "@ckeditor/ckeditor5-bookmark" "47.5.0" - "@ckeditor/ckeditor5-ckbox" "47.5.0" - "@ckeditor/ckeditor5-ckfinder" "47.5.0" - "@ckeditor/ckeditor5-clipboard" "47.5.0" - "@ckeditor/ckeditor5-cloud-services" "47.5.0" - "@ckeditor/ckeditor5-code-block" "47.5.0" - "@ckeditor/ckeditor5-core" "47.5.0" - "@ckeditor/ckeditor5-easy-image" "47.5.0" - "@ckeditor/ckeditor5-editor-balloon" "47.5.0" - "@ckeditor/ckeditor5-editor-classic" "47.5.0" - "@ckeditor/ckeditor5-editor-decoupled" "47.5.0" - "@ckeditor/ckeditor5-editor-inline" "47.5.0" - "@ckeditor/ckeditor5-editor-multi-root" "47.5.0" - "@ckeditor/ckeditor5-emoji" "47.5.0" - "@ckeditor/ckeditor5-engine" "47.5.0" - "@ckeditor/ckeditor5-enter" "47.5.0" - "@ckeditor/ckeditor5-essentials" "47.5.0" - "@ckeditor/ckeditor5-find-and-replace" "47.5.0" - "@ckeditor/ckeditor5-font" "47.5.0" - "@ckeditor/ckeditor5-fullscreen" "47.5.0" - "@ckeditor/ckeditor5-heading" "47.5.0" - "@ckeditor/ckeditor5-highlight" "47.5.0" - "@ckeditor/ckeditor5-horizontal-line" "47.5.0" - "@ckeditor/ckeditor5-html-embed" "47.5.0" - "@ckeditor/ckeditor5-html-support" "47.5.0" - "@ckeditor/ckeditor5-icons" "47.5.0" - "@ckeditor/ckeditor5-image" "47.5.0" - "@ckeditor/ckeditor5-indent" "47.5.0" - "@ckeditor/ckeditor5-language" "47.5.0" - "@ckeditor/ckeditor5-link" "47.5.0" - "@ckeditor/ckeditor5-list" "47.5.0" - "@ckeditor/ckeditor5-markdown-gfm" "47.5.0" - "@ckeditor/ckeditor5-media-embed" "47.5.0" - "@ckeditor/ckeditor5-mention" "47.5.0" - "@ckeditor/ckeditor5-minimap" "47.5.0" - "@ckeditor/ckeditor5-page-break" "47.5.0" - "@ckeditor/ckeditor5-paragraph" "47.5.0" - "@ckeditor/ckeditor5-paste-from-office" "47.5.0" - "@ckeditor/ckeditor5-remove-format" "47.5.0" - "@ckeditor/ckeditor5-restricted-editing" "47.5.0" - "@ckeditor/ckeditor5-select-all" "47.5.0" - "@ckeditor/ckeditor5-show-blocks" "47.5.0" - "@ckeditor/ckeditor5-source-editing" "47.5.0" - "@ckeditor/ckeditor5-special-characters" "47.5.0" - "@ckeditor/ckeditor5-style" "47.5.0" - "@ckeditor/ckeditor5-table" "47.5.0" - "@ckeditor/ckeditor5-theme-lark" "47.5.0" - "@ckeditor/ckeditor5-typing" "47.5.0" - "@ckeditor/ckeditor5-ui" "47.5.0" - "@ckeditor/ckeditor5-undo" "47.5.0" - "@ckeditor/ckeditor5-upload" "47.5.0" - "@ckeditor/ckeditor5-utils" "47.5.0" - "@ckeditor/ckeditor5-watchdog" "47.5.0" - "@ckeditor/ckeditor5-widget" "47.5.0" - "@ckeditor/ckeditor5-word-count" "47.5.0" + "@ckeditor/ckeditor5-adapter-ckfinder" "47.6.0" + "@ckeditor/ckeditor5-alignment" "47.6.0" + "@ckeditor/ckeditor5-autoformat" "47.6.0" + "@ckeditor/ckeditor5-autosave" "47.6.0" + "@ckeditor/ckeditor5-basic-styles" "47.6.0" + "@ckeditor/ckeditor5-block-quote" "47.6.0" + "@ckeditor/ckeditor5-bookmark" "47.6.0" + "@ckeditor/ckeditor5-ckbox" "47.6.0" + "@ckeditor/ckeditor5-ckfinder" "47.6.0" + "@ckeditor/ckeditor5-clipboard" "47.6.0" + "@ckeditor/ckeditor5-cloud-services" "47.6.0" + "@ckeditor/ckeditor5-code-block" "47.6.0" + "@ckeditor/ckeditor5-core" "47.6.0" + "@ckeditor/ckeditor5-easy-image" "47.6.0" + "@ckeditor/ckeditor5-editor-balloon" "47.6.0" + "@ckeditor/ckeditor5-editor-classic" "47.6.0" + "@ckeditor/ckeditor5-editor-decoupled" "47.6.0" + "@ckeditor/ckeditor5-editor-inline" "47.6.0" + "@ckeditor/ckeditor5-editor-multi-root" "47.6.0" + "@ckeditor/ckeditor5-emoji" "47.6.0" + "@ckeditor/ckeditor5-engine" "47.6.0" + "@ckeditor/ckeditor5-enter" "47.6.0" + "@ckeditor/ckeditor5-essentials" "47.6.0" + "@ckeditor/ckeditor5-find-and-replace" "47.6.0" + "@ckeditor/ckeditor5-font" "47.6.0" + "@ckeditor/ckeditor5-fullscreen" "47.6.0" + "@ckeditor/ckeditor5-heading" "47.6.0" + "@ckeditor/ckeditor5-highlight" "47.6.0" + "@ckeditor/ckeditor5-horizontal-line" "47.6.0" + "@ckeditor/ckeditor5-html-embed" "47.6.0" + "@ckeditor/ckeditor5-html-support" "47.6.0" + "@ckeditor/ckeditor5-icons" "47.6.0" + "@ckeditor/ckeditor5-image" "47.6.0" + "@ckeditor/ckeditor5-indent" "47.6.0" + "@ckeditor/ckeditor5-language" "47.6.0" + "@ckeditor/ckeditor5-link" "47.6.0" + "@ckeditor/ckeditor5-list" "47.6.0" + "@ckeditor/ckeditor5-markdown-gfm" "47.6.0" + "@ckeditor/ckeditor5-media-embed" "47.6.0" + "@ckeditor/ckeditor5-mention" "47.6.0" + "@ckeditor/ckeditor5-minimap" "47.6.0" + "@ckeditor/ckeditor5-page-break" "47.6.0" + "@ckeditor/ckeditor5-paragraph" "47.6.0" + "@ckeditor/ckeditor5-paste-from-office" "47.6.0" + "@ckeditor/ckeditor5-remove-format" "47.6.0" + "@ckeditor/ckeditor5-restricted-editing" "47.6.0" + "@ckeditor/ckeditor5-select-all" "47.6.0" + "@ckeditor/ckeditor5-show-blocks" "47.6.0" + "@ckeditor/ckeditor5-source-editing" "47.6.0" + "@ckeditor/ckeditor5-special-characters" "47.6.0" + "@ckeditor/ckeditor5-style" "47.6.0" + "@ckeditor/ckeditor5-table" "47.6.0" + "@ckeditor/ckeditor5-theme-lark" "47.6.0" + "@ckeditor/ckeditor5-typing" "47.6.0" + "@ckeditor/ckeditor5-ui" "47.6.0" + "@ckeditor/ckeditor5-undo" "47.6.0" + "@ckeditor/ckeditor5-upload" "47.6.0" + "@ckeditor/ckeditor5-utils" "47.6.0" + "@ckeditor/ckeditor5-watchdog" "47.6.0" + "@ckeditor/ckeditor5-widget" "47.6.0" + "@ckeditor/ckeditor5-word-count" "47.6.0" clean-stack@^2.0.0: version "2.2.0" @@ -3674,9 +3670,9 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: gopd "^1.2.0" electron-to-chromium@^1.5.263: - version "1.5.302" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz#032a5802b31f7119269959c69fe2015d8dad5edb" - integrity sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg== + version "1.5.307" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz#09f8973100c39fb0d003b890393cd1d58932b1c8" + integrity sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg== emoji-regex@^7.0.1: version "7.0.3" @@ -3693,7 +3689,7 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== -enhanced-resolve@^5.0.0, enhanced-resolve@^5.19.0: +enhanced-resolve@^5.0.0, enhanced-resolve@^5.20.0: version "5.20.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz#323c2a70d2aa7fb4bdfd6d3c24dfc705c581295d" integrity sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ== @@ -4048,9 +4044,9 @@ for-each@^0.3.3, for-each@^0.3.5: is-callable "^1.2.7" fs-extra@^11.2.0: - version "11.3.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.3.tgz#a27da23b72524e81ac6c3815cc0179b8c74c59ee" - integrity sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg== + version "11.3.4" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.4.tgz#ab6934eca8bcf6f7f6b82742e33591f86301d6fc" + integrity sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" @@ -5105,9 +5101,9 @@ marked-mangle@^1.0.1: integrity sha512-bRrqNcfU9v3iRECb7YPvA+/xKZMjHojd9R92YwHbFjdPQ+Wc7vozkbGKAv4U8AUl798mNUuY3DTBQkedsV3TeQ== marked@^17.0.1: - version "17.0.3" - resolved "https://registry.yarnpkg.com/marked/-/marked-17.0.3.tgz#0defa25b1ba288433aa847848475d11109e1b3fd" - integrity sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A== + version "17.0.4" + resolved "https://registry.yarnpkg.com/marked/-/marked-17.0.4.tgz#38293b06b0605db39107803f3398938bbbed1b28" + integrity sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ== math-intrinsics@^1.1.0: version "1.1.0" @@ -5746,9 +5742,9 @@ node-notifier@^9.0.0: which "^2.0.2" node-releases@^2.0.27: - version "2.0.27" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" - integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== + version "2.0.36" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.36.tgz#99fd6552aaeda9e17c4713b57a63964a2e325e9d" + integrity sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -6507,9 +6503,9 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss@^8.2.14, postcss@^8.2.15, postcss@^8.4.12, postcss@^8.4.40: - version "8.5.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" - integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + version "8.5.8" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.8.tgz#6230ecc8fb02e7a0f6982e53990937857e13f399" + integrity sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg== dependencies: nanoid "^3.3.11" picocolors "^1.1.1" @@ -6916,10 +6912,10 @@ safe-regex-test@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.4.1, sax@^1.4.3: - version "1.4.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.4.tgz#f29c2bba80ce5b86f4343b4c2be9f2b96627cf8b" - integrity sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw== +sax@^1.4.3, sax@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.5.0.tgz#b5549b671069b7aa392df55ec7574cf411179eb8" + integrity sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA== schema-utils@^3.0.0: version "3.3.0" @@ -7344,22 +7340,22 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== svgo@^3.2.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.3.2.tgz#ad58002652dffbb5986fc9716afe52d869ecbda8" - integrity sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw== + version "3.3.3" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.3.3.tgz#8246aee0b08791fde3b0ed22b5661b471fadf58e" + integrity sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng== dependencies: - "@trysound/sax" "0.2.0" commander "^7.2.0" css-select "^5.1.0" css-tree "^2.3.1" css-what "^6.1.0" csso "^5.0.5" picocolors "^1.0.0" + sax "^1.5.0" svgo@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-4.0.0.tgz#17e0fa2eaccf429e0ec0d2179169abde9ba8ad3d" - integrity sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw== + version "4.0.1" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-4.0.1.tgz#c82dacd04ee9f1d55cd4e0b7f9a214c86670e3ee" + integrity sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w== dependencies: commander "^11.1.0" css-select "^5.1.0" @@ -7367,7 +7363,7 @@ svgo@^4.0.0: css-what "^6.1.0" csso "^5.0.5" picocolors "^1.1.1" - sax "^1.4.1" + sax "^1.5.0" tagged-tag@^1.0.0: version "1.0.0" @@ -7406,15 +7402,14 @@ terser-webpack-plugin@^4.2.3: terser "^5.3.4" webpack-sources "^1.4.3" -terser-webpack-plugin@^5.3.0, terser-webpack-plugin@^5.3.16: - version "5.3.16" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz#741e448cc3f93d8026ebe4f7ef9e4afacfd56330" - integrity sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q== +terser-webpack-plugin@^5.3.0, terser-webpack-plugin@^5.3.17: + version "5.3.17" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.17.tgz#75ea98876297fbb190d2fbb395e982582b859a67" + integrity sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw== dependencies: "@jridgewell/trace-mapping" "^0.3.25" jest-worker "^27.4.5" schema-utils "^4.3.0" - serialize-javascript "^6.0.2" terser "^5.31.1" terser@^5.3.4, terser@^5.31.1: @@ -7846,9 +7841,9 @@ webpack-sources@^3.3.4: integrity sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q== webpack@^5.74.0: - version "5.105.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.105.3.tgz#307ad95bafffd08bc81049d6519477b16e42e7ba" - integrity sha512-LLBBA4oLmT7sZdHiYE/PeVuifOxYyE2uL/V+9VQP7YSYdJU7bSf7H8bZRRxW8kEPMkmVjnrXmoR3oejIdX0xbg== + version "5.105.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.105.4.tgz#1b77fcd55a985ac7ca9de80a746caffa38220169" + integrity sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw== dependencies: "@types/eslint-scope" "^3.7.7" "@types/estree" "^1.0.8" @@ -7860,7 +7855,7 @@ webpack@^5.74.0: acorn-import-phases "^1.0.3" browserslist "^4.28.1" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.19.0" + enhanced-resolve "^5.20.0" es-module-lexer "^2.0.0" eslint-scope "5.1.1" events "^3.2.0" @@ -7872,7 +7867,7 @@ webpack@^5.74.0: neo-async "^2.6.2" schema-utils "^4.3.3" tapable "^2.3.0" - terser-webpack-plugin "^5.3.16" + terser-webpack-plugin "^5.3.17" watchpack "^2.5.1" webpack-sources "^3.3.4" From 3480dd146e68471af674f411277e66b7a406b800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Thu, 5 Mar 2026 00:02:35 +0100 Subject: [PATCH 12/34] Do not use customer reference for digikey barcode creation info as it likely contains not the part number Fixes #1285 --- .../LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php index e24c7077..5091b987 100644 --- a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php @@ -304,11 +304,11 @@ final readonly class BarcodeScanResultHandler return null; } - // Digi-Key: can use customerPartNumber or supplierPartNumber directly + // Digi-Key: supplierPartNumber directly if ($vendor === 'digikey') { return [ 'providerKey' => 'digikey', - 'providerId' => $scanResult->customerPartNumber ?? $scanResult->supplierPartNumber, + 'providerId' => $scanResult->supplierPartNumber ?? throw new \RuntimeException('Digikey barcode does not contain required supplier part number'), ]; } @@ -316,7 +316,7 @@ final readonly class BarcodeScanResultHandler if ($vendor === 'element14') { return [ 'providerKey' => 'element14', - 'providerId' => $scanResult->supplierPartNumber, + 'providerId' => $scanResult->supplierPartNumber ?? throw new \RuntimeException('Element14 barcode does not contain required supplier part number'), ]; } From d24a50a696abb1efa2061666480a8ad5f45de8fb Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 00:04:16 +0100 Subject: [PATCH 13/34] Auto-upload built assets as release attachments on version tag push (#1287) * Initial plan * Upload built assets as release attachments on version tag push Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> --- .github/workflows/assets_artifact_build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/assets_artifact_build.yml b/.github/workflows/assets_artifact_build.yml index 2622ca33..7ee5e7fc 100644 --- a/.github/workflows/assets_artifact_build.yml +++ b/.github/workflows/assets_artifact_build.yml @@ -8,6 +8,9 @@ on: branches: - '*' - "!l10n_*" # Dont test localization branches + tags: + - 'v*.*.*' + - 'v*.*.*-**' pull_request: branches: - '*' @@ -17,6 +20,8 @@ jobs: assets_artifact_build: name: Build assets artifact runs-on: ubuntu-22.04 + permissions: + contents: write env: APP_ENV: prod @@ -90,3 +95,10 @@ jobs: with: name: Full Part-DB including dependencies and built assets path: /tmp/partdb_with_assets.zip + + - name: Upload assets as release attachment + if: startsWith(github.ref, 'refs/tags/') + run: | + gh release upload "${{ github.ref_name }}" /tmp/partdb_assets.zip /tmp/partdb_with_assets.zip --clobber + env: + GH_TOKEN: ${{ github.token }} From 616c3a6742f02f71d680505043a62b48d8622890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Thu, 5 Mar 2026 00:22:08 +0100 Subject: [PATCH 14/34] Bumped version to 2.8.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 834f2629..dbe59006 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.8.0 +2.8.1 From 83608fffcfe730b45098c1e67a8f02294f612e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Fri, 6 Mar 2026 22:28:42 +0100 Subject: [PATCH 15/34] Do not scroll up the sidebar when clicking on a treeview --- assets/controllers/elements/sidebar_tree_controller.js | 2 ++ assets/controllers/elements/tree_controller.js | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/assets/controllers/elements/sidebar_tree_controller.js b/assets/controllers/elements/sidebar_tree_controller.js index d50cf900..c80de6ed 100644 --- a/assets/controllers/elements/sidebar_tree_controller.js +++ b/assets/controllers/elements/sidebar_tree_controller.js @@ -40,6 +40,8 @@ export default class extends TreeController { //Check if we have a saved mode const stored_mode = localStorage.getItem(this._storage_key); + this._frame = this.element.dataset.frame || "content"; //By default, navigate in the content frame, if a frame is defined + //Use stored mode if possible, otherwise use default if(stored_mode) { try { diff --git a/assets/controllers/elements/tree_controller.js b/assets/controllers/elements/tree_controller.js index bb64839c..28957e2a 100644 --- a/assets/controllers/elements/tree_controller.js +++ b/assets/controllers/elements/tree_controller.js @@ -39,6 +39,8 @@ export default class extends Controller { */ _tree = null; + _frame = "frame"; + connect() { const treeElement = this.treeTarget; if (!treeElement) { @@ -48,6 +50,7 @@ export default class extends Controller { this._url = this.element.dataset.treeUrl; this._data = this.element.dataset.treeData; + this._frame = this.element.dataset.frame || "content"; //By default, navigate in the content frame, if a frame is defined if(this.element.dataset.treeShowTags === "true") { this._showTags = true; @@ -99,7 +102,7 @@ export default class extends Controller { onNodeSelected: (event) => { const node = event.detail.node; if (node.href) { - window.Turbo.visit(node.href, {action: "advance"}); + window.Turbo.visit(node.href, {action: "advance", frame: this._frame}); this._registerURLWatcher(node); } }, @@ -198,4 +201,4 @@ export default class extends Controller { return myResolve(this._data); }); } -} \ No newline at end of file +} From f95a58087b87036813782409473c86fa9cd1c08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Fri, 6 Mar 2026 23:23:38 +0100 Subject: [PATCH 16/34] Select the respective node in the sidebar treeviews, when navigating Part-DB When you open a category page from everywhere in Part-DB, the respective node will be opened --- .../elements/sidebar_tree_controller.js | 34 +++++++++++++++++++ .../controllers/elements/tree_controller.js | 29 ---------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/assets/controllers/elements/sidebar_tree_controller.js b/assets/controllers/elements/sidebar_tree_controller.js index c80de6ed..e0f012be 100644 --- a/assets/controllers/elements/sidebar_tree_controller.js +++ b/assets/controllers/elements/sidebar_tree_controller.js @@ -19,6 +19,7 @@ import {Controller} from "@hotwired/stimulus"; import {default as TreeController} from "./tree_controller"; +import {EVENT_INITIALIZED} from "@jbtronics/bs-treeview"; export default class extends TreeController { static targets = [ "tree", 'sourceText' ]; @@ -57,6 +58,39 @@ export default class extends TreeController { //Register an event listener which checks if the tree needs to be updated document.addEventListener('turbo:render', this.doUpdateIfNeeded.bind(this)); + + //Register an event listener, to check if we end up on a page we can highlight in the tree, if so then higlight it + document.addEventListener('turbo:load', this._onTurboLoad.bind(this)); + //On initial page load the tree is not available yet, so do another check after the tree is initialized + this.treeTarget.addEventListener(EVENT_INITIALIZED, (event) => { + this.selectNodeWithURL(document.location) + }); + } + + _onTurboLoad(event) { + this.selectNodeWithURL(event.detail.url); + } + + selectNodeWithURL(url) { + //Get path from url + const path = new URL(url).pathname; + + if (!this._tree) { + return; + } + + //Unselect all nodes + this._tree.unselectAll({silent: true, ignorePreventUnselect: true}); + + //Try to find a node with this path as data-path + const nodes = this._tree.findNodes(path, "href"); + if (nodes.length !== 1) { + return; //We can only work with exactly one node, if there are multiple nodes with the same path, we cannot know which one to select, so we do nothing + } + const node = nodes[0]; + + node.setSelected(true, {ignorePreventUnselect: true, silent: true}); + this._tree.revealNode(node); } doUpdateIfNeeded() diff --git a/assets/controllers/elements/tree_controller.js b/assets/controllers/elements/tree_controller.js index 28957e2a..13a7a9f9 100644 --- a/assets/controllers/elements/tree_controller.js +++ b/assets/controllers/elements/tree_controller.js @@ -113,41 +113,12 @@ export default class extends Controller { const treeView = event.detail.treeView; treeView.revealNode(treeView.getSelected()); - //Add the url watcher to all selected nodes - for (const node of treeView.getSelected()) { - this._registerURLWatcher(node); - } - //Add contextmenu event listener to the tree, which allows us to open the links in a new tab with a right click treeView.getTreeElement().addEventListener("contextmenu", this._onContextMenu.bind(this)); }); } - _registerURLWatcher(node) - { - //Register a watcher for a location change, which will unselect the node, if the location changes - const desired_url = node.href; - - //Ensure that the node is unselected, if the location changes - const unselectNode = () => { - //Parse url so we can properly compare them - const desired = new URL(node.href, window.location.origin); - - //We only compare the pathname, because the hash and parameters should not matter - if(window.location.pathname !== desired.pathname) { - //The ignore parameter is important here, otherwise the node will not be unselected - node.setSelected(false, {silent: true, ignorePreventUnselect: true}); - - //Unregister the watcher - document.removeEventListener('turbo:load', unselectNode); - } - }; - - //Register the watcher via hotwire turbo - //We must just load to have the new url in window.location - document.addEventListener('turbo:load', unselectNode); - } _onContextMenu(event) { From 30e3bc3153a430ee6ab6bcb768a9625acb297315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 00:26:20 +0100 Subject: [PATCH 17/34] Fixed highlight on url change for tools sidebar tree --- .../controllers/elements/tree_controller.js | 1 - yarn.lock | 242 +++++++++--------- 2 files changed, 121 insertions(+), 122 deletions(-) diff --git a/assets/controllers/elements/tree_controller.js b/assets/controllers/elements/tree_controller.js index 13a7a9f9..80a06bc3 100644 --- a/assets/controllers/elements/tree_controller.js +++ b/assets/controllers/elements/tree_controller.js @@ -103,7 +103,6 @@ export default class extends Controller { const node = event.detail.node; if (node.href) { window.Turbo.visit(node.href, {action: "advance", frame: this._frame}); - this._registerURLWatcher(node); } }, }, [BS5Theme, BS53Theme, FAIconTheme]); diff --git a/yarn.lock b/yarn.lock index 2f8fa801..93bf5d78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -141,10 +141,10 @@ regexpu-core "^6.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.6.6": - version "0.6.6" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz#714dfe33d8bd710f556df59953720f6eeb6c1a14" - integrity sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA== +"@babel/helper-define-polyfill-provider@^0.6.7": + version "0.6.7" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.7.tgz#8d01cba97de419115ad3497573a476db15dc6c6a" + integrity sha512-6Fqi8MtQ/PweQ9xvux65emkLQ83uB+qAVtfHkC9UodyHMIZdxNI01HjLCLUtybElp2KY2XNE0nOgyP1E1vXw9w== dependencies: "@babel/helper-compilation-targets" "^7.28.6" "@babel/helper-plugin-utils" "^7.28.6" @@ -1859,9 +1859,9 @@ integrity sha512-GZ7cijxEZ6Ig71u7rD6LHaRv/wcE/hNsc+nEfiWOkLNqUgLOwo5MNGWOy5ZV9ZUDSiQx1no7YxjTNnT4O6//cQ== "@jbtronics/bs-treeview@^1.0.1": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@jbtronics/bs-treeview/-/bs-treeview-1.0.6.tgz#7fe126a2ca4716c824d97ab6d1a5f2417750445a" - integrity sha512-fLY2tnbDYO4kCjpmGQyfvoHN8x72Rk5p+tTgVjKJUbiJHHhXt0yIW+l5P83CwYtPD5EwS7kMKc8RLuU1xA2bpA== + version "1.0.7" + resolved "https://registry.yarnpkg.com/@jbtronics/bs-treeview/-/bs-treeview-1.0.7.tgz#42a5ea40ce1bfe6cffbc1b811dc4e32dd8d0273a" + integrity sha512-AvEdkQNkNvh9+yGGHto8ABBsicEzFjLtSSbl61c9D0yq+RrIsrwTpz/H3RmDhvdtdteywQRItVuS18XOc+0p2A== "@jest/pattern@30.0.1": version "30.0.1" @@ -2156,9 +2156,9 @@ integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== "@types/node@*": - version "25.3.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-25.3.3.tgz#605862544ee7ffd7a936bcbf0135a14012f1e549" - integrity sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ== + version "25.3.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.3.5.tgz#beccb5915561f7a9970ace547ad44d6cdbf39b46" + integrity sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA== dependencies: undici-types "~7.18.0" @@ -2556,35 +2556,35 @@ available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" "babel-loader@^9.1.3 || ^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-10.0.0.tgz#b9743714c0e1e084b3e4adef3cd5faee33089977" - integrity sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA== + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-10.1.0.tgz#3ac62a9a47dba6b1be77fb24764ec5784981fbbe" + integrity sha512-5HTUZa013O4SWEYlJDHexrqSIYkWatfA9w/ZZQa7V2nMc0dRWkfu/0pmioC7XMYm8M7Z/3+q42NWj6e+fAT0MQ== dependencies: find-up "^5.0.0" babel-plugin-polyfill-corejs2@^0.4.15: - version "0.4.15" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz#808fa349686eea4741807cfaaa2aa3aa57ce120a" - integrity sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw== + version "0.4.16" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.16.tgz#a1321145f6cde738b0a412616b6bcf77f143ab36" + integrity sha512-xaVwwSfebXf0ooE11BJovZYKhFjIvQo7TsyVpETuIeH2JHv0k/T6Y5j22pPTvqYqmpkxdlPAJlyJ0tfOJAoMxw== dependencies: "@babel/compat-data" "^7.28.6" - "@babel/helper-define-polyfill-provider" "^0.6.6" + "@babel/helper-define-polyfill-provider" "^0.6.7" semver "^6.3.1" babel-plugin-polyfill-corejs3@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz#65b06cda48d6e447e1e926681f5a247c6ae2b9cf" - integrity sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ== + version "0.14.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.1.tgz#75fb533a1c23c0a976f189cba1d035199705b8ad" + integrity sha512-ENp89vM9Pw4kv/koBb5N2f9bDZsR0hpf3BdPMOg/pkS3pwO4dzNnQZVXtBbeyAadgm865DmQG2jMMLqmZXvuCw== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.6" + "@babel/helper-define-polyfill-provider" "^0.6.7" core-js-compat "^3.48.0" babel-plugin-polyfill-regenerator@^0.6.6: - version "0.6.6" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz#69f5dd263cab933c42fe5ea05e83443b374bd4bf" - integrity sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A== + version "0.6.7" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.7.tgz#eca723d67ef87b798881ad00546db1b6dd72e1ef" + integrity sha512-OTYbUlSwXhNgr4g6efMZgsO8//jA61P7ZbRX3iTT53VON8l+WQS8IAUEVo4a4cWknrg2W8Cj4gQhRYNCJ8GkAA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.6" + "@babel/helper-define-polyfill-provider" "^0.6.7" bail@^2.0.0: version "2.0.2" @@ -2692,7 +2692,7 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserslist@^4.0.0, browserslist@^4.23.0, browserslist@^4.24.0, browserslist@^4.27.0, browserslist@^4.28.1: +browserslist@^4.0.0, browserslist@^4.23.0, browserslist@^4.24.0, browserslist@^4.28.1: version "4.28.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== @@ -2789,9 +2789,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001759: - version "1.0.30001776" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz#3c64d006348a2e92037aa4302345129806a42d24" - integrity sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw== + version "1.0.30001777" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz#028f21e4b2718d138b55e692583e6810ccf60691" + integrity sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ== ccount@^2.0.0: version "2.0.1" @@ -3220,12 +3220,12 @@ css-tree@^2.3.1: source-map-js "^1.0.1" css-tree@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.1.0.tgz#7aabc035f4e66b5c86f54570d55e05b1346eb0fd" - integrity sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w== + version "3.2.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.2.1.tgz#86cac7011561272b30e6b1e042ba6ce047aa7518" + integrity sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA== dependencies: - mdn-data "2.12.2" - source-map-js "^1.0.1" + mdn-data "2.27.1" + source-map-js "^1.2.1" css-tree@~2.2.0: version "2.2.1" @@ -3281,41 +3281,41 @@ cssnano-preset-default@^6.1.2: postcss-svgo "^6.0.3" postcss-unique-selectors "^6.0.4" -cssnano-preset-default@^7.0.10: - version "7.0.10" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-7.0.10.tgz#4fb6ee962c0852a03084e8c7a4b60fb0e2db45e0" - integrity sha512-6ZBjW0Lf1K1Z+0OKUAUpEN62tSXmYChXWi2NAA0afxEVsj9a+MbcB1l5qel6BHJHmULai2fCGRthCeKSFbScpA== +cssnano-preset-default@^7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-7.0.11.tgz#ea81661d0e8fe59b752560cca4a9f2fac763e92c" + integrity sha512-waWlAMuCakP7//UCY+JPrQS1z0OSLeOXk2sKWJximKWGupVxre50bzPlvpbUwZIDylhf/ptf0Pk+Yf7C+hoa3g== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" css-declaration-sorter "^7.2.0" cssnano-utils "^5.0.1" postcss-calc "^10.1.1" - postcss-colormin "^7.0.5" - postcss-convert-values "^7.0.8" - postcss-discard-comments "^7.0.5" + postcss-colormin "^7.0.6" + postcss-convert-values "^7.0.9" + postcss-discard-comments "^7.0.6" postcss-discard-duplicates "^7.0.2" postcss-discard-empty "^7.0.1" postcss-discard-overridden "^7.0.1" postcss-merge-longhand "^7.0.5" - postcss-merge-rules "^7.0.7" + postcss-merge-rules "^7.0.8" postcss-minify-font-values "^7.0.1" postcss-minify-gradients "^7.0.1" - postcss-minify-params "^7.0.5" - postcss-minify-selectors "^7.0.5" + postcss-minify-params "^7.0.6" + postcss-minify-selectors "^7.0.6" postcss-normalize-charset "^7.0.1" postcss-normalize-display-values "^7.0.1" postcss-normalize-positions "^7.0.1" postcss-normalize-repeat-style "^7.0.1" postcss-normalize-string "^7.0.1" postcss-normalize-timing-functions "^7.0.1" - postcss-normalize-unicode "^7.0.5" + postcss-normalize-unicode "^7.0.6" postcss-normalize-url "^7.0.1" postcss-normalize-whitespace "^7.0.1" postcss-ordered-values "^7.0.2" - postcss-reduce-initial "^7.0.5" + postcss-reduce-initial "^7.0.6" postcss-reduce-transforms "^7.0.1" - postcss-svgo "^7.1.0" - postcss-unique-selectors "^7.0.4" + postcss-svgo "^7.1.1" + postcss-unique-selectors "^7.0.5" cssnano-utils@^4.0.2: version "4.0.2" @@ -3336,11 +3336,11 @@ cssnano@^6.0.3: lilconfig "^3.1.1" cssnano@^7.0.4: - version "7.1.2" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-7.1.2.tgz#a8a533a8f509d74b2d22e73d80ec1294f65fdc70" - integrity sha512-HYOPBsNvoiFeR1eghKD5C3ASm64v9YVyJB4Ivnl2gqKoQYvjjN/G0rztvKQq8OxocUtC6sjqY8jwYngIB4AByA== + version "7.1.3" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-7.1.3.tgz#2a542bb8d62b6bee9e23e455ba2e507fd102f611" + integrity sha512-mLFHQAzyapMVFLiJIn7Ef4C2UCEvtlTlbyILR6B5ZsUAV3D/Pa761R5uC1YPhyBkRd3eqaDm2ncaNrD7R4mTRg== dependencies: - cssnano-preset-default "^7.0.10" + cssnano-preset-default "^7.0.11" lilconfig "^3.1.3" csso@^5.0.5: @@ -3636,9 +3636,9 @@ domhandler@^5.0.2, domhandler@^5.0.3: domelementtype "^2.3.0" dompurify@^3.0.3: - version "3.3.1" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.3.1.tgz#c7e1ddebfe3301eacd6c0c12a4af284936dbbb86" - integrity sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q== + version "3.3.2" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.3.2.tgz#58c515d0f8508b8749452a028aa589ad80b36325" + integrity sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ== optionalDependencies: "@types/trusted-types" "^2.0.7" @@ -4956,9 +4956,9 @@ jszip@^3.2.0: setimmediate "^1.0.5" katex@^0.16.0: - version "0.16.33" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.33.tgz#5cd5af2ddc1132fe6a710ae6604ec1f19fca9e91" - integrity sha512-q3N5u+1sY9Bu7T4nlXoiRBXWfwSefNGoKeOwekV+gw0cAXQlz2Ww6BLcmBxVDeXBMUDQv6fK5bcNaJLxob3ZQA== + version "0.16.37" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.37.tgz#aae346d30ebfde946c915405a48099d71ab9b149" + integrity sha512-TIGjO2cCGYono+uUzgkE7RFF329mLLWGuHUlSr6cwIVj9O8f0VQZ783rsanmJpFUo32vvtj7XT04NGRPh+SZFg== dependencies: commander "^8.3.0" @@ -5266,10 +5266,10 @@ mdn-data@2.0.30: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== -mdn-data@2.12.2: - version "2.12.2" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.2.tgz#9ae6c41a9e65adf61318b32bff7b64fbfb13f8cf" - integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA== +mdn-data@2.27.1: + version "2.27.1" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.27.1.tgz#e37b9c50880b75366c4d40ac63d9bbcacdb61f0e" + integrity sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ== merge-stream@^2.0.0: version "2.0.0" @@ -6033,12 +6033,12 @@ postcss-colormin@^6.1.0: colord "^2.9.3" postcss-value-parser "^4.2.0" -postcss-colormin@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-7.0.5.tgz#0c7526289ab3f0daf96a376fd7430fae7258d5cf" - integrity sha512-ekIBP/nwzRWhEMmIxHHbXHcMdzd1HIUzBECaj5KEdLz9DVP2HzT065sEhvOx1dkLjYW7jyD0CngThx6bpFi2fA== +postcss-colormin@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-7.0.6.tgz#8f1bcfaa6f4959a872824f3b5bd4e1278bf35e45" + integrity sha512-oXM2mdx6IBTRm39797QguYzVEWzbdlFiMNfq88fCCN1Wepw3CYmJ/1/Ifa/KjWo+j5ZURDl2NTldLJIw51IeNQ== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" caniuse-api "^3.0.0" colord "^2.9.3" postcss-value-parser "^4.2.0" @@ -6051,12 +6051,12 @@ postcss-convert-values@^6.1.0: browserslist "^4.23.0" postcss-value-parser "^4.2.0" -postcss-convert-values@^7.0.8: - version "7.0.8" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-7.0.8.tgz#0c599dc29891d47d7b4d6db399c402cf3ba8efc3" - integrity sha512-+XNKuPfkHTCEo499VzLMYn94TiL3r9YqRE3Ty+jP7UX4qjewUONey1t7CG21lrlTLN07GtGM8MqFVp86D4uKJg== +postcss-convert-values@^7.0.9: + version "7.0.9" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-7.0.9.tgz#6ada5c2c480f1ddbd4c886339025a916ecc8ff01" + integrity sha512-l6uATQATZaCa0bckHV+r6dLXfWtUBKXxO3jK+AtxxJJtgMPD+VhhPCCx51I4/5w8U5uHV67g3w7PXj+V3wlMlg== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" postcss-value-parser "^4.2.0" postcss-discard-comments@^6.0.2: @@ -6064,12 +6064,12 @@ postcss-discard-comments@^6.0.2: resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz#e768dcfdc33e0216380623652b0a4f69f4678b6c" integrity sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw== -postcss-discard-comments@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-7.0.5.tgz#0a95aa4d229a021bc441861d4773d57145ee15dd" - integrity sha512-IR2Eja8WfYgN5n32vEGSctVQ1+JARfu4UH8M7bgGh1bC+xI/obsPJXaBpQF7MAByvgwZinhpHpdrmXtvVVlKcQ== +postcss-discard-comments@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-7.0.6.tgz#4e9c696a83391d90b3ffa4485ac144e555db443c" + integrity sha512-Sq+Fzj1Eg5/CPf1ERb0wS1Im5cvE2gDXCE+si4HCn1sf+jpQZxDI4DXEp8t77B/ImzDceWE2ebJQFXdqZ6GRJw== dependencies: - postcss-selector-parser "^7.1.0" + postcss-selector-parser "^7.1.1" postcss-discard-duplicates@^6.0.3: version "6.0.3" @@ -6154,15 +6154,15 @@ postcss-merge-rules@^6.1.1: cssnano-utils "^4.0.2" postcss-selector-parser "^6.0.16" -postcss-merge-rules@^7.0.7: - version "7.0.7" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-7.0.7.tgz#f49537e5029ce0e655c2f31fdb205f14575c7334" - integrity sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew== +postcss-merge-rules@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-7.0.8.tgz#d63ce875b9f7880ca4aa89d9ae3eaa3657215f82" + integrity sha512-BOR1iAM8jnr7zoQSlpeBmCsWV5Uudi/+5j7k05D0O/WP3+OFMPD86c1j/20xiuRtyt45bhxw/7hnhZNhW2mNFA== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" caniuse-api "^3.0.0" cssnano-utils "^5.0.1" - postcss-selector-parser "^7.1.0" + postcss-selector-parser "^7.1.1" postcss-minify-font-values@^6.1.0: version "6.1.0" @@ -6205,12 +6205,12 @@ postcss-minify-params@^6.1.0: cssnano-utils "^4.0.2" postcss-value-parser "^4.2.0" -postcss-minify-params@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-7.0.5.tgz#4a0d15e312252e41d0c8504227d43538e3f607a2" - integrity sha512-FGK9ky02h6Ighn3UihsyeAH5XmLEE2MSGH5Tc4tXMFtEDx7B+zTG6hD/+/cT+fbF7PbYojsmmWjyTwFwW1JKQQ== +postcss-minify-params@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-7.0.6.tgz#ca0df1bd4eaa70ee7a4ee17f393d275988f44657" + integrity sha512-YOn02gC68JijlaXVuKvFSCvQOhTpblkcfDre2hb/Aaa58r2BIaK4AtE/cyZf2wV7YKAG+UlP9DT+By0ry1E4VQ== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" cssnano-utils "^5.0.1" postcss-value-parser "^4.2.0" @@ -6221,13 +6221,13 @@ postcss-minify-selectors@^6.0.4: dependencies: postcss-selector-parser "^6.0.16" -postcss-minify-selectors@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz#d8c89eeeb208705ab4127a464d1f54a3bc22cae3" - integrity sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug== +postcss-minify-selectors@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-7.0.6.tgz#1e0240e1fa3372d81d3f0586591f1e8d2ae21e16" + integrity sha512-lIbC0jy3AAwDxEgciZlBullDiMBeBCT+fz5G8RcA9MWqh/hfUkpOI3vNDUNEZHgokaoiv0juB9Y8fGcON7rU/A== dependencies: cssesc "^3.0.0" - postcss-selector-parser "^7.1.0" + postcss-selector-parser "^7.1.1" postcss-mixins@^9.0.2: version "9.0.4" @@ -6364,12 +6364,12 @@ postcss-normalize-unicode@^6.1.0: browserslist "^4.23.0" postcss-value-parser "^4.2.0" -postcss-normalize-unicode@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.5.tgz#d47a3cc40529d7eeb18d7f7a8a215c38c54455cd" - integrity sha512-X6BBwiRxVaFHrb2WyBMddIeB5HBjJcAaUHyhLrM2FsxSq5TFqcHSsK7Zu1otag+o0ZphQGJewGH1tAyrD0zX1Q== +postcss-normalize-unicode@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.6.tgz#6935d6baf7f7374a34c216a7fe13229acd1073f2" + integrity sha512-z6bwTV84YW6ZvvNoaNLuzRW4/uWxDKYI1iIDrzk6D2YTL7hICApy+Q1LP6vBEsljX8FM7YSuV9qI79XESd4ddQ== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" postcss-value-parser "^4.2.0" postcss-normalize-url@^6.0.2: @@ -6424,12 +6424,12 @@ postcss-reduce-initial@^6.1.0: browserslist "^4.23.0" caniuse-api "^3.0.0" -postcss-reduce-initial@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-7.0.5.tgz#cf74bb747dfa003cd3d5372081f6157e6d8e1545" - integrity sha512-RHagHLidG8hTZcnr4FpyMB2jtgd/OcyAazjMhoy5qmWJOx1uxKh4ntk0Pb46ajKM0rkf32lRH4C8c9qQiPR6IA== +postcss-reduce-initial@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-7.0.6.tgz#fa3af45e60cd04d9a3d29315eb97c82b7b447ead" + integrity sha512-G6ZyK68AmrPdMB6wyeA37ejnnRG2S8xinJrZJnOv+IaRKf6koPAVbQsiC7MfkmXaGmF1UO+QCijb27wfpxuRNg== dependencies: - browserslist "^4.27.0" + browserslist "^4.28.1" caniuse-api "^3.0.0" postcss-reduce-transforms@^6.0.2: @@ -6454,7 +6454,7 @@ postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.16: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-selector-parser@^7.0.0, postcss-selector-parser@^7.1.0: +postcss-selector-parser@^7.0.0, postcss-selector-parser@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz#e75d2e0d843f620e5df69076166f4e16f891cb9f" integrity sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg== @@ -6475,13 +6475,13 @@ postcss-svgo@^6.0.3: postcss-value-parser "^4.2.0" svgo "^3.2.0" -postcss-svgo@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-7.1.0.tgz#7eb6764a643ac2699bf56eef6d2676d428ed4542" - integrity sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w== +postcss-svgo@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-7.1.1.tgz#14b90fd2a1b1f27bcb2d0ef0444f954237e7883c" + integrity sha512-zU9H9oEDrUFKa0JB7w+IYL7Qs9ey1mZyjhbf0KLxwJDdDRtoPvCmaEfknzqfHj44QS9VD6c5sJnBAVYTLRg/Sg== dependencies: postcss-value-parser "^4.2.0" - svgo "^4.0.0" + svgo "^4.0.1" postcss-unique-selectors@^6.0.4: version "6.0.4" @@ -6490,12 +6490,12 @@ postcss-unique-selectors@^6.0.4: dependencies: postcss-selector-parser "^6.0.16" -postcss-unique-selectors@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz#625ad1c808bdf322fab6c027ae8d4f2637140995" - integrity sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ== +postcss-unique-selectors@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-7.0.5.tgz#a7dd5652c95f459176e5f135c021473e4ee58874" + integrity sha512-3QoYmEt4qg/rUWDn6Tc8+ZVPmbp4G1hXDtCNWDx0st8SjtCbRcxRXDDM1QrEiXGG3A45zscSJFb4QH90LViyxg== dependencies: - postcss-selector-parser "^7.1.0" + postcss-selector-parser "^7.1.1" postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: version "4.2.0" @@ -7294,12 +7294,12 @@ stylehacks@^6.1.1: postcss-selector-parser "^6.0.16" stylehacks@^7.0.5: - version "7.0.7" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-7.0.7.tgz#12b0dd1eceee4d564aae6da0632804ef0004a5be" - integrity sha512-bJkD0JkEtbRrMFtwgpJyBbFIwfDDONQ1Ov3sDLZQP8HuJ73kBOyx66H4bOcAbVWmnfLdvQ0AJwXxOMkpujcO6g== + version "7.0.8" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-7.0.8.tgz#cb5d00bb1779a30c4d408a7d576c016c88b36491" + integrity sha512-I3f053GBLIiS5Fg6OMFhq/c+yW+5Hc2+1fgq7gElDMMSqwlRb3tBf2ef6ucLStYRpId4q//bQO1FjcyNyy4yDQ== dependencies: - browserslist "^4.27.0" - postcss-selector-parser "^7.1.0" + browserslist "^4.28.1" + postcss-selector-parser "^7.1.1" sugarss@^4.0.1: version "4.0.1" @@ -7352,7 +7352,7 @@ svgo@^3.2.0: picocolors "^1.0.0" sax "^1.5.0" -svgo@^4.0.0: +svgo@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/svgo/-/svgo-4.0.1.tgz#c82dacd04ee9f1d55cd4e0b7f9a214c86670e3ee" integrity sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w== From 598cf3ed80fd348f6aaf6bf5fe2eaa9a5cc05016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 00:46:34 +0100 Subject: [PATCH 18/34] Use a symfony form for login form This allows us to reuse the global form renderings --- src/Controller/SecurityController.php | 6 ++ src/Form/Security/LoginFormType.php | 83 +++++++++++++++++++++++++++ templates/security/login.html.twig | 54 ++++------------- 3 files changed, 101 insertions(+), 42 deletions(-) create mode 100644 src/Form/Security/LoginFormType.php diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index ad4d272f..93336bf9 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -25,6 +25,7 @@ namespace App\Controller; use App\Entity\UserSystem\User; use App\Events\SecurityEvent; use App\Events\SecurityEvents; +use App\Form\Security\LoginFormType; use App\Services\UserSystem\PasswordResetManager; use Doctrine\ORM\EntityManagerInterface; use Gregwar\CaptchaBundle\Type\CaptchaType; @@ -61,7 +62,12 @@ class SecurityController extends AbstractController // last username entered by the user $lastUsername = $authenticationUtils->getLastUsername(); + $form = $this->createForm(LoginFormType::class, [ + '_username' => $lastUsername, + ]); + return $this->render('security/login.html.twig', [ + 'form' => $form, 'last_username' => $lastUsername, 'error' => $error, ]); diff --git a/src/Form/Security/LoginFormType.php b/src/Form/Security/LoginFormType.php new file mode 100644 index 00000000..184f68ac --- /dev/null +++ b/src/Form/Security/LoginFormType.php @@ -0,0 +1,83 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Security; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\OptionsResolver\OptionsResolver; + +use function Symfony\Component\Translation\t; + +class LoginFormType extends AbstractType +{ + public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options): void + { + $builder + ->add('_username', TextType::class, [ + 'label' => t('login.username.label'), + 'attr' => [ + 'autofocus' => 'autofocus', + 'autocomplete' => 'username', + 'placeholder' => t('login.username.placeholder'), + ] + ]) + ->add('_password', PasswordType::class, [ + 'label' => t('login.password.label'), + 'attr' => [ + 'autocomplete' => 'current-password', + 'placeholder' => t('login.password.placeholder'), + ] + ]) + ->add('_remember_me', CheckboxType::class, [ + 'label' => t('login.rememberme'), + 'required' => false, + ]) + ->add('submit', \Symfony\Component\Form\Extension\Core\Type\SubmitType::class, [ + 'label' => t('login.btn'), + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + // This ensures CSRF protection is active for the login + 'csrf_protection' => true, + 'csrf_field_name' => '_csrf_token', + 'csrf_token_id' => 'authenticate', + 'attr' => [ + 'data-turbo' => 'false', // Disable Turbo for the login form to ensure proper redirection after login + ] + ]); + } + + public function getBlockPrefix(): string + { + // This removes the "login_form_" prefix from field names + // so that Security can find "_username" directly. + return ''; + } +} diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig index b8a0df1d..c09b3669 100644 --- a/templates/security/login.html.twig +++ b/templates/security/login.html.twig @@ -20,53 +20,23 @@ {% endblock %} {% block card_content %} -
- + {% if saml_enabled %} +
+ {% trans %}login.sso_saml_login{% endtrans %} - - - {% if saml_enabled %} -
- {% trans %}login.sso_saml_login{% endtrans %} - -

{% trans %}login.local_login_hint{% endtrans %}

-
- - {% endif %} - -
- -
- -
-
-
- -
- -
+

{% trans %}login.local_login_hint{% endtrans %}

+ {% endif %} -
-
-
- - -
-
-
+ {{ form_start(form) }} -
-
- -
-
- + {{ form_row(form._username) }} + {{ form_row(form._password) }} + {{ form_row(form._remember_me) }} + {{ form_row(form.submit) }} + + {{ form_end(form) }} {% if allow_email_pw_reset %} {% trans %}pw_reset.password_forget{% endtrans %} From e8d90487d2593763dad462d2d744a73134b46c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 00:47:31 +0100 Subject: [PATCH 19/34] Added "show password" toggle to all password fields --- src/Form/Extension/TogglePasswordTypeExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Form/Extension/TogglePasswordTypeExtension.php b/src/Form/Extension/TogglePasswordTypeExtension.php index fec4c0b3..7d49eeda 100644 --- a/src/Form/Extension/TogglePasswordTypeExtension.php +++ b/src/Form/Extension/TogglePasswordTypeExtension.php @@ -45,7 +45,7 @@ final class TogglePasswordTypeExtension extends AbstractTypeExtension public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ - 'toggle' => false, + 'toggle' => true, 'hidden_label' => new TranslatableMessage('password_toggle.hide'), 'visible_label' => new TranslatableMessage('password_toggle.show'), 'hidden_icon' => 'Default', From e84bae28072b5db76f66703bfd613e5cfbf793ea Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Mar 2026 16:14:58 +0100 Subject: [PATCH 20/34] Make form layout better at wide screens & Make horizontal form column layout configurable via global Twig variables (#1293) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * Make form column layout configurable with global Twig variables Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> * Rename form column Twig globals to shorter names: label_col, input_col, offset_col Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> * Fixed remaining places where offsets where used * Fixed margin of delete button on admin forms * Rename Twig globals: col_label, col_input, offset_label Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> * Added documentation to our twig class variables --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com> Co-authored-by: Jan Böhmer --- config/packages/twig.yaml | 5 +++++ templates/admin/_delete_form.html.twig | 4 ++-- templates/admin/_duplicate.html.twig | 4 ++-- templates/admin/_export_form.html.twig | 4 ++-- templates/admin/base_admin.html.twig | 4 ++-- templates/admin/category_admin.html.twig | 6 +++--- templates/admin/currency_admin.html.twig | 6 +++--- templates/admin/footprint_admin.html.twig | 2 +- templates/admin/label_profile_admin.html.twig | 2 +- templates/admin/project_admin.html.twig | 4 ++-- templates/admin/storelocation_admin.html.twig | 2 +- templates/admin/user_admin.html.twig | 4 ++-- templates/attachment_list.html.twig | 2 +- .../form/collection_types_layout.html.twig | 4 ++-- .../form/extended_bootstrap_layout.html.twig | 4 ++-- .../info_providers/from_url/from_url.html.twig | 2 +- .../search/part_search.html.twig | 2 +- .../settings/provider_settings.html.twig | 4 ++-- templates/label_system/dialog.html.twig | 14 +++++++------- .../label_system/scanner/scanner.html.twig | 2 +- templates/log_system/log_list.html.twig | 2 +- templates/parts/edit/_eda.html.twig | 4 ++-- templates/parts/edit/_main.html.twig | 2 +- .../parts/edit/edit_form_styles.html.twig | 4 ++-- templates/parts/edit/edit_part_info.html.twig | 2 +- templates/parts/import/parts_import.html.twig | 2 +- .../parts/info/_stocktake_modal.html.twig | 16 ++++++++-------- templates/parts/info/_withdraw_modal.html.twig | 18 +++++++++--------- templates/parts/lists/_filter.html.twig | 2 +- templates/security/2fa_base_form.html.twig | 6 +++--- templates/security/login.html.twig | 4 ++-- templates/settings/settings.html.twig | 4 ++-- templates/users/_2fa_settings.html.twig | 18 +++++++++--------- templates/users/user_settings.html.twig | 2 +- 34 files changed, 86 insertions(+), 81 deletions(-) diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 95ae4f3b..860cef42 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -18,6 +18,11 @@ twig: saml_enabled: '%partdb.saml.enabled%' part_preview_generator: '@App\Services\Attachments\PartPreviewGenerator' + # Bootstrap grid classes used for horizontal form layouts + col_label: 'col-sm-3 col-lg-2' # The column classes for form labels + col_input: 'col-sm-9 col-lg-10' # The column classes for form input fields + offset_label: 'offset-sm-3 offset-lg-2' # Offset classes for elements that should be aligned with the input fields (e.g., submit buttons) + when@test: twig: strict_variables: true diff --git a/templates/admin/_delete_form.html.twig b/templates/admin/_delete_form.html.twig index fd653256..5a1d5a1a 100644 --- a/templates/admin/_delete_form.html.twig +++ b/templates/admin/_delete_form.html.twig @@ -5,7 +5,7 @@
-
+
{% set delete_disabled = (not is_granted("delete", entity)) or (entity.group is defined and entity.id == 1) or entity == app.user %}
@@ -20,7 +20,7 @@
{% if entity.parent is defined %} -
+
diff --git a/templates/admin/_duplicate.html.twig b/templates/admin/_duplicate.html.twig index 1b18cd71..cf6e8cca 100644 --- a/templates/admin/_duplicate.html.twig +++ b/templates/admin/_duplicate.html.twig @@ -1,5 +1,5 @@
- \ No newline at end of file +
diff --git a/templates/admin/_export_form.html.twig b/templates/admin/_export_form.html.twig index 07b00d43..7ef2e269 100644 --- a/templates/admin/_export_form.html.twig +++ b/templates/admin/_export_form.html.twig @@ -35,8 +35,8 @@
-
+
- \ No newline at end of file + diff --git a/templates/admin/base_admin.html.twig b/templates/admin/base_admin.html.twig index f710981d..f19f4c44 100644 --- a/templates/admin/base_admin.html.twig +++ b/templates/admin/base_admin.html.twig @@ -129,7 +129,7 @@
-
+
{{ form_widget(form.save) }}
diff --git a/templates/form/collection_types_layout.html.twig b/templates/form/collection_types_layout.html.twig index 96b71bf0..818f0a0f 100644 --- a/templates/form/collection_types_layout.html.twig +++ b/templates/form/collection_types_layout.html.twig @@ -63,8 +63,8 @@
{{ form_row(form.mountnames) }}
- -
+ +
{{ form_widget(form.price) }} {{ form_widget(form.priceCurrency) }} diff --git a/templates/form/extended_bootstrap_layout.html.twig b/templates/form/extended_bootstrap_layout.html.twig index 1227750c..01d30815 100644 --- a/templates/form/extended_bootstrap_layout.html.twig +++ b/templates/form/extended_bootstrap_layout.html.twig @@ -17,11 +17,11 @@ {% block form_label_class -%} - col-sm-3 + {{ col_label }} {%- endblock form_label_class %} {% block form_group_class -%} - col-sm-9 + {{ col_input }} {%- endblock form_group_class %} {% block si_unit_widget %} diff --git a/templates/info_providers/from_url/from_url.html.twig b/templates/info_providers/from_url/from_url.html.twig index 5aad1a03..3370a94c 100644 --- a/templates/info_providers/from_url/from_url.html.twig +++ b/templates/info_providers/from_url/from_url.html.twig @@ -12,7 +12,7 @@ {% endblock %} {% block card_content %} -

{% trans %}info_providers.from_url.help{% endtrans %}

+

{% trans %}info_providers.from_url.help{% endtrans %}

{{ form_start(form) }} {{ form_row(form.url) }} diff --git a/templates/info_providers/search/part_search.html.twig b/templates/info_providers/search/part_search.html.twig index a5602618..eac3507d 100644 --- a/templates/info_providers/search/part_search.html.twig +++ b/templates/info_providers/search/part_search.html.twig @@ -28,7 +28,7 @@ {{ form_row(form.providers) }}
- diff --git a/templates/info_providers/settings/provider_settings.html.twig b/templates/info_providers/settings/provider_settings.html.twig index 86e5bc9b..db942f8a 100644 --- a/templates/info_providers/settings/provider_settings.html.twig +++ b/templates/info_providers/settings/provider_settings.html.twig @@ -8,7 +8,7 @@ {% block card_title %} {% trans %}info_providers.settings.title{% endtrans %}: {{ info_provider_info.name }}{% endblock %} {% block card_content %} -
+

{% if info_provider_info.url is defined %} {{ info_provider_info.name }} @@ -23,7 +23,7 @@ {{ form_start(form) }}
-
+
{{ form_help(form) }}
diff --git a/templates/label_system/dialog.html.twig b/templates/label_system/dialog.html.twig index 11877a4c..532a4b63 100644 --- a/templates/label_system/dialog.html.twig +++ b/templates/label_system/dialog.html.twig @@ -36,7 +36,7 @@ {{ form_row(form.options.supported_element) }}
{{ form_label(form.options.width) }} -
+
{{ form_widget(form.options.width) }} @@ -59,8 +59,8 @@
- -
+ +
{{ profile.name ?? '-' }} {% if profile and is_granted("edit", profile) %}
-
+
diff --git a/templates/parts/edit/_eda.html.twig b/templates/parts/edit/_eda.html.twig index 1383871e..12299add 100644 --- a/templates/parts/edit/_eda.html.twig +++ b/templates/parts/edit/_eda.html.twig @@ -4,7 +4,7 @@ {{ form_row(form.eda_info.visibility) }}
-
+
{{ form_widget(form.eda_info.exclude_from_bom) }} {{ form_widget(form.eda_info.exclude_from_board) }} {{ form_widget(form.eda_info.exclude_from_sim) }} @@ -12,7 +12,7 @@
-
+
{% trans %}eda_info.kicad_section.title{% endtrans %}:
diff --git a/templates/parts/edit/_main.html.twig b/templates/parts/edit/_main.html.twig index f153d878..06c71106 100644 --- a/templates/parts/edit/_main.html.twig +++ b/templates/parts/edit/_main.html.twig @@ -1,7 +1,7 @@ {{ form_row(form.name) }} {% if part.category is not null and part.category.partnameHint is not empty %}
-
+

{% trans %}part.edit.name.category_hint{% endtrans %}: {{ part.category.partnameHint }}

diff --git a/templates/parts/edit/edit_form_styles.html.twig b/templates/parts/edit/edit_form_styles.html.twig index 9e989c92..44c8d89c 100644 --- a/templates/parts/edit/edit_form_styles.html.twig +++ b/templates/parts/edit/edit_form_styles.html.twig @@ -107,7 +107,7 @@ {% set id = 'collapse_' ~ random() %} -
@@ -142,7 +142,7 @@
{{ form_label(form.file) }} -
+
{{ form_widget(form.file) }} {{ form_errors(form.file) }} {% trans %}attachment.max_file_size{% endtrans %}: {{ max_upload_size | format_bytes }} diff --git a/templates/parts/edit/edit_part_info.html.twig b/templates/parts/edit/edit_part_info.html.twig index 28a88132..5b6d288a 100644 --- a/templates/parts/edit/edit_part_info.html.twig +++ b/templates/parts/edit/edit_part_info.html.twig @@ -140,7 +140,7 @@
-
+
{{ form_widget(form.save) }}
diff --git a/templates/security/2fa_base_form.html.twig b/templates/security/2fa_base_form.html.twig index 847048e4..e6ec99bb 100644 --- a/templates/security/2fa_base_form.html.twig +++ b/templates/security/2fa_base_form.html.twig @@ -33,7 +33,7 @@ {% if displayTrustedOption %}
-
+
@@ -48,11 +48,11 @@ {% block submit_btn %}
-
+
{% trans %}user.logout{% endtrans %}
{% endblock %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig index c09b3669..278f860b 100644 --- a/templates/security/login.html.twig +++ b/templates/security/login.html.twig @@ -22,7 +22,7 @@ {% block card_content %} {% if saml_enabled %} -
+
{% trans %}login.sso_saml_login{% endtrans %}

{% trans %}login.local_login_hint{% endtrans %}

@@ -39,6 +39,6 @@ {{ form_end(form) }} {% if allow_email_pw_reset %} - {% trans %}pw_reset.password_forget{% endtrans %} + {% trans %}pw_reset.password_forget{% endtrans %} {% endif %} {% endblock %} diff --git a/templates/settings/settings.html.twig b/templates/settings/settings.html.twig index 96e0f209..a2c01085 100644 --- a/templates/settings/settings.html.twig +++ b/templates/settings/settings.html.twig @@ -38,12 +38,12 @@ {% if section_widget.vars.embedded_settings_metadata is defined %} {# Check if we have nested embedded settings or not #}
- + {{ (section_widget.vars.label ?? section_widget.vars.name|humanize)|trans }}
-
+
{{ form_help(section_widget) }} {{ form_errors(section_widget) }}
diff --git a/templates/users/_2fa_settings.html.twig b/templates/users/_2fa_settings.html.twig index 80392c17..da0e61ff 100644 --- a/templates/users/_2fa_settings.html.twig +++ b/templates/users/_2fa_settings.html.twig @@ -37,11 +37,11 @@ {{ form_start(google_form, { 'attr': google_form_attr}) }} {% if not tfa_google.enabled %} -
+
{% trans %}tfa_google.disabled_message{% endtrans %}
-
+
{{ tfa_google.qrContent }}
@@ -55,7 +55,7 @@
-
+
@@ -72,7 +72,7 @@ {{ form_row(google_form.google_confirmation) }} {% else %} -
+
{% trans %}tfa_google.enabled_message{% endtrans %}
{% endif %} @@ -81,7 +81,7 @@
{% if user.backupCodes is empty %} -
+
{% trans %}tfa_backup.disabled{% endtrans %}
{% trans %}tfa_backup.explanation{% endtrans %}
@@ -89,19 +89,19 @@ {% set backup_form_attr = { 'data-delete-form': true, 'data-controller': 'elements--delete-btn', 'data-action': 'submit->elements--delete-btn#submit', 'data-delete-title': 'tfa_backup.reset_codes.confirm_title' | trans, 'data-delete-message': 'tfa_backup.reset_codes.confirm_message' | trans} %} {{ form_start(backup_form, { 'attr': backup_form_attr}) }} -
+
{% trans %}tfa_backup.enabled{% endtrans %}
{% trans %}tfa_backup.explanation{% endtrans %}
-
+

{% trans %}tfa_backup.remaining_tokens{% endtrans %}: {{ user.backupCodes | length }}

{% trans %}tfa_backup.generation_date{% endtrans %}: {{ user.backupCodesGenerationDate | format_datetime }}

-
+ -
+
{{ form_widget(backup_form.reset_codes) }}
{{ form_end(backup_form) }} diff --git a/templates/users/user_settings.html.twig b/templates/users/user_settings.html.twig index 0f218a1b..36cde643 100644 --- a/templates/users/user_settings.html.twig +++ b/templates/users/user_settings.html.twig @@ -28,7 +28,7 @@ {{ form_row(settings_form.showEmailOnProfile) }} {{ form_row(settings_form.avatar_file) }}
-
+
{% if user.masterPictureAttachment %} avatar {% endif %} From ceda91488c6b0095b9d59a1e810e3bc4ad43f76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 16:20:42 +0100 Subject: [PATCH 21/34] Updated dependencies --- composer.lock | 380 +++++++++++++++++++++++++------------------------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/composer.lock b/composer.lock index 8e010d2b..12a32829 100644 --- a/composer.lock +++ b/composer.lock @@ -968,7 +968,7 @@ }, { "name": "api-platform/doctrine-common", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/doctrine-common.git", @@ -1052,13 +1052,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/doctrine-common/tree/v4.3.0-alpha.2" + "source": "https://github.com/api-platform/doctrine-common/tree/v4.3.0-beta.1" }, "time": "2026-02-13T15:07:33+00:00" }, { "name": "api-platform/doctrine-orm", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/doctrine-orm.git", @@ -1139,13 +1139,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/doctrine-orm/tree/v4.2.19" + "source": "https://github.com/api-platform/doctrine-orm/tree/v4.2.20" }, "time": "2026-02-25T15:52:40+00:00" }, { "name": "api-platform/documentation", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/documentation.git", @@ -1202,13 +1202,13 @@ ], "description": "API Platform documentation controller.", "support": { - "source": "https://github.com/api-platform/documentation/tree/v4.3.0-alpha.2" + "source": "https://github.com/api-platform/documentation/tree/v4.3.0-beta.1" }, "time": "2025-12-27T22:15:57+00:00" }, { "name": "api-platform/http-cache", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/http-cache.git", @@ -1282,13 +1282,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/http-cache/tree/v4.3.0-alpha.2" + "source": "https://github.com/api-platform/http-cache/tree/v4.3.0-beta.1" }, "time": "2026-02-13T15:07:33+00:00" }, { "name": "api-platform/hydra", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/hydra.git", @@ -1369,13 +1369,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/hydra/tree/v4.2.19" + "source": "https://github.com/api-platform/hydra/tree/v4.2.20" }, "time": "2026-02-27T10:31:31+00:00" }, { "name": "api-platform/json-api", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/json-api.git", @@ -1451,13 +1451,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/json-api/tree/v4.2.19" + "source": "https://github.com/api-platform/json-api/tree/v4.2.20" }, "time": "2026-02-27T16:03:48+00:00" }, { "name": "api-platform/json-schema", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/json-schema.git", @@ -1532,13 +1532,13 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/json-schema/tree/v4.2.19" + "source": "https://github.com/api-platform/json-schema/tree/v4.2.20" }, "time": "2026-02-25T15:52:40+00:00" }, { "name": "api-platform/jsonld", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/jsonld.git", @@ -1612,13 +1612,13 @@ "rest" ], "support": { - "source": "https://github.com/api-platform/jsonld/tree/v4.2.19" + "source": "https://github.com/api-platform/jsonld/tree/v4.2.20" }, "time": "2026-02-13T17:30:49+00:00" }, { "name": "api-platform/metadata", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/metadata.git", @@ -1710,22 +1710,22 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/metadata/tree/v4.2.19" + "source": "https://github.com/api-platform/metadata/tree/v4.2.20" }, "time": "2026-02-25T15:52:40+00:00" }, { "name": "api-platform/openapi", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/openapi.git", - "reference": "59c13717f63e21f98d4ed4e4d7122b0bade72e2e" + "reference": "dcab93037834665f16cd226dbd867022057c3a7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/openapi/zipball/59c13717f63e21f98d4ed4e4d7122b0bade72e2e", - "reference": "59c13717f63e21f98d4ed4e4d7122b0bade72e2e", + "url": "https://api.github.com/repos/api-platform/openapi/zipball/dcab93037834665f16cd226dbd867022057c3a7e", + "reference": "dcab93037834665f16cd226dbd867022057c3a7e", "shasum": "" }, "require": { @@ -1800,13 +1800,13 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/openapi/tree/v4.2.19" + "source": "https://github.com/api-platform/openapi/tree/v4.2.20" }, - "time": "2026-01-26T15:38:30+00:00" + "time": "2026-03-01T17:00:49+00:00" }, { "name": "api-platform/serializer", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/serializer.git", @@ -1893,13 +1893,13 @@ "serializer" ], "support": { - "source": "https://github.com/api-platform/serializer/tree/v4.2.19" + "source": "https://github.com/api-platform/serializer/tree/v4.2.20" }, "time": "2026-02-27T16:03:48+00:00" }, { "name": "api-platform/state", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/state.git", @@ -1990,22 +1990,22 @@ "swagger" ], "support": { - "source": "https://github.com/api-platform/state/tree/v4.2.19" + "source": "https://github.com/api-platform/state/tree/v4.2.20" }, "time": "2026-02-17T09:18:17+00:00" }, { "name": "api-platform/symfony", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/symfony.git", - "reference": "3ed112cd9e278a5ba2d7b663df04861a3c4ba905" + "reference": "8e47b4429a2c41dd9a8865b1f42f93f9beac99c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/symfony/zipball/3ed112cd9e278a5ba2d7b663df04861a3c4ba905", - "reference": "3ed112cd9e278a5ba2d7b663df04861a3c4ba905", + "url": "https://api.github.com/repos/api-platform/symfony/zipball/8e47b4429a2c41dd9a8865b1f42f93f9beac99c2", + "reference": "8e47b4429a2c41dd9a8865b1f42f93f9beac99c2", "shasum": "" }, "require": { @@ -2118,13 +2118,13 @@ "symfony" ], "support": { - "source": "https://github.com/api-platform/symfony/tree/v4.2.19" + "source": "https://github.com/api-platform/symfony/tree/v4.2.20" }, - "time": "2026-02-27T10:22:56+00:00" + "time": "2026-03-03T08:06:46+00:00" }, { "name": "api-platform/validator", - "version": "v4.2.19", + "version": "v4.2.20", "source": { "type": "git", "url": "https://github.com/api-platform/validator.git", @@ -2194,7 +2194,7 @@ "validator" ], "support": { - "source": "https://github.com/api-platform/validator/tree/v4.2.19" + "source": "https://github.com/api-platform/validator/tree/v4.2.20" }, "time": "2026-01-26T15:45:40+00:00" }, @@ -5686,16 +5686,16 @@ }, { "name": "league/commonmark", - "version": "2.8.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" + "reference": "84b1ca48347efdbe775426f108622a42735a6579" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", - "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/84b1ca48347efdbe775426f108622a42735a6579", + "reference": "84b1ca48347efdbe775426f108622a42735a6579", "shasum": "" }, "require": { @@ -5720,9 +5720,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 | ^7.0", - "symfony/process": "^5.4 | ^6.0 | ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, @@ -5789,7 +5789,7 @@ "type": "tidelift" } ], - "time": "2025-11-26T21:48:24+00:00" + "time": "2026-03-05T21:37:03+00:00" }, { "name": "league/config", @@ -10335,16 +10335,16 @@ }, { "name": "symfony/cache", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "1d06192e8f164e2729b0031e6807d72a6195b8bb" + "reference": "665522ec357540e66c294c08583b40ee576574f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/1d06192e8f164e2729b0031e6807d72a6195b8bb", - "reference": "1d06192e8f164e2729b0031e6807d72a6195b8bb", + "url": "https://api.github.com/repos/symfony/cache/zipball/665522ec357540e66c294c08583b40ee576574f0", + "reference": "665522ec357540e66c294c08583b40ee576574f0", "shasum": "" }, "require": { @@ -10415,7 +10415,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.4.6" + "source": "https://github.com/symfony/cache/tree/v7.4.7" }, "funding": [ { @@ -10435,7 +10435,7 @@ "type": "tidelift" } ], - "time": "2026-02-21T23:29:27+00:00" + "time": "2026-03-06T08:14:57+00:00" }, { "name": "symfony/cache-contracts", @@ -10593,16 +10593,16 @@ }, { "name": "symfony/config", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "9400e2f9226b3b64ebb0a8ae967ae84e54e39640" + "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9400e2f9226b3b64ebb0a8ae967ae84e54e39640", - "reference": "9400e2f9226b3b64ebb0a8ae967ae84e54e39640", + "url": "https://api.github.com/repos/symfony/config/zipball/6c17162555bfb58957a55bb0e43e00035b6ae3d5", + "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5", "shasum": "" }, "require": { @@ -10648,7 +10648,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v7.4.6" + "source": "https://github.com/symfony/config/tree/v7.4.7" }, "funding": [ { @@ -10668,20 +10668,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-06T10:41:14+00:00" }, { "name": "symfony/console", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6d643a93b47398599124022eb24d97c153c12f27" + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6d643a93b47398599124022eb24d97c153c12f27", - "reference": "6d643a93b47398599124022eb24d97c153c12f27", + "url": "https://api.github.com/repos/symfony/console/zipball/e1e6770440fb9c9b0cf725f81d1361ad1835329d", + "reference": "e1e6770440fb9c9b0cf725f81d1361ad1835329d", "shasum": "" }, "require": { @@ -10746,7 +10746,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.6" + "source": "https://github.com/symfony/console/tree/v7.4.7" }, "funding": [ { @@ -10766,7 +10766,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T17:02:47+00:00" + "time": "2026-03-06T14:06:20+00:00" }, { "name": "symfony/css-selector", @@ -10839,16 +10839,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "a3f7d594ca53a34a7d39ae683fbca09408b0c598" + "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a3f7d594ca53a34a7d39ae683fbca09408b0c598", - "reference": "a3f7d594ca53a34a7d39ae683fbca09408b0c598", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db", + "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db", "shasum": "" }, "require": { @@ -10899,7 +10899,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.4.6" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.7" }, "funding": [ { @@ -10919,7 +10919,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-03T07:48:48+00:00" }, { "name": "symfony/deprecation-contracts", @@ -10990,16 +10990,16 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "710cb7313446aa5ce67e2da06c01f1640dfbdcc6" + "reference": "4fc5e2dd41be3c0b6321e0373072782edeff45ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/710cb7313446aa5ce67e2da06c01f1640dfbdcc6", - "reference": "710cb7313446aa5ce67e2da06c01f1640dfbdcc6", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/4fc5e2dd41be3c0b6321e0373072782edeff45ed", + "reference": "4fc5e2dd41be3c0b6321e0373072782edeff45ed", "shasum": "" }, "require": { @@ -11079,7 +11079,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v7.4.6" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.4.7" }, "funding": [ { @@ -11099,7 +11099,7 @@ "type": "tidelift" } ], - "time": "2026-02-17T08:07:48+00:00" + "time": "2026-03-05T08:16:50+00:00" }, { "name": "symfony/dom-crawler", @@ -11175,16 +11175,16 @@ }, { "name": "symfony/dotenv", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "db374255a1c99511d34d5e009dce5be75d0d9c23" + "reference": "7e5529a0b02395cb4614cdf507495a4cef3115c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/db374255a1c99511d34d5e009dce5be75d0d9c23", - "reference": "db374255a1c99511d34d5e009dce5be75d0d9c23", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/7e5529a0b02395cb4614cdf507495a4cef3115c5", + "reference": "7e5529a0b02395cb4614cdf507495a4cef3115c5", "shasum": "" }, "require": { @@ -11229,7 +11229,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v7.4.6" + "source": "https://github.com/symfony/dotenv/tree/v7.4.7" }, "funding": [ { @@ -11249,7 +11249,7 @@ "type": "tidelift" } ], - "time": "2026-02-13T11:43:08+00:00" + "time": "2026-03-03T07:48:48+00:00" }, { "name": "symfony/error-handler", @@ -11775,16 +11775,16 @@ }, { "name": "symfony/form", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "1ec55f7b1a6152760a670415c334f70a08d264f9" + "reference": "5f24175103fd0a62b98442207c240688210fd88b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/1ec55f7b1a6152760a670415c334f70a08d264f9", - "reference": "1ec55f7b1a6152760a670415c334f70a08d264f9", + "url": "https://api.github.com/repos/symfony/form/zipball/5f24175103fd0a62b98442207c240688210fd88b", + "reference": "5f24175103fd0a62b98442207c240688210fd88b", "shasum": "" }, "require": { @@ -11854,7 +11854,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v7.4.6" + "source": "https://github.com/symfony/form/tree/v7.4.7" }, "funding": [ { @@ -11874,20 +11874,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-05T12:30:09+00:00" }, { "name": "symfony/framework-bundle", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "a4022da7530f794aa64cea34b388439afb6323a3" + "reference": "c94bc78c85d76af67918404a95d44940f66a7c2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/a4022da7530f794aa64cea34b388439afb6323a3", - "reference": "a4022da7530f794aa64cea34b388439afb6323a3", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c94bc78c85d76af67918404a95d44940f66a7c2f", + "reference": "c94bc78c85d76af67918404a95d44940f66a7c2f", "shasum": "" }, "require": { @@ -12012,7 +12012,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v7.4.6" + "source": "https://github.com/symfony/framework-bundle/tree/v7.4.7" }, "funding": [ { @@ -12032,20 +12032,20 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-06T15:39:55+00:00" }, { "name": "symfony/http-client", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "2bde8afd5ab2fe0b05a9c2d4c3c0e28ceb98a154" + "reference": "1010624285470eb60e88ed10035102c75b4ea6af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/2bde8afd5ab2fe0b05a9c2d4c3c0e28ceb98a154", - "reference": "2bde8afd5ab2fe0b05a9c2d4c3c0e28ceb98a154", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1010624285470eb60e88ed10035102c75b4ea6af", + "reference": "1010624285470eb60e88ed10035102c75b4ea6af", "shasum": "" }, "require": { @@ -12113,7 +12113,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.4.6" + "source": "https://github.com/symfony/http-client/tree/v7.4.7" }, "funding": [ { @@ -12133,7 +12133,7 @@ "type": "tidelift" } ], - "time": "2026-02-18T09:46:18+00:00" + "time": "2026-03-05T11:16:58+00:00" }, { "name": "symfony/http-client-contracts", @@ -12215,16 +12215,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065" + "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/fd97d5e926e988a363cef56fbbf88c5c528e9065", - "reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f94b3e7b7dafd40e666f0c9ff2084133bae41e81", + "reference": "f94b3e7b7dafd40e666f0c9ff2084133bae41e81", "shasum": "" }, "require": { @@ -12273,7 +12273,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.4.6" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.7" }, "funding": [ { @@ -12293,20 +12293,20 @@ "type": "tidelift" } ], - "time": "2026-02-21T16:25:55+00:00" + "time": "2026-03-06T13:15:18+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83" + "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/002ac0cf4cd972a7fd0912dcd513a95e8a81ce83", - "reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/3b3fcf386c809be990c922e10e4c620d6367cab1", + "reference": "3b3fcf386c809be990c922e10e4c620d6367cab1", "shasum": "" }, "require": { @@ -12392,7 +12392,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.4.6" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.7" }, "funding": [ { @@ -12412,7 +12412,7 @@ "type": "tidelift" } ], - "time": "2026-02-26T08:30:57+00:00" + "time": "2026-03-06T16:33:18+00:00" }, { "name": "symfony/intl", @@ -12590,16 +12590,16 @@ }, { "name": "symfony/mime", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f" + "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/9fc881d95feae4c6c48678cb6372bd8a7ba04f5f", - "reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f", + "url": "https://api.github.com/repos/symfony/mime/zipball/da5ab4fde3f6c88ab06e96185b9922f48b677cd1", + "reference": "da5ab4fde3f6c88ab06e96185b9922f48b677cd1", "shasum": "" }, "require": { @@ -12655,7 +12655,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.6" + "source": "https://github.com/symfony/mime/tree/v7.4.7" }, "funding": [ { @@ -12675,7 +12675,7 @@ "type": "tidelift" } ], - "time": "2026-02-05T15:57:06+00:00" + "time": "2026-03-05T15:24:09+00:00" }, { "name": "symfony/monolog-bridge", @@ -13882,23 +13882,23 @@ }, { "name": "symfony/property-info", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "6396b28f44d7c28b209a1bd73acf0dd985a0a4ef" + "reference": "02501d75fd834345da3ecdd8e3200ced39e370f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/6396b28f44d7c28b209a1bd73acf0dd985a0a4ef", - "reference": "6396b28f44d7c28b209a1bd73acf0dd985a0a4ef", + "url": "https://api.github.com/repos/symfony/property-info/zipball/02501d75fd834345da3ecdd8e3200ced39e370f8", + "reference": "02501d75fd834345da3ecdd8e3200ced39e370f8", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/string": "^6.4|^7.0|^8.0", - "symfony/type-info": "~7.3.10|^7.4.4|^8.0.4" + "symfony/type-info": "^7.4.7|^8.0.7" }, "conflict": { "phpdocumentor/reflection-docblock": "<5.2|>=7", @@ -13948,7 +13948,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v7.4.6" + "source": "https://github.com/symfony/property-info/tree/v7.4.7" }, "funding": [ { @@ -13968,7 +13968,7 @@ "type": "tidelift" } ], - "time": "2026-02-13T11:51:31+00:00" + "time": "2026-03-04T15:53:26+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -14060,16 +14060,16 @@ }, { "name": "symfony/rate-limiter", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/rate-limiter.git", - "reference": "7219be81396041c24c1d12241ca7ef1f88b80783" + "reference": "c2ff01c8d5ed54f0721f046fde14a94f2df09666" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/7219be81396041c24c1d12241ca7ef1f88b80783", - "reference": "7219be81396041c24c1d12241ca7ef1f88b80783", + "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/c2ff01c8d5ed54f0721f046fde14a94f2df09666", + "reference": "c2ff01c8d5ed54f0721f046fde14a94f2df09666", "shasum": "" }, "require": { @@ -14110,7 +14110,7 @@ "rate-limiter" ], "support": { - "source": "https://github.com/symfony/rate-limiter/tree/v7.4.6" + "source": "https://github.com/symfony/rate-limiter/tree/v7.4.7" }, "funding": [ { @@ -14130,7 +14130,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-04T13:54:41+00:00" }, { "name": "symfony/routing", @@ -14671,16 +14671,16 @@ }, { "name": "symfony/serializer", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "83c3cbd6dcb96c1dbe197499a0714f8dceb0f274" + "reference": "bd395bbc6fabd136a48e1a6f91b09f88b5050b0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/83c3cbd6dcb96c1dbe197499a0714f8dceb0f274", - "reference": "83c3cbd6dcb96c1dbe197499a0714f8dceb0f274", + "url": "https://api.github.com/repos/symfony/serializer/zipball/bd395bbc6fabd136a48e1a6f91b09f88b5050b0b", + "reference": "bd395bbc6fabd136a48e1a6f91b09f88b5050b0b", "shasum": "" }, "require": { @@ -14751,7 +14751,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v7.4.6" + "source": "https://github.com/symfony/serializer/tree/v7.4.7" }, "funding": [ { @@ -14771,7 +14771,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-06T13:15:18+00:00" }, { "name": "symfony/service-contracts", @@ -15274,16 +15274,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "8903bc9a64cf624ffe522893f3626d5a0b97175c" + "reference": "c67219ca6b79a57b64e36bbb2cd8ba741286587e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/8903bc9a64cf624ffe522893f3626d5a0b97175c", - "reference": "8903bc9a64cf624ffe522893f3626d5a0b97175c", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/c67219ca6b79a57b64e36bbb2cd8ba741286587e", + "reference": "c67219ca6b79a57b64e36bbb2cd8ba741286587e", "shasum": "" }, "require": { @@ -15365,7 +15365,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v7.4.6" + "source": "https://github.com/symfony/twig-bridge/tree/v7.4.7" }, "funding": [ { @@ -15385,7 +15385,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-04T15:37:05+00:00" }, { "name": "symfony/twig-bundle", @@ -15479,16 +15479,16 @@ }, { "name": "symfony/type-info", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/type-info.git", - "reference": "4855ceea609b2c09e48ff76e12a97a3955531735" + "reference": "31f1e40cbf7851c7354281c90eb1b352c4cb8269" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/type-info/zipball/4855ceea609b2c09e48ff76e12a97a3955531735", - "reference": "4855ceea609b2c09e48ff76e12a97a3955531735", + "url": "https://api.github.com/repos/symfony/type-info/zipball/31f1e40cbf7851c7354281c90eb1b352c4cb8269", + "reference": "31f1e40cbf7851c7354281c90eb1b352c4cb8269", "shasum": "" }, "require": { @@ -15538,7 +15538,7 @@ "type" ], "support": { - "source": "https://github.com/symfony/type-info/tree/v7.4.6" + "source": "https://github.com/symfony/type-info/tree/v7.4.7" }, "funding": [ { @@ -15558,7 +15558,7 @@ "type": "tidelift" } ], - "time": "2026-02-17T14:00:31+00:00" + "time": "2026-03-04T12:49:16+00:00" }, { "name": "symfony/uid", @@ -15824,16 +15824,16 @@ }, { "name": "symfony/validator", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "a1ceaf285712ed8034819a76b5fbba23eaf3e54d" + "reference": "3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/a1ceaf285712ed8034819a76b5fbba23eaf3e54d", - "reference": "a1ceaf285712ed8034819a76b5fbba23eaf3e54d", + "url": "https://api.github.com/repos/symfony/validator/zipball/3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203", + "reference": "3a1a460a9f8c5e5611e15c52c4baa5a62fa3c203", "shasum": "" }, "require": { @@ -15904,7 +15904,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v7.4.6" + "source": "https://github.com/symfony/validator/tree/v7.4.7" }, "funding": [ { @@ -15924,7 +15924,7 @@ "type": "tidelift" } ], - "time": "2026-02-25T16:50:00+00:00" + "time": "2026-03-06T11:10:17+00:00" }, { "name": "symfony/var-dumper", @@ -17953,29 +17953,29 @@ }, { "name": "ekino/phpstan-banned-code", - "version": "v3.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/ekino/phpstan-banned-code.git", - "reference": "27122aa1783d6521e500c0c397c53244cfbde26f" + "reference": "dffb9b755168cdf51ddb9dfa7cf5764541e07afe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ekino/phpstan-banned-code/zipball/27122aa1783d6521e500c0c397c53244cfbde26f", - "reference": "27122aa1783d6521e500c0c397c53244cfbde26f", + "url": "https://api.github.com/repos/ekino/phpstan-banned-code/zipball/dffb9b755168cdf51ddb9dfa7cf5764541e07afe", + "reference": "dffb9b755168cdf51ddb9dfa7cf5764541e07afe", "shasum": "" }, "require": { - "php": "^8.1", + "php": "^8.2", "phpstan/phpstan": "^2.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.6", "friendsofphp/php-cs-fixer": "^3.0", - "nikic/php-parser": "^4.3", + "nikic/php-parser": "^5.4", "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "symfony/var-dumper": "^5.0" + "phpunit/phpunit": "^10.5", + "symfony/var-dumper": "^6.4" }, "type": "phpstan-extension", "extra": { @@ -18013,9 +18013,9 @@ ], "support": { "issues": "https://github.com/ekino/phpstan-banned-code/issues", - "source": "https://github.com/ekino/phpstan-banned-code/tree/v3.0.0" + "source": "https://github.com/ekino/phpstan-banned-code/tree/v3.1.0" }, - "time": "2024-11-13T09:57:22+00:00" + "time": "2026-03-05T08:25:14+00:00" }, { "name": "jbtronics/translation-editor-bundle", @@ -19148,12 +19148,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "da19d9c4572f2adae57b28b2111d7fa667cd6dcb" + "reference": "68e4c6721ef8cd2c366bd5e2290baf007d3f0e6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/da19d9c4572f2adae57b28b2111d7fa667cd6dcb", - "reference": "da19d9c4572f2adae57b28b2111d7fa667cd6dcb", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/68e4c6721ef8cd2c366bd5e2290baf007d3f0e6d", + "reference": "68e4c6721ef8cd2c366bd5e2290baf007d3f0e6d", "shasum": "" }, "conflict": { @@ -19375,7 +19375,7 @@ "drupal/umami_analytics": "<1.0.1", "duncanmcclean/guest-entries": "<3.1.2", "dweeves/magmi": "<=0.7.24", - "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2", + "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.3.1", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", "egroupware/egroupware": "<23.1.20260113|>=26.0.20251208,<26.0.20260113", @@ -19478,7 +19478,7 @@ "gp247/core": "<1.1.24", "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<6.1.17", + "grumpydictator/firefly-iii": "<6.1.17|>=6.4.23,<=6.5", "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/oauth-subscriber": "<0.8.1", @@ -19579,7 +19579,7 @@ "lavalite/cms": "<=10.1", "lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", - "league/commonmark": "<2.7", + "league/commonmark": "<=2.8", "league/flysystem": "<1.1.4|>=2,<2.1.1", "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", "leantime/leantime": "<3.3", @@ -19878,7 +19878,7 @@ "slim/slim": "<2.6", "slub/slub-events": "<3.0.3", "smarty/smarty": "<4.5.3|>=5,<5.1.1", - "snipe/snipe-it": "<=8.3.4", + "snipe/snipe-it": "<8.3.7", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6", @@ -20069,7 +20069,7 @@ "wpanel/wpanel4-cms": "<=4.3.1", "wpcloud/wp-stateless": "<3.2", "wpglobus/wpglobus": "<=1.9.6", - "wwbn/avideo": "<=21", + "wwbn/avideo": "<25", "xataface/xataface": "<3", "xpressengine/xpressengine": "<3.0.15", "yab/quarx": "<2.4.5", @@ -20167,7 +20167,7 @@ "type": "tidelift" } ], - "time": "2026-03-04T22:09:37+00:00" + "time": "2026-03-07T02:54:13+00:00" }, { "name": "sebastian/cli-parser", @@ -21282,16 +21282,16 @@ }, { "name": "symfony/debug-bundle", - "version": "v7.4.0", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "329383fb895353e3c8ab792cc35c4a7e7b17881b" + "reference": "7affd8924ef9a7739ec53284c2fc30afeeae7124" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/329383fb895353e3c8ab792cc35c4a7e7b17881b", - "reference": "329383fb895353e3c8ab792cc35c4a7e7b17881b", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/7affd8924ef9a7739ec53284c2fc30afeeae7124", + "reference": "7affd8924ef9a7739ec53284c2fc30afeeae7124", "shasum": "" }, "require": { @@ -21333,7 +21333,7 @@ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v7.4.0" + "source": "https://github.com/symfony/debug-bundle/tree/v7.4.7" }, "funding": [ { @@ -21353,7 +21353,7 @@ "type": "tidelift" } ], - "time": "2025-10-24T13:56:35+00:00" + "time": "2026-03-03T07:48:48+00:00" }, { "name": "symfony/maker-bundle", @@ -21455,16 +21455,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v7.4.3", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "f933e68bb9df29d08077a37e1515a23fea8562ab" + "reference": "53c5a606cb4ae19c9466a5f8ffe60f61b0c93b5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/f933e68bb9df29d08077a37e1515a23fea8562ab", - "reference": "f933e68bb9df29d08077a37e1515a23fea8562ab", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/53c5a606cb4ae19c9466a5f8ffe60f61b0c93b5f", + "reference": "53c5a606cb4ae19c9466a5f8ffe60f61b0c93b5f", "shasum": "" }, "require": { @@ -21516,7 +21516,7 @@ "testing" ], "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.4.3" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.4.7" }, "funding": [ { @@ -21536,20 +21536,20 @@ "type": "tidelift" } ], - "time": "2025-12-09T15:33:45+00:00" + "time": "2026-03-04T13:54:41+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v7.4.6", + "version": "v7.4.7", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "952fbb5ea12e101e05510069eacf01e169955100" + "reference": "da9e91746fc9c575be8b5ff466b7572d98e7e1ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/952fbb5ea12e101e05510069eacf01e169955100", - "reference": "952fbb5ea12e101e05510069eacf01e169955100", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/da9e91746fc9c575be8b5ff466b7572d98e7e1ae", + "reference": "da9e91746fc9c575be8b5ff466b7572d98e7e1ae", "shasum": "" }, "require": { @@ -21606,7 +21606,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.4.6" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.4.7" }, "funding": [ { @@ -21626,7 +21626,7 @@ "type": "tidelift" } ], - "time": "2026-02-11T16:03:16+00:00" + "time": "2026-03-03T13:57:00+00:00" }, { "name": "theseer/tokenizer", From db8881621c091f2b0d88326ac58808ae8c42ec5b Mon Sep 17 00:00:00 2001 From: Sebastian Almberg <83243306+Sebbeben@users.noreply.github.com> Date: Sat, 7 Mar 2026 18:10:36 +0100 Subject: [PATCH 22/34] Add OPcache reset step to update and restore processes (#1288) After cache warmup, create a temporary PHP script in the public directory and invoke it via HTTP to reset OPcache in the PHP-FPM context. This prevents stale bytecode from causing 500 errors when the progress page refreshes after code has been updated. The reset is also performed after rollback and during restore. Uses a random token in the filename for security, and the script self-deletes after execution with a cleanup in the finally block. --- src/Services/System/UpdateExecutor.php | 101 +++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/src/Services/System/UpdateExecutor.php b/src/Services/System/UpdateExecutor.php index 70aea23f..77cf2942 100644 --- a/src/Services/System/UpdateExecutor.php +++ b/src/Services/System/UpdateExecutor.php @@ -207,6 +207,79 @@ class UpdateExecutor } } + /** + * Reset PHP OPcache for the web server process. + * + * OPcache in PHP-FPM is separate from CLI. After updating code files, + * PHP-FPM may still serve stale cached bytecode, causing constructor + * mismatches and 500 errors. This method creates a temporary PHP script + * in the public directory, invokes it via HTTP to reset OPcache in the + * web server context, then removes the script. + * + * @return bool Whether OPcache was successfully reset + */ + private function resetOpcache(): bool + { + $token = bin2hex(random_bytes(16)); + $resetScript = $this->project_dir . '/public/_opcache_reset_' . $token . '.php'; + + try { + // Create a temporary PHP script that resets OPcache + $scriptContent = 'filesystem->dumpFile($resetScript, $scriptContent); + + // Try to invoke it via HTTP on localhost + $urls = [ + 'http://127.0.0.1/_opcache_reset_' . $token . '.php', + 'http://localhost/_opcache_reset_' . $token . '.php', + ]; + + $success = false; + foreach ($urls as $url) { + try { + $context = stream_context_create([ + 'http' => [ + 'timeout' => 5, + 'ignore_errors' => true, + ], + ]); + + $response = @file_get_contents($url, false, $context); + if ($response === 'OK') { + $this->logger->info('OPcache reset via ' . $url); + $success = true; + break; + } + } catch (\Throwable $e) { + // Try next URL + continue; + } + } + + if (!$success) { + $this->logger->info('OPcache reset via HTTP not available, trying CLI fallback'); + // CLI opcache_reset() only affects CLI, but try anyway + if (function_exists('opcache_reset')) { + opcache_reset(); + } + } + + return $success; + } catch (\Throwable $e) { + $this->logger->warning('OPcache reset failed: ' . $e->getMessage()); + return false; + } finally { + // Ensure the temp script is removed + if (file_exists($resetScript)) { + @unlink($resetScript); + } + } + } + /** * Validate that we can perform an update. * @@ -434,12 +507,20 @@ class UpdateExecutor ], 'Warmup cache', 120); $log('cache_warmup', 'Warmed up application cache', true, microtime(true) - $stepStart); - // Step 13: Disable maintenance mode + // Step 13: Reset OPcache (if available) + $stepStart = microtime(true); + $opcacheResult = $this->resetOpcache(); + $log('opcache_reset', $opcacheResult + ? 'Reset PHP OPcache for web server' + : 'OPcache reset skipped (not available or not needed)', + true, microtime(true) - $stepStart); + + // Step 14: Disable maintenance mode $stepStart = microtime(true); $this->disableMaintenanceMode(); $log('maintenance_off', 'Disabled maintenance mode', true, microtime(true) - $stepStart); - // Step 14: Release lock + // Step 15: Release lock $stepStart = microtime(true); $this->releaseLock(); @@ -494,6 +575,9 @@ class UpdateExecutor ], 'Clear cache after rollback', 120); $log('rollback_cache', 'Cleared cache after rollback', true); + // Reset OPcache after rollback + $this->resetOpcache(); + } catch (\Exception $rollbackError) { $log('rollback_failed', 'Rollback failed: ' . $rollbackError->getMessage(), false); } @@ -682,12 +766,17 @@ class UpdateExecutor $this->runCommand(['php', 'bin/console', 'cache:warmup'], 'Warm up cache'); $log('cache_warmup', 'Warmed up application cache', true, microtime(true) - $stepStart); - // Step 6: Disable maintenance mode + // Step 6: Reset OPcache + $stepStart = microtime(true); + $this->resetOpcache(); + $log('opcache_reset', 'Reset PHP OPcache', true, microtime(true) - $stepStart); + + // Step 7: Disable maintenance mode $stepStart = microtime(true); $this->disableMaintenanceMode(); $log('maintenance_off', 'Disabled maintenance mode', true, microtime(true) - $stepStart); - // Step 7: Release lock + // Step 8: Release lock $this->releaseLock(); $totalDuration = microtime(true) - $startTime; @@ -817,7 +906,7 @@ class UpdateExecutor 'create_backup' => $createBackup, 'started_at' => (new \DateTime())->format('c'), 'current_step' => 0, - 'total_steps' => 14, + 'total_steps' => 15, 'step_name' => 'initializing', 'step_message' => 'Starting update process...', 'steps' => [], @@ -890,7 +979,7 @@ class UpdateExecutor bool $createBackup = true, ?callable $onProgress = null ): array { - $totalSteps = 12; + $totalSteps = 13; $currentStep = 0; $updateProgress = function (string $stepName, string $message, bool $success = true) use (&$currentStep, $totalSteps, $targetVersion, $createBackup): void { From 0d58262e19ae5b483745b026c9d6c38580888618 Mon Sep 17 00:00:00 2001 From: Sebastian Almberg <83243306+Sebbeben@users.noreply.github.com> Date: Sat, 7 Mar 2026 19:31:00 +0100 Subject: [PATCH 23/34] Add manual backup creation and delete buttons to Update Manager (#1255) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add manual backup creation and delete buttons to Update Manager - Add "Create Backup" button in the backups tab for on-demand backups - Add delete buttons (trash icons) for update logs and backups - New controller routes with CSRF protection and permission checks - Use data-turbo-confirm for CSP-safe confirmation dialogs - Add deleteLog() method to UpdateExecutor with filename validation * Add Docker backup support: download button, SQLite restore fix, decouple from auto-update - Decouple backup creation/restore UI from can_auto_update so Docker and other non-git installations can use backup features - Add backup download endpoint for saving backups externally - Fix SQLite restore to use configured DATABASE_URL path instead of hardcoded var/app.db (affects Docker and custom SQLite paths) - Show Docker-specific warning about var/backups/ not being persisted - Pass is_docker flag to template via InstallationTypeDetector * Add tests for backup/update manager improvements - Controller tests: auth, CSRF validation, 404 for missing backups, restore disabled check - UpdateExecutor: deleteLog validation, non-existent file, successful deletion - BackupManager: deleteBackup validation for missing/non-zip files * Fix test failures: add locale prefix to URLs, correct log directory path * Fix auth test: expect 401 instead of redirect for HTTP Basic auth * Improve test coverage for update manager controller Add happy-path tests for backup creation, deletion, download, and log deletion with valid CSRF tokens. Also test the locked state blocking backup creation. * Fix CSRF tests: initialize session before getting tokens * Fix CSRF tests: extract tokens from rendered page HTML * Harden backup security: password confirmation, CSRF, env toggle Address security review feedback from jbtronics: - Add IS_AUTHENTICATED_FULLY to all sensitive endpoints (create/delete backup, delete log, download backup, start update, restore) - Change backup download from GET to POST with CSRF token - Require password confirmation before downloading backups (backups contain sensitive data like password hashes and secrets) - Add DISABLE_BACKUP_DOWNLOAD env var (default: disabled) to control whether backup downloads are allowed - Add password confirmation modal with security warning in template - Add comprehensive tests: auth checks, env var blocking, POST-only enforcement, status/progress endpoint auth * Fix download modal: use per-backup modals for CSP/Turbo compatibility - Replace shared modal + inline JS with per-backup modals that have filename pre-set in hidden fields (no JavaScript needed) - Add data-turbo="false" to download forms for native browser handling - Add data-bs-dismiss="modal" to submit button to auto-close modal - Add hidden username field for Chrome accessibility best practice - Fix test: GET on POST-only route returns 404 not 405 * Fixed translation keys * Fixed text justification in download modal * Hardenened security of deleteLogEndpoint * Show whether backup, restores and updates are allowed or disabled by sysadmin on update manager * Added documentation for update manager related env variables --------- Co-authored-by: Jan Böhmer --- .env | 5 + docs/configuration.md | 12 + src/Controller/UpdateManagerController.php | 136 +++++ src/Services/System/BackupManager.php | 13 +- src/Services/System/UpdateExecutor.php | 27 + .../admin/update_manager/index.html.twig | 577 +++++++++++------- templates/helper.twig | 10 +- .../UpdateManagerControllerTest.php | 381 ++++++++++++ tests/Services/System/BackupManagerTest.php | 10 + tests/Services/System/UpdateExecutorTest.php | 32 + translations/messages.en.xlf | 120 ++++ 11 files changed, 1077 insertions(+), 246 deletions(-) create mode 100644 tests/Controller/UpdateManagerControllerTest.php diff --git a/.env b/.env index 3ba3d65d..447ff5de 100644 --- a/.env +++ b/.env @@ -71,6 +71,11 @@ DISABLE_WEB_UPDATES=1 # Restoring backups is a destructive operation that could overwrite your database. DISABLE_BACKUP_RESTORE=1 +# Disable backup download from the Update Manager UI (0=enabled, 1=disabled). +# Backups contain sensitive data including password hashes and secrets. +# When enabled, users must confirm their password before downloading. +DISABLE_BACKUP_DOWNLOAD=1 + ################################################################################### # SAML Single sign on-settings ################################################################################### diff --git a/docs/configuration.md b/docs/configuration.md index c5e46f21..a2f585a1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -144,6 +144,18 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept * `ALLOW_EMAIL_PW_RESET`: Set this value to true, if you want to allow users to reset their password via an email notification. You have to configure the mail provider first before via the MAILER_DSN setting. +### Update manager settings +* `DISABLE_WEB_UPDATES` (default `1`): Set this to 0 to enable web-based updates. When enabled, you can perform updates + via the web interface in the update manager. This is disabled by default for security reasons, as it can be a risk if + not used carefully. You can still use the CLI commands to perform updates, even when web updates are disabled. +* `DISABLE_BACKUP_RESTORE` (default `1`): Set this to 0 to enable backup restore via the web interface. When enabled, you can + restore backups via the web interface in the update manager. This is disabled by default for security reasons, as it can + be a risk if not used carefully. You can still use the CLI commands to perform backup restores, even when web-based + backup restore is disabled. +* `DISABLE_BACKUP_DOWNLOAD` (default `1`): Set this to 0 to enable backup download via the web interface. When enabled, you can download backups via the web interface + in the update manager. This is disabled by default for security reasons, as it can be a risk if not used carefully, as + the downloads contain sensitive data like password hashes or secrets. + ### Table related settings * `TABLE_DEFAULT_PAGE_SIZE`: The default page size for tables. This is the number of rows which are shown per page. Set diff --git a/src/Controller/UpdateManagerController.php b/src/Controller/UpdateManagerController.php index 474c86fc..70be714d 100644 --- a/src/Controller/UpdateManagerController.php +++ b/src/Controller/UpdateManagerController.php @@ -23,16 +23,21 @@ declare(strict_types=1); namespace App\Controller; +use App\Entity\UserSystem\User; use App\Services\System\BackupManager; +use App\Services\System\InstallationTypeDetector; use App\Services\System\UpdateChecker; use App\Services\System\UpdateExecutor; use Shivas\VersioningBundle\Service\VersionManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Routing\Attribute\Route; /** @@ -49,10 +54,14 @@ class UpdateManagerController extends AbstractController private readonly UpdateExecutor $updateExecutor, private readonly VersionManagerInterface $versionManager, private readonly BackupManager $backupManager, + private readonly InstallationTypeDetector $installationTypeDetector, + private readonly UserPasswordHasherInterface $passwordHasher, #[Autowire(env: 'bool:DISABLE_WEB_UPDATES')] private readonly bool $webUpdatesDisabled = false, #[Autowire(env: 'bool:DISABLE_BACKUP_RESTORE')] private readonly bool $backupRestoreDisabled = false, + #[Autowire(env: 'bool:DISABLE_BACKUP_DOWNLOAD')] + private readonly bool $backupDownloadDisabled = false, ) { } @@ -76,6 +85,16 @@ class UpdateManagerController extends AbstractController } } + /** + * Check if backup download is disabled and throw exception if so. + */ + private function denyIfBackupDownloadDisabled(): void + { + if ($this->backupDownloadDisabled) { + throw new AccessDeniedHttpException('Backup download is disabled by server configuration.'); + } + } + /** * Main update manager page. */ @@ -101,6 +120,8 @@ class UpdateManagerController extends AbstractController 'backups' => $this->backupManager->getBackups(), 'web_updates_disabled' => $this->webUpdatesDisabled, 'backup_restore_disabled' => $this->backupRestoreDisabled, + 'backup_download_disabled' => $this->backupDownloadDisabled, + 'is_docker' => $this->installationTypeDetector->isDocker(), ]); } @@ -206,6 +227,7 @@ class UpdateManagerController extends AbstractController #[Route('/start', name: 'admin_update_manager_start', methods: ['POST'])] public function startUpdate(Request $request): Response { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); $this->denyAccessUnlessGranted('@system.manage_updates'); $this->denyIfWebUpdatesDisabled(); @@ -314,12 +336,126 @@ class UpdateManagerController extends AbstractController return $this->json($details); } + /** + * Create a manual backup. + */ + #[Route('/backup', name: 'admin_update_manager_backup', methods: ['POST'])] + public function createBackup(Request $request): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + $this->denyAccessUnlessGranted('@system.manage_updates'); + + if (!$this->isCsrfTokenValid('update_manager_backup', $request->request->get('_token'))) { + $this->addFlash('error', 'Invalid CSRF token.'); + return $this->redirectToRoute('admin_update_manager'); + } + + if ($this->updateExecutor->isLocked()) { + $this->addFlash('error', 'Cannot create backup while an update is in progress.'); + return $this->redirectToRoute('admin_update_manager'); + } + + try { + $this->backupManager->createBackup(null, 'manual'); + $this->addFlash('success', 'update_manager.backup.created'); + } catch (\Exception $e) { + $this->addFlash('error', 'Backup failed: ' . $e->getMessage()); + } + + return $this->redirectToRoute('admin_update_manager'); + } + + /** + * Delete a backup file. + */ + #[Route('/backup/delete', name: 'admin_update_manager_backup_delete', methods: ['POST'])] + public function deleteBackup(Request $request): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + $this->denyAccessUnlessGranted('@system.manage_updates'); + + if (!$this->isCsrfTokenValid('update_manager_delete', $request->request->get('_token'))) { + $this->addFlash('error', 'Invalid CSRF token.'); + return $this->redirectToRoute('admin_update_manager'); + } + + $filename = $request->request->get('filename'); + if ($filename && $this->backupManager->deleteBackup($filename)) { + $this->addFlash('success', 'update_manager.backup.deleted'); + } else { + $this->addFlash('error', 'update_manager.backup.delete_error'); + } + + return $this->redirectToRoute('admin_update_manager'); + } + + /** + * Delete an update log file. + */ + #[Route('/log/delete', name: 'admin_update_manager_log_delete', methods: ['POST'])] + public function deleteLog(Request $request): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + $this->denyAccessUnlessGranted('@system.manage_updates'); + + if (!$this->isCsrfTokenValid('update_manager_delete', $request->request->get('_token'))) { + $this->addFlash('error', 'Invalid CSRF token.'); + return $this->redirectToRoute('admin_update_manager'); + } + + $filename = $request->request->get('filename'); + if ($filename && $this->updateExecutor->deleteLog($filename)) { + $this->addFlash('success', 'update_manager.log.deleted'); + } else { + $this->addFlash('error', 'update_manager.log.delete_error'); + } + + return $this->redirectToRoute('admin_update_manager'); + } + + /** + * Download a backup file. + * Requires password confirmation as backups contain sensitive data (password hashes, secrets, etc.). + */ + #[Route('/backup/download', name: 'admin_update_manager_backup_download', methods: ['POST'])] + public function downloadBackup(Request $request): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + $this->denyAccessUnlessGranted('@system.manage_updates'); + $this->denyIfBackupDownloadDisabled(); + + if (!$this->isCsrfTokenValid('update_manager_download', $request->request->get('_token'))) { + $this->addFlash('error', 'Invalid CSRF token.'); + return $this->redirectToRoute('admin_update_manager'); + } + + // Verify password + $password = $request->request->get('password', ''); + $user = $this->getUser(); + if (!$user instanceof User || !$this->passwordHasher->isPasswordValid($user, $password)) { + $this->addFlash('error', 'update_manager.backup.download.invalid_password'); + return $this->redirectToRoute('admin_update_manager'); + } + + $filename = $request->request->get('filename', ''); + $details = $this->backupManager->getBackupDetails($filename); + if (!$details) { + throw $this->createNotFoundException('Backup not found'); + } + + $response = new BinaryFileResponse($details['path']); + $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $details['file']); + + return $response; + } + /** * Restore from a backup. */ #[Route('/restore', name: 'admin_update_manager_restore', methods: ['POST'])] public function restore(Request $request): Response { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); $this->denyAccessUnlessGranted('@system.manage_updates'); $this->denyIfBackupRestoreDisabled(); diff --git a/src/Services/System/BackupManager.php b/src/Services/System/BackupManager.php index 4946bc24..621b58d7 100644 --- a/src/Services/System/BackupManager.php +++ b/src/Services/System/BackupManager.php @@ -327,14 +327,14 @@ readonly class BackupManager */ private function restoreDatabaseFromBackup(string $tempDir): void { + // Get database connection params from Doctrine + $connection = $this->entityManager->getConnection(); + $params = $connection->getParams(); + $platform = $connection->getDatabasePlatform(); + // Check for SQL dump (MySQL/PostgreSQL) $sqlFile = $tempDir . '/database.sql'; if (file_exists($sqlFile)) { - // Import SQL using mysql/psql command directly - // First, get database connection params from Doctrine - $connection = $this->entityManager->getConnection(); - $params = $connection->getParams(); - $platform = $connection->getDatabasePlatform(); if ($platform instanceof AbstractMySQLPlatform) { // Use mysql command to import - need to use shell to handle input redirection @@ -403,7 +403,8 @@ readonly class BackupManager // Check for SQLite database file $sqliteFile = $tempDir . '/var/app.db'; if (file_exists($sqliteFile)) { - $targetDb = $this->projectDir . '/var/app.db'; + // Use the actual configured SQLite path from Doctrine, not a hardcoded path + $targetDb = $params['path'] ?? $this->projectDir . '/var/app.db'; $this->filesystem->copy($sqliteFile, $targetDb, true); return; } diff --git a/src/Services/System/UpdateExecutor.php b/src/Services/System/UpdateExecutor.php index 77cf2942..0992663e 100644 --- a/src/Services/System/UpdateExecutor.php +++ b/src/Services/System/UpdateExecutor.php @@ -686,6 +686,33 @@ class UpdateExecutor } + /** + * Delete a specific update log file. + */ + public function deleteLog(string $filename): bool + { + // Validate filename pattern for security + if (!preg_match('/^update-[\w.\-]+\.log$/', $filename)) { + $this->logger->warning('Attempted to delete invalid log filename: ' . $filename); + return false; + } + + $logPath = $this->project_dir . '/' . self::UPDATE_LOG_DIR . '/' . basename($filename); + + if (!file_exists($logPath)) { + return false; + } + + try { + $this->filesystem->remove($logPath); + $this->logger->info('Deleted update log: ' . $filename); + return true; + } catch (\Exception $e) { + $this->logger->error('Failed to delete update log: ' . $e->getMessage()); + return false; + } + } + /** * Restore from a backup file with maintenance mode and cache clearing. * diff --git a/templates/admin/update_manager/index.html.twig b/templates/admin/update_manager/index.html.twig index 44b9f8c0..2c6db63c 100644 --- a/templates/admin/update_manager/index.html.twig +++ b/templates/admin/update_manager/index.html.twig @@ -1,5 +1,7 @@ {% extends "main_card.html.twig" %} +{% import "helper.twig" as helper %} + {% block title %}Part-DB {% trans %}update_manager.title{% endtrans %}{% endblock %} {% block card_title %} @@ -7,60 +9,60 @@ {% endblock %} {% block card_content %} -
+
- {# Maintenance Mode Warning #} - {% if is_maintenance %} - - {% endif %} + {# Maintenance Mode Warning #} + {% if is_maintenance %} + + {% endif %} - {# Lock Warning #} - {% if is_locked %} - - {% endif %} + {# Lock Warning #} + {% if is_locked %} + + {% endif %} - {# Web Updates Disabled Warning #} - {% if web_updates_disabled %} - - {% endif %} + {# Web Updates Disabled Warning #} + {% if web_updates_disabled %} + + {% endif %} - {# Backup Restore Disabled Warning #} - {% if backup_restore_disabled %} - - {% endif %} + {# Backup Restore Disabled Warning #} + {% if backup_restore_disabled %} + + {% endif %} -
- {# Current Version Card #} -
-
-
- {% trans %}update_manager.current_installation{% endtrans %} -
-
- - +
+ {# Current Version Card #} +
+
+
+ {% trans %}update_manager.current_installation{% endtrans %} +
+
+
+ - -
{% trans %}update_manager.version{% endtrans %} @@ -100,153 +102,159 @@
{% trans %}update_manager.auto_update_supported{% endtrans %} - {% if status.can_auto_update %} - - {% trans %}Yes{% endtrans %} - - {% else %} - - {% trans %}No{% endtrans %} - - {% endif %} + {{ helper.boolean_badge(status.can_auto_update) }}
-
- +
-
- {# Latest Version / Update Card #} -
-
-
- {% if status.update_available %} - {% trans %}update_manager.new_version_available.title{% endtrans %} - {% else %} - {% trans %}update_manager.latest_release{% endtrans %} - {% endif %} -
-
- {% if status.latest_version %} -
+ {# Latest Version / Update Card #} +
+
+
+ {% if status.update_available %} + {% trans %}update_manager.new_version_available.title{% endtrans %} + {% else %} + {% trans %}update_manager.latest_release{% endtrans %} + {% endif %} +
+
+ {% if status.latest_version %} +
{{ status.latest_tag }} - {% if not status.update_available %} -

- - {% trans %}update_manager.already_up_to_date{% endtrans %} + {% if not status.update_available %} +

+ + {% trans %}update_manager.already_up_to_date{% endtrans %} +

+ {% endif %} +
+ + {% if status.update_available and status.can_auto_update and validation.valid and not web_updates_disabled %} +
+ + + +
+ +
+ +
+ + +
+
+ {% endif %} + + {% if status.published_at %} +

+ + {% trans %}update_manager.released{% endtrans %}: {{ status.published_at|date('Y-m-d') }}

{% endif %} -
- - {% if status.update_available and status.can_auto_update and validation.valid and not web_updates_disabled %} -
- - - -
- -
- -
- - -
-
+ {% else %} +
+ +

{% trans %}update_manager.could_not_fetch_releases{% endtrans %}

+
{% endif %} - - {% if status.published_at %} -

- - {% trans %}update_manager.released{% endtrans %}: {{ status.published_at|date('Y-m-d') }} -

- {% endif %} - {% else %} -
- -

{% trans %}update_manager.could_not_fetch_releases{% endtrans %}

+
+ {% if status.latest_tag %} + {% endif %}
- {% if status.latest_tag %} - - {% endif %}
-
- {# Validation Issues #} - {% if not validation.valid %} - - {% endif %} + {# Validation Issues #} + {% if not validation.valid %} + + {% endif %} - {# Non-auto-update installations info #} - {% if not status.can_auto_update %} -
-
- {% trans%}update_manager.cant_auto_update{% endtrans%}: {{ status.installation.type_name }} -
-

{{ status.installation.update_instructions }}

-
- {% endif %} + {# Non-auto-update installations info #} + {% if not status.can_auto_update %} +
+
+ {% trans%}update_manager.cant_auto_update{% endtrans%}: {{ status.installation.type_name }} +
+

{{ status.installation.update_instructions }}

+
+ {% endif %} -
- {# Available Versions #} -
-
-
- {% trans %}update_manager.available_versions{% endtrans %} -
-
-
- - +
+ {# Available Versions #} +
+
+
+ {% trans %}update_manager.available_versions{% endtrans %} +
+
+
+
+ - - + + {% for release in all_releases %} {% endfor %} - -
{% trans %}update_manager.version{% endtrans %} {% trans %}update_manager.released{% endtrans %}
@@ -280,8 +288,8 @@
+ + +
-
- {# Update History & Backups #} -
-
-
- -
-
-
-
-
- - + {# Update History & Backups #} +
+
+
+ +
+
+
+
+
+
+ - - + + {% for log in update_logs %} - {% else %} @@ -357,22 +380,39 @@ {% endfor %} - -
{% trans %}update_manager.date{% endtrans %} {% trans %}update_manager.log_file{% endtrans %}
{{ log.date|date('Y-m-d H:i') }} {{ log.file }} - - - + +
+ + + + {% if is_granted('@system.manage_updates') %} +
+ + + +
+ {% endif %} +
+ + +
-
-
-
- - +
+ {% if is_granted('@system.manage_updates') and not is_locked %} +
+
+ + + +
+ {% endif %} + {% if is_docker %} +
+ + {% trans %}update_manager.backup.docker_warning{% endtrans %} +
+ {% endif %} +
+
+ - - + + {% for backup in backups %} @@ -410,8 +516,9 @@ {% endfor %} - -
{% trans %}update_manager.date{% endtrans %} {% trans %}update_manager.file{% endtrans %} {% trans %}update_manager.size{% endtrans %}
@@ -383,23 +423,89 @@ {{ (backup.size / 1024 / 1024)|number_format(1) }} MB - {% if status.can_auto_update and validation.valid and not backup_restore_disabled %} -
- - - - -
+ {% endif %} + {% if not backup_restore_disabled and is_granted('@system.manage_updates') %} +
+ + + + +
+ {% endif %} + {% if is_granted('@system.manage_updates') %} +
+ + + +
+ {% endif %} + + + {% if not backup_download_disabled and is_granted('@system.manage_updates') %} + {# Per-backup download modal - no inline JS needed, CSP compatible with Turbo #} + {% endif %}
+ + +
@@ -419,5 +526,5 @@
-
+ {% endblock %} diff --git a/templates/helper.twig b/templates/helper.twig index 9e68d56c..e8c926e7 100644 --- a/templates/helper.twig +++ b/templates/helper.twig @@ -1,8 +1,8 @@ {% macro boolean(value) %} {% if value %} - {% trans %}bool.true{% endtrans %} + {% trans %}Yes{% endtrans %} {% else %} - {% trans %}bool.false{% endtrans %} + {% trans %}No{% endtrans %} {% endif %} {% endmacro %} @@ -14,9 +14,9 @@ {% macro bool_icon(bool) %} {% if bool %} - + {% else %} - + {% endif %} {% endmacro %} @@ -24,7 +24,7 @@ {% if value %} {% set class = class ~ ' bg-success' %} {% else %} - {% set class = class ~ ' bg-danger' %} + {% set class = class ~ ' bg-secondary' %} {% endif %} {{ _self.bool_icon(value) }} {{ _self.boolean(value) }} diff --git a/tests/Controller/UpdateManagerControllerTest.php b/tests/Controller/UpdateManagerControllerTest.php new file mode 100644 index 00000000..0c2b2224 --- /dev/null +++ b/tests/Controller/UpdateManagerControllerTest.php @@ -0,0 +1,381 @@ +. + */ + +declare(strict_types=1); + +namespace App\Tests\Controller; + +use App\Entity\UserSystem\User; +use App\Services\System\BackupManager; +use App\Services\System\UpdateExecutor; +use PHPUnit\Framework\Attributes\Group; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + +#[Group("slow")] +#[Group("DB")] +final class UpdateManagerControllerTest extends WebTestCase +{ + private function loginAsAdmin($client): void + { + $entityManager = $client->getContainer()->get('doctrine')->getManager(); + $userRepository = $entityManager->getRepository(User::class); + $user = $userRepository->findOneBy(['name' => 'admin']); + + if (!$user) { + $this->markTestSkipped('Admin user not found'); + } + + $client->loginUser($user); + } + + /** + * Extract a CSRF token from the rendered update manager page. + */ + private function getCsrfTokenFromPage($crawler, string $formAction): string + { + $form = $crawler->filter('form[action*="' . $formAction . '"]'); + if ($form->count() === 0) { + $this->fail('Form with action containing "' . $formAction . '" not found on page'); + } + + return $form->filter('input[name="_token"]')->attr('value'); + } + + // ---- Authentication tests ---- + + public function testIndexPageRequiresAuth(): void + { + $client = static::createClient(); + + $client->request('GET', '/en/system/update-manager'); + + // Should deny access (401 with HTTP Basic auth in test env) + $this->assertResponseStatusCodeSame(401); + } + + public function testIndexPageAccessibleByAdmin(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('GET', '/en/system/update-manager'); + + $this->assertResponseIsSuccessful(); + } + + // ---- Backup creation tests ---- + + public function testCreateBackupRequiresCsrf(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('POST', '/en/system/update-manager/backup', [ + '_token' => 'invalid', + ]); + + // Should redirect with error flash + $this->assertResponseRedirects(); + } + + public function testCreateBackupWithValidCsrf(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // Load the page and extract CSRF token from the backup form + $crawler = $client->request('GET', '/en/system/update-manager'); + $csrfToken = $this->getCsrfTokenFromPage($crawler, 'backup'); + + $client->request('POST', '/en/system/update-manager/backup', [ + '_token' => $csrfToken, + ]); + + $this->assertResponseRedirects(); + + // Clean up: delete the backup that was just created + $backupManager = $client->getContainer()->get(BackupManager::class); + $backups = $backupManager->getBackups(); + foreach ($backups as $backup) { + if (str_contains($backup['file'], 'manual')) { + $backupManager->deleteBackup($backup['file']); + } + } + } + + public function testCreateBackupBlockedWhenLocked(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // Load the page first to get CSRF token before locking + $crawler = $client->request('GET', '/en/system/update-manager'); + $csrfToken = $this->getCsrfTokenFromPage($crawler, 'backup'); + + // Acquire lock to simulate update in progress + $updateExecutor = $client->getContainer()->get(UpdateExecutor::class); + $updateExecutor->acquireLock(); + + try { + $client->request('POST', '/en/system/update-manager/backup', [ + '_token' => $csrfToken, + ]); + + $this->assertResponseRedirects(); + } finally { + // Always release lock + $updateExecutor->releaseLock(); + } + } + + // ---- Backup deletion tests ---- + + public function testDeleteBackupRequiresCsrf(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('POST', '/en/system/update-manager/backup/delete', [ + '_token' => 'invalid', + 'filename' => 'test.zip', + ]); + + $this->assertResponseRedirects(); + } + + public function testDeleteBackupWithValidCsrf(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // Create a temporary backup file so the page shows the delete form + $backupManager = $client->getContainer()->get(BackupManager::class); + $backupDir = $backupManager->getBackupDir(); + if (!is_dir($backupDir)) { + mkdir($backupDir, 0755, true); + } + $testFile = 'test-delete-' . uniqid() . '.zip'; + file_put_contents($backupDir . '/' . $testFile, 'test'); + + // Load the page and extract CSRF token from the delete form + $crawler = $client->request('GET', '/en/system/update-manager'); + $csrfToken = $this->getCsrfTokenFromPage($crawler, 'backup/delete'); + + $client->request('POST', '/en/system/update-manager/backup/delete', [ + '_token' => $csrfToken, + 'filename' => $testFile, + ]); + + $this->assertResponseRedirects(); + $this->assertFileDoesNotExist($backupDir . '/' . $testFile); + } + + // ---- Log deletion tests ---- + + public function testDeleteLogRequiresCsrf(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('POST', '/en/system/update-manager/log/delete', [ + '_token' => 'invalid', + 'filename' => 'test.log', + ]); + + $this->assertResponseRedirects(); + } + + public function testDeleteLogWithValidCsrf(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // Create a temporary log file so the page shows the delete form + $projectDir = $client->getContainer()->getParameter('kernel.project_dir'); + $logDir = $projectDir . '/var/log/updates'; + if (!is_dir($logDir)) { + mkdir($logDir, 0755, true); + } + $testFile = 'update-test-delete-' . uniqid() . '.log'; + file_put_contents($logDir . '/' . $testFile, 'test log content'); + + // Load the page and extract CSRF token from the log delete form + $crawler = $client->request('GET', '/en/system/update-manager'); + $csrfToken = $this->getCsrfTokenFromPage($crawler, 'log/delete'); + + $client->request('POST', '/en/system/update-manager/log/delete', [ + '_token' => $csrfToken, + 'filename' => $testFile, + ]); + + $this->assertResponseRedirects(); + $this->assertFileDoesNotExist($logDir . '/' . $testFile); + } + + // ---- Backup download tests ---- + + public function testDownloadBackupBlockedByDefault(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // DISABLE_BACKUP_DOWNLOAD=1 is the default in .env, so this should return 403 + $client->request('POST', '/en/system/update-manager/backup/download', [ + '_token' => 'any', + 'filename' => 'test.zip', + 'password' => 'test', + ]); + + $this->assertResponseStatusCodeSame(403); + } + + public function testDownloadBackupRequiresPost(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // GET returns 404 since no GET route exists for this path + $client->request('GET', '/en/system/update-manager/backup/download'); + + $this->assertResponseStatusCodeSame(404); + } + + public function testDownloadBackupRequiresAuth(): void + { + $client = static::createClient(); + + $client->request('POST', '/en/system/update-manager/backup/download', [ + '_token' => 'any', + 'filename' => 'test.zip', + 'password' => 'test', + ]); + + // Should deny access (401 with HTTP Basic auth in test env) + $this->assertResponseStatusCodeSame(401); + } + + // ---- Backup details tests ---- + + public function testBackupDetailsReturns404ForNonExistent(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('GET', '/en/system/update-manager/backup/nonexistent.zip'); + + $this->assertResponseStatusCodeSame(404); + } + + // ---- Restore tests ---- + + public function testRestoreBlockedWhenDisabled(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // DISABLE_BACKUP_RESTORE=1 is the default in .env, so this should return 403 + $client->request('POST', '/en/system/update-manager/restore', [ + '_token' => 'invalid', + 'filename' => 'test.zip', + ]); + + $this->assertResponseStatusCodeSame(403); + } + + public function testRestoreRequiresAuth(): void + { + $client = static::createClient(); + + $client->request('POST', '/en/system/update-manager/restore', [ + '_token' => 'invalid', + 'filename' => 'test.zip', + ]); + + $this->assertResponseStatusCodeSame(401); + } + + // ---- Start update tests ---- + + public function testStartUpdateRequiresAuth(): void + { + $client = static::createClient(); + + $client->request('POST', '/en/system/update-manager/start', [ + '_token' => 'invalid', + 'version' => 'v1.0.0', + ]); + + $this->assertResponseStatusCodeSame(401); + } + + public function testStartUpdateBlockedWhenWebUpdatesDisabled(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + // DISABLE_WEB_UPDATES=1 is the default in .env + $client->request('POST', '/en/system/update-manager/start', [ + '_token' => 'invalid', + 'version' => 'v1.0.0', + ]); + + $this->assertResponseStatusCodeSame(403); + } + + // ---- Status and progress tests ---- + + public function testStatusEndpointRequiresAuth(): void + { + $client = static::createClient(); + + $client->request('GET', '/en/system/update-manager/status'); + + $this->assertResponseStatusCodeSame(401); + } + + public function testStatusEndpointAccessibleByAdmin(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('GET', '/en/system/update-manager/status'); + + $this->assertResponseIsSuccessful(); + } + + public function testProgressStatusEndpointRequiresAuth(): void + { + $client = static::createClient(); + + $client->request('GET', '/en/system/update-manager/progress/status'); + + $this->assertResponseStatusCodeSame(401); + } + + public function testProgressStatusEndpointAccessibleByAdmin(): void + { + $client = static::createClient(); + $this->loginAsAdmin($client); + + $client->request('GET', '/en/system/update-manager/progress/status'); + + $this->assertResponseIsSuccessful(); + } +} diff --git a/tests/Services/System/BackupManagerTest.php b/tests/Services/System/BackupManagerTest.php index f75ef8f3..9aa92813 100644 --- a/tests/Services/System/BackupManagerTest.php +++ b/tests/Services/System/BackupManagerTest.php @@ -82,6 +82,16 @@ final class BackupManagerTest extends KernelTestCase $this->assertSame('2.6.0', $matches[2]); } + public function testDeleteBackupReturnsFalseForNonExistentFile(): void + { + $this->assertFalse($this->backupManager->deleteBackup('non-existent.zip')); + } + + public function testDeleteBackupReturnsFalseForNonZipFile(): void + { + $this->assertFalse($this->backupManager->deleteBackup('not-a-zip.txt')); + } + /** * Test version parsing with different filename formats. */ diff --git a/tests/Services/System/UpdateExecutorTest.php b/tests/Services/System/UpdateExecutorTest.php index 48cddf8d..8b95b3b0 100644 --- a/tests/Services/System/UpdateExecutorTest.php +++ b/tests/Services/System/UpdateExecutorTest.php @@ -139,6 +139,38 @@ final class UpdateExecutorTest extends KernelTestCase $this->assertFalse($this->updateExecutor->isLocked()); } + public function testDeleteLogRejectsInvalidFilename(): void + { + // Path traversal attempts should be rejected + $this->assertFalse($this->updateExecutor->deleteLog('../../../etc/passwd')); + $this->assertFalse($this->updateExecutor->deleteLog('malicious.txt')); + $this->assertFalse($this->updateExecutor->deleteLog('')); + // Must start with "update-" + $this->assertFalse($this->updateExecutor->deleteLog('backup-v1.0.0.log')); + } + + public function testDeleteLogReturnsFalseForNonExistentFile(): void + { + $this->assertFalse($this->updateExecutor->deleteLog('update-nonexistent-file.log')); + } + + public function testDeleteLogDeletesExistingFile(): void + { + // Create a temporary log file in the update logs directory + $projectDir = self::getContainer()->getParameter('kernel.project_dir'); + $logDir = $projectDir . '/var/log/updates'; + + if (!is_dir($logDir)) { + mkdir($logDir, 0755, true); + } + + $testFile = 'update-test-delete-' . uniqid() . '.log'; + file_put_contents($logDir . '/' . $testFile, 'test log content'); + + $this->assertTrue($this->updateExecutor->deleteLog($testFile)); + $this->assertFileDoesNotExist($logDir . '/' . $testFile); + } + public function testEnableAndDisableMaintenanceMode(): void { // First, ensure maintenance mode is off diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index b84a1875..bcd07331 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -12491,6 +12491,102 @@ Buerklin-API Authentication server: Backup restore is disabled by server configuration. + + + update_manager.backup.create + Create Backup + + + + + update_manager.backup.create.confirm + Create a full backup now? This may take a moment. + + + + + update_manager.backup.created + Backup created successfully. + + + + + update_manager.backup.delete.confirm + Are you sure you want to delete this backup? + + + + + update_manager.backup.deleted + Backup deleted successfully. + + + + + update_manager.backup.delete_error + Failed to delete backup. + + + + + update_manager.log.delete.confirm + Are you sure you want to delete this log? + + + + + update_manager.log.deleted + Log deleted successfully. + + + + + update_manager.log.delete_error + Failed to delete log. + + + + + update_manager.view_log + View log + + + + + update_manager.delete + Delete + + + + + update_manager.backup.download + Download backup + + + + + update_manager.backup.download.password_label + Confirm your password to download + + + + + update_manager.backup.download.security_warning + Backups contain sensitive data including password hashes and secrets. Please confirm your password to proceed with the download. + + + + + update_manager.backup.download.invalid_password + Invalid password. Backup download denied. + + + + + update_manager.backup.docker_warning + Docker installation detected. Backups are stored in var/backups/ which is not a persistent volume. Use the download button to save backups externally, or mount var/backups/ as a volume in your docker-compose.yml. + + settings.ips.conrad @@ -12821,5 +12917,29 @@ Buerklin-API Authentication server: View as plain text + + + modal.cancel + Cancel + + + + + update_manager.web_updates_allowed + Web updates allowed + + + + + update_manager.backup_restore_allowed + Backup restore allowed + + + + + update_manager.backup_download_allowed + Backup download allowed + + From 3ed27f6c0f0ffc042fd74e0fc165f4700543e24d Mon Sep 17 00:00:00 2001 From: Niklas <44636701+MayNiklas@users.noreply.github.com> Date: Sat, 7 Mar 2026 19:31:47 +0100 Subject: [PATCH 24/34] /api/part_lots: add user_barcode filter (#1280) * /api/part_lots: add user_barcode filter * support LIKE filtering for part lot user_barcode --- src/Entity/Parts/PartLot.php | 2 +- tests/API/Endpoints/PartLotsEndpointTest.php | 26 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Entity/Parts/PartLot.php b/src/Entity/Parts/PartLot.php index 53ecd3d5..f7224843 100644 --- a/src/Entity/Parts/PartLot.php +++ b/src/Entity/Parts/PartLot.php @@ -81,7 +81,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; denormalizationContext: ['groups' => ['part_lot:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], )] #[ApiFilter(PropertyFilter::class)] -#[ApiFilter(LikeFilter::class, properties: ["description", "comment"])] +#[ApiFilter(LikeFilter::class, properties: ["description", "comment", "user_barcode"])] #[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] #[ApiFilter(BooleanFilter::class, properties: ['instock_unknown', 'needs_refill'])] #[ApiFilter(RangeFilter::class, properties: ['amount'])] diff --git a/tests/API/Endpoints/PartLotsEndpointTest.php b/tests/API/Endpoints/PartLotsEndpointTest.php index 70f1f9ab..0d48d1e7 100644 --- a/tests/API/Endpoints/PartLotsEndpointTest.php +++ b/tests/API/Endpoints/PartLotsEndpointTest.php @@ -47,6 +47,32 @@ final class PartLotsEndpointTest extends CrudEndpointTestCase $this->_testGetItem(2); } + public function testFilterByUserBarcode(): void + { + $response = self::createAuthenticatedClient()->request('GET', '/api/part_lots?user_barcode=lot2_vendor_barcode'); + + self::assertResponseIsSuccessful(); + self::assertJsonContains([ + 'hydra:totalItems' => 1, + ]); + + $json = $response->toArray(); + self::assertSame('/api/part_lots/2', $json['hydra:member'][0]['@id']); + } + + public function testFilterByUserBarcodeUsingWildcard(): void + { + $response = self::createAuthenticatedClient()->request('GET', '/api/part_lots?user_barcode=lot2_%'); + + self::assertResponseIsSuccessful(); + self::assertJsonContains([ + 'hydra:totalItems' => 1, + ]); + + $json = $response->toArray(); + self::assertSame('/api/part_lots/2', $json['hydra:member'][0]['@id']); + } + public function testCreateItem(): void { $this->_testPostItem([ From 6e4d2526178165a87ef726b79fab4f636d8a81eb Mon Sep 17 00:00:00 2001 From: Marc Date: Sat, 7 Mar 2026 19:35:08 +0100 Subject: [PATCH 25/34] Show ManufacturingStatus in BOM (#1289) --- src/DataTables/ProjectBomEntriesDataTable.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/DataTables/ProjectBomEntriesDataTable.php b/src/DataTables/ProjectBomEntriesDataTable.php index 433f6f78..0d05c248 100644 --- a/src/DataTables/ProjectBomEntriesDataTable.php +++ b/src/DataTables/ProjectBomEntriesDataTable.php @@ -23,11 +23,13 @@ declare(strict_types=1); namespace App\DataTables; use App\DataTables\Column\EntityColumn; +use App\DataTables\Column\EnumColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\MarkdownColumn; use App\DataTables\Helpers\PartDataTableHelper; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Part; +use App\Entity\Parts\ManufacturingStatus; use App\Entity\ProjectSystem\ProjectBOMEntry; use App\Services\ElementTypeNameGenerator; use App\Services\EntityURLGenerator; @@ -145,6 +147,19 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface 'orderField' => 'NATSORT(manufacturer.name)', ]) + ->add('manufacturing_status', EnumColumn::class, [ + 'label' => $this->translator->trans('part.table.manufacturingStatus'), + 'data' => static fn(ProjectBOMEntry $context): ?ManufacturingStatus => $context->getPart()?->getManufacturingStatus(), + 'class' => ManufacturingStatus::class, + 'render' => function (?ManufacturingStatus $status, ProjectBOMEntry $context): string { + if ($status === null) { + return ''; + } + + return $this->translator->trans($status->toTranslationKey()); + }, + ]) + ->add('mountnames', TextColumn::class, [ 'label' => 'project.bom.mountnames', 'render' => function ($value, ProjectBOMEntry $context) { From 463d7b89f62eb59a7b7da324763202a8b7010c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 19:45:09 +0100 Subject: [PATCH 26/34] Added part description as property to KiCad response, to show it also in Kicad 9.0.5 and 9.06 Fixes #1291 --- src/Services/EDA/KiCadHelper.php | 1 + tests/Controller/KiCadApiControllerTest.php | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Services/EDA/KiCadHelper.php b/src/Services/EDA/KiCadHelper.php index be4532ce..42cc2518 100644 --- a/src/Services/EDA/KiCadHelper.php +++ b/src/Services/EDA/KiCadHelper.php @@ -202,6 +202,7 @@ class KiCadHelper "exclude_from_bom" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromBom() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromBom() ?? false), "exclude_from_board" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromBoard() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromBoard() ?? false), "exclude_from_sim" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromSim() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromSim() ?? false), + "description" => $part->getDescription(), "fields" => [] ]; diff --git a/tests/Controller/KiCadApiControllerTest.php b/tests/Controller/KiCadApiControllerTest.php index 26a47032..8e55de85 100644 --- a/tests/Controller/KiCadApiControllerTest.php +++ b/tests/Controller/KiCadApiControllerTest.php @@ -121,6 +121,7 @@ final class KiCadApiControllerTest extends WebTestCase 'exclude_from_bom' => 'False', 'exclude_from_board' => 'True', 'exclude_from_sim' => 'False', + 'description' => '', 'fields' => array( 'footprint' => @@ -203,6 +204,7 @@ final class KiCadApiControllerTest extends WebTestCase 'exclude_from_bom' => 'False', 'exclude_from_board' => 'True', 'exclude_from_sim' => 'False', + 'description' => '', 'fields' => array ( 'footprint' => @@ -318,4 +320,4 @@ final class KiCadApiControllerTest extends WebTestCase self::assertResponseStatusCodeSame(304); } -} \ No newline at end of file +} From b8d14144037a2bce31910686b2045b974e80b6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 19:56:14 +0100 Subject: [PATCH 27/34] Handle Barcode placeholders before anything else to avoid wrong delegation Fixes issue #1268 --- .../PlaceholderProviders/BarcodeProvider.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php b/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php index 400fef35..9719917a 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php +++ b/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php @@ -114,10 +114,12 @@ final class BarcodeProvider implements PlaceholderProviderInterface return 'IPN Barcode ERROR!: '.$e->getMessage(); } } - - - - return null; } + + public static function getDefaultPriority(): int + { + //This provider should be checked before all others, so that nothing is delegated for part lots + return 1000; + } } From 12a760d27e88310a33400a1df3d5b9da896ec917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 21:08:32 +0100 Subject: [PATCH 28/34] Correctly denormalize parent-child relationships in import, when only children not parent fields are given This fixes issue #1272 --- .../StructuralElementDenormalizer.php | 39 +++++++++++++++---- .../ImportExportSystem/EntityImporter.php | 38 ++++++------------ .../StructuralElementDenormalizerTest.php | 37 ++++++++++++++++++ 3 files changed, 81 insertions(+), 33 deletions(-) diff --git a/src/Serializer/StructuralElementDenormalizer.php b/src/Serializer/StructuralElementDenormalizer.php index 9f4256f9..e5847c41 100644 --- a/src/Serializer/StructuralElementDenormalizer.php +++ b/src/Serializer/StructuralElementDenormalizer.php @@ -42,6 +42,8 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz private const ALREADY_CALLED = 'STRUCTURAL_DENORMALIZER_ALREADY_CALLED'; + private const PARENT_ELEMENT = 'STRUCTURAL_DENORMALIZER_PARENT_ELEMENT'; + private array $object_cache = []; public function __construct( @@ -89,32 +91,55 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz $context[self::ALREADY_CALLED][] = $data; + //In the first step, denormalize without children + $context_without_children = $context; + $context_without_children['groups'] = array_filter( + $context_without_children['groups'] ?? [], + static fn($group) => $group !== 'include_children', + ); + //Also unset any parent element, to avoid infinite loops. We will set the parent element in the next step, when we denormalize the children + unset($context_without_children[self::PARENT_ELEMENT]); + /** @var AbstractStructuralDBElement $entity */ + $entity = $this->denormalizer->denormalize($data, $type, $format, $context_without_children); - /** @var AbstractStructuralDBElement $deserialized_entity */ - $deserialized_entity = $this->denormalizer->denormalize($data, $type, $format, $context); + //Assign the parent element to the denormalized entity, so it can be used in the denormalization of the children (e.g. for path generation) + if (isset($context[self::PARENT_ELEMENT]) && $context[self::PARENT_ELEMENT] instanceof $entity && $entity->getID() === null) { + $entity->setParent($context[self::PARENT_ELEMENT]); + } //Check if we already have the entity in the database (via path) /** @var StructuralDBElementRepository $repo */ $repo = $this->entityManager->getRepository($type); + $deserialized_entity = $entity; $path = $deserialized_entity->getFullPath(AbstractStructuralDBElement::PATH_DELIMITER_ARROW); $db_elements = $repo->getEntityByPath($path, AbstractStructuralDBElement::PATH_DELIMITER_ARROW); if ($db_elements !== []) { //We already have the entity in the database, so we can return it - return end($db_elements); + $entity = end($db_elements); } //Check if we have created the entity in this request before (so we don't create multiple entities for the same path) //Entities get saved in the cache by type and path //We use a different cache for this then the objects created by a string value (saved in repo). However, that should not be a problem - //unless the user data has mixed structure between json data and a string path + //unless the user data has mixed structure between JSON data and a string path if (isset($this->object_cache[$type][$path])) { - return $this->object_cache[$type][$path]; + $entity = $this->object_cache[$type][$path]; + } else { + //Save the entity in the cache + $this->object_cache[$type][$path] = $deserialized_entity; } - //Save the entity in the cache - $this->object_cache[$type][$path] = $deserialized_entity; + //In the next step we can denormalize the children, and add our children to the entity. + if (in_array('include_children', $context['groups'], true) && isset($data['children']) && is_array($data['children'])) { + foreach ($data['children'] as $child_data) { + $child_entity = $this->denormalize($child_data, $type, $format, array_merge($context, [self::PARENT_ELEMENT => $entity])); + if ($child_entity !== null && !$entity->getChildren()->contains($child_entity)) { + $entity->addChild($child_entity); + } + } + } //We don't have the entity in the database, so we have to persist it $this->entityManager->persist($deserialized_entity); diff --git a/src/Services/ImportExportSystem/EntityImporter.php b/src/Services/ImportExportSystem/EntityImporter.php index 7b928d6c..e57f2126 100644 --- a/src/Services/ImportExportSystem/EntityImporter.php +++ b/src/Services/ImportExportSystem/EntityImporter.php @@ -219,11 +219,6 @@ class EntityImporter $entities = [$entities]; } - //The serializer has only set the children attributes. We also have to change the parent value (the real value in DB) - if ($entities[0] instanceof AbstractStructuralDBElement) { - $this->correctParentEntites($entities, null); - } - //Set the parent of the imported elements to the given options foreach ($entities as $entity) { if ($entity instanceof AbstractStructuralDBElement) { @@ -297,6 +292,14 @@ class EntityImporter return $resolver; } + private function persistRecursively(AbstractStructuralDBElement $entity): void + { + $this->em->persist($entity); + foreach ($entity->getChildren() as $child) { + $this->persistRecursively($child); + } + } + /** * This method deserializes the given file and writes the entities to the database (and flush the db). * The imported elements will be checked (validated) before written to database. @@ -322,7 +325,7 @@ class EntityImporter //Iterate over each $entity write it to DB (the invalid entities were already filtered out). foreach ($entities as $entity) { - $this->em->persist($entity); + $this->persistRecursively($entity); } //Save changes to database, when no error happened, or we should continue on error. @@ -400,7 +403,7 @@ class EntityImporter * * @param File $file The Excel file to convert * @param string $delimiter The CSV delimiter to use - * + * * @return string The CSV data as string */ protected function convertExcelToCsv(File $file, string $delimiter = ';'): string @@ -421,7 +424,7 @@ class EntityImporter ]); $highestColumnIndex = Coordinate::columnIndexFromString($highestColumn); - + for ($row = 1; $row <= $highestRow; $row++) { $rowData = []; @@ -431,7 +434,7 @@ class EntityImporter try { $cellValue = $worksheet->getCell("{$col}{$row}")->getCalculatedValue(); $rowData[] = $cellValue ?? ''; - + } catch (\Exception $e) { $this->logger->warning('Error reading cell value', [ 'cell' => "{$col}{$row}", @@ -484,21 +487,4 @@ class EntityImporter throw $e; } } - - - /** - * This functions corrects the parent setting based on the children value of the parent. - * - * @param iterable $entities the list of entities that should be fixed - * @param AbstractStructuralDBElement|null $parent the parent, to which the entity should be set - */ - protected function correctParentEntites(iterable $entities, ?AbstractStructuralDBElement $parent = null): void - { - foreach ($entities as $entity) { - /** @var AbstractStructuralDBElement $entity */ - $entity->setParent($parent); - //Do the same for the children of entity - $this->correctParentEntites($entity->getChildren(), $entity); - } - } } diff --git a/tests/Serializer/StructuralElementDenormalizerTest.php b/tests/Serializer/StructuralElementDenormalizerTest.php index e8e46611..c81f02e3 100644 --- a/tests/Serializer/StructuralElementDenormalizerTest.php +++ b/tests/Serializer/StructuralElementDenormalizerTest.php @@ -85,4 +85,41 @@ final class StructuralElementDenormalizerTest extends WebTestCase $result2 = $this->service->denormalize($data, Category::class, 'json', ['groups' => ['import']]); $this->assertSame($result, $result2); } + + public function testDenormalizeViaChildren(): void + { + $data = ['name' => 'Node', + 'children' => [ + ['name' => 'A', 'children' => [['name' => '1'], ['name' => '2']]], + ['name' => 'B', 'children' => [['name' => '1'], ['name' => '2']]], + ['name' => 'C', 'children' => [['name' => '1'], ['name' => '2'], ['name' => '3']]], + ] + ]; + + $result = $this->service->denormalize($data, Category::class, 'json', ['groups' => ['import', 'include_children']]); + $this->assertInstanceOf(Category::class, $result); + + $this->assertCount(3, $result->getChildren()); + $this->assertSame('A', $result->getChildren()[0]->getName()); + $this->assertSame('B', $result->getChildren()[1]->getName()); + $this->assertSame('C', $result->getChildren()[2]->getName()); + //Parents should be set correctly + $this->assertSame($result, $result->getChildren()[0]->getParent()); + $this->assertSame($result, $result->getChildren()[1]->getParent()); + $this->assertSame($result, $result->getChildren()[2]->getParent()); + + $this->assertCount(2, $result->getChildren()[0]->getChildren()); + $this->assertSame('1', $result->getChildren()[0]->getChildren()[0]->getName()); + $this->assertSame('2', $result->getChildren()[0]->getChildren()[1]->getName()); + //Parents should be set correctly + $this->assertSame($result->getChildren()[0], $result->getChildren()[0]->getChildren()[0]->getParent()); + $this->assertSame($result->getChildren()[0], $result->getChildren()[0]->getChildren()[1]->getParent()); + + $this->assertCount(2, $result->getChildren()[1]->getChildren()); + $this->assertSame('1', $result->getChildren()[1]->getChildren()[0]->getName()); + $this->assertSame('2', $result->getChildren()[1]->getChildren()[1]->getName()); + //Must be different instances than the children of A, because we create new elements for the same path, if we don't have them in the DB + $this->assertNotSame($result->getChildren()[0]->getChildren()[0], $result->getChildren()[1]->getChildren()[0]); + + } } From a722608ae89bb0b0befe0176129badca0d77d19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 21:22:29 +0100 Subject: [PATCH 29/34] Clear input after option selection in tomselect fields Fixes issue #1264 --- .../controllers/elements/attachment_autocomplete_controller.js | 1 + assets/controllers/elements/part_select_controller.js | 2 ++ assets/controllers/elements/select_controller.js | 1 + assets/controllers/elements/select_multiple_controller.js | 2 ++ .../elements/static_file_autocomplete_controller.js | 1 + .../elements/structural_entity_select_controller.js | 1 + assets/controllers/elements/tagsinput_controller.js | 1 + assets/controllers/pages/parameters_autocomplete_controller.js | 3 ++- 8 files changed, 11 insertions(+), 1 deletion(-) diff --git a/assets/controllers/elements/attachment_autocomplete_controller.js b/assets/controllers/elements/attachment_autocomplete_controller.js index 94b01136..86975c0c 100644 --- a/assets/controllers/elements/attachment_autocomplete_controller.js +++ b/assets/controllers/elements/attachment_autocomplete_controller.js @@ -45,6 +45,7 @@ export default class extends Controller { maxItems: 1, createOnBlur: true, selectOnTab: true, + clearAfterSelect: true, //This a an ugly solution to disable the delimiter parsing of the TomSelect plugin delimiter: 'VERY_L0NG_D€LIMITER_WHICH_WILL_NEVER_BE_ENCOUNTERED_IN_A_STRING', dropdownParent: dropdownParent, diff --git a/assets/controllers/elements/part_select_controller.js b/assets/controllers/elements/part_select_controller.js index b69acbbc..1edbdf67 100644 --- a/assets/controllers/elements/part_select_controller.js +++ b/assets/controllers/elements/part_select_controller.js @@ -23,6 +23,8 @@ export default class extends Controller { valueField: "id", labelField: "name", dropdownParent: dropdownParent, + selectOnTab: true, + clearAfterSelect: true, preload: "focus", render: { item: (data, escape) => { diff --git a/assets/controllers/elements/select_controller.js b/assets/controllers/elements/select_controller.js index d70e588c..11e29280 100644 --- a/assets/controllers/elements/select_controller.js +++ b/assets/controllers/elements/select_controller.js @@ -49,6 +49,7 @@ export default class extends Controller { selectOnTab: true, maxOptions: null, dropdownParent: dropdownParent, + clearAfterSelect: true, render: { item: this.renderItem.bind(this), diff --git a/assets/controllers/elements/select_multiple_controller.js b/assets/controllers/elements/select_multiple_controller.js index 17e85fae..01bbd24b 100644 --- a/assets/controllers/elements/select_multiple_controller.js +++ b/assets/controllers/elements/select_multiple_controller.js @@ -35,6 +35,8 @@ export default class extends Controller { maxItems: 1000, allowEmptyOption: true, dropdownParent: dropdownParent, + selectOnTab: true, + clearAfterSelect: true, plugins: ['remove_button'], }); } diff --git a/assets/controllers/elements/static_file_autocomplete_controller.js b/assets/controllers/elements/static_file_autocomplete_controller.js index 9703c618..bd01246a 100644 --- a/assets/controllers/elements/static_file_autocomplete_controller.js +++ b/assets/controllers/elements/static_file_autocomplete_controller.js @@ -56,6 +56,7 @@ export default class extends Controller { searchField: 'text', orderField: 'text', dropdownParent: dropdownParent, + clearAfterSelect: true, //This a an ugly solution to disable the delimiter parsing of the TomSelect plugin delimiter: 'VERY_L0NG_D€LIMITER_WHICH_WILL_NEVER_BE_ENCOUNTERED_IN_A_STRING', diff --git a/assets/controllers/elements/structural_entity_select_controller.js b/assets/controllers/elements/structural_entity_select_controller.js index 2666530b..5c462e51 100644 --- a/assets/controllers/elements/structural_entity_select_controller.js +++ b/assets/controllers/elements/structural_entity_select_controller.js @@ -58,6 +58,7 @@ export default class extends Controller { delimiter: "$$VERY_LONG_DELIMITER_THAT_SHOULD_NEVER_APPEAR$$", splitOn: null, dropdownParent: dropdownParent, + clearAfterSelect: true, searchField: [ {field: "text", weight : 2}, diff --git a/assets/controllers/elements/tagsinput_controller.js b/assets/controllers/elements/tagsinput_controller.js index 14725227..a4b1f175 100644 --- a/assets/controllers/elements/tagsinput_controller.js +++ b/assets/controllers/elements/tagsinput_controller.js @@ -49,6 +49,7 @@ export default class extends Controller { createOnBlur: true, create: true, dropdownParent: dropdownParent, + clearAfterSelect: true, }; if(this.element.dataset.autocomplete) { diff --git a/assets/controllers/pages/parameters_autocomplete_controller.js b/assets/controllers/pages/parameters_autocomplete_controller.js index e187aa42..4abea969 100644 --- a/assets/controllers/pages/parameters_autocomplete_controller.js +++ b/assets/controllers/pages/parameters_autocomplete_controller.js @@ -75,6 +75,7 @@ export default class extends Controller searchField: "name", //labelField: "name", valueField: "name", + clearAfterSelect: true, onItemAdd: this.onItemAdd.bind(this), render: { option: (data, escape) => { @@ -136,4 +137,4 @@ export default class extends Controller //Destroy the TomSelect instance this._tomSelect.destroy(); } -} \ No newline at end of file +} From 70919d953a65e8105340e88f9cd59c637b199653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 21:48:27 +0100 Subject: [PATCH 30/34] Allow to pass infos from barcodes to creation dialog --- src/Controller/PartController.php | 14 ++++++ .../BarcodeScanResultHandler.php | 49 ++++++++++++------- .../EIGP114BarcodeScanResult.php | 4 +- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/Controller/PartController.php b/src/Controller/PartController.php index b4f46a27..9b0f880e 100644 --- a/src/Controller/PartController.php +++ b/src/Controller/PartController.php @@ -290,6 +290,20 @@ final class PartController extends AbstractController $this->addFlash('warning', t("part.create_from_info_provider.no_category_yet")); } + $lotAmount = $request->query->get('lotAmount'); + $lotName = $request->query->get('lotName'); + $lotUserBarcode = $request->query->get('lotUserBarcode'); + + if ($lotAmount !== null || $lotName !== null || $lotUserBarcode !== null) { + $partLot = new PartLot(); + $partLot->setAmount($lotAmount !== null ? (float)$lotAmount : 0); + $partLot->setDescription($lotName !== null ? (string)$lotName : ''); + $partLot->setUserBarcode($lotUserBarcode !== null ? (string)$lotUserBarcode : ''); + + $new_part->addPartLot($partLot); + } + + return $this->renderPartForm('new', $request, $new_part, [ 'info_provider_dto' => $dto, ]); diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php index 5091b987..45fdd16e 100644 --- a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultHandler.php @@ -117,7 +117,8 @@ final readonly class BarcodeScanResultHandler throw InfoProviderNotActiveException::fromProvider($provider); } - return $this->urlGenerator->generate('info_providers_create_part', ['providerKey' => $infos['providerKey'], 'providerId' => $infos['providerId']]); + //So far we can just copy over our provider info array to the URL parameters: + return $this->urlGenerator->generate('info_providers_create_part', $infos); } /** @@ -146,7 +147,7 @@ final readonly class BarcodeScanResultHandler if ($barcodeScan instanceof AmazonBarcodeScanResult) { return $this->em->getRepository(Part::class)->getPartByProviderInfo($barcodeScan->asin) - ?? $this->em->getRepository(Part::class)->getPartBySPN($barcodeScan->asin); + ?? $this->em->getRepository(Part::class)->getPartBySPN($barcodeScan->asin); } return null; @@ -246,7 +247,7 @@ final readonly class BarcodeScanResultHandler * Returns null if no provider information could be extracted from the scan result, or if the scan result type is unknown and cannot be handled by this function. * It is not necessarily checked that the provider is active, or that the result actually exists on the provider side. * @param BarcodeScanResultInterface $scanResult - * @return array{providerKey: string, providerId: string}|null + * @return array{providerKey: string, providerId: string, lotAmount?: float|int, lotName?: string, lotUserBarcode?: string}|null * @throws InfoProviderNotActiveException If the scan result contains information for a provider which is currently not active in the system */ public function getCreateInfos(BarcodeScanResultInterface $scanResult): ?array @@ -256,6 +257,9 @@ final readonly class BarcodeScanResultHandler return [ 'providerKey' => 'lcsc', 'providerId' => $scanResult->lcscCode, + 'lotAmount' => $scanResult->quantity, + 'lotName' => $scanResult->orderNumber ?? $scanResult->pickBatchNumber, + 'lotUserBarcode' => $scanResult->rawInput, ]; } @@ -276,7 +280,7 @@ final readonly class BarcodeScanResultHandler /** * @param EIGP114BarcodeScanResult $scanResult - * @return array{providerKey: string, providerId: string}|null + * * @return array{providerKey: string, providerId: string, lotAmount?: float|int, lotName?: string, lotUserBarcode?: string}|null */ private function getCreationInfoForEIGP114(EIGP114BarcodeScanResult $scanResult): ?array { @@ -285,23 +289,26 @@ final readonly class BarcodeScanResultHandler // Mouser: use supplierPartNumber -> search provider -> provider_id if ($vendor === 'mouser' && $scanResult->supplierPartNumber !== null ) { - // Search Mouser using the MPN - $dtos = $this->infoRetriever->searchByKeyword( - keyword: $scanResult->supplierPartNumber, - providers: ["mouser"] - ); + // Search Mouser using the MPN + $dtos = $this->infoRetriever->searchByKeyword( + keyword: $scanResult->supplierPartNumber, + providers: ["mouser"] + ); - // If there are results, provider_id is MouserPartNumber (per MouserProvider.php) - $best = $dtos[0] ?? null; + // If there are results, provider_id is MouserPartNumber (per MouserProvider.php) + $best = $dtos[0] ?? null; - if ($best !== null) { - return [ - 'providerKey' => 'mouser', - 'providerId' => $best->provider_id, - ]; - } + if ($best !== null) { + return [ + 'providerKey' => 'mouser', + 'providerId' => $best->provider_id, + 'lotAmount' => $scanResult->quantity, + 'lotName' => $scanResult->customerPO, + 'lotUserBarcode' => $scanResult->rawInput, + ]; + } - return null; + return null; } // Digi-Key: supplierPartNumber directly @@ -309,6 +316,9 @@ final readonly class BarcodeScanResultHandler return [ 'providerKey' => 'digikey', 'providerId' => $scanResult->supplierPartNumber ?? throw new \RuntimeException('Digikey barcode does not contain required supplier part number'), + 'lotAmount' => $scanResult->quantity, + 'lotName' => $scanResult->digikeyInvoiceNumber ?? $scanResult->digikeySalesOrderNumber ?? $scanResult->customerPO, + 'lotUserBarcode' => $scanResult->rawInput, ]; } @@ -317,6 +327,9 @@ final readonly class BarcodeScanResultHandler return [ 'providerKey' => 'element14', 'providerId' => $scanResult->supplierPartNumber ?? throw new \RuntimeException('Element14 barcode does not contain required supplier part number'), + 'lotAmount' => $scanResult->quantity, + 'lotName' => $scanResult->customerPO, + 'lotUserBarcode' => $scanResult->rawInput, ]; } diff --git a/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php index 37c03f55..4a38b14f 100644 --- a/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php +++ b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php @@ -187,7 +187,7 @@ readonly class EIGP114BarcodeScanResult implements BarcodeScanResultInterface * * @param array $data The fields of the EIGP114 barcode, where the key is the field name and the value is the field content */ - public function __construct(public array $data) + public function __construct(public array $data, public readonly ?string $rawInput = null) { //IDs per EIGP 114.2018 $this->shipDate = $data['6D'] ?? null; @@ -306,7 +306,7 @@ readonly class EIGP114BarcodeScanResult implements BarcodeScanResultInterface $results[$key] = $fieldValue; } - return new self($results); + return new self($results, $input); } public function getDecodedForInfoMode(): array From 8727d830973924aec300e28aeeb48029fb497251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 21:54:46 +0100 Subject: [PATCH 31/34] Increase possible length of the vendor barcode column in part lots This allows us to store full 2D barcodes content there --- migrations/Version20260307204859.php | 73 ++++++++++++++++++++++++++++ src/Entity/Parts/PartLot.php | 5 +- 2 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 migrations/Version20260307204859.php diff --git a/migrations/Version20260307204859.php b/migrations/Version20260307204859.php new file mode 100644 index 00000000..325f41ab --- /dev/null +++ b/migrations/Version20260307204859.php @@ -0,0 +1,73 @@ +addSql('ALTER TABLE part_lots DROP INDEX part_lots_idx_barcode, ADD INDEX part_lots_idx_barcode (vendor_barcode(100))'); + $this->addSql('ALTER TABLE part_lots CHANGE vendor_barcode vendor_barcode LONGTEXT DEFAULT NULL'); + } + + public function mySQLDown(Schema $schema): void + { + $this->addSql('ALTER TABLE part_lots DROP INDEX part_lots_idx_barcode, ADD INDEX part_lots_idx_barcode (vendor_barcode)'); + $this->addSql('ALTER TABLE part_lots CHANGE vendor_barcode vendor_barcode VARCHAR(255) DEFAULT NULL'); + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__part_lots AS SELECT id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added, vendor_barcode, last_stocktake_at FROM part_lots'); + $this->addSql('DROP TABLE part_lots'); + $this->addSql('CREATE TABLE part_lots (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_store_location INTEGER DEFAULT NULL, id_part INTEGER NOT NULL, id_owner INTEGER DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, expiration_date DATETIME DEFAULT NULL, instock_unknown BOOLEAN NOT NULL, amount DOUBLE PRECISION NOT NULL, needs_refill BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, vendor_barcode CLOB DEFAULT NULL, last_stocktake_at DATETIME DEFAULT NULL, CONSTRAINT FK_EBC8F9435D8F4B37 FOREIGN KEY (id_store_location) REFERENCES storelocations (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F943C22F6CC4 FOREIGN KEY (id_part) REFERENCES parts (id) ON UPDATE NO ACTION ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F94321E5A74C FOREIGN KEY (id_owner) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO part_lots (id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added, vendor_barcode, last_stocktake_at) SELECT id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added, vendor_barcode, last_stocktake_at FROM __temp__part_lots'); + $this->addSql('DROP TABLE __temp__part_lots'); + $this->addSql('CREATE INDEX part_lots_idx_needs_refill ON part_lots (needs_refill)'); + $this->addSql('CREATE INDEX part_lots_idx_instock_un_expiration_id_part ON part_lots (instock_unknown, expiration_date, id_part)'); + $this->addSql('CREATE INDEX IDX_EBC8F9435D8F4B37 ON part_lots (id_store_location)'); + $this->addSql('CREATE INDEX IDX_EBC8F943C22F6CC4 ON part_lots (id_part)'); + $this->addSql('CREATE INDEX IDX_EBC8F94321E5A74C ON part_lots (id_owner)'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__part_lots AS SELECT id, description, comment, expiration_date, instock_unknown, amount, needs_refill, vendor_barcode, last_stocktake_at, last_modified, datetime_added, id_store_location, id_part, id_owner FROM part_lots'); + $this->addSql('DROP TABLE part_lots'); + $this->addSql('CREATE TABLE part_lots (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, expiration_date DATETIME DEFAULT NULL, instock_unknown BOOLEAN NOT NULL, amount DOUBLE PRECISION NOT NULL, needs_refill BOOLEAN NOT NULL, vendor_barcode VARCHAR(255) DEFAULT NULL, last_stocktake_at DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, id_store_location INTEGER DEFAULT NULL, id_part INTEGER NOT NULL, id_owner INTEGER DEFAULT NULL, CONSTRAINT FK_EBC8F9435D8F4B37 FOREIGN KEY (id_store_location) REFERENCES "storelocations" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F943C22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F94321E5A74C FOREIGN KEY (id_owner) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO part_lots (id, description, comment, expiration_date, instock_unknown, amount, needs_refill, vendor_barcode, last_stocktake_at, last_modified, datetime_added, id_store_location, id_part, id_owner) SELECT id, description, comment, expiration_date, instock_unknown, amount, needs_refill, vendor_barcode, last_stocktake_at, last_modified, datetime_added, id_store_location, id_part, id_owner FROM __temp__part_lots'); + $this->addSql('DROP TABLE __temp__part_lots'); + $this->addSql('CREATE INDEX IDX_EBC8F9435D8F4B37 ON part_lots (id_store_location)'); + $this->addSql('CREATE INDEX IDX_EBC8F943C22F6CC4 ON part_lots (id_part)'); + $this->addSql('CREATE INDEX IDX_EBC8F94321E5A74C ON part_lots (id_owner)'); + $this->addSql('CREATE INDEX part_lots_idx_instock_un_expiration_id_part ON part_lots (instock_unknown, expiration_date, id_part)'); + $this->addSql('CREATE INDEX part_lots_idx_needs_refill ON part_lots (needs_refill)'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + } + + public function postgreSQLUp(Schema $schema): void + { + $this->addSql('DROP INDEX part_lots_idx_barcode'); + $this->addSql('ALTER TABLE part_lots ALTER vendor_barcode TYPE TEXT'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->addSql('DROP INDEX part_lots_idx_barcode'); + $this->addSql('ALTER TABLE part_lots ALTER vendor_barcode TYPE VARCHAR(255)'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + } +} diff --git a/src/Entity/Parts/PartLot.php b/src/Entity/Parts/PartLot.php index f7224843..a15eeb4f 100644 --- a/src/Entity/Parts/PartLot.php +++ b/src/Entity/Parts/PartLot.php @@ -66,7 +66,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; #[ORM\Table(name: 'part_lots')] #[ORM\Index(columns: ['instock_unknown', 'expiration_date', 'id_part'], name: 'part_lots_idx_instock_un_expiration_id_part')] #[ORM\Index(columns: ['needs_refill'], name: 'part_lots_idx_needs_refill')] -#[ORM\Index(columns: ['vendor_barcode'], name: 'part_lots_idx_barcode')] +#[ORM\Index(name: 'part_lots_idx_barcode', columns: ['vendor_barcode'], options: ['lengths' => [100]])] #[ValidPartLot] #[UniqueEntity(['user_barcode'], message: 'validator.part_lot.vendor_barcode_must_be_unique')] #[ApiResource( @@ -166,9 +166,8 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named /** * @var string|null The content of the barcode of this part lot (e.g. a barcode on the package put by the vendor) */ - #[ORM\Column(name: "vendor_barcode", type: Types::STRING, nullable: true)] + #[ORM\Column(name: "vendor_barcode", type: Types::TEXT, nullable: true)] #[Groups(['part_lot:read', 'part_lot:write'])] - #[Length(max: 255)] protected ?string $user_barcode = null; /** From bcbbb1ecb96a591f0182df1d82bda88832041d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 22:01:50 +0100 Subject: [PATCH 32/34] Add a flash notice when automatically creating a part lot from scan --- src/Controller/PartController.php | 3 +++ translations/messages.en.xlf | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/Controller/PartController.php b/src/Controller/PartController.php index 9b0f880e..eb80d9bc 100644 --- a/src/Controller/PartController.php +++ b/src/Controller/PartController.php @@ -301,6 +301,9 @@ final class PartController extends AbstractController $partLot->setUserBarcode($lotUserBarcode !== null ? (string)$lotUserBarcode : ''); $new_part->addPartLot($partLot); + + $this->addFlash('notice', t('part.create_from_info_provider.lot_filled_from_barcode')); + } diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index bcd07331..6ff969ae 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -12941,5 +12941,11 @@ Buerklin-API Authentication server: Backup download allowed + + + part.create_from_info_provider.lot_filled_from_barcode + [Part_lot] created from barcode: Please check if the data is correct and desired. + + From 7f8f5990a72f00a5749491f41250e9cacbefc70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 22:30:39 +0100 Subject: [PATCH 33/34] Fixed phpstan issues --- composer.json | 5 ++ composer.lock | 2 +- phpstan.banned_code.neon | 86 +++++++++++++++++++ phpstan.dist.neon | 6 +- .../ImportExportSystem/EntityImporter.php | 6 +- 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 phpstan.banned_code.neon diff --git a/composer.json b/composer.json index 89e0f19b..9d51033e 100644 --- a/composer.json +++ b/composer.json @@ -177,6 +177,11 @@ "allow-contrib": false, "require": "7.4.*", "docker": true + }, + "phpstan/extension-installer": { + "ignore" : [ + "ekino/phpstan-banned-code" + ] } } } diff --git a/composer.lock b/composer.lock index 12a32829..8d224c67 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": "32c5677a31185e0ed124904012500154", + "content-hash": "8fd737684b48f8d24fcad35fce37a297", "packages": [ { "name": "amphp/amp", diff --git a/phpstan.banned_code.neon b/phpstan.banned_code.neon new file mode 100644 index 00000000..3099c384 --- /dev/null +++ b/phpstan.banned_code.neon @@ -0,0 +1,86 @@ +# Manually configure ekino/phpstan-banned-code to detect usage of echo, eval, die/exit, print, shell execution and a set of functions that should not be used in production code. + +parametersSchema: + banned_code: structure([ + nodes: listOf(structure([ + type: string() + functions: schema(listOf(string()), nullable()) + ])) + use_from_tests: bool() + non_ignorable: bool() + ]) + +parameters: + banned_code: + nodes: + # enable detection of echo + - + type: Stmt_Echo + functions: null + + # enable detection of eval + - + type: Expr_Eval + functions: null + + # enable detection of die/exit + - + type: Expr_Exit + functions: null + + # enable detection of a set of functions + - + type: Expr_FuncCall + functions: + - dd + - debug_backtrace + - dump + - exec + - passthru + - phpinfo + - print_r + - proc_open + - shell_exec + - system + - var_dump + + # enable detection of print statements + - + type: Expr_Print + functions: null + + # enable detection of shell execution by backticks + - + type: Expr_ShellExec + functions: null + + # enable detection of empty() + #- + # type: Expr_Empty + # functions: null + + # enable detection of `use Tests\Foo\Bar` in a non-test file + use_from_tests: true + + # when true, errors cannot be excluded + non_ignorable: false + +services: + - + class: Ekino\PHPStanBannedCode\Rules\BannedNodesRule + tags: + - phpstan.rules.rule + arguments: + - '%banned_code.nodes%' + + - + class: Ekino\PHPStanBannedCode\Rules\BannedUseTestRule + tags: + - phpstan.rules.rule + arguments: + - '%banned_code.use_from_tests%' + + - + class: Ekino\PHPStanBannedCode\Rules\BannedNodesErrorBuilder + arguments: + - '%banned_code.non_ignorable%' diff --git a/phpstan.dist.neon b/phpstan.dist.neon index b03c20c2..fe51518d 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,3 +1,6 @@ +includes: + - phpstan.banned_code.neon + parameters: level: 5 @@ -6,9 +9,6 @@ parameters: - src # - tests - banned_code: - non_ignorable: false # Allow to ignore some banned code - excludePaths: - src/DataTables/Adapter/* - src/Configuration/* diff --git a/src/Services/ImportExportSystem/EntityImporter.php b/src/Services/ImportExportSystem/EntityImporter.php index e57f2126..c33d6e6a 100644 --- a/src/Services/ImportExportSystem/EntityImporter.php +++ b/src/Services/ImportExportSystem/EntityImporter.php @@ -325,7 +325,11 @@ class EntityImporter //Iterate over each $entity write it to DB (the invalid entities were already filtered out). foreach ($entities as $entity) { - $this->persistRecursively($entity); + if ($entity instanceof AbstractStructuralDBElement) { + $this->persistRecursively($entity); + } else { + $this->em->persist($entity); + } } //Save changes to database, when no error happened, or we should continue on error. From 13b98cc0b1b096bc6ce1a15443abd696091037f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 7 Mar 2026 22:47:05 +0100 Subject: [PATCH 34/34] Fixed tests --- src/Serializer/StructuralElementDenormalizer.php | 9 ++++----- .../BarcodeScanner/EIGP114BarcodeScanResult.php | 4 +++- .../LabelSystem/BarcodeScanner/BarcodeScanHelperTest.php | 6 ++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Serializer/StructuralElementDenormalizer.php b/src/Serializer/StructuralElementDenormalizer.php index e5847c41..3da5f796 100644 --- a/src/Serializer/StructuralElementDenormalizer.php +++ b/src/Serializer/StructuralElementDenormalizer.php @@ -110,9 +110,8 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz //Check if we already have the entity in the database (via path) /** @var StructuralDBElementRepository $repo */ $repo = $this->entityManager->getRepository($type); - $deserialized_entity = $entity; - $path = $deserialized_entity->getFullPath(AbstractStructuralDBElement::PATH_DELIMITER_ARROW); + $path = $entity->getFullPath(AbstractStructuralDBElement::PATH_DELIMITER_ARROW); $db_elements = $repo->getEntityByPath($path, AbstractStructuralDBElement::PATH_DELIMITER_ARROW); if ($db_elements !== []) { //We already have the entity in the database, so we can return it @@ -128,7 +127,7 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz $entity = $this->object_cache[$type][$path]; } else { //Save the entity in the cache - $this->object_cache[$type][$path] = $deserialized_entity; + $this->object_cache[$type][$path] = $entity; } //In the next step we can denormalize the children, and add our children to the entity. @@ -142,9 +141,9 @@ class StructuralElementDenormalizer implements DenormalizerInterface, Denormaliz } //We don't have the entity in the database, so we have to persist it - $this->entityManager->persist($deserialized_entity); + $this->entityManager->persist($entity); - return $deserialized_entity; + return $entity; } public function getSupportedTypes(?string $format): array diff --git a/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php index 4a38b14f..38b20562 100644 --- a/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php +++ b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php @@ -271,6 +271,8 @@ readonly class EIGP114BarcodeScanResult implements BarcodeScanResultInterface */ public static function parseFormat06Code(string $input): self { + $rawInput = $input; + //Ensure that the input is a valid format06 code if (!self::isFormat06Code($input)) { throw new \InvalidArgumentException("The given input is not a valid format06 code"); @@ -306,7 +308,7 @@ readonly class EIGP114BarcodeScanResult implements BarcodeScanResultInterface $results[$key] = $fieldValue; } - return new self($results, $input); + return new self($results, $rawInput); } public function getDecodedForInfoMode(): array diff --git a/tests/Services/LabelSystem/BarcodeScanner/BarcodeScanHelperTest.php b/tests/Services/LabelSystem/BarcodeScanner/BarcodeScanHelperTest.php index 8f8c7a18..b06653e5 100644 --- a/tests/Services/LabelSystem/BarcodeScanner/BarcodeScanHelperTest.php +++ b/tests/Services/LabelSystem/BarcodeScanner/BarcodeScanHelperTest.php @@ -115,6 +115,8 @@ final class BarcodeScanHelperTest extends WebTestCase yield [new LocalBarcodeScanResult(LabelSupportedElement::PART_LOT, 2,BarcodeSourceType::USER_DEFINED), 'lot2_vendor_barcode']; + + $input = "[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04"; $eigp114Result = new EIGP114BarcodeScanResult([ 'P' => '596-777A1-ND', '1P' => 'XAF4444', @@ -122,9 +124,9 @@ final class BarcodeScanHelperTest extends WebTestCase '10D' => '1452', '1T' => 'BF1103', '4L' => 'US', - ]); + ], $input); - yield [$eigp114Result, "[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04"]; + yield [$eigp114Result, $input]; $lcscInput = '{pc:C138033,pm:RC0402FR-071ML,qty:10}'; $lcscResult = new LCSCBarcodeScanResult(